目录

1. 查找编码器的方法

2. 查找解码器的方法

3. 源码解读avcodec_find_encoder_by_name调用

4. 源码解读avcodec_find_encoder调用流程

5. 源码解读avcodec_register作用

6. 总结


ffmpeg版本:ffmpeg-4.3.4

AVCodec类型的结构体包含了对一个编码器底层实现的封装;定义如下:

typedef struct AVCodec {//编码器名,在编码器和解码器两个类别中分别具有唯一性;//如:libx264const char *name;//编码器实例的完整名称;//如:libx264 H.264/AVC/MPEG-4 AVC/MPEG-4 part 10const char *long_name;//当前编码器处理的媒体类型;enum AVMediaType type;//编码类型ID;enum AVCodecID id;//当前编码器所支持的能力;int capabilities;//支持的帧率const AVRational *supported_framerates; //支持的图像像素格式;const enum AVPixelFormat *pix_fmts;    //支持的音频采样率 const int *supported_samplerates;  //支持的音频采样格式    const enum AVSampleFormat *sample_fmts; //支持的声道布局const uint64_t *channel_layouts;      //支持的降分辨率解码;  uint8_t max_lowres;                     const AVClass *priv_class;  //支持的编码档次;      const AVProfile *profiles;              /*编码器实现的组件或封装名称,主要用于标识该编码器的外部实现者;当该字段为空时,该编码器有libavcodec库内部实现;当该字段不为空时,该编码器由硬件或操作系统等外部实现,并在字段保存AVCodec.nam的缩写;    */const char *wrapper_name;int priv_data_size;//实现链表struct AVCodec *next;int (*update_thread_context)(struct AVCodecContext *dst, const struct AVCodecContext *src);const AVCodecDefault *defaults;void (*init_static_data)(struct AVCodec *codec);int (*init)(struct AVCodecContext *);int (*encode_sub)(struct AVCodecContext *, uint8_t *buf, int buf_size,const struct AVSubtitle *sub);int (*encode2)(struct AVCodecContext *avctx, struct AVPacket *avpkt,const struct AVFrame *frame, int *got_packet_ptr);int (*decode)(struct AVCodecContext *, void *outdata, int *outdata_size, struct AVPacket *avpkt);int (*close)(struct AVCodecContext *);int (*send_frame)(struct AVCodecContext *avctx, const struct AVFrame *frame);int (*receive_packet)(struct AVCodecContext *avctx, struct AVPacket *avpkt);int (*receive_frame)(struct AVCodecContext *avctx, struct AVFrame *frame);void (*flush)(struct AVCodecContext *);int caps_internal;const char *bsfs;const struct AVCodecHWConfigInternal **hw_configs;const uint32_t *codec_tags;
} AVCodec;

1. 查找编码器的方法

//通过指定名称查找编码器实例;
AVCodec *avcodec_find_encoder_by_name(const char *name);//通过指定编码器ID查找编码器实例;
AVCodec *avcodec_find_encoder(enum AVCodecID id);

(a)其中的name为编解码器名,不知道如何填写可以看文件开头定义的很多extern结构体;

最常见的为 extern AVCodec ff_libx264_encoder;

点击去后为:

AVCodec ff_libx264_encoder = {.name             = "libx264",.long_name        = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),.type             = AVMEDIA_TYPE_VIDEO,.id               = AV_CODEC_ID_H264,.priv_data_size   = sizeof(X264Context),.init             = X264_init,.encode2          = X264_frame,.close            = X264_close,.capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS |AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,.priv_class       = &x264_class,.defaults         = x264_defaults,.init_static_data = X264_init_static,
#if X264_BUILD >= 158.caps_internal    = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_INIT_THREADSAFE,
#else.caps_internal    = FF_CODEC_CAP_INIT_CLEANUP,
#endif.wrapper_name     = "libx264",
};

可知对应的名字可以填 libx264;

而要支持x264需要configue时--enable-x264等字样去配置;

(b) enum AVCodecID id;对应codec_id.h;

2. 查找解码器的方法

//通过名字查找指定解码器
AVCodec *avcodec_find_decoder_by_name(const char *name);//通过ID查找指定解码器
AVCodec *avcodec_find_decoder(enum AVCodecID id);

libavcodec/allcodecs.c中开头定义了很多支编解码结构体;如:

