ffmpeg源码笔记-查找编解码器(一)
目录
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源码笔记-查找编解码器(一)相关推荐
- ffmpeg源码笔记-AvFrame和AvPacket(四)
在FFmpeg中,未压缩的图像和压缩的视频码流分别使用AVFrame结构和AVPacket结构保存; 针对视频编码器,其流程为从数据源获取图像格式的输入数据,保存为AVFrame对象并传入编码器,从编 ...
- 雷神FFMpeg源码学习笔记
雷神FFMpeg源码学习笔记 文章目录 雷神FFMpeg源码学习笔记 读取编码并依据编码初始化内容结构 每一帧的视频解码处理 读取编码并依据编码初始化内容结构 在开始编解码视频的时候首先第一步需要注册 ...
- 数据结构源码笔记(C语言):索引文件建立和查找
//实现索引文件建立和查找算法#include<stdio.h> #include<malloc.h> #include<string.h> #include< ...
- 数据结构源码笔记(C语言):顺序查找
//实现顺序查找的算法 #include<stdio.h> #include<malloc.h> #include<malloc.h>#define MAXL 10 ...
- 数据结构源码笔记(C语言):分块法查找
//实现分块法查找的算法#include<stdio.h> #include<malloc.h> #include<malloc.h>#define MAXL 10 ...
- 数据结构源码笔记(C语言):二分查找
//实现二分查找的算法#include<stdio.h> #include<malloc.h> #include<malloc.h>#define MAXL 100 ...
- FFMPEG 源码分析
FFMPEG基本概念: ffmpeg是一个开源的编解码框架,它提供了一个音视频录制,解码和编码库.FFMPEG是在linux下开发的,但也有windows下的编译版本. ffmpeg项目由以下几部分组 ...
- FFmpeg学习之八(FFmpeg源码编译)
FFmpeg学习之八(FFmpeg源码编译) Mac下 FFmpeg源码编译 安装 1. 使用终端安装FFmpeg 2. 手动编译 2.1 编译环境 - Xcode 2.2 安装依赖库 2.3 安装F ...
- 数据结构源码笔记(C语言描述)汇总
数据结构源码笔记(C语言):英文单词按字典序排序的基数排序 数据结构源码笔记(C语言):直接插入排序 数据结构源码笔记(C语言):直接选择排序 数据结构源码笔记(C语言):置换-选择算法 数据结构源码 ...
最新文章
- 附录:PyTorch记事本
- 从RNA-seq结果到差异表达
- variable ‘‘ of type ‘‘ referenced from scope ‘‘, but it is not defined 异常解决方法
- Caused by java.lang.ClassNotFoundException javax.xml.bind.ValidationException异常
- 《SAS编程与数据挖掘商业案例》学习笔记之九
- 异或!!不占用额外空间!!
- Springboot集成axis1.4
- Git常用命令——远程操作
- 新手做2D手游该用哪些工具?
- css3-ghostButton
- nginx location 斜杠_斜杠青年 菲斯塔车主实录
- jbpm5.1介绍(7)
- 51单片机3-红外通信
- 实验三 循环程序设计
- 分享一下杭州医院的看病流程(我去的杭州市第三人民医院)
- Tomcat的8005、8009,8080端口解释
- 密码学归约证明——计数器CTR模式
- 纳尼,五子棋AI居然这么简单?
- 学习axure都要经历哪个阶段,如何快速入门
- 便宜寄快递攻略,3.5R寄全国