From patchwork Sat Oct 27 22:19:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 10810 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 7A78A44D94D for ; Sun, 28 Oct 2018 01:20:08 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id EB9C868A31C; Sun, 28 Oct 2018 01:19:39 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1DB0F68A260 for ; Sun, 28 Oct 2018 01:19:33 +0300 (EEST) Received: by mail-wm1-f54.google.com with SMTP id f1-v6so6684922wmg.1 for ; Sat, 27 Oct 2018 15:20:03 -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=Eiz8j/dquNsvielSKG0QAkx8W0IIc196zv6M9bxhC4o=; b=HAYqbBlSuZw2vcXt8O+/ZzCiN3gaMQHITkcEdT48ecaxXUH2mw2YN1qpFsBmPV4doJ A4x2su46iyqf49Ll5YhgtRA/1b2BRGkZMVjwqb+8jfExzU216HttSuIfZdKDtv82/NuA xuZ/lxbyJSidWB3+wO8sQqJAlW398M0bIs6BCzNUsxsX4zlACufC1vuhTj8JHcu+DFUA /p3DHjHSTEhgnDf47LYVl7NYvTO4ikNjVrJy2buALzymu2rEL5sgFCNgMUk11EK6rYyQ +QCAWiQOsDWJNif/jpzQLambrr8CK6jwooptkuRFDOCptsX7dxhbClsaglA5Cyympq1u S+TQ== 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=Eiz8j/dquNsvielSKG0QAkx8W0IIc196zv6M9bxhC4o=; b=OVvVkI2PBTclB4k8tugCfJ39+xFYKacnMnh1lUeC9jyKoC2joyCgfCdV5pMDBDU+Hc o3042PkMkFGTht7WhqfSZeQQQWobpmMIi0xj6H06BpOon8JqjCl7b4oO8AaosVMFHrIe DP+nrQDVRbq7TWeSpqZfDaY3PbfcW1YjUjkb7e8Hs8VZ7xkloS+OgtOP8ZDZxYPZdVyK fOGWfuuhU+Sx1aBVqWth0kKJHQSzHiDTmkPJGvnAQM4VYUpgwfsMKdjkChDX1SaxRqdx kwmPG77ByVzB3UvuffJbX/taoyB79MpesOZAtJ5rwQH+8wMIfHC6aBHI76P05CmZfxQC nyKQ== X-Gm-Message-State: AGRZ1gJ6symQkffu/HzZ1OsH5PRGx4pMFePoHcU1AnRm4Dkepi+txKiC xyMrHw2dh+er7lGZ/EkHVAp9xPnH7EE= X-Google-Smtp-Source: AJdET5d+4LrEYavFuHSj/qlXuihdtWUzOJWf222OwqzNdf1PH9QQYcjMC7W3yI/98IxkQa30BIad2w== X-Received: by 2002:a1c:5a86:: with SMTP id o128-v6mr9163433wmb.138.1540678802315; Sat, 27 Oct 2018 15:20:02 -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 v189-v6sm1255527wmd.40.2018.10.27.15.20.01 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 27 Oct 2018 15:20:01 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Sat, 27 Oct 2018 23:19:52 +0100 Message-Id: <20181027221954.8589-4-sw@jkqxz.net> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181027221954.8589-1-sw@jkqxz.net> References: <20181027221954.8589-1-sw@jkqxz.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 4/6] 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" --- 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 53470c01ec..a1635a4b73 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -358,6 +358,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 3e41497e34..6570fa7c2c 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1068,7 +1068,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 26eb2d05d0..c2a4bd4803 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); @@ -439,6 +551,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 } };