通常建议直接用x265,应用方便和参数设置方便;
这里仅仅为了说明x265在FFmpeg中应用设置;
和x264差不多;
一:在FFmpeg中实现:
主要实现文件是:libx265.c文件中;
二:关于编码速度和profile的设置:
在x265中,x265.h:
static const char * const x265_preset_names[] = { "ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow", "placebo", 0 };
static const char * const x265_tune_names[] = { "psnr", "ssim", "grain", "zerolatency", "fastdecode", 0 };
static const cha
r * const x265_profile_names[] = {
/* HEVC v1 */
"main", "main10", "mainstillpicture", /* alias */ "msp",
/* HEVC v2 (Range Extensions) */
"main-intra", "main10-intra",
"main444-8", "main444-intra", "main444-stillpicture",
"main422-10", "main422-10-intra",
"main444-10", "main444-10-intra",
"main12", "main12-intra",
"main422-12", "main422-12-intra",
"main444-12", "main444-12-intra",
"main444-16-intra", "main444-16-stillpicture", /* Not Supported! */
0
};
在FFmpeg中,可以这么设置:
av_opt_set(c->priv_data, "preset", "ultrafast", 0);
av_opt_set(c->priv_data, "tune", "zerolatency", 0);
av_opt_set(c->priv_data, "profile", "main", 0);
也可以直接通过FFmpeg参数赋值profile:
c->profile = FF_PROFILE_HEVC_MAIN;
三:关于c->priv_data
更多细节可以参考:static av_cold int libx265_encode_init(AVCodecContext *avctx);
先看这个函数的实现:
typedef struct libx265Context {
const AVClass *class;
x265_encoder *encoder;
x265_param *params;
const x265_api *api;
float crf;
int forced_idr;
char *preset;
char *tune;
char *profile;
char *x265_opts;
} libx265Context;
static av_cold int libx265_encode_init(AVCodecContext *avctx)
{
//这个priv_data就是libx265Context 结构体;所以,具体的参数设置都在这里;
//怎么设置:就是这个函数:av_opt_set
libx265Context *ctx = avctx->priv_data;
}
四:更多参数设置:
通过源码,可以看出:
这样,应该可以设置相关的参数了;
static const AVOption options[] = {
{ "crf", "set the x265 crf", OFFSET(crf), AV_OPT_TYPE_FLOAT, { .dbl = -1 }, -1, FLT_MAX, VE },
{ "forced-idr", "if forcing keyframes, force them as IDR frames", OFFSET(forced_idr),AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
{ "preset", "set the x265 preset", OFFSET(preset), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
{ "tune", "set the x265 tune parameter", OFFSET(tune), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
{ "profile", "set the x265 profile", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
{ "x265-params", "set the x265 configuration using a :-separated list of key=value parameters", OFFSET(x265_opts), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
{ NULL }
};
注意:在FFmpeg中,每一个codec都会对应一个static const AVOption options[];可以从这里查看可以选择的参数;
更多具体用法可以参考FFmpeg中的av_opt_set;
五:再看:struct libx265Context 每一个参数都很重要;
typedef struct libx265Context {
const AVClass *class; //FFmpeg中的类;
x265_encoder *encoder; //x265中的struct;
x265_param *params; //x265中的param,很重要;
const x265_api *api; //x265的接口,可以获取,但是不建议,设置参数就可以了;
float crf;
int forced_idr; //输出IDR;
char *preset;
char *tune;
char *profile;
char *x265_opts;
} libx265Context;
前面已经看到,可以通过av_opt_set的相关函数设置,可以设置,很多参数;
但是比较麻烦;
示例:
1:设置输出IDR;
在FFmpeg输出 I 帧是: frame->pict_type = AV_PICTURE_TYPE_I;
如果要设置输出IDR,还要同时设置forced_idr = 1;
通常建议还是用这两个函数参考的AVOption options参数设置:av_opt_set 和 av_opt_set_int设置:
av_opt_set(c->priv_data, "forced-idr", "1", 0);
//或者
av_opt_set_int(c->priv_data, "forced-idr", 1, 0);
那就直接用结构体赋值:
为了简单,简单修改一下结构体:将指针类型修改为 void * ;
typedef struct libx265Context {
const void *class;
void *encoder;
void *params;
const void *api;
float crf;
int forced_idr;
char *preset;
char *tune;
char *profile;
char *x265_opts;
} libx265Context;
libx265Context * plibx265Context = (libx265Context*)c->priv_data;
plibx265Context->forced_idr = 1;
//一般这么写:av_opt_set(c->priv_data, "forced-idr", "1", 0);
encode_video_x265(...);
这样就可以输出IDR packet了;
2:为了更方便的设置,可以直接从相应的x265.h赋值到自己的工程中,然后就可以设置x265_param中的任何参数了;
更多av_opt_set的文章可以参考:
https://blog.csdn.net/leixiaohua1020/article/details/46890739
https://blog.csdn.net/xiaojun111111/article/details/53764903
AVOption (AVClass)
AVOption是FFmpeg的选项设置工具。与AVOption最相关的选项设置函数就是av_opt_set()了。AVOption的核心概念就是“根据字符串操作结构体的属性值”。例如下面代码中“#if”和“#else”之间代码的作用和“#else”和“#endif”之间代码的作用是一样的。
#if TEST_OPT
av_opt_set(pCodecCtx,"b","400000",0); //bitrate
//Another method
//av_opt_set_int(pCodecCtx,"b",400000,0); //bitrate
av_opt_set(pCodecCtx,"time_base","1/25",0); //time_base
av_opt_set(pCodecCtx,"bf","5",0); //max b frame
av_opt_set(pCodecCtx,"g","25",0); //gop
av_opt_set(pCodecCtx,"qmin","10",0); //qmin/qmax
av_opt_set(pCodecCtx,"qmax","51",0);
#else
pCodecCtx->time_base.num = 1;
pCodecCtx->time_base.den = 25;
pCodecCtx->max_b_frames=5;
pCodecCtx->bit_rate = 400000;
pCodecCtx->gop_size=25;
pCodecCtx->qmin = 10;
pCodecCtx->qmax = 51;
#endif