[x264-devel] [Git][videolan/x264][master] 2 commits: Support writing the mastering display color volume SEI message

Anton Mitrofanov gitlab at videolan.org
Wed May 5 07:23:23 UTC 2021



Anton Mitrofanov pushed to branch master at VideoLAN / x264


Commits:
8719ef8a by Phillip Blucas at 2021-05-05T07:11:57+00:00
Support writing the mastering display color volume SEI message

Use --mastering-display to specify the properties of the reference display.
A formatted string with all 10 values is required: G,B,R primaries and
white point coordinates, plus max/min brightness. Coordinates are in
0.00002 increments. Brightness units are 0.0001 cd/m^2.

For example, a 1000 nit BT.2020 display with a 0.0001 nit black level:
--mastering-display G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)

- - - - -
fa770fd5 by Phillip Blucas at 2021-05-05T07:11:57+00:00
Support writing the content light level information SEI message

Use --cll to specify the maximum content light level (MaxCLL)
and the maximum frame average light level (MaxFALL) as described
by the CTA 861.3 specification.

- - - - -


8 changed files:

- autocomplete.c
- common/base.c
- common/base.h
- encoder/encoder.c
- encoder/set.c
- encoder/set.h
- x264.c
- x264.h


Changes:

=====================================
autocomplete.c
=====================================
@@ -115,6 +115,8 @@ static const char * const opts_nosuggest[] =
     "--ipratio",
     "--keyint", "-I",
     "--lookahead-threads",
+    "--mastering-display",
+    "--cll",
     "--merange",
     "--min-keyint", "-i",
     "--mvrange",


=====================================
common/base.c
=====================================
@@ -1013,6 +1013,32 @@ REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const cha
         p->vui.i_chroma_loc = atoi(value);
         b_error = ( p->vui.i_chroma_loc < 0 || p->vui.i_chroma_loc > 5 );
     }
+    OPT("mastering-display")
+    {
+        if( strcasecmp( value, "undef" ) )
+        {
+            b_error |= sscanf( value, "G(%d,%d)B(%d,%d)R(%d,%d)WP(%d,%d)L(%"SCNd64",%"SCNd64")",
+                               &p->mastering_display.i_green_x, &p->mastering_display.i_green_y,
+                               &p->mastering_display.i_blue_x, &p->mastering_display.i_blue_y,
+                               &p->mastering_display.i_red_x, &p->mastering_display.i_red_y,
+                               &p->mastering_display.i_white_x, &p->mastering_display.i_white_y,
+                               &p->mastering_display.i_display_max, &p->mastering_display.i_display_min ) != 10;
+            p->mastering_display.b_mastering_display = !b_error;
+        }
+        else
+            p->mastering_display.b_mastering_display = 0;
+    }
+    OPT("cll")
+    {
+        if( strcasecmp( value, "undef" ) )
+        {
+            b_error |= sscanf( value, "%d,%d",
+                               &p->content_light_level.i_max_cll, &p->content_light_level.i_max_fall ) != 2;
+            p->content_light_level.b_cll = !b_error;
+        }
+        else
+            p->content_light_level.b_cll = 0;
+    }
     OPT("alternative-transfer")
         b_error |= parse_enum( value, x264_transfer_names, &p->i_alternative_transfer );
     OPT("fps")
