1. 程式人生 > >FFmpeg XAVC實現/x264實現 (2)

FFmpeg XAVC實現/x264實現 (2)

思路

    上一篇文章提到了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