AVAssetWriterInput H.264 Passthrough to QuickTime (.mov) – ¿Pasando en SPS / PPS para crear el átomo de avcC?

Tengo una secuencia de H.264 / AVC NAL que consiste en los types 1 (marco P), 5 (marco I), 7 (SPS) y 8 (PPS). Quiero escribirlos en un file .mov sin volver a codificarlos. Estoy intentando usar AVAssetWriter para hacer esto. La documentation para AVAssetWriterInput indica:

Pasar nil para outputSettings indica a la input que pase muestras muestreadas, sin procesar antes de que se escriban en el file de salida. Esto es útil si, por ejemplo, agrega búferes que ya están en un formatting comprimido deseable. Sin embargo, el passthrough es compatible actualmente solo cuando se escribe en files QuickTime Movie (es decir, el AVAssetWriter se inicializó con AVFileTypeQuickTimeMovie). Para otros types de file, debe especificar la configuration de salida no nula.

Estoy intentando crear CMSampleBuffers fuera de estos NAL y agregarlos a la input del escritor de activos, pero no puedo ingresar los datos de una manera que produzca un file .mov bien formado, y no puedo encontrar ninguna pista en ningún lugar sobre cómo hacer esto

El mejor resultado que he obtenido hasta ahora es pasar las NAL en el formatting de flujo de bytes del anexo B (en el order 7 8 5 1 1 1 … repetir) y reproducir el resultado en VLC. Debido a esto, sé que las NAL contienen datos válidos, pero debido a que el file .mov no tenía un átomo avcC y el átomo mdat se llenó con un flujo de bytes del anexo B, QuickTime no reproducirá el video.

Ahora estoy tratando de pasar los NAL con un campo de longitud de 4 bytes (según lo especificado por el campo lengthSizeMinusOne ) en lugar del delimitador del anexo B, que es como se supone que deben estar empaquetados en el átomo de mdat en la medida en que yo saber.

No tengo experiencia en cómo hacer que el escritor de activos escriba un átomo de AVCC. Cada muestra que anexo solo se introduce en el átomo de mdat.

¿Alguien sabe cómo puedo pasar los datos H.264 sin procesar a un AVAssetWriterInput configurado para pasar a través (nil outputSettings) y hacer que genere un file QuickTime correctamente formado?

He enviado una TSI con manzana y encontré la respuesta. Espero que esto ahorre time a alguien en el futuro.

Los CMSampleBuffers han asociado con ellos una CMFormatDescription, que contiene una descripción de los datos en el búfer de muestra.

El prototipo de function para crear la descripción de formatting es el siguiente:

 OSStatus CMVideoFormatDescriptionCreate ( CFAllocatorRef allocator, CMVideoCodecType codecType, int32_t width, int32_t height, CFDictionaryRef extensions, CMVideoFormatDescriptionRef *outDesc ); 

Aprendí, desde el técnico de Apple, que puedo usar el argumento de extensiones para pasar en un dictionary que contiene los datos del átomo avcC.

El dictionary de extensiones debe tener la siguiente forma:

 [kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms ---> ["avcC" ---> <avcC Data>]] 

Los [] representan dictionarys. Este dictionary puede usarse para pasar datos de átomos arbitrarios aparte de avcC.

Aquí está el código que usé para crear el dictionary de extensions que paso en CMVideoFormatDescriptionCreate :

  const char *avcC = "avcC"; const CFStringRef avcCKey = CFStringCreateWithCString(kCFAllocatorDefault, avcC, kCFStringEncodingUTF8); const CFDataRef avcCValue = CFDataCreate(kCFAllocatorDefault, [_avccData bytes], [_avccData length]); const void *atomDictKeys[] = { avcCKey }; const void *atomDictValues[] = { avcCValue }; CFDictionaryRef atomsDict = CFDictionaryCreate(kCFAllocatorDefault, atomDictKeys, atomDictValues, 1, nil, nil); const void *extensionDictKeys[] = { kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms }; const void *extensionDictValues[] = { atomsDict }; CFDictionaryRef extensionDict = CFDictionaryCreate(kCFAllocatorDefault, extensionDictKeys, extensionDictValues, 1, nil, nil);