建设一个视频教学网站,巨腾外贸网站建设公司,基于大数据的精准营销,百度大数据分析背景
整理 ffmpeg 中#xff0c;如何通过名字或者 id 找到对应编码器的。
具体流程
搜索函数
avcodec_find_encoder // 通过 ID 搜索编码器
avcodec_find_encoder_by_name // 通过名字搜索编码器源码分析
ffmpeg 中所有支持的编码器都会注册到 codec_list.c 文件中…背景
整理 ffmpeg 中如何通过名字或者 id 找到对应编码器的。
具体流程
搜索函数
avcodec_find_encoder // 通过 ID 搜索编码器
avcodec_find_encoder_by_name // 通过名字搜索编码器源码分析
ffmpeg 中所有支持的编码器都会注册到 codec_list.c 文件中保存在 codec_list 结构体中既有编码器也有解码器且该结构体最后一个是 NULL这样方便 ffmpeg 内部的迭代算法使用。
static const FFCodec *codec_list[] {ff_a64multi_encoder,ff_a64multi5_encoder,ff_alias_pix_encoder,ff_amv_encoder,...ff_av1_decoder,NULL
};搜索编码器用到的函数主要有这些主要推测是一次遍历 codec_list 结构体拿到结构体首先通过 av_codec_is_encoder 函数判断是不是编码器然后在判断 id 和传入相同。 avcodec_find_encoder_by_name 类似只是最后一步是判断 name是否相等 av_codec_iterate 写的方式很像 c 中的迭代器index 不断加1然后通过 codec_list 结构体最后的 NULL 作为结尾的判断。
// allcodecs.c 中
const AVCodec *avcodec_find_encoder(enum AVCodecID id)
{return find_codec(id, av_codec_is_encoder);
}
static const 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))) {if (!x(p))continue;if (p-id id) {//兼容代码可先不管if (p-capabilities AV_CODEC_CAP_EXPERIMENTAL !experimental) {experimental p;} elsereturn p;}}return experimental;
}const AVCodec *av_codec_iterate(void **opaque)
{uintptr_t i (uintptr_t)*opaque;const FFCodec *c codec_list[i];//av_codec_init_static 只运行一次兼容代码可先不管ff_thread_once(av_codec_static_init, av_codec_init_static);if (c) {*opaque (void*)(i 1);return c-p;}return NULL;
}// 判断这个 avcodec 是不是编码器
int av_codec_is_encoder(const AVCodec *avcodec)
{const FFCodec *const codec ffcodec(avcodec);return codec (codec-cb_type FF_CODEC_CB_TYPE_ENCODE ||codec-cb_type FF_CODEC_CB_TYPE_ENCODE_SUB ||codec-cb_type FF_CODEC_CB_TYPE_RECEIVE_PACKET);
}具体例子
该结构体在 aacenc.c 文件中 主要是 FF_CODEC_ENCODE_CB表示这个 codec 是编码器。 其他.p.xx 这些是设置 AVCodec 结构体
const FFCodec ff_aac_encoder {.p.name aac,CODEC_LONG_NAME(AAC (Advanced Audio Coding)),.p.type AVMEDIA_TYPE_AUDIO,.p.id AV_CODEC_ID_AAC,.p.capabilities AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |AV_CODEC_CAP_SMALL_LAST_FRAME,.priv_data_size sizeof(AACEncContext),.init aac_encode_init,FF_CODEC_ENCODE_CB(aac_encode_frame),.close aac_encode_end,.defaults aac_encode_defaults,.p.supported_samplerates ff_mpeg4audio_sample_rates,.caps_internal FF_CODEC_CAP_INIT_CLEANUP,.p.sample_fmts (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,AV_SAMPLE_FMT_NONE },.p.priv_class aacenc_class,
};#define CODEC_LONG_NAME(str) .p.long_name str
#define FF_CODEC_ENCODE_CB(func) \.cb_type FF_CODEC_CB_TYPE_ENCODE, \.cb.encode (func)细节推敲
为啥 AVCodec 可以强转为 FFCodec
int av_codec_is_encoder(const AVCodec *avcodec)
{**const FFCodec *const codec ffcodec(avcodec);**return codec (codec-cb_type FF_CODEC_CB_TYPE_ENCODE ||codec-cb_type FF_CODEC_CB_TYPE_ENCODE_SUB ||codec-cb_type FF_CODEC_CB_TYPE_RECEIVE_PACKET);
}看了一下 FFCodec 中的结构定义AVCodec p 是定义在FFCodec 最前面的所以如果当前使用的 AVCodec 是用FFCodec 创建的直接强转就能找到对应的 FFCodec 对象。如果 AVCodec 是独立创建的强转肯定是有问题的。感觉这块写的有点 hardcode不按 ffmpeg 约定俗成的一些规则写会有比较难查的bug。
typedef struct FFCodec {/*** The public AVCodec. See codec.h for it.*/AVCodec p;/*** Internal codec capabilities FF_CODEC_CAP_*.*/unsigned caps_internal:29;/*** This field determines the type of the codec (decoder/encoder)* and also the exact callback cb implemented by the codec.* cb_type uses enum FFCodecType values.*/unsigned cb_type:3;// .../*** List of supported codec_tags, terminated by FF_CODEC_TAGS_END.*/const uint32_t *codec_tags;
} FFCodec;