mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-24 13:56:33 +02:00
h265_metadata: Add option to set the level of the stream
To match the same option in h264_metadata.
This commit is contained in:
parent
f344bb2466
commit
c7142875c3
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user