h265_metadata: Add option to set the level of the stream

To match the same option in h264_metadata.
This commit is contained in:
Mark Thompson 2019-05-06 22:02:21 +01:00
parent f344bb2466
commit c7142875c3
3 changed files with 146 additions and 1 deletions

View File

@ -361,6 +361,15 @@ will replace the current ones if the stream is already cropped.
These fields are set in pixels. Note that some sizes may not be
representable if the chroma is subsampled (H.265 section 7.4.3.2.1).
@item level
Set the level in the VPS and SPS. See H.265 section A.4 and tables
A.6 and A.7.
The argument must be the name of a level (for example, @samp{5.1}), a
@emph{general_level_idc} value (for example, @samp{153} for level 5.1),
or the special name @samp{auto} indicating that the filter should
attempt to guess the level from the input stream properties.
@end table
@section hevc_mp4toannexb

View File

@ -1081,7 +1081,7 @@ OBJS-$(CONFIG_H264_METADATA_BSF) += h264_metadata_bsf.o h264_levels.o
OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF) += h264_mp4toannexb_bsf.o
OBJS-$(CONFIG_H264_REDUNDANT_PPS_BSF) += h264_redundant_pps_bsf.o
OBJS-$(CONFIG_HAPQA_EXTRACT_BSF) += hapqa_extract_bsf.o hap.o
OBJS-$(CONFIG_HEVC_METADATA_BSF) += h265_metadata_bsf.o
OBJS-$(CONFIG_HEVC_METADATA_BSF) += h265_metadata_bsf.o h265_profile_level.o
OBJS-$(CONFIG_HEVC_MP4TOANNEXB_BSF) += hevc_mp4toannexb_bsf.o
OBJS-$(CONFIG_IMX_DUMP_HEADER_BSF) += imx_dump_header_bsf.o
OBJS-$(CONFIG_MJPEG2JPEG_BSF) += mjpeg2jpeg_bsf.o

View File

