From patchwork Fri Sep 9 03:46:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip Langdale X-Patchwork-Id: 37777 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:139a:b0:8f:1db5:eae2 with SMTP id w26csp679779pzh; Thu, 8 Sep 2022 20:46:32 -0700 (PDT) X-Google-Smtp-Source: AA6agR67qjkztrmJ6VftMX+xr8IzuZBJXMYhJjTIWKogBs0LitDr+48Nxh9xQwRAoYGJaP1OCFK9 X-Received: by 2002:a17:907:760d:b0:741:975e:6827 with SMTP id jx13-20020a170907760d00b00741975e6827mr7987313ejc.137.1662695192178; Thu, 08 Sep 2022 20:46:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1662695192; cv=none; d=google.com; s=arc-20160816; b=XMj6zMpdNILY/t2yFelXJG2cT3kAo4W8HXWQ3fWkb32Hw/X1u8dlMCLRzLQyt9vUu2 jYy2sNAwTRBeMtwcGDXN5YkawI9KBaxsR/SilFh0gn6p3V5RoNyHsjoTse+busUK5Nga GZBPWVy3KU5WfiLTQ91OwIPU+jAZr8ev3RKvqeWO/1q+acHo3V1G/1S7BrNoGdF3SKOC L9c0p5lneaoCUoYIB43YpGX0PI8eb7IukkEYjfRCkhP5RoMnxTis2TvhfNXYTw3tJwWM 5czzwC1ZiBVjvbhIA/TyleAgRqm/5LfOYF9AlCzpHsm8CywdbGktMUBhdWY1L5dByJ29 MNEQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc: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=AzsP81NgG7M44yLCs+bkTOJBeQpvLqEChZBGrJXCrik=; b=gep+lggUrrk02ZyZtUnF9yhmjNZwP/WFiINvq9B7GXPx4KWw+OBKbZDtTPfNwHUImh xzg/YqcCKTJoMWr/ToO841ozj5M3958DtXZhqpgwtGt3L4TAKPbIhYwfWW3WweFpB/RG KMX/sueezm4m6Lf3KsIaVqNjwl9F52zV/NiWX4PAKXnwqRDJXjuSr00HCm1uHs8VD8ix u1CpmhDSj4sVPufowXbfZEfe46RjYskCtNnnAmhjf7m/zofoEy4K6TRtCXCHWZ0exWD1 n2qJn+iK1e/J2MQYuw/SVpgERo29A6VlrjcD4W84v4eTO1TQBUkkCQtdHj5pS6iGzCSO 7ynQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@overt.org header.s=mail header.b=Vy1P9jsg; 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; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=overt.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id dn7-20020a17090794c700b007313312730esi827565ejc.85.2022.09.08.20.46.31; Thu, 08 Sep 2022 20:46:32 -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=@overt.org header.s=mail header.b=Vy1P9jsg; 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; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=overt.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 219AF68BA8B; Fri, 9 Sep 2022 06:46:28 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail.overt.org (mail.overt.org [157.230.92.47]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A8E3868BA8B for ; Fri, 9 Sep 2022 06:46:21 +0300 (EEST) Received: from authenticated-user (mail.overt.org [157.230.92.47]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by mail.overt.org (Postfix) with ESMTPSA id B245A3F73F; Thu, 8 Sep 2022 22:46:19 -0500 (CDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=overt.org; s=mail; t=1662695180; bh=59IokLiniXf0CPWfpestiQPlcSUa8zwoHEvlRnt/u+0=; h=From:To:Cc:Subject:Date:From; b=Vy1P9jsgKo8tpv8cFXT3SFwaRkq/QFwA251Ex8z2TUMAvQWlrwjq15Ui6iUpunqp8 qLWQTFV1aGahUQfkj1G/MnpF2+q78JfBH0F50ka4uUv4nUzTVs4KUWmOOwjB1mQMB/ SX8/f5NQL4/pAb1PLRct7p9GFb/TFHfRiqpT+KSS3w2H/147ePujXeTV37M+PUoXSs nbUw8ow+Jhtbo+5tWdgQVobIHXlk3f8k6HqN+9D/So6Muj16lO37PeFuWLfI2dzXYN FEIsvyczFCQU2ysH9pOqqMx6PFcI25Jbif9buCwAoHtYgl1L5PwSth7tAiPQpuU4kK LNdfLFcttM1gw== From: Philip Langdale To: ffmpeg-devel@ffmpeg.org Date: Thu, 8 Sep 2022 20:46:11 -0700 Message-Id: <20220909034611.390710-1-philipl@overt.org> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] lavu/pixdesc: favour formats where bit depth exactly matches 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 Cc: Philip Langdale Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: xpp4eyhAxC4M Since introducing the various packed formats used by VAAPI (and p012), we've noticed that there's actually a gap in how av_find_best_pix_fmt_of_2 works. It doesn't actually assign any value to having the same bit depth as the source format, when comparing against formats with a higher bit depth. This usually doesn't matter, because av_get_padded_bits_per_pixel() will account for it. However, as many of these formats use padding internally, we find that av_get_padded_bits_per_pixel() actually returns the same value for the 10 bit, 12, bit, 16 bit flavours, etc. In these tied situations, we end up just picking the first of the two provided formats, even if the second one should be preferred because it matches the actual bit depth. This bug already existed if you tried to compare yuv420p10 against p016 and p010, for example, but it simply hadn't come up before so we never noticed. But now, we actually got a situation in the VAAPI VP9 decoder where it offers both p010 and p012 because Profile 3 could be either depth and ends up picking p012 for 10 bit content due to the ordering of the testing. In addition, in the process of testing the fix, I realised we have the same gap when it comes to chroma subsampling - we do not favour a format that has exactly the same subsampling vs one with less subsampling when all else is equal. To fix this, I'm introducing a small score penalty if the bit depth or subsampling doesn't exactly match the source format. This will break the tie in favour of the format with the exact match, but not offset any of the other scoring penalties we already have. I have added a set of tests around these formats which will fail without this fix. Signed-off-by: Philip Langdale --- libavutil/pixdesc.c | 16 +++++- libavutil/tests/pixfmt_best.c | 93 ++++++++++++++++++++++++++++------- tests/ref/fate/pixfmt_best | 2 +- 3 files changed, 89 insertions(+), 22 deletions(-) diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c index d7c6ebfdc4..412e257a30 100644 --- a/libavutil/pixdesc.c +++ b/libavutil/pixdesc.c @@ -3004,6 +3004,11 @@ static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt, if ((ret = get_pix_fmt_depth(&dst_min_depth, &dst_max_depth, dst_pix_fmt)) < 0) return -3; + // Favour formats where bit depth exactly matches. If all other scoring is + // equal, we'd rather use a lower bit depth that matches the source. + if (src_min_depth != dst_min_depth || src_max_depth != dst_max_depth) + score -= 64; + src_color = get_color_type(src_desc); dst_color = get_color_type(dst_desc); if (dst_pix_fmt == AV_PIX_FMT_PAL8) @@ -3020,14 +3025,21 @@ static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt, } if (consider & FF_LOSS_RESOLUTION) { + // Apply a large penalty if there's a loss of resolution, but also apply + // a small penalty of the dst resolution is higher so that we favour + // exactly matching formats. if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w) { loss |= FF_LOSS_RESOLUTION; score -= 256 << dst_desc->log2_chroma_w; - } + } else if (dst_desc->log2_chroma_w < src_desc->log2_chroma_w) + score -= 32; + if (dst_desc->log2_chroma_h > src_desc->log2_chroma_h) { loss |= FF_LOSS_RESOLUTION; score -= 256 << dst_desc->log2_chroma_h; - } + } else if (dst_desc->log2_chroma_h < src_desc->log2_chroma_h) + score -= 32; + // don't favor 422 over 420 if downsampling is needed, because 420 has much better support on the decoder side if (dst_desc->log2_chroma_w == 1 && src_desc->log2_chroma_w == 0 && dst_desc->log2_chroma_h == 1 && src_desc->log2_chroma_h == 0 ) { diff --git a/libavutil/tests/pixfmt_best.c b/libavutil/tests/pixfmt_best.c index 0542af494f..b5d4d04976 100644 --- a/libavutil/tests/pixfmt_best.c +++ b/libavutil/tests/pixfmt_best.c @@ -39,32 +39,59 @@ static const enum AVPixelFormat pixfmt_list[] = { AV_PIX_FMT_VAAPI, }; -static enum AVPixelFormat find_best(enum AVPixelFormat pixfmt) +static const enum AVPixelFormat semiplanar_list[] = { + AV_PIX_FMT_P016, + AV_PIX_FMT_P012, + AV_PIX_FMT_P010, + AV_PIX_FMT_NV12, +}; + +static const enum AVPixelFormat packed_list[] = { + AV_PIX_FMT_XV36, + AV_PIX_FMT_XV30, + AV_PIX_FMT_VUYX, + AV_PIX_FMT_Y212, + AV_PIX_FMT_Y210, + AV_PIX_FMT_YUYV422, +}; + +typedef enum AVPixelFormat (*find_best_t)(enum AVPixelFormat pixfmt); + +#define find_best_wrapper(name, list) \ +static enum AVPixelFormat find_best_ ## name (enum AVPixelFormat pixfmt) \ +{ \ + enum AVPixelFormat best = AV_PIX_FMT_NONE; \ + int i; \ + for (i = 0; i < FF_ARRAY_ELEMS(list); i++) \ + best = av_find_best_pix_fmt_of_2(best, list[i], \ + pixfmt, 0, NULL); \ + return best; \ +} + +find_best_wrapper(base, pixfmt_list) +find_best_wrapper(seminplanar, semiplanar_list) +find_best_wrapper(packed, packed_list) + +static void test(enum AVPixelFormat input, enum AVPixelFormat expected, + int *pass, int *fail, find_best_t find_best_fn) { - enum AVPixelFormat best = AV_PIX_FMT_NONE; - int i; - for (i = 0; i < FF_ARRAY_ELEMS(pixfmt_list); i++) - best = av_find_best_pix_fmt_of_2(best, pixfmt_list[i], - pixfmt, 0, NULL); - return best; + enum AVPixelFormat output = find_best_fn(input); + if (output != expected) { + printf("Matching %s: got %s, expected %s\n", + av_get_pix_fmt_name(input), + av_get_pix_fmt_name(output), + av_get_pix_fmt_name(expected)); + ++(*fail); + } else + ++(*pass); } int main(void) { - enum AVPixelFormat output; int i, pass = 0, fail = 0; -#define TEST(input, expected) do { \ - output = find_best(input); \ - if (output != expected) { \ - printf("Matching %s: got %s, expected %s\n", \ - av_get_pix_fmt_name(input), \ - av_get_pix_fmt_name(output), \ - av_get_pix_fmt_name(expected)); \ - ++fail; \ - } else \ - ++pass; \ - } while (0) +#define TEST(input, expected) \ + test(input, expected, &pass, &fail, find_best_base); // Same formats. for (i = 0; i < FF_ARRAY_ELEMS(pixfmt_list); i++) @@ -137,6 +164,34 @@ int main(void) // Opaque formats are least unlike each other. TEST(AV_PIX_FMT_DXVA2_VLD, AV_PIX_FMT_VDPAU); +#define TEST_SEMIPLANAR(input, expected) \ + test(input, expected, &pass, &fail, find_best_seminplanar); + + // Same formats. + for (i = 0; i < FF_ARRAY_ELEMS(semiplanar_list); i++) + TEST_SEMIPLANAR(semiplanar_list[i], semiplanar_list[i]); + + // Formats containing the same data in different layouts. + TEST_SEMIPLANAR(AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12); + TEST_SEMIPLANAR(AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010); + TEST_SEMIPLANAR(AV_PIX_FMT_YUV420P12, AV_PIX_FMT_P012); + TEST_SEMIPLANAR(AV_PIX_FMT_YUV420P16, AV_PIX_FMT_P016); + +#define TEST_PACKED(input, expected) \ + test(input, expected, &pass, &fail, find_best_packed); + + // Same formats. + for (i = 0; i < FF_ARRAY_ELEMS(packed_list); i++) + TEST_PACKED(packed_list[i], packed_list[i]); + + // Formats containing the same data in different layouts. + TEST_PACKED(AV_PIX_FMT_YUV444P, AV_PIX_FMT_VUYX); + TEST_PACKED(AV_PIX_FMT_YUV444P10, AV_PIX_FMT_XV30); + TEST_PACKED(AV_PIX_FMT_YUV444P12, AV_PIX_FMT_XV36); + TEST_PACKED(AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUYV422); + TEST_PACKED(AV_PIX_FMT_YUV422P10, AV_PIX_FMT_Y210); + TEST_PACKED(AV_PIX_FMT_YUV422P12, AV_PIX_FMT_Y212); + printf("%d tests passed, %d tests failed.\n", pass, fail); return !!fail; } diff --git a/tests/ref/fate/pixfmt_best b/tests/ref/fate/pixfmt_best index 783c5fe640..63911e7198 100644 --- a/tests/ref/fate/pixfmt_best +++ b/tests/ref/fate/pixfmt_best @@ -1 +1 @@ -75 tests passed, 0 tests failed. +95 tests passed, 0 tests failed.