objective-c ios video

objective c - exportAsynchronouslyWithCompletionHandler falla con varios archivos de video(Código=-11820)



objective-c (2)

Estoy grabando pequeños videos (alrededor de un segundo, tanto con la cámara frontal como con la trasera, con posibles orientaciones diferentes). Y luego intente fusionarlos usando AVAssetExportSession. Básicamente, hago una composición y una composición de video con las transformaciones y pistas de audio y video adecuadas.

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

Esto para mí parece realmente desconcertante. ¿AVAssetExportSession está haciendo algo raro o tiene alguna limitación no documentada sobre la cantidad de clips que se le pueden pasar? 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]; [video setVideo:url at:localTimeline]; localTimeline = CMTimeAdd(localTimeline, asset.duration); // Increment the timeline } [self exportVideo]; }

Y aquí está la carne de la clase 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); }


De acuerdo, también contacté a Apple sobre este problema y me dieron una respuesta:

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

También me pidieron que presentara un informe de error sobre el problema, dado que el mensaje de error que AVAssetExportSession proporciona es vago y engañoso. Así que presenté un informe de error a Apple quejándome sobre el hecho de que el mensaje de error es malo.

Por lo tanto, estos límites en AVAssetExportSession están confirmados. 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 exportación" en lugar de decirnos que tenemos alcanzar un límite


También he encontrado un problema similar. Logré solucionarlo insertando activos en la composición, no pistas en pistas mutables. Por lo tanto, en su código para "setVideo" en lugar de esta línea:

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

prueba esto:

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