指定された時間範囲に基づいてビデオをトリミングおよびエクスポートするメソッドを作成しました。また、ビデオを横向きに回転させます。
ただし、何らかの理由で、UIVideoEditorControllerを使用して以前にトリミングされたビデオを処理しようとすると、AVAssetExportSessionが失敗します。
以前にこの問題に遭遇した人はいますか?
このエラーが発生します:
AVAssetExportSessionStatusFailed: Error Domain=AVFoundationErrorDomain Code=-11841 "The operation couldn’t be completed. (AVFoundationErrorDomain error -11841.)"
この方法の場合:
- (void) trimVideoWithRange: (CMTimeRange)range fromInputURL: (NSURL *)inputURL withCompletionHandler:(void (^)(BOOL success, NSURL *outputURL))handler;
{
AVAsset *asset = [AVURLAsset assetWithURL:inputURL];
AVAssetTrack *videoTrack = [asset tracksWithMediaType:AVMediaTypeVideo][0];
AVAssetTrack *audioTrack = [asset tracksWithMediaType:AVMediaTypeAudio][0];
NSLog(@"%@, %@, %@", asset, videoTrack, audioTrack);
NSError *error;
// Create a video composition
AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableCompositionTrack *videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
error = nil;
[videoCompositionTrack insertTimeRange:videoTrack.timeRange ofTrack:videoTrack atTime:CMTimeMakeWithSeconds(0, NSEC_PER_SEC) error:&error];
NSLog(@"videoCompositionTrack timeRange: %lld, %lld", videoCompositionTrack.timeRange.start.value, videoCompositionTrack.timeRange.duration.value);
if(error)
NSLog(@"videoCompositionTrack error: %@", error);
AVMutableCompositionTrack *audioCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
error = nil;
[audioCompositionTrack insertTimeRange:audioTrack.timeRange ofTrack:audioTrack atTime:CMTimeMakeWithSeconds(0, NSEC_PER_SEC) error:&error];
NSLog(@"audioCompositionTrack timeRange: %lld, %lld", audioCompositionTrack.timeRange.start.value, audioCompositionTrack.timeRange.duration.value);
if(error)
NSLog(@"audioCompositionTrack error: %@", error);
// Rotate video if needed
CGAffineTransform rotationTransform = videoTrack.preferredTransform;
// Create video composition
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.renderScale = 1.0;
videoComposition.renderSize = videoTrack.naturalSize;
videoComposition.frameDuration = CMTimeMake(1, 30);
// Apply the transform which may have been changed
AVMutableVideoCompositionLayerInstruction *instruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
[instruction setTransform:rotationTransform atTime:kCMTimeZero];
// Set the time range and layer instructions for the video composition
AVMutableVideoCompositionInstruction *videoTrackInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
videoTrackInstruction.layerInstructions = [NSArray arrayWithObject:instruction];
videoTrackInstruction.timeRange = range;
videoComposition.instructions = @[videoTrackInstruction];
// Check so that we can proceed with our desired output preset
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:composition];
if (![compatiblePresets containsObject:AVAssetExportPreset960x540])
{
// Nope.
if(handler)
handler(NO, nil);
return;
}
// Create export session with composition
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPreset960x540];
// Configure export session
exportSession.outputURL = [NSURL fileURLWithPath:pathToTemporaryOutput];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
exportSession.videoComposition = videoComposition;
exportSession.shouldOptimizeForNetworkUse = YES;
// Export async
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status])
{
case AVAssetExportSessionStatusCompleted:
{
dispatch_async(dispatch_get_main_queue(), ^{
// Everything OK. Execute completion block with URL to rendered video
if(handler)
handler(exportSession.status == AVAssetExportSessionStatusCompleted, [NSURL fileURLWithPath:pathToTemporaryOutput]);
});
}
break;
case AVAssetExportSessionStatusFailed:
{
NSError *exportError = exportSession.error;
NSLog(@"AVAssetExportSessionStatusFailed: %@", exportError.description);
dispatch_async(dispatch_get_main_queue(), ^{
// No go. Execute handler with fail.
if(handler)
handler(NO, nil);
});
}
break;
}
}];
}