3

我创建了一种根据给定时间范围修剪和导出视频的方法。它还将视频旋转为横向。

但由于某种原因,在尝试处理之前使用 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;
        }




    }];
}
4

1 回答 1

1

这对我有用。这里exportSessionAVAssetExportSession

NSURL *videoFileUrl = [NSURL fileURLWithPath:self.originalVideoPath];

AVAsset *anAsset = [[AVURLAsset alloc] initWithURL:videoFileUrl options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:anAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetMediumQuality]) {

    self.exportSession = [[AVAssetExportSession alloc]
                          initWithAsset:anAsset presetName:AVAssetExportPresetPassthrough];
    // Implementation continues.

    NSURL *furl = [NSURL fileURLWithPath:self.tmpVideoPath];

    self.exportSession.outputURL = furl;
    //provide outputFileType acording to video format extension
    self.exportSession.outputFileType = AVFileTypeQuickTimeMovie;

    CMTime start = CMTimeMakeWithSeconds(self.startTime, anAsset.duration.timescale);
    CMTime duration = CMTimeMakeWithSeconds(self.stopTime-self.startTime, anAsset.duration.timescale);
    CMTimeRange range = CMTimeRangeMake(start, duration);
    self.exportSession.timeRange = range;

    self.self.btnTrim.hidden = YES;
    self.myActivityIndicator.hidden = NO;
    [self.myActivityIndicator startAnimating];
    [self.exportSession exportAsynchronouslyWithCompletionHandler:^{

        switch ([self.exportSession status]) {
            case AVAssetExportSessionStatusFailed:
                NSLog(@"Export failed: %@", [[self.exportSession error] localizedDescription]);
                break;
            case AVAssetExportSessionStatusCancelled:
                NSLog(@"Export canceled");
                break;
            default:
                NSLog(@"Triming Completed");
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.myActivityIndicator stopAnimating];
                    self.myActivityIndicator.hidden = YES;
                });

                break;
        }
    }];

}
于 2013-05-01T07:49:23.860 回答