2012-12-29 17 views
7

Nagrywam małe klipy wideo (około jednej sekundy, z przednim i tylnym aparatem, z możliwymi różnymi orientacjami). A następnie spróbuj połączyć je za pomocą AVAssetExportSession. Zasadniczo tworzę kompozycję i videoComposition z właściwymi transformacjami i ścieżkami wideo audio.exportAsynchronouslyWithCompletionHandler kończy się niepowodzeniem z wieloma plikami wideo (Code = -11820)

Problem polega na tym, że na iOS 5 nie powiedzie się, jeśli masz więcej niż 4 klipy wideo, a na iOS 6 limit wynosi 16 klipów.

To dla mnie wydaje się naprawdę zagadkowe. Czy AVAssetExportSession robi coś dziwnego, czy też ma jakieś nieudokumentowane ograniczenie liczby klipów, które można do niego przekazać? Oto kilka fragmentów z mojego kodu:

-(void)exportVideo 
{ 
    AVMutableComposition *composition = video.composition; 
    AVMutableVideoComposition *videoComposition = video.videoComposition; 
    NSString * presetName = AVAssetExportPresetMediumQuality; 

    AVAssetExportSession *_assetExport = [[AVAssetExportSession alloc] initWithAsset:composition presetName:presetName]; 
    self.exportSession = _assetExport; 

    videoComposition.renderSize = CGSizeMake(640, 480); 
    _assetExport.videoComposition = videoComposition; 

    NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent: @"export.mov"]; 
    NSURL *exportUrl = [NSURL fileURLWithPath:exportPath]; 

    // Delete the currently exported files if it exists 
    if([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) 
     [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil]; 

    _assetExport.outputFileType = AVFileTypeQuickTimeMovie; 
    _assetExport.outputURL = exportUrl; 
    _assetExport.shouldOptimizeForNetworkUse = YES; 

    [_assetExport exportAsynchronouslyWithCompletionHandler:^{ 
     switch (_assetExport.status) 
     { 
      case AVAssetExportSessionStatusCompleted: 
       NSLog(@"Completed exporting!"); 
       break; 
      case AVAssetExportSessionStatusFailed: 
       NSLog(@"Failed:%@", _assetExport.error.description); 
       break; 
      case AVAssetExportSessionStatusCancelled: 
       NSLog(@"Canceled:%@", _assetExport.error); 
       break; 
      default: 
       break; 
     } 
    }]; 
} 

A oto jak kompozycje są:

-(void)setVideoAndExport 
{ 
    video = nil; 
    video = [[VideoComposition alloc] initVideoTracks]; 

    CMTime localTimeline = kCMTimeZero; 

    // Create the composition of all videofiles 
    for (NSURL *url in outputFileUrlArray) { 
     AVAsset *asset = [[AVURLAsset alloc]initWithURL:url options:nil]; 
     [video setVideo:url at:localTimeline]; 
     localTimeline = CMTimeAdd(localTimeline, asset.duration); // Increment the timeline 
    } 
    [self exportVideo]; 
} 

A oto mięso klasy VideoComposition:

-(id)initVideoTracks 
{ 
    if((self = [super init])) 
    { 
     composition = [[AVMutableComposition alloc] init]; 
     addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
     mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
     instructions = [[NSMutableArray alloc] init]; 
     videoComposition = [AVMutableVideoComposition videoComposition]; 
    } 
    return self; 
} 


-(void)setVideo:(NSURL*) url at:(CMTime)to 
{ 
    asset = [[AVURLAsset alloc]initWithURL:url options:nil]; 

    AVAssetTrack *assetTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 

    AVMutableCompositionTrack *compositionTrackVideo = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [compositionTrackVideo insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack: assetTrack atTime:to error:nil]; 

    AVMutableCompositionTrack *compositionTrackAudio = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [compositionTrackAudio insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:[[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:to error:nil]; 

    mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeAdd(to, asset.duration)); 

    AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionTrackVideo]; 

    [layerInstruction setTransform: assetTrack.preferredTransform atTime: kCMTimeZero]; 
    [layerInstruction setOpacity:0.0 atTime:CMTimeAdd(to, asset.duration)]; 
    [instructions addObject:layerInstruction]; 

    mainInstruction.layerInstructions = instructions; 
    videoComposition.instructions = [NSArray arrayWithObject:mainInstruction]; 
    videoComposition.frameDuration = CMTimeMake(1, 30); 
} 

Odpowiedz

2

Ja również spotkałem się podobny problem. Udało mi się to naprawić, wstawiając zasoby do kompozycji, a nie ślady na zmienne ścieżki. Tak więc, w kodzie dla "setVideo" zamiast tej linii:

[compositionTrackVideo insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack: assetTrack atTime:to error:nil]; 

spróbuj tego:

[self insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofAsset:asset atTime:to error:nil] 
+1

Fajnie, myślę, że muszę to wypróbować. Już omijałem problem, zawsze robiąc kompozycję po każdym nagraniu (w tle), więc nie więcej niż dwa filmy są w rzeczywistości łączone. – Karvapallo

+0

Naprawdę nie mogłem tego zrobić. Może transformacje muszą być stosowane inaczej (lub po prostu nie będą działać) z tym podejściem. Czy zdarzy ci się mieć przykładowy kod leżący w pobliżu? – Karvapallo

+0

Ostatnio stworzony kod w naszym projekcie został przepisany przy użyciu AVCompositionTrackSegment. Tworzymy szereg segmentów ścieżek, sprawdzamy je i przypisujemy do właściwości segmentów AVMutableCompositionTrack. Robimy wiele czasu rozciągania/kompresji (zmiana prędkości wideo) i ta metoda zapewnia bardziej precyzyjny skład. – Jeepston

7

Okay, ja też kontaktuje się z Apple o tym problemie i dali odpowiedź:

"Jest to znany warunek: uderzasz w limit dekodera ustawiony w AVFoundation."

Poprosili mnie również o przesłanie zgłoszenia błędu dotyczącego problemu, ponieważ komunikat o błędzie, który podaje AVAssetExportSession, jest niejasny i wprowadzający w błąd. Więc zgłosiłem zgłoszenie błędu do Apple narzekającego na fakt, że komunikat o błędzie jest zły.

Te limity w AVAssetExportSession są potwierdzone. W systemie iOS 5 limit dekodowania wynosi 4, a w systemie iOS 6 został podniesiony do 16. Głównym problemem jest to, że błąd zgłoszony przez AVAssetExportSession jest zły, ponieważ raportuje tylko: 11820 "Nie można ukończyć eksportu" zamiast faktycznie powiedzieć nam, że mamy osiągnij limit.

Powiązane problemy