@@ -1389,7 +1415,7 @@ REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const cha
  ****************************************************************************/
 char *x264_param2string( x264_param_t *p, int b_res )
 {
-    int len = 1000;
+    int len = 2000;
     char *buf, *s;
     if( p->rc.psz_zones )
         len += strlen(p->rc.psz_zones);
@@ -1498,6 +1524,16 @@ char *x264_param2string( x264_param_t *p, int b_res )
     if( p->crop_rect.i_left | p->crop_rect.i_top | p->crop_rect.i_right | p->crop_rect.i_bottom )
         s += sprintf( s, " crop_rect=%d,%d,%d,%d", p->crop_rect.i_left, p->crop_rect.i_top,
                                                    p->crop_rect.i_right, p->crop_rect.i_bottom );
+    if( p->mastering_display.b_mastering_display )
+        s += sprintf( s, " mastering-display=G(%d,%d)B(%d,%d)R(%d,%d)WP(%d,%d)L(%"PRId64",%"PRId64")",
+                      p->mastering_display.i_green_x, p->mastering_display.i_green_y,
+                      p->mastering_display.i_blue_x, p->mastering_display.i_blue_y,
+                      p->mastering_display.i_red_x, p->mastering_display.i_red_y,
+                      p->mastering_display.i_white_x, p->mastering_display.i_white_y,
+                      p->mastering_display.i_display_max, p->mastering_display.i_display_min );
+    if( p->content_light_level.b_cll )
+        s += sprintf( s, " cll=%d,%d",
+                      p->content_light_level.i_max_cll, p->content_light_level.i_max_fall );
     if( p->i_frame_packing >= 0 )
         s += sprintf( s, " frame-packing=%d", p->i_frame_packing );
 


=====================================
common/base.h
=====================================
@@ -128,6 +128,8 @@ enum sei_payload_type_e
     SEI_RECOVERY_POINT         = 6,
     SEI_DEC_REF_PIC_MARKING    = 7,
     SEI_FRAME_PACKING          = 45,
+    SEI_MASTERING_DISPLAY      = 137,
+    SEI_CONTENT_LIGHT_LEVEL    = 144,
     SEI_ALTERNATIVE_TRANSFER   = 147,
 };
 


=====================================
encoder/encoder.c
=====================================
@@ -640,6 +640,41 @@ static int validate_parameters( x264_t *h, int b_open )
         return -1;
     }
 
+    if( h->param.mastering_display.b_mastering_display )
+    {
+        if( h->param.mastering_display.i_green_x > UINT16_MAX || h->param.mastering_display.i_green_x < 0 ||
+            h->param.mastering_display.i_green_y > UINT16_MAX || h->param.mastering_display.i_green_y < 0 ||
+            h->param.mastering_display.i_blue_x > UINT16_MAX || h->param.mastering_display.i_blue_x < 0 ||
+            h->param.mastering_display.i_blue_y > UINT16_MAX || h->param.mastering_display.i_blue_y < 0 ||
+            h->param.mastering_display.i_red_x > UINT16_MAX || h->param.mastering_display.i_red_x < 0 ||
+            h->param.mastering_display.i_red_y > UINT16_MAX || h->param.mastering_display.i_red_y < 0 ||
+            h->param.mastering_display.i_white_x > UINT16_MAX || h->param.mastering_display.i_white_x < 0 ||
+            h->param.mastering_display.i_white_y > UINT16_MAX || h->param.mastering_display.i_white_y < 0 )
+        {
+            x264_log( h, X264_LOG_ERROR, "mastering display xy coordinates out of range [0,%u]\n", UINT16_MAX );
+            return -1;
+        }
+        if( h->param.mastering_display.i_display_max > UINT32_MAX || h->param.mastering_display.i_display_max < 0 ||
+            h->param.mastering_display.i_display_min > UINT32_MAX || h->param.mastering_display.i_display_min < 0 )
+        {
+            x264_log( h, X264_LOG_ERROR, "mastering display brightness out of range [0,%u]\n", UINT32_MAX );
+            return -1;
+        }
+        if( h->param.mastering_display.i_display_min == 50000 && h->param.mastering_display.i_display_max == 50000 )
+        {
+            x264_log( h, X264_LOG_ERROR, "mastering display min and max brightness cannot both be 50000\n" );
+            return -1;
+        }
+    }
+
+    if( h->param.content_light_level.b_cll &&
+        (h->param.content_light_level.i_max_cll > UINT16_MAX || h->param.content_light_level.i_max_cll < 0 ||
+         h->param.content_light_level.i_max_fall > UINT16_MAX || h->param.content_light_level.i_max_fall < 0) )
+    {
+        x264_log( h, X264_LOG_ERROR, "content light levels out of range [0,%u]\n", UINT16_MAX );
+        return -1;
+    }
+
     /* Detect default ffmpeg settings and terminate with an error. */
     if( b_open )
     {
@@ -1818,6 +1853,9 @@ static int encoder_try_reconfig( x264_t *h, x264_param_t *param, int *rc_reconfi
     COPY( i_deblocking_filter_alphac0 );
     COPY( i_deblocking_filter_beta );
     COPY( i_frame_packing );
+    COPY( mastering_display );
+    COPY( content_light_level );
+    COPY( i_alternative_transfer );
     COPY( analyse.inter );
     COPY( analyse.intra );
     COPY( analyse.i_direct_mv_pred );
@@ -3691,6 +3729,33 @@ int     x264_encoder_encode( x264_t *h,
                 return -1;
             overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
         }
+
+        if( h->param.mastering_display.b_mastering_display )
+        {
+            nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
+            x264_sei_mastering_display_write( h, &h->out.bs );
+            if( nal_end( h ) )
+                return -1;
+            overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
+        }
+
+        if( h->param.content_light_level.b_cll )
+        {
+            nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
+            x264_sei_content_light_level_write( h, &h->out.bs );
+            if( nal_end( h ) )
+                return -1;
+            overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
+        }
+
+        if( h->param.i_alternative_transfer != 2 )
+        {
+            nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
+            x264_sei_alternative_transfer_write( h, &h->out.bs );
+            if( nal_end( h ) )
+                return -1;
+            overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
+        }
     }
 
     if( h->param.i_frame_packing >= 0 && (h->fenc->b_keyframe || h->param.i_frame_packing == 5) )
@@ -3702,15 +3767,6 @@ int     x264_encoder_encode( x264_t *h,
         overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
     }
 
-    if( h->param.i_alternative_transfer != 2 )
-    {
-        nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
-        x264_sei_alternative_transfer_write( h, &h->out.bs );
-        if( nal_end( h ) )
-            return -1;
-        overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD;
-    }
-
     /* generate sei pic timing */
     if( h->sps->vui.b_pic_struct_present || h->sps->vui.b_nal_hrd_parameters_present )
     {


=====================================
encoder/set.c
=====================================
@@ -703,6 +703,48 @@ void x264_sei_frame_packing_write( x264_t *h, bs_t *s )
     x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_FRAME_PACKING );
 }
 