@ -23,6 +23,7 @@
#include "cbs.h"
#include "cbs_h265.h"
#include "hevc.h"
#include "h265_profile_level.h"
enum {
PASS,
@ -30,6 +31,11 @@ enum {
REMOVE,
};
enum {
LEVEL_UNSET = -2,
LEVEL_AUTO = -1,
};
typedef struct H265MetadataContext {
const AVClass *class;
@ -58,9 +64,105 @@ typedef struct H265MetadataContext {
int crop_right;
int crop_top;
int crop_bottom;
int level;
int level_guess;
int level_warned;
} H265MetadataContext;
static void h265_metadata_guess_level(AVBSFContext *bsf,
const CodedBitstreamFragment *au)
{
H265MetadataContext *ctx = bsf->priv_data;
const H265LevelDescriptor *desc;
const H265RawProfileTierLevel *ptl = NULL;
const H265RawHRDParameters *hrd = NULL;
int64_t bit_rate = 0;
int width = 0, height = 0;
int tile_cols = 0, tile_rows = 0;
int max_dec_pic_buffering = 0;
int i;
for (i = 0; i < au->nb_units; i++) {
const CodedBitstreamUnit *unit = &au->units[i];
if (unit->type == HEVC_NAL_VPS) {
const H265RawVPS *vps = unit->content;
ptl = &vps->profile_tier_level;
max_dec_pic_buffering = vps->vps_max_dec_pic_buffering_minus1[0] + 1;
if (vps->vps_num_hrd_parameters > 0)
hrd = &vps->hrd_parameters[0];
} else if (unit->type == HEVC_NAL_SPS) {
const H265RawSPS *sps = unit->content;
ptl = &sps->profile_tier_level;
max_dec_pic_buffering = sps->sps_max_dec_pic_buffering_minus1[0] + 1;
width = sps->pic_width_in_luma_samples;
height = sps->pic_height_in_luma_samples;
if (sps->vui.vui_hrd_parameters_present_flag)
hrd = &sps->vui.hrd_parameters;
} else if (unit->type == HEVC_NAL_PPS) {
const H265RawPPS *pps = unit->content;
if (pps->tiles_enabled_flag) {
tile_cols = pps->num_tile_columns_minus1 + 1;
tile_rows = pps->num_tile_rows_minus1 + 1;
}
}
}
if (hrd) {
if (hrd->nal_hrd_parameters_present_flag) {
bit_rate = (hrd->nal_sub_layer_hrd_parameters[0].bit_rate_value_minus1[0] + 1) *
(INT64_C(1) << hrd->bit_rate_scale + 6);
} else if (hrd->vcl_hrd_parameters_present_flag) {
bit_rate = (hrd->vcl_sub_layer_hrd_parameters[0].bit_rate_value_minus1[0] + 1) *
(INT64_C(1) << hrd->bit_rate_scale + 6);
// Adjust for VCL vs. NAL limits.
bit_rate = bit_rate * 11 / 10;
}
}
desc = ff_h265_guess_level(ptl, bit_rate, width, height,
0, tile_cols, tile_rows,
max_dec_pic_buffering);
if (desc) {
av_log(bsf, AV_LOG_DEBUG, "Stream appears to conform to "
"level %s.\n", desc->name);
ctx->level_guess = desc->level_idc;
}
}
static void h265_metadata_update_level(AVBSFContext *bsf,
uint8_t *level_idc)
{
H265MetadataContext *ctx = bsf->priv_data;
if (ctx->level != LEVEL_UNSET) {
if (ctx->level == LEVEL_AUTO) {
if (ctx->level_guess) {
*level_idc = ctx->level_guess;
} else {
if (!ctx->level_warned) {
av_log(bsf, AV_LOG_WARNING, "Unable to determine level "
"of stream: using level 8.5.\n");
ctx->level_warned = 1;
}
*level_idc = 255;
}
} else {
*level_idc = ctx->level;
}
}
}
static int h265_metadata_update_vps(AVBSFContext *bsf,
H265RawVPS *vps)
{
@ -86,6 +188,8 @@ static int h265_metadata_update_vps(AVBSFContext *bsf,
}
}
h265_metadata_update_level(bsf, &vps->profile_tier_level.general_level_idc);
return 0;
}
@ -227,6 +331,8 @@ static int h265_metadata_update_sps(AVBSFContext *bsf,
if (need_vui)
sps->vui_parameters_present_flag = 1;
h265_metadata_update_level(bsf, &sps->profile_tier_level.general_level_idc);
return 0;
}
@ -297,6 +403,9 @@ static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *out)
}
}
if (ctx->level == LEVEL_AUTO && !ctx->level_guess)
h265_metadata_guess_level(bsf, au);
for (i = 0; i < au->nb_units; i++) {
if (au->units[i].type == HEVC_NAL_VPS) {
err = h265_metadata_update_vps(bsf, au->units[i].content);
@ -348,6 +457,9 @@ static int h265_metadata_init(AVBSFContext *bsf)
goto fail;
}
if (ctx->level == LEVEL_AUTO)
h265_metadata_guess_level(bsf, au);
for (i = 0; i < au->nb_units; i++) {
if (au->units[i].type == HEVC_NAL_VPS) {
err = h265_metadata_update_vps(bsf, au->units[i].content);
@ -441,6 +553,30 @@ static const AVOption h265_metadata_options[] = {
OFFSET(crop_bottom), AV_OPT_TYPE_INT,
{ .i64 = -1 }, -1, HEVC_MAX_HEIGHT, FLAGS },
{ "level", "Set level (tables A.6 and A.7)",
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", 30) },
{ LEVEL("2", 60) },
{ LEVEL("2.1", 63) },
{ LEVEL("3", 90) },
{ LEVEL("3.1", 93) },
{ LEVEL("4", 120) },
{ LEVEL("4.1", 123) },
{ LEVEL("5", 150) },
{ LEVEL("5.1", 153) },
{ LEVEL("5.2", 156) },
{ LEVEL("6", 180) },
{ LEVEL("6.1", 183) },
{ LEVEL("6.2", 186) },
{ LEVEL("8.5", 255) },
#undef LEVEL
{ NULL }
};