2012-12-29 17 views
7

Sto registrando piccoli video clip (circa un secondo circa, con la fotocamera anteriore e posteriore, con possibili orientamenti diversi). Quindi provare a unirli utilizzando AVAssetExportSession. Fondamentalmente realizzo una composizione e una composizione video con le giuste trasformazioni e tracce audio video &.exportAsynchronouslyWithCompletionHandler ha esito negativo con più file video (Codice = -11820)

Il problema è che su iOS 5 fallisce se si hanno più di 4 video clip e su iOS 6 il limite sembra essere di 16 clip.

Questo per me sembra davvero sconcertante. AVAssetExportSession fa qualcosa di strano o presenta qualche limitazione non documentata sul numero di clip che possono essere passati ad esso? Ecco alcuni estratti dal mio codice:

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

Ed ecco come le composizioni sono fatte:

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

Ed ecco la carne della classe 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); 
} 

risposta

2

ho anche incontrato problema simile Sono riuscito a sistemarlo inserendo asset in composizione, non tracce in tracce mutabili. Così, nel codice per "setVideo" invece di questa linea:

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

provare questo:

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

Bello, penso di aver bisogno di provarlo. Ho già aggirato il problema effettuando sempre una composizione dopo ogni registrazione (sullo sfondo) in modo che non vengano mai composti più di due video. – Karvapallo

+0

Non riuscivo davvero a farlo funzionare. Forse le trasformazioni devono essere applicate in modo diverso (o semplicemente non funzioneranno) con questo approccio. Ti capita di avere qualche codice di esempio in giro? – Karvapallo

+0

Il codice creato di recente composizione nel nostro progetto è stato riscritto utilizzando AVCompositionTrackSegment. Creiamo una serie di segmenti di traccia, li convalidiamo e assegniamo alle proprietà dei segmenti di AVMutableCompositionTrack. Stiamo facendo molto stretching/compressione (cambiando la velocità del video) e questo metodo fornisce una composizione più precisa. – Jeepston

7

Va bene, ho anche contattato di Apple su questo problema e hanno dato una risposta:

"Questa è una condizione nota. Stai colpendo il limite del decodificatore impostato in AVFoundation."

Mi hanno anche chiesto di presentare una segnalazione di errore sul problema, poiché il messaggio di errore che AVAssetExportSession fornisce se vago e fuorviante. Così ho presentato una segnalazione di bug a Apple lamentandosi del fatto che il messaggio di errore è sbagliato.

Quindi questi limiti in AVAssetExportSession sono confermati. In iOS 5 il limite del decoder è 4 e in iOS 6 è stato portato a 16. Il problema principale qui è che l'errore segnalato da AVAssetExportSession è errato poiché riporta solo: 11820 "Impossibile completare l'esportazione" invece di dirci che abbiamo colpire un limite.

Problemi correlati