[FFmpeg-devel,v2,29/36] h264_metadata: Add option to set the level of the stream

Submitted by Mark Thompson on June 7, 2018, 11:43 p.m.

Details

Message ID 20180607234331.32139-30-sw@jkqxz.net
State New
Headers show

Commit Message

Mark Thompson June 7, 2018, 11:43 p.m.
---
 doc/bitstream_filters.texi     |  9 +++++
 libavcodec/h264_metadata_bsf.c | 90 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+)

Comments

Michael Niedermayer June 8, 2018, 11:19 p.m.
On Fri, Jun 08, 2018 at 12:43:24AM +0100, Mark Thompson wrote:
> ---
>  doc/bitstream_filters.texi     |  9 +++++
>  libavcodec/h264_metadata_bsf.c | 90 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 99 insertions(+)

this breaks the mingw64 build

LD	ffmpeg_g.exe
libavcodec/libavcodec.a(h264_metadata_bsf.o): In function `h264_metadata_update_sps':
mingw64/src/libavcodec/h264_metadata_bsf.c:243: undefined reference to `ff_h264_guess_level'
mingw64/src/libavcodec/h264_metadata_bsf.c:243:(.text+0x36c): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `ff_h264_guess_level'
collect2: error: ld returned 1 exit status
make: *** [ffmpeg_g.exe] Error 1

[...]
Haihao Xiang June 15, 2018, 2:49 a.m.
On Fri, 2018-06-08 at 00:43 +0100, Mark Thompson wrote:
> ---

>  doc/bitstream_filters.texi     |  9 +++++

>  libavcodec/h264_metadata_bsf.c | 90

> ++++++++++++++++++++++++++++++++++++++++++

>  2 files changed, 99 insertions(+)

> 

> diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi

> index 7d7e97503a..d948c6d658 100644

> --- a/doc/bitstream_filters.texi

> +++ b/doc/bitstream_filters.texi

> @@ -215,6 +215,15 @@ insert the string ``hello'' associated with the given

> UUID.

>  @item delete_filler

>  Deletes both filler NAL units and filler SEI messages.

>  

> +@item level

> +Set the level in the SPS.  Refer to H.264 section A.3 and tables A-1

> +to A-5.

> +

> +The argument must be the name of a level (for example, @samp{4.2}), a

> +level_idc value (for example, @samp{42}), or the special name @samp{auto}

> +indicating that the filter should attempt to guess the level from the

> +input stream properties.

> +

>  @end table

>  

>  @section h264_mp4toannexb

> diff --git a/libavcodec/h264_metadata_bsf.c b/libavcodec/h264_metadata_bsf.c

> index 90ad4aad98..cb1a835fb8 100644

> --- a/libavcodec/h264_metadata_bsf.c

> +++ b/libavcodec/h264_metadata_bsf.c

> @@ -25,6 +25,7 @@

>  #include "cbs.h"

>  #include "cbs_h264.h"

>  #include "h264.h"

> +#include "h264_levels.h"

>  #include "h264_sei.h"

>  

>  enum {

> @@ -39,6 +40,11 @@ enum {

>      FLIP_VERTICAL   = 2,

>  };

>  

> +enum {

> +    LEVEL_UNSET = -2,

> +    LEVEL_AUTO  = -1,

> +};

> +

>  typedef struct H264MetadataContext {

>      const AVClass *class;

>  

> @@ -74,6 +80,8 @@ typedef struct H264MetadataContext {

>      int display_orientation;

>      double rotate;

>      int flip;

> +

> +    int level;

>  } H264MetadataContext;

>  

>  

> @@ -208,6 +216,58 @@ static int h264_metadata_update_sps(AVBSFContext *bsf,

>      CROP(bottom, crop_unit_y);

>  #undef CROP

>  

> +    if (ctx->level != LEVEL_UNSET) {

> +        int level_idc;

> +

> +        if (ctx->level == LEVEL_AUTO) {

> +            const H264LevelDescriptor *desc;

> +            int64_t bit_rate;

> +            int width, height;

> +

> +            if (sps->vui.nal_hrd_parameters_present_flag) {

> +                bit_rate = (sps-

> >vui.nal_hrd_parameters.bit_rate_value_minus1[0] + 1) *

> +                     (1 << (sps->vui.nal_hrd_parameters.bit_rate_scale + 6));

> +            } else if (sps->vui.vcl_hrd_parameters_present_flag) {

> +                bit_rate = (sps-

> >vui.vcl_hrd_parameters.bit_rate_value_minus1[0] + 1) *

> +                     (1 << (sps->vui.vcl_hrd_parameters.bit_rate_scale + 6));

> +                // Adjust for VCL vs. NAL limits.

> +                bit_rate = bit_rate * 6 / 5;

> +            } else {

> +                bit_rate = 0;

> +            }

> +

> +            width  = 16 * (sps->pic_width_in_mbs_minus1 + 1);

> +            height = 16 * (sps->pic_height_in_map_units_minus1 + 1) *

> +                (2 - sps->frame_mbs_only_flag);

> +

> +            desc = ff_h264_guess_level(sps->profile_idc, bit_rate,

> +                                       width, height,

> +                                       sps->vui.max_dec_frame_buffering);

> +            if (desc) {

> +                level_idc = desc->level_idc;

> +            } else {

> +                av_log(bsf, AV_LOG_WARNING, "Stream does not appear to "

> +                       "conform to any level: using level 6.2.\n");

> +                level_idc = 62;

> +            }

> +        } else {

> +            level_idc = ctx->level;

> +        }

> +

> +        if (level_idc == 9) {

> +            if (sps->profile_idc == 66 ||

> +                sps->profile_idc == 77 ||

> +                sps->profile_idc == 88) {

> +                sps->level_idc = 10;

> +                sps->constraint_set3_flag = 1;

> +            } else {

> +                sps->level_idc = 9;

> +            }

> +        } else {

> +            sps->level_idc = level_idc;

> +        }

> +    }

> +

>      if (need_vui)

>          sps->vui_parameters_present_flag = 1;

>  

> @@ -683,6 +743,36 @@ static const AVOption h264_metadata_options[] = {

>          0, AV_OPT_TYPE_CONST,

>          { .i64 = FLIP_VERTICAL },   .flags = FLAGS, .unit = "flip" },

>  

> +    { "level", "Set level (table A-1)",

> +        OFFSET(level), AV_OPT_TYPE_INT,

> +        { .i64 = LEVEL_UNSET }, LEVEL_UNSET, 0xff, FLAGS, "level" },

> +    { "auto", "Attempt to guess level from stream properties",

> +        0, AV_OPT_TYPE_CONST,

> +        { .i64 = LEVEL_AUTO }, 0, 0, FLAGS, "level" },


Could you please use the same code style for AV_OPT_TYPE_CONST ?

> +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \

> +        { .i64 = value }, 0, 0, FLAGS, "level"


Also here.

> +    { LEVEL("1",   10) },

> +    { LEVEL("1b",   9) },

> +    { LEVEL("1.1", 11) },

> +    { LEVEL("1.2", 12) },

> +    { LEVEL("1.3", 13) },

> +    { LEVEL("2",   20) },

> +    { LEVEL("2.1", 21) },

> +    { LEVEL("2.2", 22) },

> +    { LEVEL("3",   30) },

> +    { LEVEL("3.1", 31) },

> +    { LEVEL("3.2", 32) },

> +    { LEVEL("4",   40) },

> +    { LEVEL("4.1", 41) },

> +    { LEVEL("4.2", 42) },

> +    { LEVEL("5",   50) },

> +    { LEVEL("5.1", 51) },

> +    { LEVEL("5.2", 52) },

> +    { LEVEL("6",   60) },

> +    { LEVEL("6.1", 61) },

> +    { LEVEL("6.2", 62) },

> +#undef LEVEL

> +

>      { NULL }

>  };

>
Mark Thompson June 17, 2018, 2:20 p.m.
On 15/06/18 03:49, Xiang, Haihao wrote:
> On Fri, 2018-06-08 at 00:43 +0100, Mark Thompson wrote:
>> ---
>>  doc/bitstream_filters.texi     |  9 +++++
>>  libavcodec/h264_metadata_bsf.c | 90
>> ++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 99 insertions(+)
>>
>> ...
>> diff --git a/libavcodec/h264_metadata_bsf.c b/libavcodec/h264_metadata_bsf.c
>> index 90ad4aad98..cb1a835fb8 100644
>> --- a/libavcodec/h264_metadata_bsf.c
>> +++ b/libavcodec/h264_metadata_bsf.c
>> ...
>> @@ -683,6 +743,36 @@ static const AVOption h264_metadata_options[] = {
>>          0, AV_OPT_TYPE_CONST,
>>          { .i64 = FLIP_VERTICAL },   .flags = FLAGS, .unit = "flip" },
>>  
>> +    { "level", "Set level (table A-1)",
>> +        OFFSET(level), AV_OPT_TYPE_INT,
>> +        { .i64 = LEVEL_UNSET }, LEVEL_UNSET, 0xff, FLAGS, "level" },
>> +    { "auto", "Attempt to guess level from stream properties",
>> +        0, AV_OPT_TYPE_CONST,
>> +        { .i64 = LEVEL_AUTO }, 0, 0, FLAGS, "level" },
> 
> Could you please use the same code style for AV_OPT_TYPE_CONST ?
> 
>> +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
>> +        { .i64 = value }, 0, 0, FLAGS, "level"
> 
> Also here.

Both changed to use the designated initialiser.

>> +    { LEVEL("1",   10) },
>> +    { LEVEL("1b",   9) },
>> +    { LEVEL("1.1", 11) },
>> +    { LEVEL("1.2", 12) },
>> +    { LEVEL("1.3", 13) },
>> +    { LEVEL("2",   20) },
>> +    { LEVEL("2.1", 21) },
>> +    { LEVEL("2.2", 22) },
>> +    { LEVEL("3",   30) },
>> +    { LEVEL("3.1", 31) },
>> +    { LEVEL("3.2", 32) },
>> +    { LEVEL("4",   40) },
>> +    { LEVEL("4.1", 41) },
>> +    { LEVEL("4.2", 42) },
>> +    { LEVEL("5",   50) },
>> +    { LEVEL("5.1", 51) },
>> +    { LEVEL("5.2", 52) },
>> +    { LEVEL("6",   60) },
>> +    { LEVEL("6.1", 61) },
>> +    { LEVEL("6.2", 62) },
>> +#undef LEVEL
>> +
>>      { NULL }
>>  };
>>  

Thanks,

- Mark

Patch hide | download patch | download mbox

diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi
index 7d7e97503a..d948c6d658 100644
--- a/doc/bitstream_filters.texi
+++ b/doc/bitstream_filters.texi
@@ -215,6 +215,15 @@  insert the string ``hello'' associated with the given UUID.
 @item delete_filler
 Deletes both filler NAL units and filler SEI messages.
 
+@item level
+Set the level in the SPS.  Refer to H.264 section A.3 and tables A-1
+to A-5.
+
+The argument must be the name of a level (for example, @samp{4.2}), a
+level_idc value (for example, @samp{42}), or the special name @samp{auto}
+indicating that the filter should attempt to guess the level from the
+input stream properties.
+
 @end table
 
 @section h264_mp4toannexb
diff --git a/libavcodec/h264_metadata_bsf.c b/libavcodec/h264_metadata_bsf.c
index 90ad4aad98..cb1a835fb8 100644
--- a/libavcodec/h264_metadata_bsf.c
+++ b/libavcodec/h264_metadata_bsf.c
@@ -25,6 +25,7 @@ 
 #include "cbs.h"
 #include "cbs_h264.h"
 #include "h264.h"
+#include "h264_levels.h"
 #include "h264_sei.h"
 
 enum {
@@ -39,6 +40,11 @@  enum {
     FLIP_VERTICAL   = 2,
 };
 
+enum {
+    LEVEL_UNSET = -2,
+    LEVEL_AUTO  = -1,
+};
+
 typedef struct H264MetadataContext {
     const AVClass *class;
 
@@ -74,6 +80,8 @@  typedef struct H264MetadataContext {
     int display_orientation;
     double rotate;
     int flip;
+
+    int level;
 } H264MetadataContext;
 
 
@@ -208,6 +216,58 @@  static int h264_metadata_update_sps(AVBSFContext *bsf,
     CROP(bottom, crop_unit_y);
 #undef CROP
 
+    if (ctx->level != LEVEL_UNSET) {
+        int level_idc;
+
+        if (ctx->level == LEVEL_AUTO) {
+            const H264LevelDescriptor *desc;
+            int64_t bit_rate;
+            int width, height;
+
+            if (sps->vui.nal_hrd_parameters_present_flag) {
+                bit_rate = (sps->vui.nal_hrd_parameters.bit_rate_value_minus1[0] + 1) *
+                     (1 << (sps->vui.nal_hrd_parameters.bit_rate_scale + 6));
+            } else if (sps->vui.vcl_hrd_parameters_present_flag) {
+                bit_rate = (sps->vui.vcl_hrd_parameters.bit_rate_value_minus1[0] + 1) *
+                     (1 << (sps->vui.vcl_hrd_parameters.bit_rate_scale + 6));
+                // Adjust for VCL vs. NAL limits.
+                bit_rate = bit_rate * 6 / 5;
+            } else {
+                bit_rate = 0;
+            }
+
+            width  = 16 * (sps->pic_width_in_mbs_minus1 + 1);
+            height = 16 * (sps->pic_height_in_map_units_minus1 + 1) *
+                (2 - sps->frame_mbs_only_flag);
+
+            desc = ff_h264_guess_level(sps->profile_idc, bit_rate,
+                                       width, height,
+                                       sps->vui.max_dec_frame_buffering);
+            if (desc) {
+                level_idc = desc->level_idc;
+            } else {
+                av_log(bsf, AV_LOG_WARNING, "Stream does not appear to "
+                       "conform to any level: using level 6.2.\n");
+                level_idc = 62;
+            }
+        } else {
+            level_idc = ctx->level;
+        }
+
+        if (level_idc == 9) {
+            if (sps->profile_idc == 66 ||
+                sps->profile_idc == 77 ||
+                sps->profile_idc == 88) {
+                sps->level_idc = 10;
+                sps->constraint_set3_flag = 1;
+            } else {
+                sps->level_idc = 9;
+            }
+        } else {
+            sps->level_idc = level_idc;
+        }
+    }
+
     if (need_vui)
         sps->vui_parameters_present_flag = 1;
 
@@ -683,6 +743,36 @@  static const AVOption h264_metadata_options[] = {
         0, AV_OPT_TYPE_CONST,
         { .i64 = FLIP_VERTICAL },   .flags = FLAGS, .unit = "flip" },
 
+    { "level", "Set level (table A-1)",
+        OFFSET(level), AV_OPT_TYPE_INT,
+        { .i64 = LEVEL_UNSET }, LEVEL_UNSET, 0xff, FLAGS, "level" },
+    { "auto", "Attempt to guess level from stream properties",
+        0, AV_OPT_TYPE_CONST,
+        { .i64 = LEVEL_AUTO }, 0, 0, FLAGS, "level" },
+#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
+        { .i64 = value }, 0, 0, FLAGS, "level"
+    { LEVEL("1",   10) },
+    { LEVEL("1b",   9) },
+    { LEVEL("1.1", 11) },
+    { LEVEL("1.2", 12) },
+    { LEVEL("1.3", 13) },
+    { LEVEL("2",   20) },
+    { LEVEL("2.1", 21) },
+    { LEVEL("2.2", 22) },
+    { LEVEL("3",   30) },
+    { LEVEL("3.1", 31) },
+    { LEVEL("3.2", 32) },
+    { LEVEL("4",   40) },
+    { LEVEL("4.1", 41) },
+    { LEVEL("4.2", 42) },
+    { LEVEL("5",   50) },
+    { LEVEL("5.1", 51) },
+    { LEVEL("5.2", 52) },
+    { LEVEL("6",   60) },
+    { LEVEL("6.1", 61) },
+    { LEVEL("6.2", 62) },
+#undef LEVEL
+
     { NULL }
 };