先看它的使用,知道使用后就非常简单了。如果不看使用,直接看实现的话,那可够看的。
AVCodec ff_libx264_encoder = {
.name = "libx264",
.type = AVMEDIA_TYPE_VIDEO,
.id = CODEC_ID_H264,
.priv_data_size = sizeof(X264Context),
.init = X264_init,
.encode = X264_frame,
.close = X264_close,
.capabilities = CODEC_CAP_DELAY,
.pix_fmts = (const enum PixelFormat[]) { PIX_FMT_YUV420P, PIX_FMT_YUVJ420P, PIX_FMT_NONE },
.long_name = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
.priv_class = &class,
};
static const AVClass class = { "libx264", av_default_item_name, options, LIBAVUTIL_VERSION_INT };
static const AVOption options[] = {
{"preset", "Set the encoding preset", OFFSET(preset), FF_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
{"tune", "Tune the encoding params", OFFSET(tune), FF_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
{"fastfirstpass", "Use fast settings when encoding first pass", OFFSET(fastfirstpass), FF_OPT_TYPE_INT, {.dbl=1}, 0, 1, VE},
{"profile", "Set profile restrictions", OFFSET(profile), FF_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
{"level", "Specify level (as defined by Annex A)", OFFSET(level), FF_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
{"passlogfile", "Filename for 2 pass stats", OFFSET(stats), FF_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
{"wpredp", "Weighted prediction for P-frames", OFFSET(weightp), FF_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
{"x264opts", "x264 options", OFFSET(x264opts), FF_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
{ NULL },
};
typedef struct X264Context {
AVClass *class;
x264_param_t params;
x264_t *enc;
x264_picture_t pic;
uint8_t *sei;
int sei_size;
AVFrame out_pic;
char *preset;
char *tune;
char *profile;
char *level;
int fastfirstpass;
char *stats;
char *weightp;
char *x264opts;
} X264Context;
这是ffmpeg中libx264.h中对于AVClass和AVOption的使用。看它们的关系,static变量class为 AVCodec.priv_classs,options为变量class.option,sizeof(X264Context)为ff_libx264_encoder.priv_data_size。
有一个很明显的东西看options.name,譬如”preset”,在X264Context中有一个preset变量。这让我想起了java中的映射,通过一个字符串,也就是名字来获取到这个以字符串为名字的变量的值。
有一个特点是AVClass *class;是X264Context的第一个变量,并且必须是。在实现中,通过opeion中的一个偏移量来获取到这个变量的地址,那么必须得保证X264Context的地址和AVClass的地址必须一样,这样才能使用偏移量。
option有很多针对于int,double,string等类型的get,set操作,而真正操作的option里面的dictionary。看一个set的例子,我去掉很多代码后,真正的代码就两步:一步find,一步赋值。
static int av_set_number2(void *obj, const char *name, double num, int den, int64_t intnum, const AVOption **o_out)
{
const AVOption *o = av_opt_find(obj, name, NULL, 0, 0);
void *dst;
dst= ((uint8_t*)obj) + o->offset;
switch (o->type) {
case FF_OPT_TYPE_FLAGS:
case FF_OPT_TYPE_INT: *(int *)dst= llrint(num/den)*intnum; break;
default:
return AVERROR(EINVAL);
}
return 0;
}
虽然说实现的时候ffmpeg考虑到了很多东东。但是功能非常清晰了。