2013-11-26 34 views
6

我想將.mov視頻轉換爲.mp4,並在同一時間更正方向。 如果視頻從相機膠捲我得到這個錯誤選擇的記錄使用UIImagePickerController但是視頻時,我用下面的代碼的偉大工程,我不明白爲什麼:AVAssetExportSession旋轉錯誤當視頻來自相機滾動

導出失敗:操作已停止:錯誤 域名= AVFoundationErrorDomain代碼= -11841 「停止運行」 的UserInfo = {0x1815ca50 = NSLocalizedDescription停止運行, NSLocalizedFailureReason =該視頻無法組成。}

我已經試過先保存視頻到另一個文件,但它沒有任何區別。

這裏是我使用的視頻轉換代碼:

- (void)convertVideoToLowQuailtyAndFixRotationWithInputURL:(NSURL*)inputURL handler:(void (^)(NSURL *outURL))handler 
{ 
    if ([[inputURL pathExtension] isEqualToString:@"MOV"]) 
    { 
     NSURL *outputURL = [inputURL URLByDeletingPathExtension]; 
     outputURL = [outputURL URLByAppendingPathExtension:@"mp4"]; 

     AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:inputURL options:nil]; 

     AVAssetTrack *sourceVideoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 
     AVAssetTrack *sourceAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; 

     AVMutableComposition* composition = [AVMutableComposition composition]; 

     AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo 
                        preferredTrackID:kCMPersistentTrackID_Invalid]; 
     [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) 
             ofTrack:sourceVideoTrack 
             atTime:kCMTimeZero error:nil]; 
     [compositionVideoTrack setPreferredTransform:sourceVideoTrack.preferredTransform]; 

     AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio 
                        preferredTrackID:kCMPersistentTrackID_Invalid]; 
     [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) 
             ofTrack:sourceAudioTrack 
             atTime:kCMTimeZero error:nil]; 

     AVMutableVideoComposition *videoComposition = [self getVideoComposition:avAsset]; 

     NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset]; 
     if ([compatiblePresets containsObject:AVAssetExportPresetMediumQuality]) 
     { 
      AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:composition presetName:AVAssetExportPresetMediumQuality]; 
      exportSession.outputURL = outputURL; 
      exportSession.outputFileType = AVFileTypeMPEG4; 
      exportSession.shouldOptimizeForNetworkUse = YES; 
      exportSession.videoComposition = videoComposition; 
      [exportSession exportAsynchronouslyWithCompletionHandler:^{ 

       switch ([exportSession status]) 
       { 
        case AVAssetExportSessionStatusFailed: 
         NSLog(@"Export failed: %@ : %@", [[exportSession error] localizedDescription], [exportSession error]); 
         handler(nil); 

         break; 
        case AVAssetExportSessionStatusCancelled: 

         NSLog(@"Export canceled"); 
         handler(nil); 

         break; 
        default: 

         handler(outputURL); 

         break; 

       } 
      }]; 
     } 

    } else { 
     handler(inputURL); 
    } 
} 

- (AVMutableVideoComposition *)getVideoComposition:(AVAsset *)asset 
{ 
    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 
    AVMutableComposition *composition = [AVMutableComposition composition]; 
    AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; 
    CGSize videoSize = videoTrack.naturalSize; 
    BOOL isPortrait_ = [self isVideoPortrait:asset]; 
    if(isPortrait_) { 
//  NSLog(@"video is portrait "); 
     videoSize = CGSizeMake(videoSize.height, videoSize.width); 
    } 
    composition.naturalSize  = videoSize; 
    videoComposition.renderSize = videoSize; 
    videoComposition.frameDuration = CMTimeMakeWithSeconds(1/videoTrack.nominalFrameRate, 600); 

    AVMutableCompositionTrack *compositionVideoTrack; 
    compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:videoTrack atTime:kCMTimeZero error:nil]; 
    AVMutableVideoCompositionLayerInstruction *layerInst; 
    layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; 
    [layerInst setTransform:videoTrack.preferredTransform atTime:kCMTimeZero]; 
    AVMutableVideoCompositionInstruction *inst = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
    inst.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration); 
    inst.layerInstructions = [NSArray arrayWithObject:layerInst]; 
    videoComposition.instructions = [NSArray arrayWithObject:inst]; 
    return videoComposition; 
} 

