From patchwork Mon May 6 21:02:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 13016 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id AAB074421D8 for ; Tue, 7 May 2019 00:11:38 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id ED86D68ADC6; Tue, 7 May 2019 00:02:42 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f67.google.com (mail-wm1-f67.google.com [209.85.128.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 9120568AA78 for ; Tue, 7 May 2019 00:02:34 +0300 (EEST) Received: by mail-wm1-f67.google.com with SMTP id q15so17511898wmf.3 for ; Mon, 06 May 2019 14:02:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jkqxz-net.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=B/JxABZQ7utJbNcUlr19s/uWJ5EsY/343vNfIP7k7A4=; b=XRKzGHFZf6zCytU9waRQxd/+gWx3Aq9IMn1ojh9SHYqFnlpvA7C/VwurQZBr5IchVu Lg2pP+I9vHoOqx6BR+cCpyqMHPNI0MtVQvQZsp+QIIIHZDiunrw8aU5OA9bThMC6Sl/Y TXHABY1v2BywzSZ4Tl+/xWI4p1jVe/mdcf9MSVdlA7eyvSrZ56QlrNgOvIpWTVGSHVpQ S+6p3tCePlPeyrL2JB03rCaoEa83XG4BKbpKDKqxOySHm8umxyXRXjAK6F/x5lq1QXH4 ewNo9ZShcSon99jQO7PLuZwcxtdJV05oSGPadXjLNgeLVtz/Hbs44S3QJnSj9UKVz+rh oT2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=B/JxABZQ7utJbNcUlr19s/uWJ5EsY/343vNfIP7k7A4=; b=GZYohjVQeTlmE3pKBqqb4sZFxs60ey5iHwnlleL81YYiI36iLR+plhRBhQHG9RpF1X IbzACE9OEXI7OOZotIIQmD/QxyynyKnemAGF3jBaN286IHFCFMKIN61ye9JpdVZE0qed 021bKsIEhrK8BBXsjwSx4+xG6R28KN22xwMqpkTMcGX/nwxfxNEvp+Ta8tMzdShlgMbZ mhIzFSyJqy+b6zxqSkQzMJHbLAU8K7MqjOZLW/gC8wfviE6+8JQdzGdmhcFSFo8Qtr8D +VggextLYz+jOVE8Yjw219IUt3vfWIvim9FALbnDqsgunmXJ6bHQhCgK5Y3hN6+l0SBQ myRA== X-Gm-Message-State: APjAAAWMNoSxmU/MnSnZ5N2dMK0hbE+sncz2SwmceZJeZFWlSumBt9U8 ky9LxcyPrEtPLRmfVU63pPzosD2HKbg= X-Google-Smtp-Source: APXvYqwqZhCUNWD6y5Oe+2HRactHqKwfYyS9QhVFJZ9aDkgvGUcwgBHKfQaL4jPAI4/UO01yaqNfwg== X-Received: by 2002:a7b:cd06:: with SMTP id f6mr17135607wmj.61.1557176553711; Mon, 06 May 2019 14:02:33 -0700 (PDT) Received: from rywe.jkqxz.net (cpc91242-cmbg18-2-0-cust650.5-4.cable.virginm.net. [82.8.130.139]) by smtp.gmail.com with ESMTPSA id u11sm20777747wmu.15.2019.05.06.14.02.32 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 May 2019 14:02:32 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Mon, 6 May 2019 22:02:21 +0100 Message-Id: <20190506210223.25159-3-sw@jkqxz.net> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190506210223.25159-1-sw@jkqxz.net> References: <20190506210223.25159-1-sw@jkqxz.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v4 3/5] h265_metadata: Add option to set the level of the stream X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" To match the same option in h264_metadata. --- doc/bitstream_filters.texi | 9 +++ libavcodec/Makefile | 2 +- libavcodec/h265_metadata_bsf.c | 136 +++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 1 deletion(-) diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index 25bbf8372b..823d4ba809 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -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 diff --git a/libavcodec/Makefile b/libavcodec/Makefile index f37135fc07..489820eead 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -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 diff --git a/libavcodec/h265_metadata_bsf.c b/libavcodec/h265_metadata_bsf.c index 0683cc2f9d..c7a635ebe2 100644 --- a/libavcodec/h265_metadata_bsf.c +++ b/libavcodec/h265_metadata_bsf.c @@ -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 } };