extern AVCodec ff_h264_decoder;
...//音频编解码器
extern AVCodec ff_aac_encoder;
extern AVCodec ff_aac_decoder;
...//PCM编解码器
extern AVCodec ff_pcm_alaw_encoder;
extern AVCodec ff_pcm_alaw_decoder;
...//DPCM编解码器
extern AVCodec ff_derf_dpcm_decoder;
extern AVCodec ff_gremlin_dpcm_decoder;
...//ADPCM编解码器
extern AVCodec ff_adpcm_4xm_decoder;
extern AVCodec ff_adpcm_adx_encoder;
...//字幕编解码器
extern AVCodec ff_ssa_encoder;
extern AVCodec ff_ssa_decoder;
...//外部库、
extern AVCodec ff_aac_at_encoder;
extern AVCodec ff_aac_at_decoder;
...
//优于libwebp
extern AVCodec ff_libx264_encoder;//文本
extern AVCodec ff_bintext_decoder;
extern AVCodec ff_xbin_decoder;
extern AVCodec ff_idf_decoder;//其他外部库
extern AVCodec ff_aac_mf_encoder;
extern AVCodec ff_ac3_mf_encoder;
...

3. 源码解读avcodec_find_encoder_by_name调用

avcodec_find_encoder_by_name调用了find_codec_by_name;

//参数1,需要查找的编解码器名  参数2:回调函数指针,用于判断下面查找出来的AVCodec是否为编/解码器
static AVCodec *find_codec_by_name(const char *name, int (*x)(const AVCodec *))
{void *i = 0;const AVCodec *p;if (!name)return NULL;//av_codec_iterate相当于迭代器遍历所有的codec_list数组,返回值p为遍历到的编/解码器while ((p = av_codec_iterate(&i))) {if (!x(p)) //既不是编码器也不是解码器,滤过;continue;if (strcmp(name, p->name) == 0) //比较名字return (AVCodec*)p;}return NULL;//没有找到
}

其中调用的av_codec_iterate如下:

//传入的是上面的整形值i的地址,二级指针,可以改传入的地址值;
const AVCodec *av_codec_iterate(void **opaque)
{uintptr_t i = (uintptr_t)*opaque;const AVCodec *c = codec_list[i];ff_thread_once(&av_codec_static_init, av_codec_init_static);if (c) //若codec_list不为NULL,继续下一个*opaque = (void*)(i + 1); //相当于i++return c; //返回AVCodec,可能为NULL;
}

其中又调用ff_thread_once;

 4. 源码解读avcodec_find_encoder调用流程

avcodec_find_encoder调用了find_codec,

static AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *))
{const AVCodec *p, *experimental = NULL;void *i = 0;//看名字是重映射,实际啥都没干;id = remap_deprecated_codec_id(id);while ((p = av_codec_iterate(&i))) { //通过codec_list数组获取AVCodecif (!x(p)) //判断是否为编/解码器continue;if (p->id == id) { //比较ID//判断编/解码器是否是实验性的,优先选择非实验性的;if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {experimental = p;} elsereturn (AVCodec*)p;}}return (AVCodec*)experimental;
}

5. 源码解读avcodec_register作用

调用了 ff_thread_once(&av_codec_next_init, av_codec_init_next);