回答

13

AVFoundation錯誤常量-11841意味着你有一個無效的視頻組成。看到這個鏈接,如果你想了解更多關於錯誤常量的信息: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVFoundation_ErrorConstants/Reference/reference.html

雖然沒有重大錯誤立即彈出,但我可以建議採用以下方法來縮小問題的根源。

首先,強似nilerror參數在這些調用:

[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) 
             ofTrack:sourceVideoTrack 
             atTime:kCMTimeZero error:nil]; 

創建一個NSError對象和引用傳遞給它,像這樣:

NSError *error = nil; 
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) 
             ofTrack:sourceVideoTrack 
             atTime:kCMTimeZero error:&error]; 

檢查錯誤,使確保您的視頻和音頻軌道正確插入合成軌道。如果一切順利,錯誤應該是nil

if(error) 
    NSLog(@"Insertion error: %@", error); 

您可能還需要檢查你的AVAsset的composableexportable,並hasProtectedContent性能。如果這些分別不是YES,YES和NO,則在創建新視頻文件時可能會遇到問題。

偶爾我遇到了一個問題,即在帶有視頻軌道的合成中使用時,爲音軌創建時間範圍不像600時間標度。你可能想在

CMTimeRangeMake(kCMTimeZero, avAsset.duration) 

創造的持續時間(avAsset.duration)的新CMTime僅用於插入音頻軌道。在新的CMTime中,使用44100的時間刻度(或音軌的採樣率)。videoComposition.frameDuration也是如此。根據您的視頻軌道的nominalFrameRate,您的時間可能無法用600時標正確表示。

最後,還有蘋果提供調試視頻組成一個有用的工具:

https://developer.apple.com/library/mac/samplecode/AVCompositionDebugViewer/Introduction/Intro.html

它給你的作文的視覺表現,你能看到的東西並不像他們應該。

+0

感謝您非常詳細的答覆。我仍然無法使用它:( 'composable','exportable'&'hasProtectedContent' are4 all as you say。從你的第一個建議中沒有返回錯誤,我試着改變音軌使用44,100。 如果我註釋掉'exportSession.videoComposition = videoComposition',它可以正常工作,但視頻不會旋轉,所以問題肯定在某處。謝謝 – Darren

+0

我注意到你在' - (AVMutableVideoComposition *)中創建了一個'AVMutableComposition',然後在' - (void)convertVideoToLowQuailtyAndFixRotationWithInputURL:handler:' ,你有一個傳遞給'AVExportSession'的_different_'AVMutableComposition'。試着將這個組合傳遞給getVideoComposition',然後創建'AVMutableCompositionTrack'。從它創建AVMutableCompositionTracks,所以只有一個。 – jlw

+0

我只是嘗試將'AVMutableVideoComposition'與'AVMutableVideoCompositionLayerInstruction'一起移動到主轉換方法中,因此它只有1個'AVMutableComposition',但結果仍然相同。從相機膠捲中選擇一個視頻時,它會在將它傳遞過來之前對其進行壓縮,但不知道這是否有所不同。 – Darren

2

嘗試註釋以下行並運行項目

exportSession.videoComposition = videoComposition; 
+0

這對我有效。謝謝 –

+2

這將刪除添加到可變視頻作品中的任何轉換,作物等,因此在這種情況下無法使用。 –

+0

這也適用於我。但我很好奇。有人知道嗎? –

1

你一定要使用的方法isValidForAsset:TIMERANGE:validationDelegate:AVVideoCompostion,就會診斷任何問題與您的視頻組成。 我有同樣的問題,對我來說,解決方案是創建與AVMutableCompositionTrack代替了原來的軌道layerInstruction:

layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack];