思路
上一篇文章提到了XAVC的一些背景,以及非每帧固定码率的实现方法。然而如果要实现XAVC中的CBG模式(Constrained Bytes per GOP)就必须修改x264源码固定每帧码率。
x264中对松下 AVC Intra Class 有支持,AVC Intra Class 100/200是定义在HD下的与XAVC类似的标准。因此可以通过扩展这部分的代码功能来实现4K XAVC Intra Class 300/480。
应用设置接口参数 avcintra-class=300 avcintra-flavor=sony进行编码标准的设置。
代码
diff --git a/encoder/encoder.c b/encoder/encoder.c
index 074c4a5c..5fb84fcd 100644
--- a/encoder/encoder.c
+++ b/encoder/encoder.c
@@ -678,9 +678,13 @@ static int validate_parameters( x264_t *h, int b_open )
return -1;
}
- int type = h->param.i_avcintra_class == 200 ? 2 :
+ int type = h->param.i_avcintra_class == 480 ? 4 :
+ h->param.i_avcintra_class == 300 ? 3 :
+ h->param.i_avcintra_class == 200 ? 2 :
h->param.i_avcintra_class == 100 ? 1 :
h->param.i_avcintra_class == 50 ? 0 : -1;
+ int xavc = (h->param.i_avcintra_flavor == X264_AVCINTRA_FLAVOR_SONY);
+
if( type < 0 )
{
x264_log( h, X264_LOG_ERROR, "Invalid AVC-Intra class\n" );
@@ -733,21 +737,101 @@ static int validate_parameters( x264_t *h, int b_open )
{ 24000, 1001, 0, 7444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}}
};
- int res = -1;
- if( i_csp >= X264_CSP_I420 && i_csp < X264_CSP_I422 && !type )
+ /* [50/100/200/300/480][720p/1440x1080/1080p/2048x1080/4K][fps] */
+ static const struct
{
- if( h->param.i_width == 1440 && h->param.i_height == 1080 ) res = 1;
- else if( h->param.i_width == 960 && h->param.i_height == 720 ) res = 0;
- }
- else if( i_csp >= X264_CSP_I422 && i_csp < X264_CSP_I444 && type )
+ uint16_t fps_num;
+ uint16_t fps_den;
+ uint8_t interlaced;
+ uint16_t frame_size;
+ const uint8_t *cqm_4ic;
+ const uint8_t *cqm_8iy;
+ } xavcintra_lut[5][5][7] =
{
- if( h->param.i_width == 1920 && h->param.i_height == 1080 ) res = 1;
- else if( h->param.i_width == 1280 && h->param.i_height == 720 ) res = 0;
- }
- else
+ {{{}},
+ {{ 50, 1, 1, 2120, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 60000, 1001, 1, 1744, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 24000, 1001, 0, 1744, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 25, 1, 0, 2120, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy },
+ { 30000, 1001, 0, 1744, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }}},
+ {{{ 60000, 1001, 0, 1804, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy },
+ { 50, 1, 0, 2180, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }},
+ {{}},
+ {{ 50, 1, 1, 4368, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy },
+ { 60000, 1001, 1, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy },
+ { 24000, 1001, 0, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 25, 1, 0, 4368, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 30000, 1001, 0, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 50, 1, 0, 4368, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 60000, 1001, 0, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }},
+ {{ 24000, 1001, 0, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 24, 1, 0, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 25, 1, 0, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 30000, 1001, 0, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 50, 1, 0, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 60000, 1001, 0, 3616, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}},
+ {{{}},
+ {{}},
+ {{ 50, 1, 1, 8864, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy },
+ { 60000, 1001, 1, 7368, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy },
+ { 24000, 1001, 0, 7368, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 25, 1, 0, 8864, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 30000, 1001, 0, 7368, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 50, 1, 0, 8864, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 60000, 1001, 0, 7368, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}},
+ {{{}},
+ {{}},
+ {{}},
+ {{}},
+ {{ 24000, 1001, 0, 9768, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 25, 1, 0, 9768, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 30000, 1001, 0, 9768, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 50, 1, 0, 9768, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 60000, 1001, 0, 9768, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}},
+ {{{}},
+ {{}},
+ {{}},
+ {{}},
+ {{ 24000, 1001, 0,15624, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 25, 1, 0,15624, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 30000, 1001, 0,15624, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 50, 1, 0,15624, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy },
+ { 60000, 1001, 0,15624, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}},
+ };
+
+ int res = -1;
+ if(xavc)
{
- x264_log( h, X264_LOG_ERROR, "Invalid colorspace for AVC-Intra %d\n", h->param.i_avcintra_class );
- return -1;
+ if( i_csp >= X264_CSP_I422 && i_csp < X264_CSP_I444 && type )
+ {
+ if( h->param.i_width == 1280 && h->param.i_height == 720 ) res = 0;
+ else if(h->param.i_width == 1440 && h->param.i_height == 1080 ) res = 1;
+ else if(h->param.i_width == 1920 && h->param.i_height == 1080 ) res = 2;
+ else if(h->param.i_width == 2048 && h->param.i_height == 1080 ) res = 3;
+ else if(h->param.i_width == 3840 && h->param.i_height == 2160 ) res = 4;
+ else if(h->param.i_width == 4096 && h->param.i_height == 2160 ) res = 4;
+ }
+ else
+ {
+ x264_log( h, X264_LOG_ERROR, "Invalid colorspace for XAVC-Intra %d\n", h->param.i_avcintra_class );
+ return -1;
+ }
+ } else {
+ if( i_csp >= X264_CSP_I420 && i_csp < X264_CSP_I422 && !type )
+ {
+ if( h->param.i_width == 1440 && h->param.i_height == 1080 ) res = 1;
+ else if( h->param.i_width == 960 && h->param.i_height == 720 ) res = 0;
+ }
+ else if( i_csp >= X264_CSP_I422 && i_csp < X264_CSP_I444 && type )
+ {
+ if( h->param.i_width == 1920 && h->param.i_height == 1080 ) res = 1;
+ else if( h->param.i_width == 1280 && h->param.i_height == 720 ) res = 0;
+ }
+ else
+ {
+ x264_log( h, X264_LOG_ERROR, "Invalid colorspace for AVC-Intra %d\n", h->param.i_avcintra_class );
+ return -1;
+ }
}
if( res < 0 )
@@ -774,11 +858,20 @@ static int validate_parameters( x264_t *h, int b_open )
x264_reduce_fraction( &fps_num, &fps_den );
for( i = 0; i < 7; i++ )
{
- if( avcintra_lut[type][res][i].fps_num == fps_num &&
- avcintra_lut[type][res][i].fps_den == fps_den &&
- avcintra_lut[type][res][i].interlaced == PARAM_INTERLACED )
- {
- break;
+ if (xavc) {
+ if( xavcintra_lut[type][res][i].fps_num == fps_num &&
+ xavcintra_lut[type][res][i].fps_den == fps_den &&
+ xavcintra_lut[type][res][i].interlaced == PARAM_INTERLACED )
+ {
+ break;
+ }
+ } else {
+ if( avcintra_lut[type][res][i].fps_num == fps_num &&
+ avcintra_lut[type][res][i].fps_den == fps_den &&
+ avcintra_lut[type][res][i].interlaced == PARAM_INTERLACED )
+ {
+ break;
+ }
}
}
if( i == 7 )
@@ -806,7 +899,7 @@ static int validate_parameters( x264_t *h, int b_open )
h->param.analyse.intra = X264_ANALYSE_I8x8;
h->param.analyse.i_chroma_qp_offset = res && type ? 3 : 4;
h->param.b_cabac = !type;
- h->param.rc.i_vbv_buffer_size = avcintra_lut[type][res][i].frame_size;
+ h->param.rc.i_vbv_buffer_size = xavc ? xavcintra_lut[type][res][i].frame_size : avcintra_lut[type][res][i].frame_size;
h->param.rc.i_vbv_max_bitrate =
h->param.rc.i_bitrate = h->param.rc.i_vbv_buffer_size * fps_num / fps_den;
h->param.rc.i_rc_method = X264_RC_ABR;
@@ -814,8 +907,13 @@ static int validate_parameters( x264_t *h, int b_open )
h->param.rc.b_filler = 1;
h->param.i_cqm_preset = X264_CQM_CUSTOM;
memcpy( h->param.cqm_4iy, x264_cqm_jvt4i, sizeof(h->param.cqm_4iy) );
- memcpy( h->param.cqm_4ic, avcintra_lut[type][res][i].cqm_4ic, sizeof(h->param.cqm_4ic) );
- memcpy( h->param.cqm_8iy, avcintra_lut[type][res][i].cqm_8iy, sizeof(h->param.cqm_8iy) );
+ if (xavc) {
+ memcpy( h->param.cqm_4ic, xavcintra_lut[type][res][i].cqm_4ic, sizeof(h->param.cqm_4ic) );
+ memcpy( h->param.cqm_8iy, xavcintra_lut[type][res][i].cqm_8iy, sizeof(h->param.cqm_8iy) );
+ } else {
+ memcpy( h->param.cqm_4ic, avcintra_lut[type][res][i].cqm_4ic, sizeof(h->param.cqm_4ic) );
+ memcpy( h->param.cqm_8iy, avcintra_lut[type][res][i].cqm_8iy, sizeof(h->param.cqm_8iy) );
+ }
/* Sony XAVC flavor much more simple */
if( h->param.i_avcintra_flavor == X264_AVCINTRA_FLAVOR_SONY )
运行
./ffmpeg -i '/home/lyh/4K/Customer/Sobey/2018080927test_video/10M_SR012CA3.mp4' -r 50 -pix_fmt yuv422p10le -c:v libx264 -avcintra-class 300 -x264opts avcintra-class=300 -x264opts avcintra-flavor=sony 1.mxf