ffmpeg 枚举decoders, encoders 分析
$ffmpeg -decoders
调用 print_codecs(0);
$ffmpeg -encoders
调用 print_codecs(1);
$ffmpeg -codecs
调用 show_codecs() 跟单列出一种大同小异。
下面对 print_codecs ()进行代码分析。
第一步, 获取所有codecs 描述符
const AVCodecDescriptor **codecs;
unsigned i, nb_codecs = get_codecs_sorted(&codecs);
怎样获取codecs 描述符指针的指针?
原来codec_descriptors[] 是一个大大的数组。codec 描述符是一个结构。
static const AVCodecDescriptor codec_descriptors[] = {
/* video codecs */
{
.id = AV_CODEC_ID_MPEG1VIDEO,
.type = AVMEDIA_TYPE_VIDEO,
.name = "mpeg1video",
.long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video"),
.props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
},
{
.id = AV_CODEC_ID_MPEG2VIDEO,
.type = AVMEDIA_TYPE_VIDEO,
.name = "mpeg2video",
.long_name = NULL_IF_CONFIG_SMALL("MPEG-2 video"),
.props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
.profiles = NULL_IF_CONFIG_SMALL(ff_mpeg2_video_profiles),
},
{
.id = AV_CODEC_ID_H261,
.type = AVMEDIA_TYPE_VIDEO,
.name = "h261",
.long_name = NULL_IF_CONFIG_SMALL("H.261"),
.props = AV_CODEC_PROP_LOSSY,
},
... //忽略, 很多
};
typedef struct AVCodecDescriptor {
enum AVCodecID id;
enum AVMediaType type;
const char *name;
const char *long_name;
int props;
const char *const *mime_types;
const struct AVProfile *profiles;
} AVCodecDescriptor;
该函数要做的只是把描述符指针组织成一个数组而已. 采用了2次扫描原则,
第一遍获得了个数, 然后分配了指针内存,第二遍把各地址填充了进去。
第二步,由id可以获得对应的codec指针。
codec 列表也定义了一个大的数组。
static const AVCodec * const codec_list[] = {
&ff_a64multi_encoder,
&ff_a64multi5_encoder,
&ff_alias_pix_encoder,
&ff_amv_encoder,
&ff_apng_encoder,
&ff_asv1_encoder,
&ff_asv2_encoder,
&ff_avrp_encoder,
.... // 很多,180个encoder, 480个decoder
}
每种codec 是一种对象,其对应的类为:
type = const struct AVCodec {
const char *name;
const char *long_name;
enum AVMediaType type;
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;
const char *wrapper_name;
int priv_data_size;
struct AVCodec *next;
int (*update_thread_context)(struct AVCodecContext *, const struct AVCodecContext *);
const AVCodecDefault *defaults;
void (*init_static_data)(struct AVCodec *);
int (*init)(struct AVCodecContext *);
int (*encode_sub)(struct AVCodecContext *, uint8_t *, int, const struct AVSubtitle *);
int (*encode2)(struct AVCodecContext *, struct AVPacket *, const struct AVFrame *, int *);
int (*decode)(struct AVCodecContext *, void *, int *, struct AVPacket *);
int (*close)(struct AVCodecContext *);
int (*receive_packet)(struct AVCodecContext *, struct AVPacket *);
int (*receive_frame)(struct AVCodecContext *, struct AVFrame *);
void (*flush)(struct AVCodecContext *);
int caps_internal;
const char *bsfs;
const struct AVCodecHWConfigInternal * const *hw_configs;
const uint32_t *codec_tags;
}
当你实现一种codec 时,可能只要实现必需的几个函数接口就可以了。
列出codec 列表,也只是枚举各codec,打印了其能力,名称,长名称而已.
分析以后发现,概念比较简单,属于数据组织而已。