2013-11-26 11 views
6

Próbuję konwertować wideo .mov na .mp4 i jednocześnie korygować orientację. Kod używam poniżej działa świetnie podczas nagrywania wideo za pomocą UIImagePickerController jednak jeśli film jest wybrany z rolki aparatu otrzymuję ten błąd i nie widzę dlaczego:Błąd obracania AVAssetExportSession, gdy wideo pochodzi z rolki kamery.

Export failed: Operation Zatrzymany: Błąd domain = Kod AVFoundationErrorDomain = -11841 "Operacja zatrzymana" UserInfo = 0x1815ca50 {NSLocalizedDescription = Operacja zatrzymana, NSLocalizedFailureReason = film nie mógł być złożony.}

próbowałem najpierw zapisywanie wideo do innego pliku, ale to nie miało znaczenia.

Oto kod używam do konwersji wideo:

- (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; 
} 

Odpowiedz

13

AVFoundation Błąd Stała -11841 oznacza, że ​​masz nieprawidłowy skład wideo. Zobacz ten link, jeśli chcesz uzyskać więcej informacji na temat stałych błędów: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVFoundation_ErrorConstants/Reference/reference.html

Podczas gdy nie pojawiają się u mnie żadne poważne błędy, mogę zasugerować następujące sposoby zawężenia źródła problemu.

Po pierwsze, zamiast przekazywać nil parametru w tych połączeń error:

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

utworzyć obiekt NSError i przekazać odniesienie do niej tak:

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

Zbadać błąd, aby upewnij się, że twoje ścieżki audio i wideo zostały poprawnie wstawione do ścieżki kompozycji. Błąd powinien być nil, jeśli wszystko pójdzie dobrze.

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

Można też, by sprawdzić wiadomości AVAsset za composable i exportable i hasProtectedContent właściwości. Jeśli nie są to odpowiednio TAK, TAK i NIE, możesz mieć problem z utworzeniem nowego pliku wideo.

Czasami widziałem problem polegający na tym, że tworzenie przedziału czasowego dla ścieżki dźwiękowej nie odpowiada 600-krotnej skali czasu w przypadku korzystania z kompozycji ze ścieżką wideo. Możesz utworzyć nowy CMTime na czas (avAsset.duration) w

CMTimeRangeMake(kCMTimeZero, avAsset.duration) 

tylko na wstawianie ścieżki dźwiękowej. W nowym CMTime użyj skali czasowej 44100 (lub jakiejkolwiek częstotliwości próbkowania ścieżki audio). To samo dotyczy Twojego videoComposition.frameDuration. W zależności od numeru ścieżki wideo, Twój czas może nie być poprawnie odwzorowany w 600-stopniowej skali.

Wreszcie, jest to pomocne narzędzie dostarczane przez firmę Apple do kompozycji wideo Debug:

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

Daje wizualną reprezentację swojego składu i można zobaczyć, gdzie rzeczy nie wyglądają tak jak powinny.

+0

dziękuję za bardzo szczegółową odpowiedź. Nadal nie mogę go uruchomić :( 'composable',' exportable' & 'hasProtectedContent' are4 wszystko, co powinieneś.Jednak nie ma błędów zwrócony z pierwszej sugestii.Próbowałem zmienić ścieżkę audio, aby użyć 44 100. Jeśli skomentuję 'exportSession.videoComposition = videoComposition;' działa dobrze, ale wideo nie jest obrócone, więc problem musi gdzieś tam być.Dziękuję – Darren

+0

Zauważam, że tworzysz 'AVMutableComposition' w' - (AVMutableVideoComposition *) getVideoComposition', i stwórz 'AVMutableCompositionTrack's z tego.} Jednakże w' - (void) convertVideoToLowQuailtyAndFixRotationWithInputURL: handler: ' , masz _różny_" AVMutableComposition ", który przechodzisz do' AVExportSession'. Spróbuj przekazać tę kompozycję do getVideoComposition aby utworzyć ścieżki AVMutableComposition Track z niego, więc jest tylko jeden. – jlw

+0

Po prostu próbowałem przesuwać 'AVMutableVideoComposition' za pomocą' AVMutableVideoCompositionLayerInstruction' do głównej metody konwersji, tak aby zawierała tylko 1 'AVMutableComposition', ale wciąż takie same wyniki. Wybierając wideo z rolki aparatu, kompresuje je przed przekazaniem, nie będąc pewnym, czy to właśnie robi różnicę. – Darren

2

Spróbuj komentując poniżej linii i uruchomić projekt

exportSession.videoComposition = videoComposition; 
+0

To zadziałało dla mnie. Dzięki –

+2

To usunie wszelkie transformacje, zbiory itp. Dodane do zmieniającego się składu wideo, więc nie ma w tym przypadku zastosowania. –

+0

To działało również dla mnie. Jestem ciekawy dlaczego. Czy ktoś wie? –

1

powinno się używać isValidForAsset metoda: timeRange: validationDelegate: od AVVideoCompostion będzie zdiagnozować problem ze swoim składzie wideo. miałem ten sam problem i rozwiązanie dla mnie było stworzenie layerInstruction z AVMutableCompositionTrack zamiast oryginalnego utworu:

layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack]; 
Powiązane problemy