ffmpeg 添加自定义编解码插件

发布时间 2023-12-15 16:51:38作者: 林西索

有两种方法:

一. ffmpeg 添加自定义编解码插件(以修改ffmpeg源码的方式添加)

例:添加一个解码器,给这个解码器取个名字叫mydecoder,可以通过下面的步骤添加:

1.在libavcodec目录下,新建文件mydecoder.c

#include "avcodec.h"
#include "codec_internal.h"

//自己封装的编解码器的头文件
#include "MyDecoder.h"

static av_cold int mk_init_decoder(AVCodecContext *avctx)
{
    //...
    return 0;
}

static int mk_decode(AVCodecContext *avctx, AVFrame *frame, int *got_frame,
                     AVPacket *avpkt)
{
    printf("decode in\n");
    //...
    return 0;
}

static av_cold int mk_close_decoder(AVCodecContext *avctx)
{
    //...
    return 0;
}

static void mk_flush(AVCodecContext *avctx)
{
    //...
}

//通过此结构体,来完成对mydecoder解码器的调用
//结构体的命名规则必须为 ff_xxx_decoder
//如果是编码器则为 ff_xxx_encoder
const FFCodec ff_mydecode_decoder = {
    .p.name = "myvideo",
    CODEC_LONG_NAME("mk video"),
    .p.type = AVMEDIA_TYPE_VIDEO,
    .p.id = AV_CODEC_ID_MYVIDEO,//需要手动在code_id.h头文件中声明
    .p.capabilities = AV_CODEC_CAP_PARAM_CHANGE,
    .init = mk_init_decoder,
    FF_CODEC_DECODE_CB(mk_decode),
    .close = mk_close_decoder,
    .flush = mk_flush};

2.嵌入mydecoder,使ffmpeg能识别到mydecoder解码器

  • 1.在 libavcodec/code_id.h 头文件中声明 AV_CODEC_ID_MYVIDEO。后面可以通过这个ID来找到mydecoder解码器

  • 2.在 libavcodec/codec_desc.cAVCodecDescriptor 编解码描述结构体中中添加如下代码

...
    {
        .id = AV_CODEC_ID_LEAD,
        .type = AVMEDIA_TYPE_VIDEO,
        .name = "lead",
        .long_name = NULL_IF_CONFIG_SMALL("LEAD MCMP"),
        .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
    },
	
	//mydecoder解码器的描述
    {
        .id = AV_CODEC_ID_MYVIDEO,
        .type = AVMEDIA_TYPE_VIDEO,
        .name = "myvideo",
        .long_name = NULL_IF_CONFIG_SMALL("mk video"),
        .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
    },

    /* various PCM "codecs" */
    {
        .id = AV_CODEC_ID_PCM_S16LE,
        .type = AVMEDIA_TYPE_AUDIO,
        .name = "pcm_s16le",
        .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit little-endian"),
        .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
    },
...
  • 3.在 allcodecs.c 中添加 ff_mydecode_decoder 的声明。configure时,会通过解析此文件获取到可用的编解码器。mydecode为解码器名字,decoder表示为解码器
...
extern const FFCodec ff_mjpeg_decoder;
extern const FFCodec ff_mjpegb_decoder;

//根据这个声明,可以查找到mydecoder解码器
//ps:在执行configure时,也会根据此文件中声明的变量来获取编解码器
extern const FFCodec ff_mydecode_decoder;

extern const FFCodec ff_mmvideo_decoder;
extern const FFCodec ff_mobiclip_decoder;
...

3.修改Makefile,使mydecoder能编译进ffmpeg

...
OBJS-$(CONFIG_LIBOPENJPEG_ENCODER)        += libopenjpegenc.o

#添加下面行,在编译时会把mydecoder.c链接到libavcodec库中
#CONFIG_MYDECODE_DECODER变量是在configure的时候根据ff_mydecode_decoder生成
OBJS-$(CONFIG_MYDECODE_DECODER)            += mydecode.o
...

4.生成带mydecoder解码器的ffmpeg

  • 1.执行 ./configure --list-decoders 查看mydecoder解码器是否已添加

  • 2.执行 ./configure --disable-x86asm --enable-shared 生成配置文件

  • 2.1 可以通过 ./configure --help 查看使用说明

  • 2.2 执行configure后,会在ffbuild目录下生成一堆文件,主要关注 .mak 文件。可以参考 https://blog.csdn.net/sunshineywz/article/details/105855939

  • 3.执行 make 开始编译ffmpeg

二. 不修改ffmpeg源码的方式添加编解码器

  • allcodecs.c 源文件中声明了全部的编解码器。ffmpeg实现部分的编解码器,还有一部分只做了声明
    ,我们直接找到一个未做实现的编码器,比如 extern const FFCodec ff_h264_mf_encoder;,然后直接在
    自己的项目中实现它,如下:
const FFCodec ff_h264_mf_encoder = {
    .p.name = "myvideo00",
    CODEC_LONG_NAME("mk video"),
    .p.type = AVMEDIA_TYPE_VIDEO,
    .p.id = AV_CODEC_ID_H264,
    .p.capabilities = AV_CODEC_CAP_PARAM_CHANGE,
    .init = mk_init_encoder,//初始化
    FF_CODEC_ENCODE_CB(mk_encode),//编码一帧数据
    .close = mk_close_encoder,//关闭

最后,当使用const AVCodec *codec = avcodec_find_encoder_by_name("myvideo00");,查找编码器时,就会直接找到我们自定义的编码器。


两种添加自定义编解码器的方法的优缺点:

在C++工程中使用ffmpeg需要注意:

注意包含头文件的方法:

//在C++项目中,必须使用extern包含ffmpeg头文件,让编译器以C风格来解释ffmpeg接口
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
...
}