static AVOnce av_codec_next_init = AV_ONCE_INIT; //标识只初始化一次static void av_codec_init_next(void)
{AVCodec *prev = NULL, *p;void *i = 0;while ((p = (AVCodec*)av_codec_iterate(&i))) {if (prev)prev->next = p; //把所有编/解码器连接起来prev = p;}
}

6. 总结

avcodec_find_encoder_by_name查找编码器可以使开发者对系统的控制性更强,但整体兼容性较弱,因为一旦当前使用的FFmpeg不支持指定的编码器,则整个流程将以错误结束;

若使用avcodec_find_encoder,则调用者无法指定特定的编码器进行编码,只能由系统根据优先级自动选择,因此兼容性更好;

实际开发时根据需求选择;

补充说明:

#if CONFIG_OSSFUZZ
AVCodec * codec_list[] = {NULL,NULL,NULL
};
#else
#include "libavcodec/codec_list.c"
#endif

源码中有codec_list数组,其内容在#include "libavcodec/codec_list.c"当中,但是源码中并没有该文件; 而在编译后的源码中有此文件;所以该文件是编译时根据版本等来生成的;其内容部分如下:

static const AVCodec * const codec_list[] = {&ff_a64multi_encoder,&ff_a64multi5_encoder,&ff_alias_pix_encoder,&ff_amv_encoder,&ff_asv1_encoder,&ff_asv2_encoder,&ff_avrp_encoder,&ff_avui_encoder,......
};

下一篇: https://blog.csdn.net/qq_39048131/article/details/125707330

ffmpeg源码笔记-查找编解码器(一)相关推荐

  1. ffmpeg源码笔记-AvFrame和AvPacket(四)

    在FFmpeg中,未压缩的图像和压缩的视频码流分别使用AVFrame结构和AVPacket结构保存; 针对视频编码器,其流程为从数据源获取图像格式的输入数据,保存为AVFrame对象并传入编码器,从编 ...

  2. 雷神FFMpeg源码学习笔记

    雷神FFMpeg源码学习笔记 文章目录 雷神FFMpeg源码学习笔记 读取编码并依据编码初始化内容结构 每一帧的视频解码处理 读取编码并依据编码初始化内容结构 在开始编解码视频的时候首先第一步需要注册 ...

  3. 数据结构源码笔记(C语言):索引文件建立和查找

    //实现索引文件建立和查找算法#include<stdio.h> #include<malloc.h> #include<string.h> #include< ...

  4. 数据结构源码笔记(C语言):顺序查找

    //实现顺序查找的算法 #include<stdio.h> #include<malloc.h> #include<malloc.h>#define MAXL 10 ...

  5. 数据结构源码笔记(C语言):分块法查找

    //实现分块法查找的算法#include<stdio.h> #include<malloc.h> #include<malloc.h>#define MAXL 10 ...

  6. 数据结构源码笔记(C语言):二分查找

    //实现二分查找的算法#include<stdio.h> #include<malloc.h> #include<malloc.h>#define MAXL 100 ...

  7. FFMPEG 源码分析

    FFMPEG基本概念: ffmpeg是一个开源的编解码框架,它提供了一个音视频录制,解码和编码库.FFMPEG是在linux下开发的,但也有windows下的编译版本. ffmpeg项目由以下几部分组 ...

  8. FFmpeg学习之八(FFmpeg源码编译)

    FFmpeg学习之八(FFmpeg源码编译) Mac下 FFmpeg源码编译 安装 1. 使用终端安装FFmpeg 2. 手动编译 2.1 编译环境 - Xcode 2.2 安装依赖库 2.3 安装F ...

  9. 数据结构源码笔记(C语言描述)汇总

    数据结构源码笔记(C语言):英文单词按字典序排序的基数排序 数据结构源码笔记(C语言):直接插入排序 数据结构源码笔记(C语言):直接选择排序 数据结构源码笔记(C语言):置换-选择算法 数据结构源码 ...

最新文章

  1. 附录:PyTorch记事本
  2. 从RNA-seq结果到差异表达
  3. variable ‘‘ of type ‘‘ referenced from scope ‘‘, but it is not defined 异常解决方法
  4. Caused by java.lang.ClassNotFoundException javax.xml.bind.ValidationException异常
  5. 《SAS编程与数据挖掘商业案例》学习笔记之九
  6. 异或!!不占用额外空间!!
  7. Springboot集成axis1.4
  8. Git常用命令——远程操作
  9. 新手做2D手游该用哪些工具?
  10. css3-ghostButton
  11. nginx location 斜杠_斜杠青年 菲斯塔车主实录
  12. jbpm5.1介绍(7)
  13. 51单片机3-红外通信
  14. 实验三 循环程序设计
  15. 分享一下杭州医院的看病流程(我去的杭州市第三人民医院)
  16. Tomcat的8005、8009,8080端口解释
  17. 密码学归约证明——计数器CTR模式
  18. 纳尼,五子棋AI居然这么简单?
  19. 学习axure都要经历哪个阶段,如何快速入门
  20. 便宜寄快递攻略,3.5R寄全国

热门文章

  1. 《极简主义》:用更少的东西过更有意义的生活
  2. PC通过WIFI向Kindle无线传输电子书+Everything
  3. SpringMVC获取前端传来的json数据的四种方法(前后端json交互总结)
  4. 如何获取微信公众号一键关注链接
  5. 2007版WORD删除分节符
  6. 佳能Canon iR-ADV 4225 一体机驱动
  7. numpy 基础教程【清晰详细带思维导图】
  8. 西游记中好色的猪八戒
  9. 沃通免费ssl服务器证书,新版《沃通免费SSL证书申请指南》
  10. 同声翻译哪款软件好用?请接下这份同声翻译手机软件安利