+void x264_sei_mastering_display_write( x264_t *h, bs_t *s )
+{
+    bs_t q;
+    ALIGNED_4( uint8_t tmp_buf[100] );
+    M32( tmp_buf ) = 0; // shut up gcc
+    bs_init( &q, tmp_buf, 100 );
+
+    bs_realign( &q );
+
+    bs_write( &q, 16, h->param.mastering_display.i_green_x );
+    bs_write( &q, 16, h->param.mastering_display.i_green_y );
+    bs_write( &q, 16, h->param.mastering_display.i_blue_x );
+    bs_write( &q, 16, h->param.mastering_display.i_blue_y );
+    bs_write( &q, 16, h->param.mastering_display.i_red_x );
+    bs_write( &q, 16, h->param.mastering_display.i_red_y );
+    bs_write( &q, 16, h->param.mastering_display.i_white_x );
+    bs_write( &q, 16, h->param.mastering_display.i_white_y );
+    bs_write32( &q, h->param.mastering_display.i_display_max );
+    bs_write32( &q, h->param.mastering_display.i_display_min );
+
+    bs_align_10( &q );
+
+    x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_MASTERING_DISPLAY );
+}
+
+void x264_sei_content_light_level_write( x264_t *h, bs_t *s )
+{
+    bs_t q;
+    ALIGNED_4( uint8_t tmp_buf[100] );
+    M32( tmp_buf ) = 0; // shut up gcc
+    bs_init( &q, tmp_buf, 100 );
+
+    bs_realign( &q );
+
+    bs_write( &q, 16, h->param.content_light_level.i_max_cll );
+    bs_write( &q, 16, h->param.content_light_level.i_max_fall );
+
+    bs_align_10( &q );
+
+    x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_CONTENT_LIGHT_LEVEL );
+}
+
 void x264_sei_alternative_transfer_write( x264_t *h, bs_t *s )
 {
     bs_t q;


=====================================
encoder/set.h
=====================================
@@ -53,6 +53,10 @@ void x264_sei_pic_timing_write( x264_t *h, bs_t *s );
 void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s );
 #define x264_sei_frame_packing_write x264_template(sei_frame_packing_write)
 void x264_sei_frame_packing_write( x264_t *h, bs_t *s );
