Cómo agregar códec a FFmpeg


FFmpeg es un gran proyecto de código abierto, una especie de enciclopedia multimedia. Con FFmpeg puede resolver una gran cantidad de tareas multimedia de computadora. Pero aún así, a veces es necesario expandir FFmpeg. La forma estándar es realizar cambios en el código del proyecto y luego compilar la nueva versión. El artículo detalla cómo agregar un nuevo códec. También se consideran algunas características para conectar funciones externas a FFmpeg. Si no es necesario agregar un códec, el artículo puede ser útil para comprender mejor la arquitectura de los códecs FFmpeg y su configuración. Se supone que el lector está familiarizado con la arquitectura de FFmpeg, el proceso de compilación de FFmpeg, y también tiene experiencia en programación utilizando la API de FFmpeg. La descripción es válida para FFmpeg 4.2 "Ada", agosto de 2019.



Tabla de contenidos



Introduccion


El códec (códec, proviene de la combinación de los términos COder y DECoder) es un término muy común y, como suele suceder en tales casos, su significado varía un poco según el contexto. El significado principal es software o hardware para comprimir / descomprimir datos de medios. En lugar de los términos compresión / descompresión, a menudo se usan los términos codificación / decodificación. Pero en algunos casos, se entiende que un códec significa simplemente un formato de compresión (también dicen el formato de códec), independientemente de los medios utilizados para la compresión / descompresión. Veamos cómo se usa el término códec en FFmpeg.



1. Identificación del códec


Los códecs FFmpeg se compilan en la biblioteca libavcodec .



1.1. ID de códec


