exportAsynchronouslyWithCompletionHandler falla con varios files de video (Código = -11820)

Estoy grabando pequeños clips de video (alnetworkingedor de un segundo más o less, con la camera delantera y trasera, con posibles orientaciones diferentes). Y luego intente fusionarlos usando AVAssetExportSession. Básicamente, hago una composition y una composition de video con las transformaciones adecuadas y las pistas de audio y video.

El problema es que en iOS 5 falla si tienes más de 4 videoclips y en iOS 6 el límite parece ser 16 clips.

Esto para mí parece realmente desconcertante. ¿AVAssetExportSession está haciendo algo extraño o tiene alguna limitación no documentada sobre el número de clips que se pueden pasar a él? Aquí hay algunos extractos de mi código:

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

Y así es como se hacen las composiciones:

 -(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]; ; localTimeline = CMTimeAdd(localTimeline, asset.duration); // Increment the timeline } [self exportVideo]; } 

Y aquí está la carne de la class VideoComposition:

 -(id)initVideoTracks { if((self = [super init])) { composition = [[AVMutableComposition alloc] init]; addMutableTrackWithMediaType:AVMediaTypeVideo prefernetworkingTrackID: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 prefernetworkingTrackID:kCMPersistentTrackID_Invalid]; [compositionTrackVideo insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack: assetTrack atTime:to error:nil]; AVMutableCompositionTrack *compositionTrackAudio = [composition addMutableTrackWithMediaType:AVMediaTypeAudio prefernetworkingTrackID: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.prefernetworkingTransform 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); } 

Bien, también contacté a Apple sobre este problema y me respondieron:

"Esta es una condición conocida. Estás golpeando el límite del decodificador establecido en AVFoundation".

También me pidieron que presente un informe de error sobre el problema, ya que el post de error que AVAssetExportSession da si es vago y engañoso. Así que archivé un informe de error a Apple quejándose sobre el hecho de que el post de error es malo.

Entonces, se confirman estos límites en AVAssetExportSession. En iOS 5, el límite del decodificador es 4 y en iOS 6 se elevó a 16. El problema principal aquí es que el error informado por AVAssetExportSession es malo, ya que solo informa: 11820 "No se puede completar la export" en lugar de decirnos realmente que tenemos golpear un limite

También he encontrado un problema similar. Me las arreglé para insert los resources en la composition, no rastrear en pistas mutables. Entonces, en su código para "setVideo" en lugar de esta línea:

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

testing esto:

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