summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Thompson <sw@jkqxz.net>2018-09-18 23:30:59 +0100
committerMark Thompson <sw@jkqxz.net>2018-09-23 14:42:34 +0100
commit6522ba30e93cd9060da011c8c591dce1b273c4ce (patch)
tree5d712fe033a62f4e8307e65d6920d4102e321c5d
parentbb3503164eed2a1217315f9d54e986e7276183c6 (diff)
h264_metadata: Add option to set the level of the stream
-rw-r--r--doc/bitstream_filters.texi9
-rw-r--r--libavcodec/h264_metadata_bsf.c90
2 files changed, 99 insertions, 0 deletions
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..991fcfa537 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 }, .flags = FLAGS, .unit = "level" },
+#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
+ { .i64 = value }, .flags = FLAGS, .unit = "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 }
};