La enum AVCodecID define en el enum AVCodecID libavcodec/avcodec.h . Cada elemento de esta enumeración identifica el formato de compresión. Los elementos de esta enumeración deben tener la forma AV_CODEC_ID_XXX , donde XXX nombre único del identificador de códec en mayúsculas. Aquí hay ejemplos de identificadores de códec: AV_CODEC_ID_H264 , AV_CODEC_ID_AAC . Para obtener una descripción más detallada del identificador de códec, use la estructura AVCodecDescriptor (declarada en libavcodec/avcodec.h , en forma abreviada):


 typedef struct AVCodecDescriptor { enum AVCodecID id; enum AVMediaType type; const char *name; const char *long_name; // ... } AVCodecDescriptor; 

El miembro clave de esta estructura es id , el resto de los miembros proporcionan información adicional sobre el identificador de códec. Cada identificador de códec está asociado de forma exclusiva con un tipo de medio (miembro de type ) y tiene un nombre único (miembro de name ), escrito en minúsculas. Una matriz de tipo AVCodecDescriptor define en el archivo libavcodec/codec_desc.c AVCodecDescriptor . Para cada identificador de códec, hay un elemento de matriz correspondiente. Los elementos de esta matriz deben ordenarse por valores de id , ya que la búsqueda binaria se usa para buscar elementos. Para obtener información sobre el identificador de códec, puede usar las funciones:


 const AVCodecDescriptor* avcodec_descriptor_get(enum AVCodecID id); const AVCodecDescriptor* avcodec_descriptor_get_by_name(const char *name); enum AVMediaType avcodec_get_type(enum AVCodecID codec_id); const char* avcodec_get_name(enum AVCodecID id); 


1.2. Códec


El códec mismo, un conjunto de herramientas necesarias para realizar la codificación / decodificación de datos multimedia, combina la estructura AVCodec (declarada en libavcodec/avcodec.h ). Aquí está su versión resumida, más completa se discutirá a continuación.


 typedef struct AVCodec { const char *name; const char *long_name; enum AVMediaType type; enum AVCodecID id; // ... } AVCodec; 

El miembro más importante de esta estructura es id , el identificador de códec, también hay un miembro que define el tipo de medio ( type ), pero su valor debe coincidir con el valor del mismo miembro de AVCodecDescriptor . Los códecs se dividen en dos categorías: codificadores, que comprimen o codifican los medios, y decodificadores, que realizan la operación opuesta: descomprimir o decodificar. (A veces, en textos rusos, en lugar del término, el codificador usa papel de calco del inglés: el codificador). No hay ningún miembro especial en AVCodec defina la categoría de códec (aunque la categoría se puede determinar indirectamente utilizando las funciones av_codec_is_encoder() y av_codec_is_decoder() , esta categoría se determina durante el registro. A continuación se mostrará cómo se hará: Varios códecs pueden tener el mismo identificador de códec. Si tienen la misma categoría, deben diferir por nombre ( name miembro). Un codificador y decodificador que tenga el mismo identificador de códec puede tener uno el mismo nombre, que también puede coincidir con el nombre del identificador de códec (pero estas coincidencias son opcionales). Tal situación puede generar cierta confusión, pero no hay nada que hacer, debe comprender claramente a qué entidad pertenece el nombre. Dentro de una categoría, el nombre El códec debe ser único. Para buscar códecs registrados, hay funciones:


 AVCodec* avcodec_find_encoder_by_name(const char *name); AVCodec* avcodec_find_decoder_by_name(const char *name); AVCodec* avcodec_find_encoder(enum AVCodecID id); AVCodec* avcodec_find_decoder(enum AVCodecID id); 

Dado que varios códecs pueden tener el mismo identificador, las dos últimas funciones devuelven uno de ellos, que puede considerarse el códec predeterminado para un identificador de códec dado.


Se puede solicitar una lista de todos los códecs registrados con el comando


ffmpeg -codecs >codecs.txt


Después de ejecutar el comando, el archivo codecs.txt contendrá esta lista. Cada identificador de códec estará representado por un registro separado (línea). Aquí, por ejemplo, la entrada para el identificador de códec AV_CODEC_ID_H264 :


DEV.LS
h264
H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
(decoders: h264 h264_qsv h264_cuvid)
(encoders: libx264 libx264rgb h264_amf h264_nvenc h264_qsv nvenc nvenc_h264)


Al comienzo de la grabación, hay caracteres especiales que determinan las características comunes disponibles para este identificador de códec: D - los decodificadores están registrados, E - los codificadores están registrados, V - se usa para video, L - existe la posibilidad de compresión con pérdidas, S - existe la posibilidad de compresión sin pérdidas. Luego viene el nombre del identificador de códec ( h264 ), seguido de un nombre de identificador de códec largo ( H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 ), y luego una lista de nombres de decodificadores y codificadores registrados.



2. Agregar un nuevo códec a FFmpeg


Consideraremos el procedimiento para agregar un nuevo códec a FFmpeg usando un ejemplo de códec de audio, al que llamaremos FROX .


Paso 1. Agregue un nuevo elemento a la enum AVCodecID .


Este listado está en el libavcodec/avcodec.h . Al agregar, debe seguir las reglas:


  1. El valor de un elemento no debe coincidir con los valores de los elementos de enumeración existentes;
  2. No cambie los valores de los elementos de enumeración existentes;
  3. Publique un nuevo valor en un grupo de códecs similares.

Según la plantilla, el identificador de este elemento debe ser AV_CODEC_ID_FROX . Colóquelo antes de AV_CODEC_ID_PCM_S64LE y dé el valor 0x10700 .


Paso 2. Agregue el elemento a la matriz codec_descriptors (archivo libavcodec/codec_desc.c ).


 static const AVCodecDescriptor codec_descriptors[] = { // ... { .id = AV_CODEC_ID_FROX, .type = AVMEDIA_TYPE_AUDIO, .name = "frox", .long_name = NULL_IF_CONFIG_SMALL("FROX audio"), .props = AV_CODEC_PROP_LOSSLESS, }, // ... }; 

Debe agregar el elemento al lugar "correcto", no se debe violar la monotonicidad de los elementos de la matriz por el valor de id .


Paso 3. Defina instancias de AVCodec por separado para el codificador y el decodificador.


Para hacer esto, primero debe determinar la estructura para el contexto del códec y varias funciones que realizarán la codificación / decodificación real y algunas otras operaciones necesarias. En esta sección, estas definiciones se realizarán de manera extremadamente esquemática; más adelante se realizará una descripción más detallada. libavcodec/frox.c el código en el archivo libavcodec/frox.c


 #include "avcodec.h" // context typedef struct FroxContext { // ... } FroxContext; // decoder static int frox_decode_init(AVCodecContext *codec_ctx) { return -1; } static int frox_decode_close(AVCodecContext *codec_ctx) { return -1; } static int frox_decode(AVCodecContext *codec_ctx, void* outdata, int *outdata_size, AVPacket *pkt) { return -1; } AVCodec ff_frox_decoder = { .name = "frox_dec", .long_name = NULL_IF_CONFIG_SMALL("FROX audio decoder"), .type = AVMEDIA_TYPE_AUDIO, .id = AV_CODEC_ID_FROX, .priv_data_size = sizeof(FroxContext), .init = frox_decode_init, .close = frox_decode_close, .decode = frox_decode, .capabilities = AV_CODEC_CAP_LOSSLESS, .sample_fmts = (const enum AVSampleFormat[]) {AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE}, .channel_layouts = (const int64_t[]) {AV_CH_LAYOUT_MONO, 0 }, }; // encoder static int frox_encode_init(AVCodecContext *codec_ctx) { return -1; } static int frox_encode_close(AVCodecContext *codec_ctx) { return -1; } static int frox_encode(AVCodecContext *codec_ctx, AVPacket *pkt, const AVFrame *frame, int *got_pkt_ptr) { return -1; } AVCodec ff_frox_encoder = { .name = "frox_enc", .long_name = NULL_IF_CONFIG_SMALL("FROX audio encoder"), .type = AVMEDIA_TYPE_AUDIO, .id = AV_CODEC_ID_FROX, .priv_data_size = sizeof(FroxContext), .init = frox_encode_init, .close = frox_encode_close, .encode2 = frox_encode, .sample_fmts = (const enum AVSampleFormat[]) {AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE}, .channel_layouts = (const int64_t[]) {AV_CH_LAYOUT_MONO, 0 }, }; 

Para simplificar, en este ejemplo, el codificador y el decodificador tienen el mismo contexto: FroxContext , pero la mayoría de las veces el codificador y el decodificador tienen contextos diferentes. También tenga en cuenta que los AVCodec instancia AVCodec deben seguir un patrón especial.


Paso 4. Agregue instancias de AVCodec a la lista de registro.


Vaya al archivo libavcodec/allcodecs.c . Al principio de este archivo hay una lista de declaraciones de todos los códecs registrados. Agregue nuestros códecs a esta lista:


 extern AVCodec ff_frox_decoder; extern AVCodec ff_frox_encoder; 

Durante la ejecución, el script de configure encuentra todas esas declaraciones y genera el libavcodec/codec_list.c , que contiene una matriz de punteros a los códecs declarados en libavcodec/allcodecs.c . Después de ejecutar el script en el archivo libavcodec/codec_list.c veremos:


 static const AVCodec * const codec_list[] = { // ... &ff_frox_encoder, // ... &ff_frox_decoder, // ... NULL }; 

Además, durante la ejecución del script de configure , se config.h archivo config.h , en el que encontramos las declaraciones


 #define CONFIG_FROX_DECODER 1 #define CONFIG_FROX_ENCODER 1 

Paso 5. Edite libavcodec/Makefile


Abra libavcodec/Makefile . Encontramos la sección # decoders/encoders , y agregamos allí


 OBJS-$(CONFIG_FROX_DECODER) += frox.o OBJS-$(CONFIG_FROX_ENCODER) += frox.o 

Paso 6. Edite el código del multiplexor y demultiplexor.


El multiplexor (muxer) y el demultiplexor (demuxer) deben "conocer" el nuevo códec. Al grabar, es necesario registrar la información de identificación para este códec, mientras lee, determinar el identificador del códec a partir de la información de identificación. Esto es lo que debe hacer para el formato matroska ( *.mkv ).


1. En el archivo libavformat/matroska.c , agregue un elemento para el nuevo códec a la matriz libavformat/matroska.c :


 const CodecTags ff_mkv_codec_tags[] = { // ... {"A_FROX", AV_CODEC_ID_FROX}, // ... }; 

Cadena "A_FROX" y el multiplexor lo escribirá en el archivo como información de identificación. En esta matriz, está asociada con el identificador de códec, por lo tanto, al leer, el demultiplexor puede determinarlo fácilmente. El demultiplexor escribe el identificador de códec en el miembro codec_id de la estructura codec_id . Un puntero a esta estructura es un miembro de la estructura AVStream .


2. En el archivo libavformat/matroskaenc.c , agregue el elemento a la matriz Additional_audio_tags:


 static const AVCodecTag additional_audio_tags[] = { // ... { AV_CODEC_ID_FROX, 0XFFFFFFFF }, // ... }; 

Entonces todo está listo. Primero, ejecute el script de configure . Después de eso, debe asegurarse de que se realicen los cambios descritos anteriormente en los archivos libavcodec/codec_list.c y config.h . Entonces puedes ejecutar la compilación:


make clean
make


Si la compilación se realizó ffmpeg.exe , aparece el ejecutable ffmpeg (o ffmpeg.exe , si el sistema operativo de destino es Windows). Ejecutar el comando


./ffmpeg -codecs >codecs.txt


y asegúrese de que FFmpeg "vea" nuestros nuevos códecs, encontramos la entrada en el archivo codecs.txt


DEA..S frox FROX audio (decoders: frox_dec) (encoders: frox_enc)



3. Descripción detallada del contexto y funciones requeridas.


En esta sección, describimos con más detalle cómo puede verse la estructura del contexto del códec y las funciones necesarias.



3.1. Contexto de códec


El contexto del códec puede admitir la instalación de opciones. Para los codificadores, este soporte se usa con la frecuencia suficiente, para los decodificadores con menos frecuencia. La estructura que soporta la instalación de opciones debe tener un puntero a la estructura AVClass como primer miembro y luego las opciones mismas.


 #include "libavutil/opt.h" typedef struct FroxContext { const AVClass *av_class; int frox_int; char *frox_str; uint8_t *frox_bin; int bin_size; } FroxContext; 

A continuación, debe definir una matriz de tipo AVOption , cada elemento del cual describe una opción específica.


 static const AVOption frox_options[] = { { "frox_int", "This is a demo option of int type.", offsetof(FroxContext, frox_int), AV_OPT_TYPE_INT, { .i64 = -1 }, 1, SHRT_MAX }, { "frox_str", "This is a demo option of string type.", offsetof(FroxContext, frox_str), AV_OPT_TYPE_STRING }, { "frox_bin", "This is a demo option of binary type.", offsetof(FroxContext, frox_bin), AV_OPT_TYPE_BINARY }, { NULL }, }; 

Para cada opción, debe definir un nombre, descripción, desplazamiento en la estructura, tipo. También puede definir un valor predeterminado y para opciones enteras un rango de valores válidos.


A continuación, debe definir una instancia de tipo AVClass .


 static const AVClass frox_class = { .class_name = "FroxContext", .item_name = av_default_item_name, .option = frox_options, .version = LIBAVUTIL_VERSION_INT, }; 

Se debe utilizar un puntero a esta instancia para inicializar el miembro AVCodec correspondiente.


 AVCodec ff_frox_decoder = { // ... .priv_data_size = sizeof(FroxContext), .priv_class = &frox_class, // ... }; AVCodec ff_frox_encoder = { // ... .priv_data_size = sizeof(FroxContext), .priv_class = &frox_class, // ... }; 

Ahora al ejecutar la función


 AVCodecContext *avcodec_alloc_context3(const AVCodec *codec); 

se AVCodecContext una instancia de la estructura AVCodecContext y se inicializa el miembro del codec . A continuación, en función del valor codec->priv_data_size , se codec->priv_data_size la memoria necesaria para la instancia de FroxContext , utilizando el valor codec->priv_class primer miembro de esta instancia y luego se av_opt_set_defaults() función av_opt_set_defaults() , que establecerá los valores predeterminados para las opciones. Un puntero a una instancia de FroxContext estará disponible a través del miembro priv_data de la estructura priv_data .


Al trabajar con la API de FFmpeg, los valores para las opciones se pueden establecer directamente.


 const AVCodec *codec; // ... AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); // ... av_opt_set(codec_ctx->priv_data, "frox_str", "meow", 0); av_opt_set_int(codec_ctx->priv_data, "frox_int", 42, 0); 

Otra forma es usar el diccionario de opciones, que se pasará como el tercer argumento al llamar a avcodec_open2() (ver más abajo).


Usando la función


 const AVOption* av_opt_next(const void* ctx, const AVOption* prev); 

Puede obtener una lista de todas las opciones admitidas por el contexto de códec. Esto es útil al examinar un códec. Pero antes de eso, debe asegurarse de que codec_ctx->codec->priv_class configurado en un valor distinto de cero, de lo contrario, el contexto no admite opciones y cualquier operación con opciones bloqueará el programa.



3.2. Las funciones


Examinemos ahora con más detalle cómo se organizan las funciones utilizadas en la inicialización del códec y la codificación / decodificación real. Por lo general, siempre necesitan obtener un puntero a un FroxContext .


 AVCodecContext *codec_ctx; // ... FroxContext* frox_ctx = codec_ctx->priv_data; 

Las frox_decode_init() y frox_encode_init() cuando se ejecute la función


 int avcodec_open2( AVCodecContext *codec_ctx, const AVCodec *codec, AVDictionary **options); 

Deben asignar los recursos necesarios para que funcione el códec y, si es necesario, inicializar algunos miembros de la estructura AVCodecContext , por ejemplo, frame_size para un frame_size audio.


Las frox_decode_close() y frox_encode_close() cuando se ejecuten


 int avcodec_close(AVCodecContext *codec_ctx); 

Necesitan liberar los recursos asignados.


Considere una función para implementar la decodificación


 int frox_decode( AVCodecContext *codec_ctx, void *outdata, int *outdata_size, AVPacket *pkt); 

Ella debe implementar las siguientes operaciones:


  1. Decodificación real;
  2. Asignación del búfer necesario para la trama de salida;
  3. Copie los datos decodificados al buffer de cuadros

Considere cómo asignar el búfer necesario para el marco de salida. El parámetro outdata realidad apunta a un AVFrame , por lo que primero debe realizar una conversión de tipo:


 AVFrame* frm = outdata; 

A continuación, debe asignar un búfer para almacenar datos de trama. Para hacer esto, inicialice los miembros de AVFrame que determinan el tamaño del búfer de trama. Para audio, esto es nb_samples , channel_layout , format (para width , height , format video).


Después de eso, debes llamar a la función


 int av_frame_get_buffer(AVFrame* frm, int alignment); 

El puntero al marco, que es el parámetro de datos outdata convertidos, se usa como primer argumento; se recomienda pasar cero como segundo argumento. Después de usar el marco (esto ya ocurre fuera del códec), la función libera el búfer asignado por esta función


 void av_frame_unref(AVFrame* frm); 

La función frox_decode() debería devolver el número de bytes utilizados para la decodificación del paquete al que apunta pkt . Si se completa la formación de trama, la variable a la que apunta outdata_size asigna un valor distinto de cero; de lo contrario, esta variable obtiene el valor 0 .


Considere una función para implementar la codificación


 int frox_encode( AVCodecContext *codec_ctx, AVPacket *pkt, const AVFrame *frame, int *got_pkt_ptr); 

Ella debe implementar las siguientes operaciones:


  1. Codificación real;
  2. Asignación del búfer necesario para el paquete de salida;
  3. Copie los datos codificados al búfer de paquetes.

Para seleccionar el búfer requerido, use la función


 int av_new_packet(AVPacket *pkt, int pack_size); 

El parámetro pkt utiliza como primer argumento, y el tamaño de los datos codificados es el segundo. Después de usar el paquete (esto ya ocurre fuera del códec), los buffers asignados por esta función son liberados por la función


 void av_packet_unref(AVPacket *pkt); 

Si el paquete se completa, la variable a la que apunta got_pkt_ptr asigna un valor distinto de cero; de lo contrario, esta variable obtiene el valor 0 . Si no hay error, la función devuelve cero, de lo contrario, un código de error.


Al implementar el códec, generalmente se usa el registro (para errores, esto puede considerarse un requisito obligatorio). Aquí hay un ejemplo:


 static int frox_decode_close(AVCodecContext *codec_ctx) { av_log(codec_ctx, AV_LOG_INFO, "FROX decode close\n"); // ... } 

En este caso, cuando salga al registro, el nombre del códec se usará como nombre de contexto.



3.3. Sellos de tiempo


Para establecer el tiempo en FFmpeg, se usa una base de tiempo, especificada en segundos usando el número racional representado por el tipo AVRational . (Se utiliza un enfoque similar en C ++ 11. Por ejemplo, 1/1000 establece el milisegundo). Los marcos y los paquetes tienen marcas de tiempo del tipo int64_t , sus valores contienen tiempo en las unidades de tiempo correspondientes. Un cuadro, es decir, una estructura AVFrame , tiene un miembro pts (marca de tiempo de presentación), cuyo valor determina el tiempo relativo de la escena capturada en el cuadro. Un paquete, es decir, una estructura AVPacket , tiene miembros pts (marca de tiempo de presentación) y dts (marca de tiempo de descompresión). El valor dts determina el tiempo relativo de transmisión del paquete para la decodificación. Para los códecs simples, es lo mismo que pts , pero para los códecs complejos puede ser diferente (por ejemplo, para h264 cuando se usan cuadros B), es decir, los paquetes se pueden decodificar en el orden incorrecto en el que se deben usar los cuadros.


La unidad de tiempo se define para la secuencia y el códec, la estructura AVStream tiene un miembro correspondiente: time_base , el mismo miembro tiene la estructura AVCodecContext .


Las marcas de tiempo del paquete extraído de la secuencia utilizando av_read_frame() se especificarán en unidades de tiempo de esta secuencia. Al decodificar, no se utiliza la unidad de tiempo del códec. Para un decodificador de video, por lo general simplemente no está configurado, para un decodificador de audio tiene un valor estándar: el inverso de la frecuencia de muestreo. El decodificador debe establecer una marca de tiempo para el marco de salida en función de la marca de tiempo del paquete. FFmpeg define de forma independiente dicha etiqueta y la escribe en el miembro best_effort_timestamp de la estructura best_effort_timestamp . Todas estas marcas de tiempo utilizarán la unidad de tiempo de la secuencia de la que se extrae el paquete.


Para el codificador, debe especificar la unidad de tiempo. En el código del cliente que organiza la decodificación, debe establecer el valor para el miembro time_base de la estructura time_base antes de llamar a avcodec_open2() . Por lo general, toma la unidad de tiempo utilizada para las marcas de tiempo del marco codificado. Si esto no se hace, los codificadores de video generalmente dan un error, los codificadores de audio establecen el valor predeterminado: el inverso de la frecuencia de muestreo. No está del todo claro si un códec puede cambiar una unidad de tiempo dada. Por si acaso, es mejor verificar siempre el valor de time_base después de llamar a avcodec_open2() y, si ha cambiado, recalcular las marcas de tiempo de los marcos de entrada por unidad de tiempo del códec. En el proceso de codificación, debe instalar los pts y dts paquete. Después de la codificación, antes de escribir un paquete en el flujo de salida, es necesario volver a calcular las marcas de tiempo del paquete desde la unidad de tiempo del códec a la unidad de tiempo del flujo. Para hacer esto, use la función


 void av_packet_rescale_ts( AVPacket *pkt, AVRational tb_src, AVRational tb_dst); 

Al escribir paquetes en la secuencia, es necesario asegurarse de que los valores dts aumenten estrictamente; de ​​lo contrario, el multiplexor arrojará un error. (Para obtener más información, consulte la documentación de la función av_interleaved_write_frame() ).



3.4. Otras funciones utilizadas por el códec


Cuando inicializa una instancia de AVCodec , se pueden registrar dos funciones más. Estos son los miembros relevantes de AVCodec :


 typedef struct AVCodec { // ... void (*init_static_data)(AVCodec *codec); void (*flush)(AVCodecContext *codec_ctx); // ... } AVCodec; 

El primero de ellos se llama una vez al registrarse el códec.


El segundo restablece el estado interno del códec, se llamará durante la ejecución de la función.


 void avcodec_flush_buffers(AVCodecContext *codec_ctx); 

Esta llamada es necesaria, por ejemplo, cuando se cambia por la fuerza la posición de reproducción actual.



4. Implementación externa del códec



4.1. Conexión de función externa


Considere la siguiente organización de códec: el códec registrado en FFmpeg desempeña el papel de un marco y delega el procedimiento de codificación / decodificación real a funciones externas (algún tipo de complementos) implementadas fuera de FFmpeg.


. Aquí hay algunos de ellos:


  1. , FFmpeg ;
  2. C, , C++;
  3. framework, FFmpeg.

, FFmpeg «», FFmpeg API. «» FFmpeg ( , ), . — . .


 typedef int(*dec_extern_t)(const void*, int, void*); static int frox_decode( AVCodecContext* codec_ctx, void* outdata, int *outdata_size, AVPacket* pkt) { int ret = -1; void* out_buff; //      out_buff FroxContext *fc = codec_ctx->priv_data; if (fc->bin_size > 0) { if (fc->bin_size == sizeof(dec_extern_t)) { dec_extern_t edec; memcpy(&edec, fc->frox_bin, fc->bin_size); ret = (*edec)(pkt->data, pkt->size, out_buff); if (ret >= 0) { //     out_buff   } } else { /*  */ } } else { /*    */ } // ... return ret; } 

FFmpeg API ( C++) .


 extern "C" { int DecodeFroxData(const void* buff, int size, void* outBuff); typedef int(*dec_extern_t)(const void*, int, void*); #include <libavcodec/avcodec.h> #include <libavutil/opt.h> } // ... AVCodecContext* ctx; // ... dec_extern_t dec = DecodeFroxData; void* pv = &dec; auto pb = static_cast<const uint8_t*>(pv); auto sz = sizeof(dec); av_opt_set_bin(ctx->priv_data, "frox_bin", pb, sz, 0); 


4.2.


— . , . , . , , FFmpeg , «» , . . , . FFmpeg API - , , . . , . PC (Windows) DirectShow AVI . PC - DirectShow. 32- FourCC. ( biCompression BITMAPINFOHEADER .) , DirectShow , PC -. FFmpeg , , , codec_tag AVCodecParameters FourCC, . FFmpeg API , . FFmpeg FFmpeg API.


, *.mkv FFmpeg ( ENCODER ).



Conclusión


, , FFmpeg: , changelog, .. «» FFmpeg, , .



Recursos


FFmpeg


[1] FFmpeg —
[2] FFmpeg —
[3] FFmpeg —
[4] FFmpeg — Ubuntu



[5] FFmpeg Compilation Guide
[6] Compilation of FFmpeg 4.0 in Windows 10


FFmpeg API


[7] ffmpeg



[8] FFmpeg codec HOWTO
[9] FFmpeg video codec tutorial




Source: https://habr.com/ru/post/480714/


All Articles