ios avfoundation avassetexportsession

ios - AVAssetExportSession deja de progresar



avfoundation (3)

¡He encontrado eso!

Necesitas establecer las instrucciones de capa correctas:

AVMutableCompositionTrack *track = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; AVMutableVideoCompositionLayerInstruction * layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:track]; AVMutableVideoCompositionInstruction * MainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; MainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, allTime); MainInstruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];

De lo contrario simplemente se atascó.

Tengo un problema con AVAssetExportSession donde el progreso deja de aumentar pero el estado aún dice que se está exportando. Esto es realmente una ocurrencia bastante rara, funciona sin problemas aproximadamente el 99.99% del tiempo, pero quiero solucionar el problema de todos modos.

Así que empiezo la exportación:

exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetMediumQuality]; exportSession.videoComposition = videoComposition; exportSession.outputFileType = @"com.apple.quicktime-movie"; exportSession.outputURL = outputURL; [exportSession exportAsynchronouslyWithCompletionHandler:^{ ... }];

Entonces ten un temporizador que compruebe el progreso:

AVAssetExportSessionStatus status = [exportSession status]; float progress = 0; if (status == AVAssetExportSessionStatusExporting) { progress = [exportSession progress]; } else if (status == AVAssetExportSessionStatusCompleted) { progress = 1; } NSLog(@"%d %f", status, progress); [delegate processor:self didProgress:progress];

Y la salida termina pareciéndose a:

2012-05-23 14:28:59.494 **********[1899:707] 2 0.125991 2012-05-23 14:28:59.994 **********[1899:707] 2 0.185280 2012-05-23 14:29:00.494 **********[1899:707] 2 0.259393 2012-05-23 14:29:00.994 **********[1899:707] 2 0.326093 2012-05-23 14:29:01.494 **********[1899:707] 2 0.400206 2012-05-23 14:29:01.995 **********[1899:707] 2 0.481729 2012-05-23 14:29:02.495 **********[1899:707] 2 0.541019 2012-05-23 14:29:02.997 **********[1899:707] 2 0.622542 2012-05-23 14:29:03.493 **********[1899:707] 2 0.681832 2012-05-23 14:29:03.995 **********[1899:707] 2 0.763355 2012-05-23 14:29:04.494 **********[1899:707] 2 0.822645 2012-05-23 14:29:04.994 **********[1899:707] 2 0.880082 2012-05-23 14:29:05.493 **********[1899:707] 2 0.880082 2012-05-23 14:29:05.994 **********[1899:707] 2 0.880082 ... 2012-05-23 14:43:22.994 **********[1899:707] 2 0.880082 2012-05-23 14:43:23.493 **********[1899:707] 2 0.880082 2012-05-23 14:43:23.994 **********[1899:707] 2 0.880082 2012-05-23 14:43:24.494 **********[1899:707] 2 0.880082

(Nota: no se detiene en el mismo porcentaje cada vez, es totalmente aleatorio)

Como puede ver en las marcas de tiempo, tardó 5 segundos en hacer el primer 88%, y luego lo dejé correr por otros 13 minutos (el procesamiento completo del video generalmente no toma más de 10 segundos) sin cambios en el progreso.

Actualmente, mi única opción es verificar si el progreso no ha cambiado en los últimos X segundos y solo decirle al usuario que falló y volver a intentarlo.

¿Alguien tiene alguna idea?


En mi caso, este problema provino de mp4s que fueron codificados con configuraciones inusuales. Pero en última instancia, un error en el código de Apple causa el problema.

Específicamente estaba trabajando con mp4s en Facebook. Parece que cuando Facebook codifica videos, cae o cambia el primer cuadro de la pista de video. El examen del video con ffprobe mostró:

"r_frame_rate": "722/25", "avg_frame_rate": "722/25", "time_base": "1/28880", "start_pts": 1000, "start_time": "0.034626",

0.034626 es exactamente el tiempo para el fotograma 2. La pista de audio, sin embargo, comenzó en 0.

Desafortunadamente, las API de Apple no informan correctamente esta hora de inicio para la pista. Después de obtener el AVAssetTrack del AVAsset y verificar su timeRange, informó que la hora de inicio era 0. Es posible que no esté entendiendo la naturaleza de la sincronización de la pista y los recursos, pero esto parece un error.

Por supuesto, al crear la composición de video para la sesión de exportación, utilicé el rango de tiempo de seguimiento que era incorrecto. Sospecho que cuando la sesión de exportación busca datos en la pista en el momento 0 y no encuentra nada, se confunde, y luego, como hemos visto, simplemente se cuelga y ni siquiera informa un error, otro error. Incluso crear la composición con videoCompositionWithPropertiesOfAsset: no ayuda.

Todavía no he intentado usar AVAssetReader y AVAssetWriter en lugar de AVAssetExportSession, así que no sé si se encontraría con la misma situación allí. Hasta que tenga más tiempo para explorar que he encontrado este truco como solución:

Restablezca el intervalo de tiempo utilizado para la inserción de pistas y las instrucciones de video para comenzar en 1 o 2 cuadros en:

CMTimeRange videoTimeRange = videoTrack.timeRange; videoTimeRange.start = CMTimeMake(1, ceil(videoTrack.nominalFrameRate));

Obviamente, este truco solo se aplica a la situación particular en la que la hora de inicio de la pista de video no es 0. Supongo que, en general, este error se debe a las inusuales codificaciones de medios que AVAssetExportSession y sus clases relacionadas no esperan.


Me pregunto si es un problema con el enhebrado, si el temporizador y el exportador terminan en diferentes hilos. (La guía AVFoundation dice que no se garantiza que el exportador se ejecute en ningún subproceso en particular).

¿Ha intentado usar la observación de valores clave en lugar de un temporizador?

Ejemplo de Barebones:

// register for the notification [exportSession addObserver:someProcessor forKeyPath:@"progress" options:NSKeyValueObservingOptionNew context:NULL];

Luego en su procesador:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { // add some checks here NSNumber *processNumber = [change objectForKey:NSKeyValueChangeNewKey]; float process = [processNumber floatValue]; [delegate processor:self didProgress:progress]; }