From patchwork Wed Jun 5 19:59:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 49596 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:ce4e:0:b0:478:35e:29dc with SMTP id n14csp21652vqx; Wed, 5 Jun 2024 12:59:44 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXC3mgM+EUXlid5TMvHuUlmgywuEsnvEAnV9sZnb1t/R0xPDB/hZoc6BzO6u433Hm3V/hXJ5J2UqbDoaSUQ4+7JrftaG5DIjKveoQ== X-Google-Smtp-Source: AGHT+IEB5o8yIRlSVRlnYUFS6BSkY23yOBiVLzOxhxXb/kQ4GVdqifTVOpIvGJwNollLAPh1lgjW X-Received: by 2002:a2e:a786:0:b0:2ea:81b3:d7f2 with SMTP id 38308e7fff4ca-2eac79f228dmr25877541fa.4.1717617583782; Wed, 05 Jun 2024 12:59:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1717617583; cv=none; d=google.com; s=arc-20160816; b=HuQYtadm/oKG5LXNZNC1nJqP/Co4383/bqkhc4x0ZJvqWTIU7G/gQUzwdQ5KFwmQnp bAAGtXJ1h6ntGepwf1ZIc+iAaV3UgTqglBVJdxft691IHIwb4L/WVFyyBGbJNoVMDNHT 6N+7YTQBIZpQmlovqQ8GDDHeJufeOwzynhJCxZ6Lf3SIztdcyborDzER/ybdpRMWcFTo neui1MvudQ/WRuKn5yJHnkeFpqtZ9zt51O+VNERzULdOpNcV1URsLpujcyoJy5O9ydd8 aycFZCxSviqzcj076PVuVfLEDOWSj28wVXiW1Gap8r/HoqECUZ6ci1ePkvOel6Bp/Ttk gZbw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; 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:message-id:date:to:from :dkim-signature:delivered-to; bh=Ablj7FKu6rp6QsMDw5n0t5EN1Y4kZKPcge+MpBBvoZA=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=zG8+lGd7Yei7TGf3iBZjau+zZyAuej1UWc1x57cyIkuIo6gqEsoYU3bZq9jHS5oBlt jitCMt+dca5DTzL39OJEtYkTBK48Z+OlJ1DX+KXZmG6TprW0NX2TlUGT5cZh+n4pWAwH LO7mmBturNHxoM1Y3nb7HUtO+mS4T8t2XX9Rt+8CZE92N/QilxlZ/5Uwoc8QrlqKf3UC ArTts9eQ5fLsp3rCNvUzTaoJ+HbsM48q94g9dOzDFUHL0X8mvfyyzccMe8ADHESu7TON R70mjioCmpdodQWUzjp4qxdQIfuI/N9mnfnackQjI6rRxW6U260/u5wl2qfW15revN9y cXhw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@jkqxz-net.20230601.gappssmtp.com header.s=20230601 header.b=AGw9Nmui; 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 4fb4d7f45d1cf-57a31ba63bbsi6715118a12.157.2024.06.05.12.59.42; Wed, 05 Jun 2024 12:59:43 -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=@jkqxz-net.20230601.gappssmtp.com header.s=20230601 header.b=AGw9Nmui; 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 E33CE68D612; Wed, 5 Jun 2024 22:59:38 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f53.google.com (mail-wm1-f53.google.com [209.85.128.53]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BF5F668D52E for ; Wed, 5 Jun 2024 22:59:31 +0300 (EEST) Received: by mail-wm1-f53.google.com with SMTP id 5b1f17b1804b1-42121d27861so2943915e9.0 for ; Wed, 05 Jun 2024 12:59:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jkqxz-net.20230601.gappssmtp.com; s=20230601; t=1717617571; x=1718222371; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=DNHXJvXy61/grKz+OELs6UFt+iDeyisqzGDriJc7jd4=; b=AGw9Nmui3xzw4mAp8JKjl4wtj3O63/i9NmgT+hoFS7H3FFqTD1BXQHqRTJ5q4M6TB0 X1MKEvBxCrvqblL3UxouYSyt8grBXeDJe4wmaxZg2R53y2kaKGjHQ8lcnjFlAndXZawk FefPIDKVsNViOuFdrtFG+RzfMpiUmbWMIGr3mnL+1j3o6tQ9HbjauL54IBn8ozbNlaYI ZXAxk8CyVQBUhD/TBMecBYmq7ZSQDi/G65K4Kcac+rx5+ZjU5hNOHq//F0eAlBEKy/AK sZoAmuScVmxOILGTwDtowqNscAlVdqu0HW9jhvi50IyhSM2ELeF36B48lFesPyGoTWrp VoMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717617571; x=1718222371; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=DNHXJvXy61/grKz+OELs6UFt+iDeyisqzGDriJc7jd4=; b=mFuopidcKMAbu/2pF+etDy9cW/bbQofrNQ25Ro0+dOyvbSBxbkTkw0GV03ke75I+fV iNP0gXJtLzAaGlcetKezrTzXDv5hIcDMghBwHHHA8m2r1CYotSlNsy+9HMNMCq0kKWTf j0h77B7E8ew22YjmOZuyE3LgGvVL4bMc3NBw4RL+0OlTh7iqFGyjo6Z/ytOjjhHr2dZQ 5166C5Wh3LU8AN9gM2FDloqtkTrg4lK3Snm0BE723mIhfsPaBPDPtEqPb9pbSldv1GB5 7gPYWMHchdtGoNePk3GS4owUNKgbn93qslmlGkYhvR/tHO/hgPDw9eKyt35NWbPOSv4z moQQ== X-Gm-Message-State: AOJu0YwQkJ5CBn91F/Cb6uIxzHlOUjDgO/FYuq03a4ejoyCT4axuvAj6 jKnDs4r/XWC5YaZMLpFmvOU4qi0lF+q3uuVDI+PRFGScnd2EUhItjMAqvNgpHYBPpZXnkPc5VGJ 5 X-Received: by 2002:a05:600c:1f93:b0:421:b79:93fd with SMTP id 5b1f17b1804b1-421562e7053mr28790925e9.21.1717617570789; Wed, 05 Jun 2024 12:59:30 -0700 (PDT) Received: from localhost.localdomain (cpc92302-cmbg19-2-0-cust1183.5-4.cable.virginm.net. [82.1.212.160]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42158110dd7sm33675725e9.17.2024.06.05.12.59.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Jun 2024 12:59:30 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Wed, 5 Jun 2024 20:59:42 +0100 Message-ID: <20240605195950.2297433-1-sw@jkqxz.net> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 1/3] lavc/h265_profile_level: Expand profile compatibility checking 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: riYhDQ6eQFoo Replace existing get_profile() with find_profile(), which finds the lowest compatible profile rather than requiring an exact match. --- Now with an enum tag. libavcodec/h265_profile_level.c | 80 +++++++++++++++++++++------------ libavcodec/h265_profile_level.h | 70 ++++++++++++++++++++++++++++- libavcodec/tests/h265_levels.c | 2 +- libavcodec/vaapi_hevc.c | 2 +- libavcodec/vdpau_hevc.c | 2 +- 5 files changed, 124 insertions(+), 32 deletions(-) diff --git a/libavcodec/h265_profile_level.c b/libavcodec/h265_profile_level.c index 7ff9681f65..1e96ec1c32 100644 --- a/libavcodec/h265_profile_level.c +++ b/libavcodec/h265_profile_level.c @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "h265_profile_level.h" @@ -40,6 +42,7 @@ static const H265LevelDescriptor h265_levels[] = { }; static const H265ProfileDescriptor h265_profiles[] = { + { "Invalid" }, // profile_idc 8bit one-picture // HT-profile | 422chroma | lower-bit-rate // | 14bit | | 420chroma | | CpbVclFactor MinCrScaleFactor @@ -119,41 +122,62 @@ static const H265ProfileDescriptor h265_profiles[] = { 5, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 4000, 4400, 6.000, 0.5, 6 }, }; +static_assert(H265_PROFILE_COUNT == FF_ARRAY_ELEMS(h265_profiles), + "Incorrect H.265 profiles table."); + -const H265ProfileDescriptor *ff_h265_get_profile(const H265RawProfileTierLevel *ptl) +const int ff_h265_profile_compatible(const H265RawProfileTierLevel *ptl, + enum H265Profile profile) { - int i; + const H265ProfileDescriptor *desc; + + av_assert0(profile > H265_PROFILE_INVALID && + profile < H265_PROFILE_COUNT); if (ptl->general_profile_space) - return NULL; + return 0; - for (i = 0; i < FF_ARRAY_ELEMS(h265_profiles); i++) { - const H265ProfileDescriptor *profile = &h265_profiles[i]; + desc = &h265_profiles[profile]; - if (ptl->general_profile_idc && - ptl->general_profile_idc != profile->profile_idc) - continue; - if (!ptl->general_profile_compatibility_flag[profile->profile_idc]) - continue; + if (ptl->general_profile_idc && + ptl->general_profile_idc != desc->profile_idc) + return 0; + if (!ptl->general_profile_compatibility_flag[desc->profile_idc]) + return 0; -#define check_flag(name) \ - if (profile->name < 2) { \ - if (profile->name != ptl->general_ ## name ## _constraint_flag) \ - continue; \ - } - check_flag(max_14bit); - check_flag(max_12bit); - check_flag(max_10bit); - check_flag(max_8bit); - check_flag(max_422chroma); - check_flag(max_420chroma); - check_flag(max_monochrome); - check_flag(intra); - check_flag(one_picture_only); - check_flag(lower_bit_rate); +#define check_flag(flag) \ + if (desc->flag < 2 && \ + desc->flag > ptl->general_ ## flag ## _constraint_flag) \ + return 0; + check_flag(max_14bit); + check_flag(max_12bit); + check_flag(max_10bit); + check_flag(max_8bit); + check_flag(max_422chroma); + check_flag(max_420chroma); + check_flag(max_monochrome); + check_flag(intra); + check_flag(one_picture_only); + check_flag(lower_bit_rate); #undef check_flag - return profile; + return 1; +} + + +const H265ProfileDescriptor *ff_h265_get_profile(enum H265Profile profile) +{ + av_assert0(profile > H265_PROFILE_INVALID && + profile < H265_PROFILE_COUNT); + + return &h265_profiles[profile]; +} + +const H265ProfileDescriptor *ff_h265_find_profile(const H265RawProfileTierLevel *ptl) +{ + for (int p = 1; p < H265_PROFILE_COUNT; p++) { + if (ff_h265_profile_compatible(ptl, p)) + return &h265_profiles[p]; } return NULL; @@ -171,12 +195,12 @@ const H265LevelDescriptor *ff_h265_guess_level(const H265RawProfileTierLevel *pt int i; if (ptl) - profile = ff_h265_get_profile(ptl); + profile = ff_h265_find_profile(ptl); else profile = NULL; if (!profile) { // Default to using multiplication factors for Main profile. - profile = &h265_profiles[4]; + profile = &h265_profiles[H265_PROFILE_MAIN]; } pic_size = width * height; diff --git a/libavcodec/h265_profile_level.h b/libavcodec/h265_profile_level.h index cd30ac5c50..c019c738a7 100644 --- a/libavcodec/h265_profile_level.h +++ b/libavcodec/h265_profile_level.h @@ -24,6 +24,50 @@ #include "cbs_h265.h" +// Enumeration of all H.265 profiles. +// The list is ordered to match table A.10; numeric values are an index +// into the latest version of this table and have no codec meaning. +enum H265Profile { + H265_PROFILE_INVALID, + H265_PROFILE_MONOCHROME, + H265_PROFILE_MONOCHROME_10, + H265_PROFILE_MONOCHROME_12, + H265_PROFILE_MONOCHROME_16, + H265_PROFILE_MAIN, + H265_PROFILE_SCREEN_EXTENDED_MAIN, + H265_PROFILE_MAIN_10, + H265_PROFILE_SCREEN_EXTENDED_MAIN_10, + H265_PROFILE_MAIN_12, + H265_PROFILE_MAIN_STILL_PICTURE, + H265_PROFILE_MAIN_10_STILL_PICTURE, + H265_PROFILE_MAIN_422_10, + H265_PROFILE_MAIN_422_12, + H265_PROFILE_MAIN_444, + H265_PROFILE_HIGH_THROUGHPUT_444, + H265_PROFILE_SCREEN_EXTENDED_MAIN_444, + H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444, + H265_PROFILE_MAIN_444_10, + H265_PROFILE_HIGH_THROUGHPUT_444_10, + H265_PROFILE_SCREEN_EXTENDED_MAIN_444_10, + H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, + H265_PROFILE_MAIN_444_12, + H265_PROFILE_HIGH_THROUGHPUT_444_14, + H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, + H265_PROFILE_MAIN_INTRA, + H265_PROFILE_MAIN_10_INTRA, + H265_PROFILE_MAIN_12_INTRA, + H265_PROFILE_MAIN_422_10_INTRA, + H265_PROFILE_MAIN_422_12_INTRA, + H265_PROFILE_MAIN_444_INTRA, + H265_PROFILE_MAIN_444_10_INTRA, + H265_PROFILE_MAIN_444_12_INTRA, + H265_PROFILE_MAIN_444_16_INTRA, + H265_PROFILE_MAIN_444_STILL_PICTURE, + H265_PROFILE_MAIN_444_16_STILL_PICTURE, + H265_PROFILE_HIGH_THROUGHPUT_444_16_INTRA, + H265_PROFILE_COUNT, +}; + typedef struct H265LevelDescriptor { char name[4]; // Large enough for all current levels like "4.1" uint8_t level_idc; @@ -70,7 +114,31 @@ typedef struct H265ProfileDescriptor { } H265ProfileDescriptor; -const H265ProfileDescriptor *ff_h265_get_profile(const H265RawProfileTierLevel *ptl); +/** + * Test whether the PTL structure is compatible with the given profile. + * + * @param ptl PTL structure to check. + * @param profile Profile to test compatibility with. + * @return Nonzero if compatible, zero if incompatible. + */ +const int ff_h265_profile_compatible(const H265RawProfileTierLevel *ptl, + enum H265Profile profile); + +/** + * Return profile descriptor for the given profile. + * + * @param profile Profile. + * @return Profile descriptor. + */ +const H265ProfileDescriptor *ff_h265_get_profile(enum H265Profile profile); + +/** + * Find the first profile compatible with the given PTL structure. + * + * @param ptl PTL structure to search for. + * @return First compatible profile, or NULL if no compatible profiles. + */ +const H265ProfileDescriptor *ff_h265_find_profile(const H265RawProfileTierLevel *ptl); /** diff --git a/libavcodec/tests/h265_levels.c b/libavcodec/tests/h265_levels.c index 66d72c63a3..9923f346f7 100644 --- a/libavcodec/tests/h265_levels.c +++ b/libavcodec/tests/h265_levels.c @@ -275,7 +275,7 @@ int main(void) } for (i = 0; i < FF_ARRAY_ELEMS(test_bitrate); i++) { - profile = ff_h265_get_profile(test_bitrate[i].ptl); + profile = ff_h265_find_profile(test_bitrate[i].ptl); level = ff_h265_guess_level(test_bitrate[i].ptl, test_bitrate[i].bitrate, 0, 0, 0, 0, 0, 0); diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c index 051762bfef..6164a1d223 100644 --- a/libavcodec/vaapi_hevc.c +++ b/libavcodec/vaapi_hevc.c @@ -603,7 +603,7 @@ VAProfile ff_vaapi_parse_hevc_rext_scc_profile(AVCodecContext *avctx) /* convert PTLCommon to H265RawProfileTierLevel */ ptl_convert(general_ptl, &h265_raw_ptl); - profile = ff_h265_get_profile(&h265_raw_ptl); + profile = ff_h265_find_profile(&h265_raw_ptl); if (!profile) { av_log(avctx, AV_LOG_WARNING, "HEVC profile is not found.\n"); goto end; diff --git a/libavcodec/vdpau_hevc.c b/libavcodec/vdpau_hevc.c index f7cf1bd9c0..e7587f9994 100644 --- a/libavcodec/vdpau_hevc.c +++ b/libavcodec/vdpau_hevc.c @@ -478,7 +478,7 @@ static int vdpau_hevc_parse_rext_profile(AVCodecContext *avctx, VdpDecoderProfil /* convert PTLCommon to H265RawProfileTierLevel */ ptl_convert(general_ptl, &h265_raw_ptl); - profile = ff_h265_get_profile(&h265_raw_ptl); + profile = ff_h265_find_profile(&h265_raw_ptl); if (!profile) { av_log(avctx, AV_LOG_WARNING, "HEVC profile is not found.\n"); if (avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) { From patchwork Wed Jun 5 19:59:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 49597 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:ce4e:0:b0:478:35e:29dc with SMTP id n14csp21731vqx; Wed, 5 Jun 2024 12:59:53 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWOCltalI8IMBa5EEmughsXiCn9XsEecoiDMUGQg02dthYcoLa6JiwWwtq+45jlny+e/Kq3iXN+W7U/7ofg6wTCgZNrrHkXpdW+nA== X-Google-Smtp-Source: AGHT+IHtiovQDLCDfnHg7/1/1RNc6d2Mt9xF8Ky7mq0zfxs8o/9/3X3GsMw4HjLbkwr92GMh+eg9 X-Received: by 2002:a05:6512:3a8e:b0:52b:8c88:2d6b with SMTP id 2adb3069b0e04-52bab4c858emr2603406e87.11.1717617592999; Wed, 05 Jun 2024 12:59:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1717617592; cv=none; d=google.com; s=arc-20160816; b=QG5n0mtH51mogNjZCdQ0rNUAFE+PkTgmRAQtyjgOyDfX0wwMSqxk38LsiXJU7nXt4/ Xy7hIHMViT9KDDpoKDy+84PzdXKb6p+WD/BFqI8Y7q0Vwh7z6WPb3GOOY9alP5aVSxTA jn/mxSpPL/BM4H0d0ML2t7bir+0S3DRp/pJJFNjWhKEV0Dm3Ac/PZKeqJk3Unqife6Wz /MKmNskZXYQO5mcy6DBxyKq+QK9HVs3PAAHXZY7G28oJ650MH103Qcx+tSeww3UMYrkU IpnVdgIW671YW7PCnNV49BW56IoBIWHEQb6GqQ+pugmyXIPv6ub4GfHTKXpDOUH583JL 3IBw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; 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=IYOgIuNsuiWHkU/4AUClrqx7I5ArQ3gET27IQCTXO6k=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=VxrS/SJOU2cBFjUD+9fo818ETicdb6GF7v873j9OaQbW3vQmbPjLtfuLyweJF3QYxA 1sWdmpT4ez/AI1ZpPFJkzeQf8Xxo7umCMzN7nfp/lXolITZWFaJ3jWzfdmET7V/lKsI7 xBzvXrL2IyVYEXs1NMfLsOpYH93ygp85546P1fNyYkJUya5I5AcGX6H4yRnLsXJQdadv Dl2a5rPq0cgvQLy2BihWg6oC1FotYEtc6wvvg7+oHJNMlWc0hxyAFSf3fqUogQXk1qY+ GdoLqJx5xLuq/j+Xkbk5Krj4InPM3NRv9BUK5ar/M70q/Xp2HtIT6L3qAxfX4UrIbssG mHyQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@jkqxz-net.20230601.gappssmtp.com header.s=20230601 header.b=rlo2592q; 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-52bb2194a48si100221e87.112.2024.06.05.12.59.52; Wed, 05 Jun 2024 12:59:52 -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=@jkqxz-net.20230601.gappssmtp.com header.s=20230601 header.b=rlo2592q; 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 0708268D52E; Wed, 5 Jun 2024 22:59:40 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1967068D52E for ; Wed, 5 Jun 2024 22:59:32 +0300 (EEST) Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-42121d27861so2944005e9.0 for ; Wed, 05 Jun 2024 12:59:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jkqxz-net.20230601.gappssmtp.com; s=20230601; t=1717617571; x=1718222371; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=psvBdyUTBGITjsGNhI/bfLlNriAgth0tO4XuZHQ1hVs=; b=rlo2592qWC6RGMgDrDRZLasYuqJ0PJCEtoD3C7oJAc2zbg3RNCP+0Ur1f5cy2Lg67h tQEPQLYQfbS0lBWKPBGnFXpOyA+7uKrRR8S0S4oO4DfeqNwh+p/EbzslRxGnqgnHW/d2 nK5O7rvQ8P0kWfqiGoPS47Niv3wH5X9LlLE+FaYKbQj8npdCm99UI9PYR+v5IeKOXQIA agu0bsZw6WM2wPyuWgcP1jICL6RONBOPC3uegBED8mY4u4orHeFfWPHUT3JhV7rHikkA 8usZBt1zbGN2if4NvlNNTmTypgTKDOyvotjdz1Ws8vGf+RWG5PWZFUFYtG4jUxZFiTHz KNVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717617571; x=1718222371; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=psvBdyUTBGITjsGNhI/bfLlNriAgth0tO4XuZHQ1hVs=; b=DynDQ0HgVx5XjBE67ZVX30Ism4s+bzWAvjzp49kOQYX9BUzYBurNsoy9w8FytXgFrD kO1MAZ0ALJVmVMwFdZ4Kp/PeFplZDxvummwqdgrsKhzmxsc0Rqcx++AiX+zjxFK/jlBj ev7qa914Nsm8Dtf5LoN5x9V5M0GoosbdDZSTBdf2rNSWQx2a07KbPJsDVvaiNYlflUBW QqOGkIjwnFIsVpk9JPiTWXk4p6ALkDRCmZoJFeiSRn9P4JzN/qjRCqUisc5gT8qdAlz4 MzkSah0otazHeAceDOXw7S024jf6IbDIsuMtlqPraWYxSLyT0lD1DS1/0RiJdLTYgUTc 5AEQ== X-Gm-Message-State: AOJu0Yx07bw/UVWhV/V4lEtFIsLz3GfGYbZOKWIgzxqjswYdr+7I4yHy 7i1x+SK1zEl8tab2G8+iIRWGpBh8aIdi3moS3V4orHdy3XtfPhUddKKYjOBqz5DQBweNi8RRe/n A X-Received: by 2002:a05:600c:3505:b0:421:5329:23d with SMTP id 5b1f17b1804b1-421562c8050mr28258455e9.6.1717617571302; Wed, 05 Jun 2024 12:59:31 -0700 (PDT) Received: from localhost.localdomain (cpc92302-cmbg19-2-0-cust1183.5-4.cable.virginm.net. [82.1.212.160]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42158110dd7sm33675725e9.17.2024.06.05.12.59.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Jun 2024 12:59:31 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Wed, 5 Jun 2024 20:59:43 +0100 Message-ID: <20240605195950.2297433-2-sw@jkqxz.net> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240605195950.2297433-1-sw@jkqxz.net> References: <20240605195950.2297433-1-sw@jkqxz.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 2/3] lavc: Add test for H.265 profile handling 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: dnrABkoI13El --- libavcodec/Makefile | 2 +- libavcodec/tests/.gitignore | 1 + libavcodec/tests/h265_profiles.c | 440 +++++++++++++++++++++++++++++++ tests/fate/libavcodec.mak | 5 + 4 files changed, 447 insertions(+), 1 deletion(-) create mode 100644 libavcodec/tests/h265_profiles.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 8ab4398b6c..e7973fb2e6 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1297,7 +1297,7 @@ TESTPROGS-$(CONFIG_MJPEG_ENCODER) += mjpegenc_huffman TESTPROGS-$(HAVE_MMX) += motion TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate TESTPROGS-$(CONFIG_H264_METADATA_BSF) += h264_levels -TESTPROGS-$(CONFIG_HEVC_METADATA_BSF) += h265_levels +TESTPROGS-$(CONFIG_HEVC_METADATA_BSF) += h265_levels h265_profiles TESTPROGS-$(CONFIG_RANGECODER) += rangecoder TESTPROGS-$(CONFIG_SNOW_ENCODER) += snowenc diff --git a/libavcodec/tests/.gitignore b/libavcodec/tests/.gitignore index 0df4ae10a0..bf29f03911 100644 --- a/libavcodec/tests/.gitignore +++ b/libavcodec/tests/.gitignore @@ -10,6 +10,7 @@ /golomb /h264_levels /h265_levels +/h265_profiles /htmlsubtitles /iirfilter /jpeg2000dwt diff --git a/libavcodec/tests/h265_profiles.c b/libavcodec/tests/h265_profiles.c new file mode 100644 index 0000000000..37fc545558 --- /dev/null +++ b/libavcodec/tests/h265_profiles.c @@ -0,0 +1,440 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/bprint.h" +#include "libavutil/common.h" +#include "libavcodec/h265_profile_level.h" + + +enum { + TYPE_MAIN, + TYPE_SP, + TYPE_REXT_INTER, + TYPE_REXT_INTRA, + TYPE_HT, + TYPE_HT_INTRA, + TYPE_SCC, + TYPE_HT_SCC, + TYPE_COUNT, +}; +enum { + DEPTH_8, + DEPTH_10, + DEPTH_12, + DEPTH_14, + DEPTH_16, + DEPTH_COUNT, +}; +enum { + CHROMA_MONO, + CHROMA_420, + CHROMA_422, + CHROMA_444, + CHROMA_COUNT, +}; + +// Table of all profiles indexed by chroma subsampling, bit depth and +// profile type. This is currently only being used to verify that +// profile properties are correct, but if there is some other need for +// this lookup in lavc then the table should be moved to the common +// profile-level code. All profiles should appear exactly once in this +// table (also verified by a test below). +static enum H265Profile profile_table[CHROMA_COUNT][DEPTH_COUNT][TYPE_COUNT] = { + [CHROMA_MONO] = { + [DEPTH_8] = { + [TYPE_REXT_INTER] = H265_PROFILE_MONOCHROME, + }, + [DEPTH_10] = { + [TYPE_REXT_INTER] = H265_PROFILE_MONOCHROME_10, + }, + [DEPTH_12] = { + [TYPE_REXT_INTER] = H265_PROFILE_MONOCHROME_12, + }, + [DEPTH_16] = { + [TYPE_REXT_INTER] = H265_PROFILE_MONOCHROME_16, + }, + }, + [CHROMA_420] = { + [DEPTH_8] = { + [TYPE_MAIN] = H265_PROFILE_MAIN, + [TYPE_SP] = H265_PROFILE_MAIN_STILL_PICTURE, + [TYPE_REXT_INTRA] = H265_PROFILE_MAIN_INTRA, + [TYPE_SCC] = H265_PROFILE_SCREEN_EXTENDED_MAIN, + }, + [DEPTH_10] = { + [TYPE_MAIN] = H265_PROFILE_MAIN_10, + [TYPE_SP] = H265_PROFILE_MAIN_10_STILL_PICTURE, + [TYPE_REXT_INTRA] = H265_PROFILE_MAIN_10_INTRA, + [TYPE_SCC] = H265_PROFILE_SCREEN_EXTENDED_MAIN_10, + }, + [DEPTH_12] = { + [TYPE_REXT_INTER] = H265_PROFILE_MAIN_12, + [TYPE_REXT_INTRA] = H265_PROFILE_MAIN_12_INTRA, + }, + }, + [CHROMA_422] ={ + [DEPTH_10] = { + [TYPE_REXT_INTER] = H265_PROFILE_MAIN_422_10, + [TYPE_REXT_INTRA] = H265_PROFILE_MAIN_422_10_INTRA, + }, + [DEPTH_12] = { + [TYPE_REXT_INTER] = H265_PROFILE_MAIN_422_12, + [TYPE_REXT_INTRA] = H265_PROFILE_MAIN_422_12_INTRA, + }, + }, + [CHROMA_444] ={ + [DEPTH_8] = { + [TYPE_SP] = H265_PROFILE_MAIN_444_STILL_PICTURE, + [TYPE_REXT_INTER] = H265_PROFILE_MAIN_444, + [TYPE_REXT_INTRA] = H265_PROFILE_MAIN_444_INTRA, + [TYPE_HT] = H265_PROFILE_HIGH_THROUGHPUT_444, + [TYPE_SCC] = H265_PROFILE_SCREEN_EXTENDED_MAIN_444, + [TYPE_HT_SCC] = H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444, + }, + [DEPTH_10] = { + [TYPE_REXT_INTER] = H265_PROFILE_MAIN_444_10, + [TYPE_REXT_INTRA] = H265_PROFILE_MAIN_444_10_INTRA, + [TYPE_HT] = H265_PROFILE_HIGH_THROUGHPUT_444_10, + [TYPE_SCC] = H265_PROFILE_SCREEN_EXTENDED_MAIN_444_10, + [TYPE_HT_SCC] = H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_10, + }, + [DEPTH_12] = { + [TYPE_REXT_INTER] = H265_PROFILE_MAIN_444_12, + [TYPE_REXT_INTRA] = H265_PROFILE_MAIN_444_12_INTRA, + }, + [DEPTH_14] = { + [TYPE_HT] = H265_PROFILE_HIGH_THROUGHPUT_444_14, + [TYPE_HT_SCC] = H265_PROFILE_SCREEN_EXTENDED_HIGH_THROUGHPUT_444_14, + }, + [DEPTH_16] = { + [TYPE_SP] = H265_PROFILE_MAIN_444_16_STILL_PICTURE, + [TYPE_REXT_INTRA] = H265_PROFILE_MAIN_444_16_INTRA, + [TYPE_HT_INTRA] = H265_PROFILE_HIGH_THROUGHPUT_444_16_INTRA, + }, + }, +}; + +static int check_flags(const H265ProfileDescriptor *desc, + int chroma, int depth) +{ + int errors = 0; + if (chroma > CHROMA_MONO && desc->max_monochrome == 1) { + av_log(NULL, AV_LOG_ERROR, "%s requires monochrome.\n", + desc->name); + ++errors; + } + if (chroma > CHROMA_422 && desc->max_420chroma == 1) { + av_log(NULL, AV_LOG_ERROR, "%s requires 4:2:0.\n", + desc->name); + ++errors; + } + if (chroma > CHROMA_444 && desc->max_422chroma == 1) { + av_log(NULL, AV_LOG_ERROR, "%s requires 4:2:2.\n", + desc->name); + ++errors; + } + if (depth > DEPTH_8 && desc->max_8bit == 1) { + av_log(NULL, AV_LOG_ERROR, "%s requires 8-bit.\n", + desc->name); + ++errors; + } + if (depth > DEPTH_10 && desc->max_10bit == 1) { + av_log(NULL, AV_LOG_ERROR, "%s requires 10-bit.\n", + desc->name); + ++errors; + } + if (depth > DEPTH_12 && desc->max_12bit == 1) { + av_log(NULL, AV_LOG_ERROR, "%s requires 12-bit.\n", + desc->name); + ++errors; + } + if (depth > DEPTH_14 && desc->max_14bit == 1) { + av_log(NULL, AV_LOG_ERROR, "%s requires 14-bit.\n", + desc->name); + ++errors; + } + return errors; +} + +static int check_profile_table(void) +{ + // Ensure that the profile table contains every non-still-picture + // profile exactly once, and that a profile for a given chroma mode + // and depth actually supports that chroma mode and depth. + int errors = 0; + + for (int p = H265_PROFILE_MONOCHROME; p < H265_PROFILE_COUNT; p++) { + const H265ProfileDescriptor *desc = ff_h265_get_profile(p); + int found = 0; + + for (int type= 0; type < TYPE_COUNT; type++) { + for (int chroma = 0; chroma < CHROMA_COUNT; chroma++) { + for (int depth = 0; depth < DEPTH_COUNT; depth++) { + if (profile_table[chroma][depth][type] == p) { + ++found; + errors += check_flags(desc, chroma, depth); + } + } + } + } + + if (found != 1) { + av_log(NULL, AV_LOG_ERROR, + "%s appears %d times in the profile table.\n", + desc->name, found); + + ++errors; + } + } + return errors; +} + +static enum H265Profile get_profile(int type, int chroma, int depth) +{ + av_assert0(type >= 0 && type < TYPE_COUNT); + av_assert0(chroma >= 0 && chroma < CHROMA_COUNT); + av_assert0(depth >= 0 && depth < DEPTH_COUNT); + return profile_table[chroma][depth][type]; +} + +static void minimal_ptl_from_desc(H265RawProfileTierLevel *ptl, + const H265ProfileDescriptor *desc) +{ + *ptl = (H265RawProfileTierLevel) { + .general_profile_space = 0, + .general_profile_idc = desc->profile_idc, + // Tier/interlace/stereo/layering/level flags are ignored in + // this test. + }; + + ptl->general_profile_compatibility_flag[desc->profile_idc] = 1; + +#define FLAG(name) do { \ + ptl->general_ ## name ## _constraint_flag = desc->name; \ + } while (0) + + FLAG(max_14bit); + FLAG(max_12bit); + FLAG(max_10bit); + FLAG(max_8bit); + FLAG(max_422chroma); + FLAG(max_420chroma); + FLAG(max_monochrome); + FLAG(intra); + FLAG(one_picture_only); + FLAG(lower_bit_rate); + +#undef FLAG +} + +static void bprint_ptl(AVBPrint *buf, const H265RawProfileTierLevel *ptl) +{ + av_bprintf(buf, "profile_space %d tier %d profile_idc %d", + ptl->general_profile_space, + ptl->general_tier_flag, + ptl->general_profile_idc); + + av_bprintf(buf, " profile_compatibility { "); + for (int i = 0; i < 32; i++) + av_bprintf(buf, "%d", + ptl->general_profile_compatibility_flag[i]); + av_bprintf(buf, " }"); + + av_bprintf(buf, " progressive %d interlaced %d", + ptl->general_progressive_source_flag, + ptl->general_interlaced_source_flag); + av_bprintf(buf, " non_packed %d frame_only %d", + ptl->general_non_packed_constraint_flag, + ptl->general_frame_only_constraint_flag); + +#define profile_compatible(x) (ptl->general_profile_idc == (x) || \ + ptl->general_profile_compatibility_flag[x]) + if (profile_compatible(4) || profile_compatible(5) || + profile_compatible(6) || profile_compatible(7) || + profile_compatible(8) || profile_compatible(9) || + profile_compatible(10) || profile_compatible(11)) { + + av_bprintf(buf, " 12bit %d", ptl->general_max_12bit_constraint_flag); + av_bprintf(buf, " 10bit %d", ptl->general_max_10bit_constraint_flag); + av_bprintf(buf, " 8bit %d", ptl->general_max_8bit_constraint_flag); + av_bprintf(buf, " 422chroma %d", ptl->general_max_422chroma_constraint_flag); + av_bprintf(buf, " 420chroma %d", ptl->general_max_420chroma_constraint_flag); + av_bprintf(buf, " monochrome %d", ptl->general_max_monochrome_constraint_flag); + av_bprintf(buf, " intra %d", ptl->general_intra_constraint_flag); + av_bprintf(buf, " one_picture %d", ptl->general_one_picture_only_constraint_flag); + av_bprintf(buf, " lower_bit_rate %d", ptl->general_lower_bit_rate_constraint_flag); + + if (profile_compatible(5) || profile_compatible(9) || + profile_compatible(10) || profile_compatible(11)) { + av_bprintf(buf, " 14bit %d", ptl->general_max_14bit_constraint_flag); + } + + if (profile_compatible(1) || profile_compatible(2) || + profile_compatible(3) || profile_compatible(4) || + profile_compatible(5) || profile_compatible(9) || + profile_compatible(11)) { + av_bprintf(buf, " inbld %d", ptl->general_inbld_flag); + } + } +#undef profile_compatible + + av_bprintf(buf, " level %d", ptl->general_level_idc); +} + + +#define CHECK_COMPATIBILITY(expected, ptl, profile) do { \ + if (expected == !ff_h265_profile_compatible(ptl, profile)) { \ + AVBPrint buf; \ + char *str; \ + const H265ProfileDescriptor *desc = \ + ff_h265_get_profile(profile); \ + av_log(NULL, AV_LOG_ERROR, expected ? \ + "Incorrectly incompatible with %s:\n" : \ + "Incorrectly compatible with %s:\n", \ + desc->name); \ + av_bprint_init(&buf, 1024, -1); \ + bprint_ptl(&buf, ptl); \ + av_bprint_finalize(&buf, &str); \ + av_log(NULL, AV_LOG_ERROR, "%s\n", str); \ + return 1; \ + } \ + } while (0) + +static int check_simple_rext_profiles(void) +{ + static const H265RawProfileTierLevel rext_420_8 = { + .general_profile_space = 0, + .general_profile_idc = 4, + .general_tier_flag = 0, + .general_profile_compatibility_flag[4] = 1, + .general_max_12bit_constraint_flag = 1, + .general_max_10bit_constraint_flag = 1, + .general_max_8bit_constraint_flag = 1, + .general_max_422chroma_constraint_flag = 1, + .general_max_420chroma_constraint_flag = 1, + .general_max_monochrome_constraint_flag = 0, + .general_intra_constraint_flag = 0, + .general_one_picture_only_constraint_flag = 0, + .general_lower_bit_rate_constraint_flag = 1, + }; + static const H265RawProfileTierLevel rext_420_10 = { + .general_profile_space = 0, + .general_profile_idc = 4, + .general_tier_flag = 0, + .general_profile_compatibility_flag[4] = 1, + .general_max_12bit_constraint_flag = 1, + .general_max_10bit_constraint_flag = 1, + .general_max_8bit_constraint_flag = 0, + .general_max_422chroma_constraint_flag = 1, + .general_max_420chroma_constraint_flag = 1, + .general_max_monochrome_constraint_flag = 0, + .general_intra_constraint_flag = 0, + .general_one_picture_only_constraint_flag = 0, + .general_lower_bit_rate_constraint_flag = 1, + }; + static const H265RawProfileTierLevel rext_422_8 = { + .general_profile_space = 0, + .general_profile_idc = 4, + .general_tier_flag = 0, + .general_profile_compatibility_flag[4] = 1, + .general_max_12bit_constraint_flag = 1, + .general_max_10bit_constraint_flag = 1, + .general_max_8bit_constraint_flag = 1, + .general_max_422chroma_constraint_flag = 1, + .general_max_420chroma_constraint_flag = 0, + .general_max_monochrome_constraint_flag = 0, + .general_intra_constraint_flag = 0, + .general_one_picture_only_constraint_flag = 0, + .general_lower_bit_rate_constraint_flag = 1, + }; + + CHECK_COMPATIBILITY(0, &rext_420_8, H265_PROFILE_MAIN); + CHECK_COMPATIBILITY(0, &rext_420_8, H265_PROFILE_MAIN_10); + CHECK_COMPATIBILITY(1, &rext_420_8, H265_PROFILE_MAIN_12); + CHECK_COMPATIBILITY(1, &rext_420_8, H265_PROFILE_MAIN_422_10); + CHECK_COMPATIBILITY(1, &rext_420_8, H265_PROFILE_MAIN_444); + CHECK_COMPATIBILITY(1, &rext_420_8, H265_PROFILE_MAIN_444_10); + + CHECK_COMPATIBILITY(0, &rext_420_10, H265_PROFILE_MAIN); + CHECK_COMPATIBILITY(0, &rext_420_10, H265_PROFILE_MAIN_10); + CHECK_COMPATIBILITY(1, &rext_420_10, H265_PROFILE_MAIN_12); + CHECK_COMPATIBILITY(1, &rext_420_10, H265_PROFILE_MAIN_422_10); + CHECK_COMPATIBILITY(0, &rext_420_10, H265_PROFILE_MAIN_444); + CHECK_COMPATIBILITY(1, &rext_420_10, H265_PROFILE_MAIN_444_10); + + CHECK_COMPATIBILITY(0, &rext_422_8, H265_PROFILE_MAIN); + CHECK_COMPATIBILITY(0, &rext_422_8, H265_PROFILE_MAIN_10); + CHECK_COMPATIBILITY(0, &rext_422_8, H265_PROFILE_MAIN_12); + CHECK_COMPATIBILITY(1, &rext_422_8, H265_PROFILE_MAIN_422_10); + CHECK_COMPATIBILITY(1, &rext_422_8, H265_PROFILE_MAIN_444); + CHECK_COMPATIBILITY(1, &rext_422_8, H265_PROFILE_MAIN_444_10); + + return 0; +} + +int main(void) +{ + if (check_profile_table()) + return 1; + + if (check_simple_rext_profiles()) + return 1; + + // Check compatibility pairs between all profiles of the same type. + // Profile A should be compatibile with a profile B which supports + // at least the same chroma subsampling and at least the same depth + // (including if A and B are the same). + for (int type = TYPE_REXT_INTER; type < TYPE_COUNT; type++) { + for (int chroma_a = 0; chroma_a < CHROMA_COUNT; chroma_a++) { + for (int depth_a = 0; depth_a < DEPTH_COUNT; depth_a++) { + enum H265Profile profile_a; + const H265ProfileDescriptor *desc_a; + H265RawProfileTierLevel ptl_a; + + profile_a = get_profile(type, chroma_a, depth_a); + if (profile_a == H265_PROFILE_INVALID) + continue; + desc_a = ff_h265_get_profile(profile_a); + minimal_ptl_from_desc(&ptl_a, desc_a); + + for (int chroma_b = 0; chroma_b < CHROMA_COUNT; chroma_b++) { + for (int depth_b = 0; depth_b < DEPTH_COUNT; depth_b++) { + enum H265Profile profile_b; + const H265ProfileDescriptor *desc_b; + int expect_compatible = (depth_b >= depth_a && + chroma_b >= chroma_a); + + profile_b = get_profile(type, chroma_b, depth_b); + if (profile_b == H265_PROFILE_INVALID) + continue; + desc_b = ff_h265_get_profile(profile_b); + + av_log(NULL, AV_LOG_INFO, + "%d: A (%s: %d,%d) B (%s: %d,%d)\n", type, + desc_a->name, chroma_a, depth_a, + desc_b->name, chroma_b, depth_b); + CHECK_COMPATIBILITY(expect_compatible, + &ptl_a, profile_b); + } + } + } + } + } + + return 0; +} diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak index 1a5694fa5f..a47e8b8237 100644 --- a/tests/fate/libavcodec.mak +++ b/tests/fate/libavcodec.mak @@ -71,6 +71,11 @@ fate-h265-levels: libavcodec/tests/h265_levels$(EXESUF) fate-h265-levels: CMD = run libavcodec/tests/h265_levels$(EXESUF) fate-h265-levels: REF = /dev/null +FATE_LIBAVCODEC-$(CONFIG_HEVC_METADATA_BSF) += fate-h265-profiles +fate-h265-profiles: libavcodec/tests/h265_profiles$(EXESUF) +fate-h265-profiles: CMD = run libavcodec/tests/h265_profiles$(EXESUF) +fate-h265-profiles: REF = /dev/null + FATE_LIBAVCODEC-$(CONFIG_IIRFILTER) += fate-iirfilter fate-iirfilter: libavcodec/tests/iirfilter$(EXESUF) fate-iirfilter: CMD = run libavcodec/tests/iirfilter$(EXESUF) From patchwork Wed Jun 5 19:59:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 49598 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:ce4e:0:b0:478:35e:29dc with SMTP id n14csp21843vqx; Wed, 5 Jun 2024 13:00:03 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWBHGHBNTVFdEa9VmXzh2GXKD67s0iqgiB7sQ1Kd6YMkGKC6xhFFkwHc5XFuUET/rsIJQEyv2WCzbGvcaVvAMY+jVDKiD2dEDO97w== X-Google-Smtp-Source: AGHT+IESTtvzQufEwkxYUowjndj6vdWcQTyHoL7a0ejmsBrt/TmH+DLiG+OffCBDIViq0sJciVvt X-Received: by 2002:a50:9518:0:b0:57a:30db:d9ce with SMTP id 4fb4d7f45d1cf-57a8bcadc93mr2191335a12.3.1717617602934; Wed, 05 Jun 2024 13:00:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1717617602; cv=none; d=google.com; s=arc-20160816; b=wfxACjqC/b5g46slYe/W6rlE/H5w8nLoL4FB+gyb+e6AlnSR6sHL7LftCmeVgYw1CZ jT0bFiwNyWKm9BK4yODcgyUu5tUCY3K9/2408xERKIPPmaqPPkQVC611OK4pxnE3Bqfi zpwBwai0IdQ5c58LswZrbvUuD+By7JXlOnCfevAV7jSgTKk984ZSWPzxghxkhBuR1RAG Ld6xZO9H4EYeX6dNZQb2d0ZvbiyOv6eVt5raU9nhV+BtW778szelPQSAvcrjf0il22O7 E+8ru021C8sXFD2zQofSsaq2rgiLceclC9mw7j5BF+WbXWlSKsbjKTIlZ3DbPlvUBKJ5 BkzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; 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=0yflivlUqyyoQ8z0PvgxVMGWl6lyWo9HoCPd+fcwMf4=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=EpQA+e9RH/Mgmf7ZmfklHNXYQzY5z5l3xMwPgW6cSyteBdPwV2npbY80o1zHm4+/e0 szE6WuTqzR3kkxh8pOSI9Ja79u3V0r3py7rAxWFuwdRLGzfX+6bFG+kP4Q6wJSFYVQxE lMHW4e+SrtjHC1+0mQzQM6Hf3RdmCvSVmMwzKCLeL47bhFAalpt+6j8759aWsMHpVEAB uuW6CNHwgbHDsbNo8Ov830mHaxeaho6sZ35tkT6eodvXy2j/qn/073kPo/h7gkwKqU74 tyQqHpTsTLZ5koTiVGFCFuUhJuPuMzYqsjROQX1dSgH4zGjIP6B+fHFn9t6aV08Oc0+4 t6wg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@jkqxz-net.20230601.gappssmtp.com header.s=20230601 header.b=KKe62tme; 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 4fb4d7f45d1cf-57a31c62f33si6517554a12.294.2024.06.05.13.00.01; Wed, 05 Jun 2024 13:00:02 -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=@jkqxz-net.20230601.gappssmtp.com header.s=20230601 header.b=KKe62tme; 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 1244368D6E2; Wed, 5 Jun 2024 22:59:41 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4453B68D5F9 for ; Wed, 5 Jun 2024 22:59:33 +0300 (EEST) Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-4212b4eea2eso2449875e9.2 for ; Wed, 05 Jun 2024 12:59:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jkqxz-net.20230601.gappssmtp.com; s=20230601; t=1717617572; x=1718222372; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=S2gqsJbD6zdaBl5d/igOar152J/6V3l2z5gTGxyKy4E=; b=KKe62tmenB6YaVpF38EYyrARtJOjQIQx1sH7cECMb/SUwyY+G2KWM25Kt7CWAlNVp4 tNQGoVX0GuxBrLEnmbfjpuR4zXG9FN9ahcgLJhe3n5DNOnkdBNUaKJ7RH/tBaB90J/lK /D/RLklX3dC0ya2wA8S3YDRgPVL6l5MLUwfjWrto/uNXZINwhYpx+iFQutrP3AwfhN00 je+oP6rpjLAtjF29rnuSQ+G+pQYvfYn1ABsFIHeNY7UR2eTnbkOZ5gCGf91S+tJ1JuT/ MQt+vtjoohs1ASL1KHpRxfi16rvOGZjetYwRjhhKGnKiEKf4LPJMKwCAcfrGCV9mJqTZ Xr6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1717617572; x=1718222372; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=S2gqsJbD6zdaBl5d/igOar152J/6V3l2z5gTGxyKy4E=; b=Ih701R9HUNPvqVQSig6dXoyDTRxy2Qthr6xn6lktizNg6YCjgLUuONtuUcipjt+bzm OF5MQ7pCsQ00sUOaJ92w6idCVvqmnz6iUYX0MvDFTIDSO9kQpLMhJacEXODzSa1yWxRL uhhsgNOyIr3MBxaXopl8G6yAftqEoTXwAl5qYHF5aKBBEF/2a4ELUJOQaA2KppCdtvih 3YZXn2K62HWQzkWZMuH8G7FjR/Juc3tQFo7S/z13yjRhBnvdy2NQIl66voob+0Lua449 F7lnDF2/ULJ8mnqT1/fot2C/NVwibgwsmo86t+AHH3BSJcbKZDn4SFCI7a459WjV2G5A qu/Q== X-Gm-Message-State: AOJu0YyjcLj92i2j+sNsZ1lyNjonVW4VTW9SOdaSDpBj9tasduZNWsnD LOklxRwBXvBmUqTL2OE00GpHXHME4sNMWsB/SbWdYGofUuFFGrvu9D+ahzeBRLMK22hh2SY79UU / X-Received: by 2002:a05:600c:4fd6:b0:420:29dd:84d0 with SMTP id 5b1f17b1804b1-42156351b60mr28888125e9.29.1717617571925; Wed, 05 Jun 2024 12:59:31 -0700 (PDT) Received: from localhost.localdomain (cpc92302-cmbg19-2-0-cust1183.5-4.cable.virginm.net. [82.1.212.160]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42158110dd7sm33675725e9.17.2024.06.05.12.59.31 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Jun 2024 12:59:31 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Wed, 5 Jun 2024 20:59:44 +0100 Message-ID: <20240605195950.2297433-3-sw@jkqxz.net> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240605195950.2297433-1-sw@jkqxz.net> References: <20240605195950.2297433-1-sw@jkqxz.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 3/3] lavc/vaapi_hevc: Don't require exact profiles 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: NS0J7EMSRoVO Rather than turning the constraint flags into a single profile and then searching for that profile (and failing if it doesn't match any profile exactly), instead search all supported profiles and use the first one which supports the given set of constraint flags. --- libavcodec/vaapi_decode.c | 45 +++++++++++------- libavcodec/vaapi_hevc.c | 99 ++++++++++++++++++++++----------------- libavcodec/vaapi_hevc.h | 4 +- 3 files changed, 87 insertions(+), 61 deletions(-) diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c index 7c91d50f7b..c9d8add69f 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -393,7 +393,9 @@ static const struct { enum AVCodecID codec_id; int codec_profile; VAProfile va_profile; - VAProfile (*profile_parser)(AVCodecContext *avctx); + VAProfile (*match_profile)(AVCodecContext *avctx, + const VAProfile *profile_list, + int profile_count); } vaapi_profile_map[] = { #define MAP(c, p, v, ...) { AV_CODEC_ID_ ## c, AV_PROFILE_ ## p, VAProfile ## v, __VA_ARGS__ } MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple ), @@ -420,9 +422,9 @@ static const struct { #endif #if VA_CHECK_VERSION(1, 2, 0) && CONFIG_HEVC_VAAPI_HWACCEL MAP(HEVC, HEVC_REXT, None, - ff_vaapi_parse_hevc_rext_scc_profile ), + ff_vaapi_hevc_match_rext_scc_profile ), MAP(HEVC, HEVC_SCC, None, - ff_vaapi_parse_hevc_rext_scc_profile ), + ff_vaapi_hevc_match_rext_scc_profile ), #endif MAP(MJPEG, MJPEG_HUFFMAN_BASELINE_DCT, JPEGBaseline), @@ -505,22 +507,33 @@ static int vaapi_decode_make_config(AVCodecContext *avctx, vaapi_profile_map[i].codec_profile == AV_PROFILE_UNKNOWN) profile_match = 1; - va_profile = vaapi_profile_map[i].profile_parser ? - vaapi_profile_map[i].profile_parser(avctx) : - vaapi_profile_map[i].va_profile; codec_profile = vaapi_profile_map[i].codec_profile; - - for (j = 0; j < profile_count; j++) { - if (va_profile == profile_list[j]) { - exact_match = profile_match; + if (vaapi_profile_map[i].match_profile) { + va_profile = + vaapi_profile_map[i].match_profile(avctx, profile_list, + profile_count); + if (va_profile != VAProfileNone) { + matched_va_profile = va_profile; + matched_ff_profile = codec_profile; + exact_match = 1; break; } - } - if (j < profile_count) { - matched_va_profile = va_profile; - matched_ff_profile = codec_profile; - if (exact_match) - break; + } else { + va_profile = vaapi_profile_map[i].va_profile; + + for (j = 0; j < profile_count; j++) { + if (va_profile == profile_list[j]) { + exact_match = profile_match; + break; + } + } + + if (j < profile_count) { + matched_va_profile = va_profile; + matched_ff_profile = codec_profile; + if (exact_match) + break; + } } } av_freep(&profile_list); diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c index 6164a1d223..716a4a4b43 100644 --- a/libavcodec/vaapi_hevc.c +++ b/libavcodec/vaapi_hevc.c @@ -589,63 +589,74 @@ static int ptl_convert(const PTLCommon *general_ptl, H265RawProfileTierLevel *h2 } /* - * Find exact va_profile for HEVC Range Extension and Screen Content Coding Extension + * Find compatible va_profile for HEVC Range Extension and Screen + * Content Coding Extension profiles. */ -VAProfile ff_vaapi_parse_hevc_rext_scc_profile(AVCodecContext *avctx) +VAProfile ff_vaapi_hevc_match_rext_scc_profile(AVCodecContext *avctx, + const VAProfile *profile_list, + int profile_count) { const HEVCContext *h = avctx->priv_data; const HEVCSPS *sps = h->ps.sps; const PTL *ptl = &sps->ptl; const PTLCommon *general_ptl = &ptl->general_ptl; - const H265ProfileDescriptor *profile; H265RawProfileTierLevel h265_raw_ptl = {0}; + static const struct { + enum H265Profile profile; + VAProfile va_profile; + } map[] = { +#if VA_CHECK_VERSION(1, 2, 0) + { H265_PROFILE_MAIN_12, + VAProfileHEVCMain12 }, + { H265_PROFILE_MAIN_422_10, + VAProfileHEVCMain422_10 }, + { H265_PROFILE_MAIN_422_12, + VAProfileHEVCMain422_12 }, + { H265_PROFILE_MAIN_444, + VAProfileHEVCMain444 }, + { H265_PROFILE_MAIN_444_10, + VAProfileHEVCMain444_10 }, + { H265_PROFILE_MAIN_444_12, + VAProfileHEVCMain444_12 }, + { H265_PROFILE_SCREEN_EXTENDED_MAIN, + VAProfileHEVCSccMain }, + { H265_PROFILE_SCREEN_EXTENDED_MAIN_10, + VAProfileHEVCSccMain10 }, + { H265_PROFILE_SCREEN_EXTENDED_MAIN_444, + VAProfileHEVCSccMain444 }, +#endif +#if VA_CHECK_VERSION(1, 8, 0) + { H265_PROFILE_SCREEN_EXTENDED_MAIN_444_10, + VAProfileHEVCSccMain444_10 }, +#endif + }; + /* convert PTLCommon to H265RawProfileTierLevel */ ptl_convert(general_ptl, &h265_raw_ptl); - profile = ff_h265_find_profile(&h265_raw_ptl); - if (!profile) { - av_log(avctx, AV_LOG_WARNING, "HEVC profile is not found.\n"); - goto end; - } else { - av_log(avctx, AV_LOG_VERBOSE, "HEVC profile %s is found.\n", profile->name); + for (int i = 0; i < FF_ARRAY_ELEMS(map); i++) { + int available = 0; + for (int j = 0; j < profile_count; j++) { + if (profile_list[j] == map[i].va_profile) { + available = 1; + break; + } + } + if (!available) + continue; + + if (ff_h265_profile_compatible(&h265_raw_ptl, + map[i].profile)) { + const H265ProfileDescriptor *profile_desc = + ff_h265_get_profile(map[i].profile); + av_log(avctx, AV_LOG_VERBOSE, + "Decoding with HEVC profile %s.\n", + profile_desc->name); + return map[i].va_profile; + } } -#if VA_CHECK_VERSION(1, 2, 0) - if (!strcmp(profile->name, "Main 12") || - !strcmp(profile->name, "Main 12 Intra")) - return VAProfileHEVCMain12; - else if (!strcmp(profile->name, "Main 4:2:2 10") || - !strcmp(profile->name, "Main 4:2:2 10 Intra")) - return VAProfileHEVCMain422_10; - else if (!strcmp(profile->name, "Main 4:2:2 12") || - !strcmp(profile->name, "Main 4:2:2 12 Intra")) - return VAProfileHEVCMain422_12; - else if (!strcmp(profile->name, "Main 4:4:4") || - !strcmp(profile->name, "Main 4:4:4 Intra")) - return VAProfileHEVCMain444; - else if (!strcmp(profile->name, "Main 4:4:4 10") || - !strcmp(profile->name, "Main 4:4:4 10 Intra")) - return VAProfileHEVCMain444_10; - else if (!strcmp(profile->name, "Main 4:4:4 12") || - !strcmp(profile->name, "Main 4:4:4 12 Intra")) - return VAProfileHEVCMain444_12; - else if (!strcmp(profile->name, "Screen-Extended Main")) - return VAProfileHEVCSccMain; - else if (!strcmp(profile->name, "Screen-Extended Main 10")) - return VAProfileHEVCSccMain10; - else if (!strcmp(profile->name, "Screen-Extended Main 4:4:4")) - return VAProfileHEVCSccMain444; -#if VA_CHECK_VERSION(1, 8, 0) - else if (!strcmp(profile->name, "Screen-Extended Main 4:4:4 10")) - return VAProfileHEVCSccMain444_10; -#endif -#else - av_log(avctx, AV_LOG_WARNING, "HEVC profile %s is " - "not supported with this VA version.\n", profile->name); -#endif - -end: if (avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) { // Default to selecting Main profile if profile mismatch is allowed return VAProfileHEVCMain; diff --git a/libavcodec/vaapi_hevc.h b/libavcodec/vaapi_hevc.h index 449635d0d7..455c68e6ba 100644 --- a/libavcodec/vaapi_hevc.h +++ b/libavcodec/vaapi_hevc.h @@ -22,6 +22,8 @@ #include #include "avcodec.h" -VAProfile ff_vaapi_parse_hevc_rext_scc_profile(AVCodecContext *avctx); +VAProfile ff_vaapi_hevc_match_rext_scc_profile(AVCodecContext *avctx, + const VAProfile *profile_list, + int profile_count); #endif /* AVCODEC_VAAPI_HEVC_H */