The branch, master has been updated via 9b8b78a8153f9ca94b7eb9cba87442954787912a (commit) via ae3c5ac2c1c8f073bcb32980983ddb17098ded91 (commit) via c96ccd78fcc9fdfe7efe340879576eaf50881375 (commit) via 2968f30a15e0b8dcd3872436bcff51bddbd9a933 (commit) via 34ad857d2b1021a3ca2bd33860a72cdcf63affa3 (commit) from 11a89bfe7bedc88980a178c565cc4d237e1ba0d8 (commit)
- Log ----------------------------------------------------------------- commit 9b8b78a8153f9ca94b7eb9cba87442954787912a Author: Niklas Haas <g...@haasn.dev> AuthorDate: Sat Aug 16 18:18:53 2025 +0200 Commit: Niklas Haas <ffm...@haasn.dev> CommitDate: Mon Aug 18 18:50:00 2025 +0000 avfilter/vf_colordetect: detect fully opaque alpha planes It can be useful to know if the alpha plane consists of fully opaque pixels or not, in which case it can e.g. safely be stripped. This only requires a very minor modification to the AVX2 routines, adding an extra AND on the read alpha value with the reference alpha value, and a single extra cheap test per line. detect_alpha_8_full_c: 2849.1 ( 1.00x) detect_alpha_8_full_avx2: 260.3 (10.95x) detect_alpha_8_full_avx512icl: 130.2 (21.87x) detect_alpha_8_limited_c: 8349.2 ( 1.00x) detect_alpha_8_limited_avx2: 756.6 (11.04x) detect_alpha_8_limited_avx512icl: 364.2 (22.93x) detect_alpha_16_full_c: 1652.8 ( 1.00x) detect_alpha_16_full_avx2: 236.5 ( 6.99x) detect_alpha_16_full_avx512icl: 134.6 (12.28x) detect_alpha_16_limited_c: 5263.1 ( 1.00x) detect_alpha_16_limited_avx2: 797.4 ( 6.60x) detect_alpha_16_limited_avx512icl: 400.3 (13.15x) diff --git a/doc/filters.texi b/doc/filters.texi index 908c98a3cf..fbd1d1959b 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -9880,7 +9880,7 @@ which indicates that this is a full range YUV source. @item alpha_mode Detect if the source contains color values above the alpha channel, which indicates that the alpha channel is independent (straight), rather than -premultiplied. +premultiplied. Also detects if the alpha plane is fully opaque or not. @item all Enable detection of all of the above properties. This is the default. @end table diff --git a/libavfilter/vf_colordetect.c b/libavfilter/vf_colordetect.c index fadb5c38f8..a7fc98e2f1 100644 --- a/libavfilter/vf_colordetect.c +++ b/libavfilter/vf_colordetect.c @@ -180,10 +180,9 @@ static int detect_alpha(AVFilterContext *ctx, void *arg, ret = s->dsp.detect_alpha(in->data[i] + y_start * stride, stride, alpha, alpha_stride, w, h_slice, alpha_max, mpeg_range, offset); - if (ret) { - atomic_store(&s->detected_alpha, ret); + ret |= atomic_fetch_or_explicit(&s->detected_alpha, ret, memory_order_relaxed); + if (ret == FF_ALPHA_STRAIGHT) break; - } } return 0; @@ -197,7 +196,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (s->mode & COLOR_DETECT_COLOR_RANGE && s->detected_range == AVCOL_RANGE_UNSPECIFIED) ff_filter_execute(ctx, detect_range, in, NULL, nb_threads); - if (s->mode & COLOR_DETECT_ALPHA_MODE && s->detected_alpha == FF_ALPHA_UNDETERMINED) + + if (s->mode & COLOR_DETECT_ALPHA_MODE && s->detected_alpha != FF_ALPHA_NONE && + s->detected_alpha != FF_ALPHA_STRAIGHT) ff_filter_execute(ctx, detect_alpha, in, NULL, nb_threads); return ff_filter_frame(inlink->dst->outputs[0], in); @@ -218,9 +219,10 @@ static av_cold void uninit(AVFilterContext *ctx) if (s->mode & COLOR_DETECT_ALPHA_MODE) { av_log(ctx, AV_LOG_INFO, " Alpha mode: %s\n", - s->detected_alpha == FF_ALPHA_NONE ? "none" : - s->detected_alpha == FF_ALPHA_STRAIGHT ? "straight / independent" - : "undertermined"); + s->detected_alpha == FF_ALPHA_NONE ? "none" : + s->detected_alpha == FF_ALPHA_STRAIGHT ? "straight" : + s->detected_alpha == FF_ALPHA_TRANSPARENT ? "undetermined" + : "opaque"); } } diff --git a/libavfilter/vf_colordetect.h b/libavfilter/vf_colordetect.h index 22fdbf6189..0c0dc889dc 100644 --- a/libavfilter/vf_colordetect.h +++ b/libavfilter/vf_colordetect.h @@ -27,9 +27,10 @@ #include <libavutil/pixfmt.h> enum FFAlphaDetect { - FF_ALPHA_NONE = -1, + FF_ALPHA_NONE = -1, FF_ALPHA_UNDETERMINED = 0, - FF_ALPHA_STRAIGHT, + FF_ALPHA_TRANSPARENT = 1 << 0, ///< alpha < alpha_max + FF_ALPHA_STRAIGHT = (1 << 1) | FF_ALPHA_TRANSPARENT, ///< alpha < pixel /* No way to positively identify premultiplied alpha */ }; @@ -113,16 +114,19 @@ ff_detect_alpha_full_c(const uint8_t *color, ptrdiff_t color_stride, ptrdiff_t width, ptrdiff_t height, int alpha_max, int mpeg_range, int offset) { + uint8_t transparent = 0; while (height--) { - uint8_t cond = 0; - for (int x = 0; x < width; x++) - cond |= color[x] > alpha[x]; - if (cond) + uint8_t straight = 0; + for (int x = 0; x < width; x++) { + straight |= color[x] > alpha[x]; + transparent |= alpha[x] != alpha_max; + } + if (straight) return FF_ALPHA_STRAIGHT; color += color_stride; alpha += alpha_stride; } - return 0; + return transparent ? FF_ALPHA_TRANSPARENT : 0; } static inline int @@ -131,16 +135,19 @@ ff_detect_alpha_limited_c(const uint8_t *color, ptrdiff_t color_stride, ptrdiff_t width, ptrdiff_t height, int alpha_max, int mpeg_range, int offset) { + uint8_t transparent = 0; while (height--) { - uint8_t cond = 0; - for (int x = 0; x < width; x++) - cond |= alpha_max * color[x] - offset > mpeg_range * alpha[x]; - if (cond) + uint8_t straight = 0; + for (int x = 0; x < width; x++) { + straight |= alpha_max * color[x] - offset > mpeg_range * alpha[x]; + transparent |= alpha[x] != alpha_max; + } + if (straight) return FF_ALPHA_STRAIGHT; color += color_stride; alpha += alpha_stride; } - return 0; + return transparent ? FF_ALPHA_TRANSPARENT : 0; } static inline int @@ -149,18 +156,21 @@ ff_detect_alpha16_full_c(const uint8_t *color, ptrdiff_t color_stride, ptrdiff_t width, ptrdiff_t height, int alpha_max, int mpeg_range, int offset) { + uint8_t transparent = 0; while (height--) { const uint16_t *color16 = (const uint16_t *) color; const uint16_t *alpha16 = (const uint16_t *) alpha; - uint8_t cond = 0; - for (int x = 0; x < width; x++) - cond |= color16[x] > alpha16[x]; - if (cond) + uint8_t straight = 0; + for (int x = 0; x < width; x++) { + straight |= color16[x] > alpha16[x]; + transparent |= alpha16[x] != alpha_max; + } + if (straight) return FF_ALPHA_STRAIGHT; color += color_stride; alpha += alpha_stride; } - return 0; + return transparent ? FF_ALPHA_TRANSPARENT : 0; } static inline int @@ -169,17 +179,19 @@ ff_detect_alpha16_limited_c(const uint8_t *color, ptrdiff_t color_stride, ptrdiff_t width, ptrdiff_t height, int alpha_max, int mpeg_range, int offset) { + uint8_t transparent = 0; while (height--) { const uint16_t *color16 = (const uint16_t *) color; const uint16_t *alpha16 = (const uint16_t *) alpha; for (int x = 0; x < width; x++) { if ((int64_t) alpha_max * color16[x] - offset > (int64_t) mpeg_range * alpha16[x]) return FF_ALPHA_STRAIGHT; + transparent |= alpha16[x] != alpha_max; } color += color_stride; alpha += alpha_stride; } - return 0; + return transparent ? FF_ALPHA_TRANSPARENT : 0; } #endif /* AVFILTER_COLORDETECT_H */ diff --git a/libavfilter/x86/vf_colordetect.asm b/libavfilter/x86/vf_colordetect.asm index 53ff17cf5c..7a96b6933c 100644 --- a/libavfilter/x86/vf_colordetect.asm +++ b/libavfilter/x86/vf_colordetect.asm @@ -69,8 +69,19 @@ cglobal detect_range%1, 4, 7, 5, data, stride, width, height, mpeg_min, mpeg_max RET %endmacro +%define FF_ALPHA_STRAIGHT 0x3 + %macro detect_alpha_fn 3 ; suffix, hsuffix, range -cglobal detect_alpha%1_%3, 6, 7, 6, color, color_stride, alpha, alpha_stride, width, height, x +%if ARCH_X86_64 +cglobal detect_alpha%1_%3, 6, 8, 7, color, color_stride, alpha, alpha_stride, width, height, ret, x +%else +cglobal detect_alpha%1_%3, 1, 6, 7, color, ret, alpha, x, width, height +%define color_strideq r1m +%define alpha_strideq r3m + mov alphad, r2m + mov widthd, r4m + mov heightd, r5m +%endif pxor m0, m0 add colorq, widthq add alphaq, widthq @@ -79,17 +90,23 @@ cglobal detect_alpha%1_%3, 6, 7, 6, color, color_stride, alpha, alpha_stride, wi vpbroadcast%2 m3, r6m ; alpha_max vpbroadcast%2 m4, r7m ; mpeg_range vpbroadcast%2 m5, r8m ; offset +%else + vpbroadcast%1 m3, r6m ; alpha_max %endif + mova m6, m3 + xor retd, retd .lineloop: mov xq, widthq .loop: %ifidn %3, full movu m1, [colorq + xq] movu m2, [alphaq + xq] + pand m6, m2 pmaxu%1 m1, m2 %else pmovzx%1%2 m1, [colorq + xq] pmovzx%1%2 m2, [alphaq + xq] + pand m6, m2 pmull%2 m1, m3 pmull%2 m2, m4 %ifidn %1, b @@ -121,15 +138,28 @@ cglobal detect_alpha%1_%3, 6, 7, 6, color, color_stride, alpha, alpha_stride, wi %endif jnz .found +%if cpuflag(avx512) + vpandnq m1, m6, m3 ; m1 = ~m6 & m3 + vptestmq k1, m1, m1 + kortestb k1, k1 + setnz xb +%else + ptest m6, m3 + setnc xb ; CF = !(~m6 & m3) +%endif + or retb, xb + add colorq, color_strideq add alphaq, alpha_strideq dec heightq jg .lineloop - xor eax, eax +%ifnidn retd, eax + mov eax, retd +%endif RET .found: - mov eax, 1 + mov eax, FF_ALPHA_STRAIGHT RET %endmacro diff --git a/tests/checkasm/vf_colordetect.c b/tests/checkasm/vf_colordetect.c index 7498d6141a..9a16de7392 100644 --- a/tests/checkasm/vf_colordetect.c +++ b/tests/checkasm/vf_colordetect.c @@ -87,7 +87,7 @@ static void check_alpha_detect(int depth, enum AVColorRange range) LOCAL_ALIGNED_32(uint8_t, luma, [HEIGHT * STRIDE]); LOCAL_ALIGNED_32(uint8_t, alpha, [HEIGHT * STRIDE]); memset(luma, 0x80, HEIGHT * STRIDE); - memset(alpha, 0xFF, HEIGHT * STRIDE); + memset(alpha, 0xF0, HEIGHT * STRIDE); /* Try and force overflow */ if (depth > 8 && range == AVCOL_RANGE_MPEG) { commit ae3c5ac2c1c8f073bcb32980983ddb17098ded91 Author: Niklas Haas <g...@haasn.dev> AuthorDate: Fri Aug 15 23:15:06 2025 +0200 Commit: Niklas Haas <ffm...@haasn.dev> CommitDate: Mon Aug 18 18:50:00 2025 +0000 avfilter/vf_colordetect: remove extra safety margin on premul check This safety margin was motivated by the fact that vf_premultiply sometimes produces such illegally high values, but this has since been fixed by 603334a04362e7, so there's no more reason to have this safety margin, at least for our own code. (Of course, other sources may also produce such broken files, but we shouldn't work around that - garbage in, garbage out.) See-Also: 603334a04362e7a466cbdf9a25892ded167e3ce0 diff --git a/libavfilter/vf_colordetect.c b/libavfilter/vf_colordetect.c index 68b0e5b0fa..fadb5c38f8 100644 --- a/libavfilter/vf_colordetect.c +++ b/libavfilter/vf_colordetect.c @@ -168,12 +168,11 @@ static int detect_alpha(AVFilterContext *ctx, void *arg, * = alpha_max * x - offset > mpeg_range * a in the below formula. * * We subtract an additional offset of (1 << (depth - 1)) to account for - * rounding errors in the value of `x`, and an extra safety margin of - * mpeg_range because vf_premultiply.c et al. add an offset of (a >> 1) & 1. + * rounding errors in the value of `x`. */ const int alpha_max = (1 << s->depth) - 1; const int mpeg_range = s->mpeg_max - s->mpeg_min; - const int offset = alpha_max * s->mpeg_min + mpeg_range + (1 << (s->depth - 1)); + const int offset = alpha_max * s->mpeg_min + (1 << (s->depth - 1)); int ret = 0; for (int i = 0; i < nb_planes; i++) { diff --git a/tests/checkasm/vf_colordetect.c b/tests/checkasm/vf_colordetect.c index 9c5f68f855..7498d6141a 100644 --- a/tests/checkasm/vf_colordetect.c +++ b/tests/checkasm/vf_colordetect.c @@ -75,7 +75,7 @@ static void check_alpha_detect(int depth, enum AVColorRange range) const int mpeg_max = 235 << (depth - 8); const int alpha_max = (1 << depth) - 1; const int mpeg_range = mpeg_max - mpeg_min; - const int offset = alpha_max * mpeg_min + mpeg_range + (1 << (depth - 1)); + const int offset = alpha_max * mpeg_min + (1 << (depth - 1)); int res_ref, res_new; FFColorDetectDSPContext dsp = {0}; commit c96ccd78fcc9fdfe7efe340879576eaf50881375 Author: Niklas Haas <g...@haasn.dev> AuthorDate: Fri Aug 15 23:13:16 2025 +0200 Commit: Niklas Haas <ffm...@haasn.dev> CommitDate: Mon Aug 18 18:50:00 2025 +0000 avfilter/vf_colordetect: rename p, q, k variables for clarity Purely cosmetic. Motivated in part because I want to depend on the assumption that P represents the maximum alpha channel value. diff --git a/libavfilter/vf_colordetect.c b/libavfilter/vf_colordetect.c index bc29cfb1b0..68b0e5b0fa 100644 --- a/libavfilter/vf_colordetect.c +++ b/libavfilter/vf_colordetect.c @@ -165,21 +165,22 @@ static int detect_alpha(AVFilterContext *ctx, void *arg, * * This simplifies to: * (x - mpeg_min) * pixel_max > (mpeg_max - mpeg_min) * a - * = P * x - K > Q * a in the below formula. + * = alpha_max * x - offset > mpeg_range * a in the below formula. * * We subtract an additional offset of (1 << (depth - 1)) to account for * rounding errors in the value of `x`, and an extra safety margin of - * Q because vf_premultiply.c et al. add an offset of (a >> 1) & 1. + * mpeg_range because vf_premultiply.c et al. add an offset of (a >> 1) & 1. */ - const int p = (1 << s->depth) - 1; - const int q = s->mpeg_max - s->mpeg_min; - const int k = p * s->mpeg_min + q + (1 << (s->depth - 1)); + const int alpha_max = (1 << s->depth) - 1; + const int mpeg_range = s->mpeg_max - s->mpeg_min; + const int offset = alpha_max * s->mpeg_min + mpeg_range + (1 << (s->depth - 1)); int ret = 0; for (int i = 0; i < nb_planes; i++) { const ptrdiff_t stride = in->linesize[i]; ret = s->dsp.detect_alpha(in->data[i] + y_start * stride, stride, - alpha, alpha_stride, w, h_slice, p, q, k); + alpha, alpha_stride, w, h_slice, alpha_max, + mpeg_range, offset); if (ret) { atomic_store(&s->detected_alpha, ret); break; diff --git a/libavfilter/vf_colordetect.h b/libavfilter/vf_colordetect.h index 6626f88d26..22fdbf6189 100644 --- a/libavfilter/vf_colordetect.h +++ b/libavfilter/vf_colordetect.h @@ -43,7 +43,7 @@ typedef struct FFColorDetectDSPContext { int (*detect_alpha)(const uint8_t *color, ptrdiff_t color_stride, const uint8_t *alpha, ptrdiff_t alpha_stride, ptrdiff_t width, ptrdiff_t height, - int p, int q, int k); + int alpha_max, int mpeg_range, int offset); } FFColorDetectDSPContext; void ff_color_detect_dsp_init(FFColorDetectDSPContext *dsp, int depth, @@ -111,7 +111,7 @@ static inline int ff_detect_alpha_full_c(const uint8_t *color, ptrdiff_t color_stride, const uint8_t *alpha, ptrdiff_t alpha_stride, ptrdiff_t width, ptrdiff_t height, - int p, int q, int k) + int alpha_max, int mpeg_range, int offset) { while (height--) { uint8_t cond = 0; @@ -129,12 +129,12 @@ static inline int ff_detect_alpha_limited_c(const uint8_t *color, ptrdiff_t color_stride, const uint8_t *alpha, ptrdiff_t alpha_stride, ptrdiff_t width, ptrdiff_t height, - int p, int q, int k) + int alpha_max, int mpeg_range, int offset) { while (height--) { uint8_t cond = 0; for (int x = 0; x < width; x++) - cond |= p * color[x] - k > q * alpha[x]; + cond |= alpha_max * color[x] - offset > mpeg_range * alpha[x]; if (cond) return FF_ALPHA_STRAIGHT; color += color_stride; @@ -147,7 +147,7 @@ static inline int ff_detect_alpha16_full_c(const uint8_t *color, ptrdiff_t color_stride, const uint8_t *alpha, ptrdiff_t alpha_stride, ptrdiff_t width, ptrdiff_t height, - int p, int q, int k) + int alpha_max, int mpeg_range, int offset) { while (height--) { const uint16_t *color16 = (const uint16_t *) color; @@ -167,13 +167,13 @@ static inline int ff_detect_alpha16_limited_c(const uint8_t *color, ptrdiff_t color_stride, const uint8_t *alpha, ptrdiff_t alpha_stride, ptrdiff_t width, ptrdiff_t height, - int p, int q, int k) + int alpha_max, int mpeg_range, int offset) { while (height--) { const uint16_t *color16 = (const uint16_t *) color; const uint16_t *alpha16 = (const uint16_t *) alpha; for (int x = 0; x < width; x++) { - if ((int64_t) p * color16[x] - k > (int64_t) q * alpha16[x]) + if ((int64_t) alpha_max * color16[x] - offset > (int64_t) mpeg_range * alpha16[x]) return FF_ALPHA_STRAIGHT; } color += color_stride; diff --git a/libavfilter/x86/vf_colordetect.asm b/libavfilter/x86/vf_colordetect.asm index 44562bc57a..53ff17cf5c 100644 --- a/libavfilter/x86/vf_colordetect.asm +++ b/libavfilter/x86/vf_colordetect.asm @@ -76,9 +76,9 @@ cglobal detect_alpha%1_%3, 6, 7, 6, color, color_stride, alpha, alpha_stride, wi add alphaq, widthq neg widthq %ifidn %3, limited - vpbroadcast%2 m3, r6m ; p - vpbroadcast%2 m4, r7m ; q - vpbroadcast%2 m5, r8m ; k + vpbroadcast%2 m3, r6m ; alpha_max + vpbroadcast%2 m4, r7m ; mpeg_range + vpbroadcast%2 m5, r8m ; offset %endif .lineloop: mov xq, widthq diff --git a/tests/checkasm/vf_colordetect.c b/tests/checkasm/vf_colordetect.c index 785fc08892..9c5f68f855 100644 --- a/tests/checkasm/vf_colordetect.c +++ b/tests/checkasm/vf_colordetect.c @@ -73,9 +73,9 @@ static void check_alpha_detect(int depth, enum AVColorRange range) { const int mpeg_min = 16 << (depth - 8); const int mpeg_max = 235 << (depth - 8); - const int p = (1 << depth) - 1; - const int q = mpeg_max - mpeg_min; - const int k = p * mpeg_min + q + (1 << (depth - 1)); + const int alpha_max = (1 << depth) - 1; + const int mpeg_range = mpeg_max - mpeg_min; + const int offset = alpha_max * mpeg_min + mpeg_range + (1 << (depth - 1)); int res_ref, res_new; FFColorDetectDSPContext dsp = {0}; @@ -115,20 +115,20 @@ static void check_alpha_detect(int depth, enum AVColorRange range) if (check_func(dsp.detect_alpha, "detect_alpha_%d_%s", depth, range == AVCOL_RANGE_JPEG ? "full" : "limited")) { /* Test increasing height, to ensure we hit the placed 0 eventually */ for (int h = 1; h <= HEIGHT; h++) { - res_ref = call_ref(luma, STRIDE, alpha, STRIDE, w, h, p, q, k); - res_new = call_new(luma, STRIDE, alpha, STRIDE, w, h, p, q, k); + res_ref = call_ref(luma, STRIDE, alpha, STRIDE, w, h, alpha_max, mpeg_range, offset); + res_new = call_new(luma, STRIDE, alpha, STRIDE, w, h, alpha_max, mpeg_range, offset); if (res_ref != res_new) fail(); } /* Test base case without any out-of-range values */ memset(alpha, 0xFF, HEIGHT * STRIDE); - res_ref = call_ref(luma, STRIDE, alpha, STRIDE, w, HEIGHT, p, q, k); - res_new = call_new(luma, STRIDE, alpha, STRIDE, w, HEIGHT, p, q, k); + res_ref = call_ref(luma, STRIDE, alpha, STRIDE, w, HEIGHT, alpha_max, mpeg_range, offset); + res_new = call_new(luma, STRIDE, alpha, STRIDE, w, HEIGHT, alpha_max, mpeg_range, offset); if (res_ref != res_new) fail(); - bench_new(luma, STRIDE, alpha, STRIDE, w, HEIGHT, p, q, k); + bench_new(luma, STRIDE, alpha, STRIDE, w, HEIGHT, alpha_max, mpeg_range, offset); } } commit 2968f30a15e0b8dcd3872436bcff51bddbd9a933 Author: Niklas Haas <g...@haasn.dev> AuthorDate: Fri Aug 15 23:07:28 2025 +0200 Commit: Niklas Haas <ffm...@haasn.dev> CommitDate: Mon Aug 18 18:50:00 2025 +0000 tests/checkasm/vf_colordetect: also test opaque alpha base case Preemptively adding a check for a following commit. diff --git a/tests/checkasm/vf_colordetect.c b/tests/checkasm/vf_colordetect.c index 4979931cd3..785fc08892 100644 --- a/tests/checkasm/vf_colordetect.c +++ b/tests/checkasm/vf_colordetect.c @@ -76,6 +76,7 @@ static void check_alpha_detect(int depth, enum AVColorRange range) const int p = (1 << depth) - 1; const int q = mpeg_max - mpeg_min; const int k = p * mpeg_min + q + (1 << (depth - 1)); + int res_ref, res_new; FFColorDetectDSPContext dsp = {0}; ff_color_detect_dsp_init(&dsp, depth, range); @@ -114,14 +115,19 @@ static void check_alpha_detect(int depth, enum AVColorRange range) if (check_func(dsp.detect_alpha, "detect_alpha_%d_%s", depth, range == AVCOL_RANGE_JPEG ? "full" : "limited")) { /* Test increasing height, to ensure we hit the placed 0 eventually */ for (int h = 1; h <= HEIGHT; h++) { - int res_ref = call_ref(luma, STRIDE, alpha, STRIDE, w, h, p, q, k); - int res_new = call_new(luma, STRIDE, alpha, STRIDE, w, h, p, q, k); + res_ref = call_ref(luma, STRIDE, alpha, STRIDE, w, h, p, q, k); + res_new = call_new(luma, STRIDE, alpha, STRIDE, w, h, p, q, k); if (res_ref != res_new) fail(); } - /* Test performance of base case without any out-of-range values */ + /* Test base case without any out-of-range values */ memset(alpha, 0xFF, HEIGHT * STRIDE); + res_ref = call_ref(luma, STRIDE, alpha, STRIDE, w, HEIGHT, p, q, k); + res_new = call_new(luma, STRIDE, alpha, STRIDE, w, HEIGHT, p, q, k); + if (res_ref != res_new) + fail(); + bench_new(luma, STRIDE, alpha, STRIDE, w, HEIGHT, p, q, k); } } commit 34ad857d2b1021a3ca2bd33860a72cdcf63affa3 Author: Niklas Haas <g...@haasn.dev> AuthorDate: Fri Aug 15 22:55:30 2025 +0200 Commit: Niklas Haas <ffm...@haasn.dev> CommitDate: Mon Aug 18 18:50:00 2025 +0000 avfilter/vf_colordetect: slightly change detect_alpha() signature Basically cosmetic. I want to expand this to detect more than a single property about the alpha channel at the same time; so we first need a way for this function to return a more complex result. Move the enum AlphaMode to the header and formally generalize the return signature a bit to allow returning more than just one value. diff --git a/libavfilter/vf_colordetect.c b/libavfilter/vf_colordetect.c index 11e23ccbff..bc29cfb1b0 100644 --- a/libavfilter/vf_colordetect.c +++ b/libavfilter/vf_colordetect.c @@ -39,13 +39,6 @@ #include "vf_colordetect.h" -enum AlphaMode { - ALPHA_NONE = -1, - ALPHA_UNDETERMINED = 0, - ALPHA_STRAIGHT, - /* No way to positively identify premultiplied alpha */ -}; - enum ColorDetectMode { COLOR_DETECT_COLOR_RANGE = 1 << 0, COLOR_DETECT_ALPHA_MODE = 1 << 1, @@ -64,7 +57,7 @@ typedef struct ColorDetectContext { int mpeg_max; atomic_int detected_range; // enum AVColorRange - atomic_int detected_alpha; // enum AlphaMode + atomic_int detected_alpha; // enum FFAlphaDetect } ColorDetectContext; #define OFFSET(x) offsetof(ColorDetectContext, x) @@ -124,9 +117,9 @@ static int config_input(AVFilterLink *inlink) if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) { s->idx_a = desc->comp[desc->nb_components - 1].plane; - atomic_init(&s->detected_alpha, ALPHA_UNDETERMINED); + atomic_init(&s->detected_alpha, FF_ALPHA_UNDETERMINED); } else { - atomic_init(&s->detected_alpha, ALPHA_NONE); + atomic_init(&s->detected_alpha, FF_ALPHA_NONE); } ff_color_detect_dsp_init(&s->dsp, depth, inlink->color_range); @@ -182,12 +175,14 @@ static int detect_alpha(AVFilterContext *ctx, void *arg, const int q = s->mpeg_max - s->mpeg_min; const int k = p * s->mpeg_min + q + (1 << (s->depth - 1)); + int ret = 0; for (int i = 0; i < nb_planes; i++) { const ptrdiff_t stride = in->linesize[i]; - if (s->dsp.detect_alpha(in->data[i] + y_start * stride, stride, - alpha, alpha_stride, w, h_slice, p, q, k)) { - atomic_store(&s->detected_alpha, ALPHA_STRAIGHT); - return 0; + ret = s->dsp.detect_alpha(in->data[i] + y_start * stride, stride, + alpha, alpha_stride, w, h_slice, p, q, k); + if (ret) { + atomic_store(&s->detected_alpha, ret); + break; } } @@ -202,7 +197,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (s->mode & COLOR_DETECT_COLOR_RANGE && s->detected_range == AVCOL_RANGE_UNSPECIFIED) ff_filter_execute(ctx, detect_range, in, NULL, nb_threads); - if (s->mode & COLOR_DETECT_ALPHA_MODE && s->detected_alpha == ALPHA_UNDETERMINED) + if (s->mode & COLOR_DETECT_ALPHA_MODE && s->detected_alpha == FF_ALPHA_UNDETERMINED) ff_filter_execute(ctx, detect_alpha, in, NULL, nb_threads); return ff_filter_frame(inlink->dst->outputs[0], in); @@ -223,9 +218,9 @@ static av_cold void uninit(AVFilterContext *ctx) if (s->mode & COLOR_DETECT_ALPHA_MODE) { av_log(ctx, AV_LOG_INFO, " Alpha mode: %s\n", - s->detected_alpha == ALPHA_NONE ? "none" : - s->detected_alpha == ALPHA_STRAIGHT ? "straight / independent" - : "undetermined"); + s->detected_alpha == FF_ALPHA_NONE ? "none" : + s->detected_alpha == FF_ALPHA_STRAIGHT ? "straight / independent" + : "undertermined"); } } diff --git a/libavfilter/vf_colordetect.h b/libavfilter/vf_colordetect.h index 24279643d3..6626f88d26 100644 --- a/libavfilter/vf_colordetect.h +++ b/libavfilter/vf_colordetect.h @@ -26,13 +26,20 @@ #include <libavutil/macros.h> #include <libavutil/pixfmt.h> +enum FFAlphaDetect { + FF_ALPHA_NONE = -1, + FF_ALPHA_UNDETERMINED = 0, + FF_ALPHA_STRAIGHT, + /* No way to positively identify premultiplied alpha */ +}; + typedef struct FFColorDetectDSPContext { /* Returns 1 if an out-of-range value was detected, 0 otherwise */ int (*detect_range)(const uint8_t *data, ptrdiff_t stride, ptrdiff_t width, ptrdiff_t height, int mpeg_min, int mpeg_max); - /* Returns 1 if the color value exceeds the alpha value, 0 otherwise */ + /* Returns an FFAlphaDetect enum value */ int (*detect_alpha)(const uint8_t *color, ptrdiff_t color_stride, const uint8_t *alpha, ptrdiff_t alpha_stride, ptrdiff_t width, ptrdiff_t height, @@ -111,7 +118,7 @@ ff_detect_alpha_full_c(const uint8_t *color, ptrdiff_t color_stride, for (int x = 0; x < width; x++) cond |= color[x] > alpha[x]; if (cond) - return 1; + return FF_ALPHA_STRAIGHT; color += color_stride; alpha += alpha_stride; } @@ -129,7 +136,7 @@ ff_detect_alpha_limited_c(const uint8_t *color, ptrdiff_t color_stride, for (int x = 0; x < width; x++) cond |= p * color[x] - k > q * alpha[x]; if (cond) - return 1; + return FF_ALPHA_STRAIGHT; color += color_stride; alpha += alpha_stride; } @@ -149,7 +156,7 @@ ff_detect_alpha16_full_c(const uint8_t *color, ptrdiff_t color_stride, for (int x = 0; x < width; x++) cond |= color16[x] > alpha16[x]; if (cond) - return 1; + return FF_ALPHA_STRAIGHT; color += color_stride; alpha += alpha_stride; } @@ -167,7 +174,7 @@ ff_detect_alpha16_limited_c(const uint8_t *color, ptrdiff_t color_stride, const uint16_t *alpha16 = (const uint16_t *) alpha; for (int x = 0; x < width; x++) { if ((int64_t) p * color16[x] - k > (int64_t) q * alpha16[x]) - return 1; + return FF_ALPHA_STRAIGHT; } color += color_stride; alpha += alpha_stride; ----------------------------------------------------------------------- Summary of changes: doc/filters.texi | 2 +- libavfilter/vf_colordetect.c | 47 ++++++++++++------------ libavfilter/vf_colordetect.h | 73 ++++++++++++++++++++++++-------------- libavfilter/x86/vf_colordetect.asm | 42 ++++++++++++++++++---- tests/checkasm/vf_colordetect.c | 22 +++++++----- 5 files changed, 119 insertions(+), 67 deletions(-) hooks/post-receive -- _______________________________________________ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog To unsubscribe, visit link above, or email ffmpeg-cvslog-requ...@ffmpeg.org with subject "unsubscribe".