之前多多少少接触过一些编解码参数,CRF 参数也用过,然而最近在和敌人们聊天时,说到应用 FFMPEG 过程中碰到 CRF 参数,以及具体作用流程,这个之前始终没有跟踪过,也没有具体记录过,所以吊起了本人的好奇心,于是决定搞清楚一下,便开始了这次 CRF 的神奇之旅。CRF 简介:
恒定速率因子(CRF,Constant Rate Factor)是一种编码模式,能够向上或向下调整文件数据速率以达到选定的品质级别,而不是特定的数据速率。
如果要放弃最佳品质,而又不怎么放心文件大小,这时候就能够应用 CRF 速率管制模式。这是大多数状况下倡议的速率管制模式。当输入文件的大小不太重要时,此办法容许编码器尝试为整个文件实现冀望指标视频品质的文件输入,即所谓的一次编码便可在预期视频品质下取得最大的视频压缩效率。CRF 模式次要原理是在编码过程中通过动静调整每帧视频的 QP 值,以便能够取得放弃所需视频品质程度比特率。
然而 CRF 毛病是不能告知编码器冀望取得特定大小的文件或不超过特定大小或比特率。同时须要留神的是采纳 CRF 时不倡议间接用来编码视频以进行流媒体传输。
通常倡议个别应用两种速率管制模式:恒定速率因子(CRF)或 2-pass ABR。速率管制决定每个帧将应用多少位。这将确定文件大小以及品质调配形式。CRF 实操演示
通过 FFMPEG 二进制文件尝试用参数 CRF 进行压缩,如下图所示:
FFMPEG 采纳 CRF 别离为 18、24 进行压缩,以及和源文件的比拟。
ffmpeg -i test.mp4 -c:v libx264 -crf 18 test18.mp4
理论转码中
转码完结后,会显示具体的编码相干信息,包含 ref,crf 值,qp 量化步长等,以及 I 帧、P 帧、B 帧所占比重。还蕴含了音频相干信息如下图:
用命令 ffmpeg -i test.mp4 -c:v libx264 -crf 24 test24.mp4,进行 CRF=24 的转码,转码后果如下图所示:
转码后别离对三个文件进行参数查看,并造成比照,其后果如下图所示:
上述参数只能大略理解三个视频根本信息,之后通过 Elecard eye 业余工具查看该变动产生起因的直观图,三个文件码流剖析后果:
三个文件比照状况总结如下:
能够看出:CRF 参数的应用,I 帧数量急剧缩小、同时引入 B 帧;熵编码采纳了 CABAC 形式,这样压缩率就晋升很多,文件大小变小。同时随着 CRF 值变大,P 帧和 B 帧压缩率也变大,文件更小。CRF 代码走读
尽管之前走读过 FFMPEG 代码,然而具体 CRF 参数的品读还没齐全留神到过。为了不是只知其一; 不知其二的明确该问题,还是强制本人走一遍代码,加强印象,粗浅意识,也为关怀该参数的小伙伴铺垫一下根底。*•CRF 定义
首先在 X264 中能够看到该值的定义:
typedef struct X264Context {
AVClass *class;
x264_param_t params;
......
float crf;
......
}
在 AVOption 具体定义如下:
static const AVOption options[] = {{ "preset", "Set the encoding preset (cf. x264 --fullhelp)", OFFSET(preset), AV_OPT_TYPE_STRING, {.str = "medium"}, 0, 0, VE},
{"tune", "Tune the encoding params (cf. x264 --fullhelp)", OFFSET(tune), AV_OPT_TYPE_STRING, {0}, 0, 0, VE},
{"profile", "Set profile restrictions (cf. x264 --fullhelp)", OFFSET(profile), AV_OPT_TYPE_STRING, {0}, 0, 0, VE},
......
{"x264opts", "x264 options", OFFSET(x264opts), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
{"crf", "Select the quality for constant quality mode", OFFSET(crf), AV_OPT_TYPE_FLOAT, {.dbl = -1}, -1, FLT_MAX, VE },
{"crf_max", "In CRF mode, prevents VBV from lowering quality beyond this point.",OFFSET(crf_max), AV_OPT_TYPE_FLOAT, {.dbl = -1}, -1, FLT_MAX, VE },
......
}
CRF 依然属于 Rate control 的一中,所以能够看到其 RC 相干定义如下:
#define X264_RC_CQP 0
#define X264_RC_CRF 1
#define X264_RC_ABR 2
•FFMPEG 接口梳理
波及到 FFMPEG 代码走读的局部太多了,在此只是简述 CRF 对应的局部,其余编解码流程大家能够依据网上其余大神的代码走读流程实现即可。此篇文章默认大家有足够根底:X264 的编解码入口合乎 FFMPEG 接口定义,对应关系如下图所示:
此处借用雷神的一张图阐明:(https://blog.csdn.net/leixiaohua1020/article/details/45960409)
- X264_init()
X264_init 函数次要作用就是将之前赋值和初始化的 option 值顺次传递到 libx264 模块中,进行 X264 参数初始化,以及 RC 参数赋值。这些值是从 AVCodecContext 传递过去,以及 X264Context 的默认值。相熟 FFMPEG 的人都理解,AVCodecContext 中蕴含输出命令行中编解码选项值,以及 FFMPEG 命令中蕴含的 option 值,而 X264Context 蕴含 x264 的相干选项,两者联合形成残缺的 x264 编解码选项值。
在 X264_init 的最初,进行 X264Codec 的 OPEN 动作,以及编码全局 header 的动作。
- x264_param_default
x264_param_default 设置默认参数,包含其余的选项值,在此只关怀 CRF 相干选项。x264_param_default 中将 CRF 默认开启,同时设置 CRF 选项 f_rf_constant 置为 23,这也是其余很多文章中讲到的默认值 23 的起因。
同时留神,察看到在 x264_param_default 默认参数中 B 帧是再次设置并置位的,而且 cabac 默认开启。所以如果用 FFMPEG bin 文件进行转码进去的文件中 cabac 是默认开启的,这也是工具端查看时会呈现 CABAC 以及减少 B 帧的根本原因了。
- x264_encoder_open
在初始化具体参数后,init 函数接下来进行 x264_encoder_open(相干代码位于 encoder\encoder.c)的操作,这时会具体关上到 x264 中 h264 相干编码器。
之后在 x264_encoder_open 中次要用于关上编码器,其中校验、初始化了 libx264 编码所须要的各种变量,并实现 sps、pps、qm 初始化。
- validate_parameters
调用 validate_parameters 会进行输出参数的校验,避免输出参数异样导致编码失败。此函数中实现 CRF 相干参数校验、更新和赋值。
其余流程局部能够参考其余大神的文章,再次不再累述。(雷神的解析十分详尽了,敬请膜拜即可 x264 源代码简略剖析:编码器骨干局部 -1_雷霄骅 (leixiaohua1020) 的专栏 -CSDN 博客)
- x264_ratecontrol_new
x264_encoder_open 最初会调用 x264_ratecontrol_new 实现码率管制相干变量初始化。
x264_ratecontrol_new,次要设置码率管制的外围参数,须要对 x264 码率管制比拟理解能力真正明确,否则会容易看晕。
x264_ratecontrol_new 函数中根据传入参数是 CRF 模式,以及 b_stat_read 默认值为 0 即可将 b_abr 参数的置位为 1,同时 b_2pass 置位为 0,也就是说 CRF 模式在 rate_control 中依照 abr、非 2-pass 进行解决的。
在 x264_ratecontrol_init_reconfigurable 函数中会进行 VBV 参数初始化,以及 CRF 相干参数 base_cplx、rate_factor_constant 的更新。
同时 x264_ratecontrol_init_reconfigurable 中设置被调用时,传入 b_init=1 的参数,这时 CRF 置位了 VBV 模式,为后续的 rate_control 做了铺垫。
- X264_frame
X264_frame()用于根据传入 packet 数据进行一帧视频数据的残缺编码。该函数局部定义如下所示。
- reconfig_encoder
reconfig_encoder 次要作用就是将 RC 相干的参数和 AVCodecContext 中参数进行比拟,如果不统一,则重新配置编码器。比方 CRF 值初始设置为 24,然而命令行中设置为 18,这时两个值不统一,则须要依照命令行中值进行赋值并重新配置编码器,以便最终合乎用户预期。具体配置大家简略看一下就好,这里不再开展。
- x264_encoder_encode
x264_encoder_encode 是真正编码的开始,在 x264_encoder_encode 这个函数外面将一帧残缺 YUV 图像编码成 H264 视频流,这个过程能够参考雷神的文章,解析十分好,https://blog.csdn.net/leixiao…
这边关怀的是 CRF 中波及到的局部内容,在 x264_encoder_encode 中和码率管制相干的内容次要是一下接口:
x264_thread_sync_ratecontrol():
x264_ratecontrol_zone_init():
x264_ratecontrol_start():开启码率管制,针对每一帧进行码率管制。在 x264_ratecontrol_start 中会依据码率管制模式的不同,抉择不同的 qp 进行压缩。之前剖析可知,CRF 是属于 abr 模式,同时减少了 B 帧,所以导致每帧图像的 qp 都是不同的,这样压缩后雷同品质的条件下编码后文件大小就不能确定了。
x264_ratecontrol_qp():
码率管制是一个大块内容,设计的算法也比较复杂,该文只关注了如何将 crf 模式转换到 vbv 模式,以及对影响编码的局部参数,整个过程下一篇文章咱们再进行剖析和跟踪。
以上是集体的一些认识,可能有不正确的中央,欢送大家一起探讨学习。
如果该文章对您有帮忙,欢送点赞,珍藏,转发、关注,在下继续更新音视频相干内容。