+#define x264_sei_mastering_display_write x264_template(sei_mastering_display_write)
+void x264_sei_mastering_display_write( x264_t *h, bs_t *s );
+#define x264_sei_content_light_level_write x264_template(sei_content_light_level_write)
+void x264_sei_content_light_level_write( x264_t *h, bs_t *s );
 #define x264_sei_alternative_transfer_write x264_template(sei_alternative_transfer_write)
 void x264_sei_alternative_transfer_write( x264_t *h, bs_t *s );
 #define x264_sei_avcintra_umid_write x264_template(sei_avcintra_umid_write)


=====================================
x264.c
=====================================
@@ -874,6 +874,10 @@ static void help( x264_param_t *defaults, int longhelp )
                                        strtable_lookup( x264_colmatrix_names, defaults->vui.i_colmatrix ) );
     H2( "      --chromaloc <integer>   Specify chroma sample location (0 to 5) [%d]\n",
                                        defaults->vui.i_chroma_loc );
+    H2( "      --mastering-display <string> Specify 'G(x,y)B(x,y)R(x,y)WP(x,y)L(max,min)'\n"
+        "                              for primaries, white point, and display brightness\n" );
+    H2( "      --cll <string>          Specify 'max_content,max_frame_average' content\n"
+        "                              light levels\n" );
     H2( "      --alternative-transfer <string> Specify an alternative transfer\n"
         "                              characteristics [\"%s\"]\n"
         "                                  - same values as --transfer\n",
@@ -1160,6 +1164,8 @@ static struct option long_options[] =
     { "pulldown",    required_argument, NULL, OPT_PULLDOWN },
     { "fake-interlaced",   no_argument, NULL, 0 },
     { "frame-packing",     required_argument, NULL, 0 },
+    { "mastering-display", required_argument, NULL, 0 },
+    { "cll",         required_argument, NULL, 0 },
     { "alternative-transfer", required_argument, NULL, 0 },
     { "vf",          required_argument, NULL, OPT_VIDEO_FILTER },
     { "video-filter", required_argument, NULL, OPT_VIDEO_FILTER },


=====================================
x264.h
=====================================
@@ -45,7 +45,7 @@ extern "C" {
 
 #include "x264_config.h"
 
-#define X264_BUILD 161
+#define X264_BUILD 163
 
 #ifdef _WIN32
 #   define X264_DLL_IMPORT __declspec(dllimport)
@@ -485,6 +485,31 @@ typedef struct x264_param_t
     /* frame packing arrangement flag */
     int i_frame_packing;
 
+    /* mastering display SEI: Primary and white point chromaticity coordinates
+       in 0.00002 increments. Brightness units are 0.0001 cd/m^2. */
+    struct
+    {
+        int b_mastering_display;    /* enable writing this SEI */
+        int i_green_x;
+        int i_green_y;
+        int i_blue_x;
+        int i_blue_y;
+        int i_red_x;
+        int i_red_y;
+        int i_white_x;
+        int i_white_y;
+        int64_t i_display_max;
+        int64_t i_display_min;
+    } mastering_display;
+
+    /* content light level SEI */
+    struct
+    {
+        int b_cll;                  /* enable writing this SEI */
+        int i_max_cll;
+        int i_max_fall;
+    } content_light_level;
+
     /* alternative transfer SEI */
     int i_alternative_transfer;
 



View it on GitLab: https://code.videolan.org/videolan/x264/-/compare/4459373fd7d3eac92507372b55e4af93c04d4be9...fa770fd537f776beb2bd3f1080503b3797b66b88

-- 
View it on GitLab: https://code.videolan.org/videolan/x264/-/compare/4459373fd7d3eac92507372b55e4af93c04d4be9...fa770fd537f776beb2bd3f1080503b3797b66b88
You're receiving this email because of your account on code.videolan.org.




More information about the x264-devel mailing list