From patchwork Sat Sep 14 10:45:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 51597 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:9fc3:0:b0:48e:c0f8:d0de with SMTP id k3csp314343vqy; Sat, 14 Sep 2024 04:49:11 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWQpbfW/SVDCqBj/x7UcBGGvUSBPFbIeQDe8EVkpMub8DnghcCM8Xta3d0rp6XkcbKhbU247lQIqTziyFpwvGFK@gmail.com X-Google-Smtp-Source: AGHT+IEMT7QsCASqY2IGYSyIVMF7X5t7he5URe5TX4DAPykBt2xVe5l/w5jKs4RJAyiXRbx0Zo9F X-Received: by 2002:a05:6512:2812:b0:536:561c:a0cb with SMTP id 2adb3069b0e04-53678fb6d6amr5352958e87.18.1726314551053; Sat, 14 Sep 2024 04:49:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1726314551; cv=none; d=google.com; s=arc-20240605; b=Ue/jETM5NMVLt/StVBKyYBb5sERj7s7QVJbv6b7akBB+0sCYLJ+nfWICuecwQc5plX qYi48LCgUUR++MXf1VDTiVe6NZXy5MzP9ajKqVIkCV/51J2mbh2qfPt7DkAr5UKd8UOg kAUztu6F8/JZK2VGK/UUxRcQCpp2aORR+9s3B+BY3WtAOLbDrnTUGxvWTZlF7AVsI1gE cgHdCwb0DbNwB2jUnkWLOd82L3EYbWzDz1k2y8j+RkepRYogPNYk181Za4Y3pbgZ95qK G4uV6C9KRe0n43i+jdgPzKC58hngDIOO9nGAFBSTqj2py6dE0BdiQ4RhEormkrugsHu0 3JsQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:references:in-reply-to:message-id :date:to:from:dkim-signature:delivered-to; bh=U7gQ1NFnH1yp5IAp1w8kS/b9pL3l+mcHmT7iInaiDOc=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=HpshlV13EVG3d8D8se32QIVamTH5FFWzpXliilycLtXEEXRmGsSk5u7KMRbIZTSvSe j7ZPdLYLph951jNZyZSDMgvqSsUOWibX2K+wJimml3CiuTab6L67xUtdvLz6kvs0GlFA E+8pM06HbMSFrU536ylvUzIrRKNZiTMqLaCnf7YUOchrygCdRoEqVVirlTUOWHDJ2bsN QZncgRwSG7Tnj/IlofYK/UbkPrOzViXlugFUFmYjaxAchkCu4XhLY2bwvI13KFoBv742 Vqhb14sL9TRKulp2lII/IsOBU+tlPh/UGt+dLaXUfOZqRrxhJD/Ndmn43TbSSGF/xXYx johQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=MOSTg3Uh; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id 2adb3069b0e04-53687048fd9si419601e87.140.2024.09.14.04.49.10; Sat, 14 Sep 2024 04:49:10 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=MOSTg3Uh; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 9A34B68DE3E; Sat, 14 Sep 2024 14:11:05 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail1.khirnov.net (quelana.khirnov.net [94.230.150.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 6268D68DC92 for ; Sat, 14 Sep 2024 14:10:53 +0300 (EEST) Authentication-Results: mail1.khirnov.net; dkim=pass (2048-bit key; unprotected) header.d=khirnov.net header.i=@khirnov.net header.a=rsa-sha256 header.s=mail header.b=MOSTg3Uh; dkim-atps=neutral Received: from localhost (mail1.khirnov.net [IPv6:::1]) by mail1.khirnov.net (Postfix) with ESMTP id 13A484E0A for ; Sat, 14 Sep 2024 13:10:49 +0200 (CEST) Received: from mail1.khirnov.net ([IPv6:::1]) by localhost (mail1.khirnov.net [IPv6:::1]) (amavis, port 10024) with ESMTP id 86F1z6F3B88B for ; Sat, 14 Sep 2024 13:10:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=khirnov.net; s=mail; t=1726312246; bh=PJb6qu3lnTtU922ZwFxhb8LQe0fXZVsT/CmQop5eQQg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=MOSTg3UhZifYOIpNN6EOPfBHx+WBDw35EznfStrAED60smCQZmAtXC3ezUz+o0O7s 8XdGMKzE0ZyPxWOaEbsSukPN0HNxGHVRPTAqZPYftROePq/HPaLd+FvPjShgvUeax1 hFEmz5jUNcba1lpJnRXnUk7hjicR/3z4Jb+5peAsrn7sZPA2vTVRYE0niGhspMCFRJ 3Z7Mx4oGJzEh3SwlYH8voqNIVjZKB9YSFppQoHqAVOAsf8l1hTtZ4HelRGUkCgYsMk UkTtRFOfhwkt00mwxSYReyOX4y2dKCdTZMT+Btr2hEI+zR1tYBCQMF2875idSBiOrE e6Sp2Z0U2mvuQ== Received: from libav.khirnov.net (libav.khirnov.net [IPv6:2a00:c500:561:201::7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "libav.khirnov.net", Issuer "smtp.khirnov.net SMTP CA" (verified OK)) by mail1.khirnov.net (Postfix) with ESMTPS id 60A624E07 for ; Sat, 14 Sep 2024 13:10:46 +0200 (CEST) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:::1]) by libav.khirnov.net (Postfix) with ESMTP id 1FCEB3A164C for ; Sat, 14 Sep 2024 13:10:41 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Sat, 14 Sep 2024 12:45:31 +0200 Message-ID: <20240914111036.17164-7-anton@khirnov.net> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240914111036.17164-1-anton@khirnov.net> References: <20240914111036.17164-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 06/23] lavc/hevc_ps: parse VPS extension X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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" X-TUID: j4UeYi3W8Pfl From: Niklas Haas Only implementing what's needed for MV-HEVC with two views. Signed-off-by: Anton Khirnov --- libavcodec/hevc/hevc.h | 9 +- libavcodec/hevc/ps.c | 307 +++++++++++++++++++++++++++++++++++++++-- libavcodec/hevc/ps.h | 62 +++++++++ 3 files changed, 364 insertions(+), 14 deletions(-) diff --git a/libavcodec/hevc/hevc.h b/libavcodec/hevc/hevc.h index 9fdbc0a224..8bd59142db 100644 --- a/libavcodec/hevc/hevc.h +++ b/libavcodec/hevc/hevc.h @@ -100,11 +100,14 @@ enum HEVCSliceType { enum { // 7.4.3.1: vps_max_layers_minus1 is in [0, 62]. - HEVC_MAX_LAYERS = 63, + HEVC_MAX_LAYERS = 63, // 7.4.3.1: vps_max_sub_layers_minus1 is in [0, 6]. - HEVC_MAX_SUB_LAYERS = 7, + HEVC_MAX_SUB_LAYERS = 7, // 7.4.3.1: vps_num_layer_sets_minus1 is in [0, 1023]. - HEVC_MAX_LAYER_SETS = 1024, + HEVC_MAX_LAYER_SETS = 1024, + // 7.4.3.1: vps_max_layer_id is in [0, 63]. + HEVC_MAX_LAYER_ID = 63, + HEVC_MAX_NUH_LAYER_ID = 62, // 7.4.2.1: vps_video_parameter_set_id is u(4). HEVC_MAX_VPS_COUNT = 16, diff --git a/libavcodec/hevc/ps.c b/libavcodec/hevc/ps.c index 2c3b335966..35de26644c 100644 --- a/libavcodec/hevc/ps.c +++ b/libavcodec/hevc/ps.c @@ -311,11 +311,17 @@ static int decode_profile_tier_level(GetBitContext *gb, AVCodecContext *avctx, } static int parse_ptl(GetBitContext *gb, AVCodecContext *avctx, - PTL *ptl, int max_num_sub_layers) + int profile_present, PTL *ptl, int max_num_sub_layers) { - int i; - if (decode_profile_tier_level(gb, avctx, &ptl->general_ptl) < 0 || - get_bits_left(gb) < 8 + (8*2 * (max_num_sub_layers - 1 > 0))) { + int i, status = 0; + + if (profile_present) { + status = decode_profile_tier_level(gb, avctx, &ptl->general_ptl); + } else { + memset(&ptl->general_ptl, 0, sizeof(ptl->general_ptl)); + } + + if (status < 0 || get_bits_left(gb) < 8 + (8*2 * (max_num_sub_layers - 1 > 0))) { av_log(avctx, AV_LOG_ERROR, "PTL information too short\n"); return -1; } @@ -444,13 +450,273 @@ static void hevc_vps_free(FFRefStructOpaque opaque, void *obj) av_freep(&vps->data); } +enum ScalabilityMask { + HEVC_SCALABILITY_DEPTH = 0, + HEVC_SCALABILITY_MULTIVIEW = 1, + HEVC_SCALABILITY_SPATIAL = 2, + HEVC_SCALABILITY_AUXILIARY = 3, + HEVC_SCALABILITY_MASK_MAX = 15, +}; + +enum DependencyType { + HEVC_DEP_TYPE_SAMPLE = 0, + HEVC_DEP_TYPE_MV = 1, + HEVC_DEP_TYPE_BOTH = 2, +}; + +static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps, + uint64_t layer1_id_included) +{ + PTL ptl_dummy; + uint8_t max_sub_layers[HEVC_MAX_LAYERS]; + + int splitting_flag, dimension_id_len, view_id_len, num_add_olss, + default_output_layer_idc, direct_dep_type_len, direct_dep_type, + sub_layers_max_present, sub_layer_flag_info_present_flag, nb_ptl; + unsigned non_vui_extension_length; + + if (vps->vps_max_layers == 1 || vps->vps_num_layer_sets == 1) { + av_log(avctx, AV_LOG_VERBOSE, "Ignoring VPS extensions with a single layer\n"); + return 0; + } + + if (vps->vps_max_layers > 2) { + av_log(avctx, AV_LOG_ERROR, + "VPS has %d layers, only 2 layers are supported\n", + vps->vps_max_layers); + return AVERROR_PATCHWELCOME; + } + if (vps->vps_num_layer_sets > 2) { + av_log(avctx, AV_LOG_ERROR, + "VPS has %d layer sets, only 2 layer sets are supported\n", + vps->vps_num_layer_sets); + return AVERROR_PATCHWELCOME; + } + + align_get_bits(gb); + + /** + * For stereoscopic MV-HEVC, the following simplifying assumptions are made: + * + * - vps_max_layers = 2 (one base layer, one multiview layer) + * - vps_num_layer_sets = 2 (one output layer set for each view) + * - NumScalabilityTypes = 1 (only HEVC_SCALABILITY_MULTIVIEW) + * - direct_dependency_flag[1][0] = 1 (second layer depends on first) + * - num_add_olss = 0 (no extra output layer sets) + * - default_output_layer_idc = 0 (1:1 mapping between OLSs and layers) + * - layer_id_included_flag[1] = {1, 1} (consequence of layer dependencies) + * - vps_num_rep_formats_minus1 = 0 (all layers have the same size) + * + * Which results in the following derived variables: + * - ViewOrderIdx = {0, 1} + * - NumViews = 2 + * - DependencyFlag[1][0] = 1 + * - NumDirectRefLayers = {0, 1} + * - NumRefLayers = {0, 1} + * - NumPredictedLayers = {1, 0} + * - NumIndependentLayers = 1 + * - NumLayersInTreePartition = {2} + * - NumLayerSets = 2 + * - NumOutputLayerSets = 2 + * - OlsIdxToLsIdx = {0, 1} + * - LayerIdxInVps = {0, 1} + * - NumLayersInIdList = {1, 2} + * - NumNecessaryLayers = {1, 2} + * - NecessaryLayerFlag = {{1, 0}, {1, 1}} + * - NumOutputLayersInOutputLayerSet = {1, 2} + * - OutputLayerFlag = {{1, 0}, {1, 1}} + */ + vps->nb_layers = 2; + + if (parse_ptl(gb, avctx, 0, &ptl_dummy, vps->vps_max_sub_layers) < 0) + return AVERROR_INVALIDDATA; + + splitting_flag = get_bits1(gb); + for (int i = 0; i <= HEVC_SCALABILITY_MASK_MAX; i++) { + int scalability_mask_flag = get_bits1(gb); + if (scalability_mask_flag != (i == HEVC_SCALABILITY_MULTIVIEW)) { + av_log(avctx, AV_LOG_ERROR, "Scalability type %d not supported\n", i); + return AVERROR_PATCHWELCOME; + } + } + + if (!splitting_flag) + dimension_id_len = get_bits(gb, 3) + 1; + + if (get_bits1(gb)) { /* vps_nuh_layer_id_present_flag */ + int layer_id_in_nuh = get_bits(gb, 6); + if (layer_id_in_nuh >= FF_ARRAY_ELEMS(vps->layer_idx)) { + av_log(avctx, AV_LOG_ERROR, "Invalid layer_id_in_nuh[1]: %d\n", + layer_id_in_nuh); + return AVERROR_INVALIDDATA; + } + vps->layer_idx[layer_id_in_nuh] = 1; + vps->layer_id_in_nuh[1] = layer_id_in_nuh; + } else { + vps->layer_idx[1] = 1; + vps->layer_id_in_nuh[1] = 1; + } + + if (!splitting_flag) { + int view_idx = get_bits(gb, dimension_id_len); + if (view_idx != 1) { + av_log(avctx, AV_LOG_ERROR, "Unexpected ViewOrderIdx: %d\n", view_idx); + return AVERROR_PATCHWELCOME; + } + } + + view_id_len = get_bits(gb, 4); + if (view_id_len) + for (int i = 0; i < 2 /* NumViews */; i++) + vps->view_id[i] = get_bits(gb, view_id_len); + + if (!get_bits1(gb) /* direct_dependency_flag */) { + av_log(avctx, AV_LOG_WARNING, "Independent output layers not supported\n"); + return AVERROR_PATCHWELCOME; + } + vps->num_direct_ref_layers[1] = 1; + + sub_layers_max_present = get_bits1(gb); // vps_sub_layers_max_minus1_present_flag + for (int i = 0; i < vps->vps_max_layers; i++) + max_sub_layers[i] = sub_layers_max_present ? get_bits(gb, 3) + 1 : + vps->vps_max_sub_layers; + + if (get_bits1(gb) /* max_tid_ref_present_flag */) + skip_bits(gb, 3); // max_tid_il_ref_pics_plus1 + + vps->default_ref_layers_active = get_bits1(gb); + + nb_ptl = get_ue_golomb(gb) + 1; + /* idx [0] is signalled in base VPS, idx [1] is signalled at the + * start of VPS extension, indices 2+ are signalled here; + * we ignore all but the first one anyway */ + for (int i = 2; i < nb_ptl; i++) { + int profile_present = get_bits1(gb); + if (parse_ptl(gb, avctx, profile_present, &ptl_dummy, vps->vps_max_sub_layers) < 0) + return AVERROR_INVALIDDATA; + } + + num_add_olss = get_ue_golomb(gb); + if (num_add_olss != 0) { + /* Since we don't implement support for independent output layer sets + * and auxiliary layers, this should never nonzero */ + av_log(avctx, AV_LOG_ERROR, "Unexpected num_add_olss: %d\n", num_add_olss); + return AVERROR_PATCHWELCOME; + } + + default_output_layer_idc = get_bits(gb, 2); + if (default_output_layer_idc != 0) { + av_log(avctx, AV_LOG_WARNING, "Unsupported default_output_layer_idc: %d\n", + default_output_layer_idc); + return AVERROR_PATCHWELCOME; + } + + /* Consequence of established layer dependencies */ + if (layer1_id_included != ((1 << vps->layer_id_in_nuh[0]) | + (1 << vps->layer_id_in_nuh[1]))) { + av_log(avctx, AV_LOG_ERROR, "Dependent layer not included in layer ID?\n"); + return AVERROR_PATCHWELCOME; + } + + vps->num_output_layer_sets = 2; + vps->ols[1] = 3; + + for (int j = 0; j < av_popcount64(vps->ols[1]); j++) { + int ptl_idx = get_bits(gb, av_ceil_log2(nb_ptl)); + if (ptl_idx < 1 || ptl_idx >= nb_ptl) { + av_log(avctx, AV_LOG_ERROR, "Invalid PTL index: %d\n", ptl_idx); + return AVERROR_INVALIDDATA; + } + } + + if (get_ue_golomb_31(gb) != 0 /* vps_num_rep_formats_minus1 */) { + av_log(avctx, AV_LOG_ERROR, "Unexpected extra rep formats\n"); + return AVERROR_INVALIDDATA; + } + + vps->rep_format.pic_width_in_luma_samples = get_bits(gb, 16); + vps->rep_format.pic_height_in_luma_samples = get_bits(gb, 16); + + if (!get_bits1(gb) /* chroma_and_bit_depth_vps_present_flag */) { + av_log(avctx, AV_LOG_ERROR, + "chroma_and_bit_depth_vps_present_flag=0 in first rep_format\n"); + return AVERROR_INVALIDDATA; + } + vps->rep_format.chroma_format_idc = get_bits(gb, 2); + if (vps->rep_format.chroma_format_idc == 3) + vps->rep_format.separate_colour_plane_flag = get_bits1(gb); + vps->rep_format.bit_depth_luma = get_bits(gb, 4) + 8; + vps->rep_format.bit_depth_chroma = get_bits(gb, 4) + 8; + if (vps->rep_format.bit_depth_luma > 16 || + vps->rep_format.bit_depth_chroma > 16 || + vps->rep_format.bit_depth_luma != vps->rep_format.bit_depth_chroma) { + av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth: %"PRIu8" %"PRIu8"\n", + vps->rep_format.bit_depth_luma, vps->rep_format.bit_depth_chroma); + return AVERROR_PATCHWELCOME; + } + + if (get_bits1(gb) /* conformance_window_vps_flag */) { + int vert_mult = hevc_sub_height_c[vps->rep_format.chroma_format_idc]; + int horiz_mult = hevc_sub_width_c[vps->rep_format.chroma_format_idc]; + vps->rep_format.conf_win_left_offset = get_ue_golomb(gb) * horiz_mult; + vps->rep_format.conf_win_right_offset = get_ue_golomb(gb) * horiz_mult; + vps->rep_format.conf_win_top_offset = get_ue_golomb(gb) * vert_mult; + vps->rep_format.conf_win_bottom_offset = get_ue_golomb(gb) * vert_mult; + } + + vps->max_one_active_ref_layer = get_bits1(gb); + vps->poc_lsb_aligned = get_bits1(gb); + + sub_layer_flag_info_present_flag = get_bits1(gb); + for (int j = 0; j < FFMAX(max_sub_layers[0], max_sub_layers[1]); j++) { + int sub_layer_dpb_info_present_flag = 1; + if (j > 0 && sub_layer_flag_info_present_flag) + sub_layer_dpb_info_present_flag = get_bits1(gb); + if (sub_layer_dpb_info_present_flag) { + for (int k = 0; k < av_popcount64(vps->ols[1]); k++) + vps->dpb_size.max_dec_pic_buffering = get_ue_golomb_long(gb) + 1; + vps->dpb_size.max_num_reorder_pics = get_ue_golomb_long(gb); + vps->dpb_size.max_latency_increase = get_ue_golomb_long(gb) - 1; + } + } + + direct_dep_type_len = get_ue_golomb_31(gb) + 2; + if (direct_dep_type_len > 32) { + av_log(avctx, AV_LOG_ERROR, "Invalid direct_dep_type_len: %d\n", + direct_dep_type_len); + return AVERROR_INVALIDDATA; + } + + skip_bits1(gb); /* direct_depenency_all_layers_flag */ + direct_dep_type = get_bits_long(gb, direct_dep_type_len); + if (direct_dep_type > HEVC_DEP_TYPE_BOTH) { + av_log(avctx, AV_LOG_WARNING, "Unsupported direct_dep_type: %d\n", + direct_dep_type); + return AVERROR_PATCHWELCOME; + } + + non_vui_extension_length = get_ue_golomb(gb); + if (non_vui_extension_length > 4096) { + av_log(avctx, AV_LOG_ERROR, "vps_non_vui_extension_length too large: %u\n", + non_vui_extension_length); + return AVERROR_INVALIDDATA; + } + skip_bits_long(gb, non_vui_extension_length * 8); + + if (get_bits1(gb)) // vps_vui_present_flag + av_log(avctx, AV_LOG_WARNING, "VPS VUI not supported\n"); + + return 0; +} + int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, HEVCParamSets *ps) { - int i,j; + int i; int vps_id = get_bits(gb, 4); ptrdiff_t nal_size = gb->buffer_end - gb->buffer; int ret = AVERROR_INVALIDDATA; + uint64_t layer1_id_included = 0; HEVCVPS *vps; if (ps->vps_list[vps_id]) { @@ -494,7 +760,7 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, goto err; } - if (parse_ptl(gb, avctx, &vps->ptl, vps->vps_max_sub_layers) < 0) + if (parse_ptl(gb, avctx, 1, &vps->ptl, vps->vps_max_sub_layers) < 0) goto err; vps->vps_sub_layer_ordering_info_present_flag = get_bits1(gb); @@ -526,9 +792,14 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, goto err; } - for (i = 1; i < vps->vps_num_layer_sets; i++) - for (j = 0; j <= vps->vps_max_layer_id; j++) - skip_bits(gb, 1); // layer_id_included_flag[i][j] + vps->num_output_layer_sets = 1; + vps->ols[0] = 1; + + // we support at most 2 layers, so ignore the others + if (vps->vps_num_layer_sets > 1) + layer1_id_included = get_bits64(gb, vps->vps_max_layer_id + 1); // layer_id_included_flag + if (vps->vps_num_layer_sets > 2) + skip_bits_long(gb, (vps->vps_num_layer_sets - 2) * (vps->vps_max_layer_id + 1)); vps->vps_timing_info_present_flag = get_bits1(gb); if (vps->vps_timing_info_present_flag) { @@ -560,7 +831,21 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, vps->vps_max_sub_layers); } } - get_bits1(gb); /* vps_extension_flag */ + + vps->nb_layers = 1; + vps->layer_idx[0] = 0; + for (int i = 1; i < FF_ARRAY_ELEMS(vps->layer_idx); i++) + vps->layer_idx[i] = -1; + + if (vps->vps_max_layers > 1 && get_bits1(gb)) { /* vps_extension_flag */ + int ret = decode_vps_ext(gb, avctx, vps, layer1_id_included); + if (ret == AVERROR_PATCHWELCOME) { + vps->nb_layers = 1; + av_log(avctx, AV_LOG_WARNING, "Ignoring unsupported VPS extension\n"); + ret = 0; + } else if (ret < 0) + goto err; + } if (get_bits_left(gb) < 0) { av_log(avctx, AV_LOG_ERROR, @@ -893,7 +1178,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->temporal_id_nesting = get_bits(gb, 1); - if ((ret = parse_ptl(gb, avctx, &sps->ptl, sps->max_sub_layers)) < 0) + if ((ret = parse_ptl(gb, avctx, 1, &sps->ptl, sps->max_sub_layers)) < 0) return ret; *sps_id = get_ue_golomb_long(gb); diff --git a/libavcodec/hevc/ps.h b/libavcodec/hevc/ps.h index 331d163476..bd1acf12e6 100644 --- a/libavcodec/hevc/ps.h +++ b/libavcodec/hevc/ps.h @@ -32,6 +32,8 @@ #include "hevc.h" +#define HEVC_VPS_MAX_LAYERS 2 + typedef struct HEVCSublayerHdrParams { uint32_t bit_rate_value_minus1[HEVC_MAX_CPB_CNT]; uint32_t cpb_size_value_minus1[HEVC_MAX_CPB_CNT]; @@ -153,6 +155,19 @@ typedef struct PTL { uint8_t sub_layer_level_present_flag[HEVC_MAX_SUB_LAYERS]; } PTL; +typedef struct RepFormat { + uint16_t pic_width_in_luma_samples; + uint16_t pic_height_in_luma_samples; + uint8_t chroma_format_idc; + uint8_t separate_colour_plane_flag; + uint8_t bit_depth_luma; ///< bit_depth_vps_luma_minus8 + 8 + uint8_t bit_depth_chroma; ///< bit_depth_vps_chroma_minus8 + 8 + uint16_t conf_win_left_offset; + uint16_t conf_win_right_offset; + uint16_t conf_win_top_offset; + uint16_t conf_win_bottom_offset; +} RepFormat; + typedef struct HEVCVPS { unsigned int vps_id; @@ -176,6 +191,53 @@ typedef struct HEVCVPS { HEVCHdrParams *hdr; + /* VPS extension */ + + /* Number of layers this VPS was parsed for, between 1 and + * min(HEVC_VPS_MAX_LAYERS, vps_max_layers). + * + * Note that vps_max_layers contains the layer count declared in the + * bitstream, while nb_layers contains the number of layers exported to + * users of this API (which may be smaller as we only support a subset of + * multilayer extensions). + * + * Arrays below documented as [layer_idx] have nb_layers valid entries. + */ + int nb_layers; + + // LayerIdxInVps[nuh_layer_id], i.e. a mapping of nuh_layer_id to VPS layer + // indices. Valid values are between 0 and HEVC_VPS_MAX_LAYERS. Entries for + // unmapped values of nuh_layer_id are set to -1. + int8_t layer_idx[HEVC_MAX_NUH_LAYER_ID + 1]; + + uint8_t layer_id_in_nuh[HEVC_VPS_MAX_LAYERS]; + + uint8_t default_ref_layers_active; + uint8_t max_one_active_ref_layer; + uint8_t poc_lsb_aligned; + // bitmask of poc_lsb_not_present[layer_idx] + uint8_t poc_lsb_not_present; + + struct { + unsigned max_dec_pic_buffering; // max_vps_dec_pic_buffering_minus1 + 1 + unsigned max_num_reorder_pics; // max_vps_num_reorder_pics + unsigned max_latency_increase; // max_vps_latency_increase_plus1 - 1 + } dpb_size; + + // ViewId[layer_idx] + uint16_t view_id[HEVC_VPS_MAX_LAYERS]; + + // NumOutputLayerSets + uint8_t num_output_layer_sets; + // Bitmasks specifying output layer sets. i-th bit set means layer with VPS + // index i is present in the layer set. + uint64_t ols[HEVC_VPS_MAX_LAYERS]; + + // NumDirectRefLayers[layer_idx] + uint8_t num_direct_ref_layers[HEVC_VPS_MAX_LAYERS]; + + RepFormat rep_format; + uint8_t *data; int data_size; } HEVCVPS;