PR #25244 opened by Nathan Moinvaziri (nmoinvaz)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25244
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25244.patch

The multi-tap vertical filters of the packed RGB, full chroma RGB, P010/P012 
and 16-bit packed RGB writers summed every tap per output sample. Each store to 
`dest` made the compiler reload the source and filter pointers, and the loops 
did not vectorize.

Each commit sums a span of up to 128 samples one tap at a time with 
`vfilter_span()`, then runs the existing per-pixel conversion over the span. 
The sums use unsigned arithmetic, as most of these writers already did, and the 
output is identical, dithering and alpha included.

aarch64 has no SIMD for these writers. On x86, inline MMXEXT writers handle 
bgra, rgba, bgr24, rgb555 and rgb565 by default, so there the gain is in rgb24, 
argb, abgr, rgb0, rgb444, the 8-bit and 4-bit formats, full chroma output, 
P010/P012, rgb48 and rgba64.

The output md5s match master for 544 conversions, covering 25 output formats 
including big-endian rgb48, rgba64 and P010, the bicubic, lanczos, area, 
`full_chroma_int` and `accurate_rnd` flags, downscaling, upscaling, odd widths, 
and 4:4:4, 10-bit and alpha input. FATE passes.

| 48 frames, 1080p to 720p, 1 thread | master | this PR | time |
|---|---|---|---|
| to `rgb24` | 0.53 s | 0.38 s | -29% |
| `yuv444p` to `rgb24` | 1.23 s | 0.83 s | -33% |
| to `p010le` | 0.55 s | 0.22 s | -60% |
| to `rgb48le` | 0.66 s | 0.50 s | -24% |

These are median CPU times of 11 interleaved runs with other load on the 
machine. An earlier run on an idle machine gave -44%, -37%, -57% and -22%.

Measured on an i7-1185G7 with GCC 16.



>From e9234769f072e9453eaac625703e04000475e508 Mon Sep 17 00:00:00 2001
From: Nathan Moinvaziri <[email protected]>
Date: Sun, 18 Oct 2026 13:14:32 -0700
Subject: [PATCH 1/4] swscale/output: sum the vertical filter of packed RGB tap
 by tap

The multi-tap packed RGB writer summed every tap per output pair, which
reloaded the source and filter pointers after each store to dest. Summing
a span of 128 pairs one tap at a time lets the compiler vectorize it,
keeps the output identical, and makes scaling to rgb24 about 40% faster.
---
 libswscale/output.c | 91 ++++++++++++++++++++++++++-------------------
 1 file changed, 52 insertions(+), 39 deletions(-)

diff --git a/libswscale/output.c b/libswscale/output.c
index 5cc5cf026db..18caf97176f 100644
--- a/libswscale/output.c
+++ b/libswscale/output.c
@@ -1789,6 +1789,25 @@ yuv2rgb_write(uint8_t *_dest, int i, int Y1, int Y2,
     }
 }
 
+#define VFILTER_SPAN 128
+
+/**
+ * Sum the vertical filter taps of n samples from start, one tap at a time so 
the loop
+ * vectorizes. The products are unsigned, so the sums wrap instead of 
overflowing.
+ */
+static av_always_inline void vfilter_span(int *dst, const int16_t **src, const 
int16_t *filter,
+                                          int filter_size, int start, int n)
+{
+    for (int k = 0; k < n; k++)
+        dst[k] = 1 << 18;
+    for (int j = 0; j < filter_size; j++) {
+        const int16_t *s = src[j] + start;
+        const unsigned f = filter[j];
+        for (int k = 0; k < n; k++)
+            dst[k] += s[k] * f;
+    }
+}
+
 static av_always_inline void
 yuv2rgb_X_c_template(SwsInternal *c, const int16_t *lumFilter,
                      const int16_t **lumSrc, int lumFilterSize,
@@ -1797,49 +1816,43 @@ yuv2rgb_X_c_template(SwsInternal *c, const int16_t 
*lumFilter,
                      const int16_t **alpSrc, uint8_t *dest, int dstW,
                      int y, enum AVPixelFormat target, int hasAlpha)
 {
-    int i;
+    const int pairs = (dstW + 1) >> 1;
+    int ysum[2 * VFILTER_SPAN], usum[VFILTER_SPAN], vsum[VFILTER_SPAN], asum[2 
* VFILTER_SPAN];
 
-    for (i = 0; i < ((dstW + 1) >> 1); i++) {
-        int j, A1, A2;
-        int Y1 = 1 << 18;
-        int Y2 = 1 << 18;
-        int U  = 1 << 18;
-        int V  = 1 << 18;
-        const void *r, *g, *b;
+    for (int i0 = 0; i0 < pairs; i0 += VFILTER_SPAN) {
+        const int n = FFMIN(VFILTER_SPAN, pairs - i0);
 
-        for (j = 0; j < lumFilterSize; j++) {
-            Y1 += lumSrc[j][i * 2]     * (unsigned)lumFilter[j];
-            Y2 += lumSrc[j][i * 2 + 1] * (unsigned)lumFilter[j];
-        }
-        for (j = 0; j < chrFilterSize; j++) {
-            U += chrUSrc[j][i] * (unsigned)chrFilter[j];
-            V += chrVSrc[j][i] * (unsigned)chrFilter[j];
-        }
-        Y1 >>= 19;
-        Y2 >>= 19;
-        U  >>= 19;
-        V  >>= 19;
-        if (hasAlpha) {
-            A1 = 1 << 18;
-            A2 = 1 << 18;
-            for (j = 0; j < lumFilterSize; j++) {
-                A1 += alpSrc[j][i * 2    ] * (unsigned)lumFilter[j];
-                A2 += alpSrc[j][i * 2 + 1] * (unsigned)lumFilter[j];
-            }
-            A1 >>= 19;
-            A2 >>= 19;
-            if ((A1 | A2) & 0x100) {
-                A1 = av_clip_uint8(A1);
-                A2 = av_clip_uint8(A2);
+        vfilter_span(ysum, lumSrc,  lumFilter, lumFilterSize, 2 * i0, 2 * n);
+        vfilter_span(usum, chrUSrc, chrFilter, chrFilterSize, i0, n);
+        vfilter_span(vsum, chrVSrc, chrFilter, chrFilterSize, i0, n);
+        if (hasAlpha)
+            vfilter_span(asum, alpSrc, lumFilter, lumFilterSize, 2 * i0, 2 * 
n);
+
+        for (int k = 0; k < n; k++) {
+            const int i = i0 + k;
+            int A1, A2;
+            int Y1 = ysum[2 * k]     >> 19;
+            int Y2 = ysum[2 * k + 1] >> 19;
+            int U  = usum[k] >> 19;
+            int V  = vsum[k] >> 19;
+            const void *r, *g, *b;
+
+            if (hasAlpha) {
+                A1 = asum[2 * k]     >> 19;
+                A2 = asum[2 * k + 1] >> 19;
+                if ((A1 | A2) & 0x100) {
+                    A1 = av_clip_uint8(A1);
+                    A2 = av_clip_uint8(A2);
+                }
             }
+
+            r =  c->table_rV[V + YUVRGB_TABLE_HEADROOM];
+            g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + 
YUVRGB_TABLE_HEADROOM]);
+            b =  c->table_bU[U + YUVRGB_TABLE_HEADROOM];
+
+            yuv2rgb_write(dest, i, Y1, Y2, hasAlpha ? A1 : 0, hasAlpha ? A2 : 
0,
+                          r, g, b, y, target, hasAlpha);
         }
-
-        r =  c->table_rV[V + YUVRGB_TABLE_HEADROOM];
-        g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + 
YUVRGB_TABLE_HEADROOM]);
-        b =  c->table_bU[U + YUVRGB_TABLE_HEADROOM];
-
-        yuv2rgb_write(dest, i, Y1, Y2, hasAlpha ? A1 : 0, hasAlpha ? A2 : 0,
-                      r, g, b, y, target, hasAlpha);
     }
 }
 
-- 
2.54.0


>From f9870975466ad1c564168715a5a03a0528c4b989 Mon Sep 17 00:00:00 2001
From: Nathan Moinvaziri <[email protected]>
Date: Sun, 18 Oct 2026 13:17:01 -0700
Subject: [PATCH 2/4] swscale/output: sum the vertical filter of full chroma
 RGB tap by tap

The full chroma packed RGB writer summed every tap per output pixel like
the subsampled one did. Summing spans one tap at a time keeps the output
identical, dithering included, and makes scaling 4:4:4 input to rgb24
about 40% faster.
---
 libswscale/output.c | 67 +++++++++++++++++++++------------------------
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/libswscale/output.c b/libswscale/output.c
index 18caf97176f..424d5c7e5d4 100644
--- a/libswscale/output.c
+++ b/libswscale/output.c
@@ -1792,14 +1792,14 @@ yuv2rgb_write(uint8_t *_dest, int i, int Y1, int Y2,
 #define VFILTER_SPAN 128
 
 /**
- * Sum the vertical filter taps of n samples from start, one tap at a time so 
the loop
- * vectorizes. The products are unsigned, so the sums wrap instead of 
overflowing.
+ * Sum the vertical filter taps of n samples from start onto init, one tap at 
a time so the
+ * loop vectorizes. The products are unsigned, so the sums wrap instead of 
overflowing.
  */
 static av_always_inline void vfilter_span(int *dst, const int16_t **src, const 
int16_t *filter,
-                                          int filter_size, int start, int n)
+                                          int filter_size, int start, int n, 
int init)
 {
     for (int k = 0; k < n; k++)
-        dst[k] = 1 << 18;
+        dst[k] = init;
     for (int j = 0; j < filter_size; j++) {
         const int16_t *s = src[j] + start;
         const unsigned f = filter[j];
@@ -1822,11 +1822,11 @@ yuv2rgb_X_c_template(SwsInternal *c, const int16_t 
*lumFilter,
     for (int i0 = 0; i0 < pairs; i0 += VFILTER_SPAN) {
         const int n = FFMIN(VFILTER_SPAN, pairs - i0);
 
-        vfilter_span(ysum, lumSrc,  lumFilter, lumFilterSize, 2 * i0, 2 * n);
-        vfilter_span(usum, chrUSrc, chrFilter, chrFilterSize, i0, n);
-        vfilter_span(vsum, chrVSrc, chrFilter, chrFilterSize, i0, n);
+        vfilter_span(ysum, lumSrc,  lumFilter, lumFilterSize, 2 * i0, 2 * n, 1 
<< 18);
+        vfilter_span(usum, chrUSrc, chrFilter, chrFilterSize, i0, n, 1 << 18);
+        vfilter_span(vsum, chrVSrc, chrFilter, chrFilterSize, i0, n, 1 << 18);
         if (hasAlpha)
-            vfilter_span(asum, alpSrc, lumFilter, lumFilterSize, 2 * i0, 2 * 
n);
+            vfilter_span(asum, alpSrc, lumFilter, lumFilterSize, 2 * i0, 2 * 
n, 1 << 18);
 
         for (int k = 0; k < n; k++) {
             const int i = i0 + k;
@@ -2182,46 +2182,41 @@ yuv2rgb_full_X_c_template(SwsInternal *c, const int16_t 
*lumFilter,
                           const int16_t **alpSrc, uint8_t *dest,
                           int dstW, int y, enum AVPixelFormat target, int 
hasAlpha)
 {
-    int i;
     int step = (target == AV_PIX_FMT_RGB24 || target == AV_PIX_FMT_BGR24) ? 3 
: 4;
     int err[4] = {0};
     int A = 0; //init to silence warning
+    int ysum[VFILTER_SPAN], usum[VFILTER_SPAN], vsum[VFILTER_SPAN], 
asum[VFILTER_SPAN];
 
     if(   target == AV_PIX_FMT_BGR4_BYTE || target == AV_PIX_FMT_RGB4_BYTE
        || target == AV_PIX_FMT_BGR8      || target == AV_PIX_FMT_RGB8)
         step = 1;
 
-    for (i = 0; i < dstW; i++) {
-        int j;
-        int Y = 1<<9;
-        int U = (1<<9)-(128 << 19);
-        int V = (1<<9)-(128 << 19);
+    for (int i0 = 0; i0 < dstW; i0 += VFILTER_SPAN) {
+        const int n = FFMIN(VFILTER_SPAN, dstW - i0);
 
-        for (j = 0; j < lumFilterSize; j++) {
-            Y += lumSrc[j][i] * (unsigned)lumFilter[j];
-        }
-        for (j = 0; j < chrFilterSize; j++) {
-            U += chrUSrc[j][i] * (unsigned)chrFilter[j];
-            V += chrVSrc[j][i] * (unsigned)chrFilter[j];
-        }
-        Y >>= 10;
-        U >>= 10;
-        V >>= 10;
-        if (hasAlpha) {
-            A = 1 << 18;
-            for (j = 0; j < lumFilterSize; j++) {
-                A += alpSrc[j][i] * (unsigned)lumFilter[j];
+        vfilter_span(ysum, lumSrc,  lumFilter, lumFilterSize, i0, n, 1 << 9);
+        vfilter_span(usum, chrUSrc, chrFilter, chrFilterSize, i0, n, (1 << 9) 
- (128 << 19));
+        vfilter_span(vsum, chrVSrc, chrFilter, chrFilterSize, i0, n, (1 << 9) 
- (128 << 19));
+        if (hasAlpha)
+            vfilter_span(asum, alpSrc, lumFilter, lumFilterSize, i0, n, 1 << 
18);
+
+        for (int k = 0; k < n; k++) {
+            int Y = ysum[k] >> 10;
+            int U = usum[k] >> 10;
+            int V = vsum[k] >> 10;
+
+            if (hasAlpha) {
+                A = asum[k] >> 19;
+                if (A & 0x100)
+                    A = av_clip_uint8(A);
             }
-            A >>= 19;
-            if (A & 0x100)
-                A = av_clip_uint8(A);
+            yuv2rgb_write_full(c, dest, i0 + k, Y, A, U, V, y, target, 
hasAlpha, err);
+            dest += step;
         }
-        yuv2rgb_write_full(c, dest, i, Y, A, U, V, y, target, hasAlpha, err);
-        dest += step;
     }
-    c->dither_error[0][i] = err[0];
-    c->dither_error[1][i] = err[1];
-    c->dither_error[2][i] = err[2];
+    c->dither_error[0][dstW] = err[0];
+    c->dither_error[1][dstW] = err[1];
+    c->dither_error[2][dstW] = err[2];
 }
 
 static av_always_inline void
-- 
2.54.0


>From 28a932181a43acd739c32235ae708176979ba37f Mon Sep 17 00:00:00 2001
From: Nathan Moinvaziri <[email protected]>
Date: Sun, 18 Oct 2026 13:18:45 -0700
Subject: [PATCH 3/4] swscale/output: sum the vertical filter of P010 and P012
 tap by tap

The luma and chroma writers of the P01x formats summed every tap per
output sample. Summing spans one tap at a time keeps the output
identical and makes scaling to p010le about 50% faster.
---
 libswscale/output.c | 69 ++++++++++++++++++++++-----------------------
 1 file changed, 33 insertions(+), 36 deletions(-)

diff --git a/libswscale/output.c b/libswscale/output.c
index 424d5c7e5d4..d7d4bda176e 100644
--- a/libswscale/output.c
+++ b/libswscale/output.c
@@ -528,6 +528,25 @@ static void yuv2nv12cX_c(enum AVPixelFormat dstFormat, 
const uint8_t *chrDither,
 }
 
 
+#define VFILTER_SPAN 128
+
+/**
+ * Sum the vertical filter taps of n samples from start onto init, one tap at 
a time so the
+ * loop vectorizes. The products are unsigned, so the sums wrap instead of 
overflowing.
+ */
+static av_always_inline void vfilter_span(int *dst, const int16_t **src, const 
int16_t *filter,
+                                          int filter_size, int start, int n, 
int init)
+{
+    for (int k = 0; k < n; k++)
+        dst[k] = init;
+    for (int j = 0; j < filter_size; j++) {
+        const int16_t *s = src[j] + start;
+        const unsigned f = filter[j];
+        for (int k = 0; k < n; k++)
+            dst[k] += s[k] * f;
+    }
+}
+
 #define output_pixel(pos, val) \
     if (big_endian) { \
         AV_WB16(pos, av_clip_uintp2(val >> shift, output_bits) << 
output_shift); \
@@ -552,16 +571,15 @@ static void yuv2p01xlX_c(const int16_t *filter, int 
filterSize,
                          const int16_t **src, uint16_t *dest, int dstW,
                          int big_endian, int output_bits, int output_shift)
 {
-    int i, j;
     int shift = 11 + 16 - output_bits;
+    int sum[VFILTER_SPAN];
 
-    for (i = 0; i < dstW; i++) {
-        int val = 1 << (shift - 1);
+    for (int i0 = 0; i0 < dstW; i0 += VFILTER_SPAN) {
+        const int n = FFMIN(VFILTER_SPAN, dstW - i0);
 
-        for (j = 0; j < filterSize; j++)
-            val += src[j][i] * filter[j];
-
-        output_pixel(&dest[i], val);
+        vfilter_span(sum, src, filter, filterSize, i0, n, 1 << (shift - 1));
+        for (int k = 0; k < n; k++)
+            output_pixel(&dest[i0 + k], sum[k]);
     }
 }
 
@@ -571,20 +589,18 @@ static void yuv2p01xcX_c(int big_endian, const uint8_t 
*chrDither,
                          uint8_t *dest8, int chrDstW, int output_bits, int 
output_shift)
 {
     uint16_t *dest = (uint16_t*)dest8;
-    int i, j;
     int shift = 11 + 16 - output_bits;
+    int usum[VFILTER_SPAN], vsum[VFILTER_SPAN];
 
-    for (i = 0; i < chrDstW; i++) {
-        int u = 1 << (shift - 1);
-        int v = 1 << (shift - 1);
+    for (int i0 = 0; i0 < chrDstW; i0 += VFILTER_SPAN) {
+        const int n = FFMIN(VFILTER_SPAN, chrDstW - i0);
 
-        for (j = 0; j < chrFilterSize; j++) {
-            u += chrUSrc[j][i] * (unsigned)chrFilter[j];
-            v += chrVSrc[j][i] * (unsigned)chrFilter[j];
+        vfilter_span(usum, chrUSrc, chrFilter, chrFilterSize, i0, n, 1 << 
(shift - 1));
+        vfilter_span(vsum, chrVSrc, chrFilter, chrFilterSize, i0, n, 1 << 
(shift - 1));
+        for (int k = 0; k < n; k++) {
+            output_pixel(&dest[2 * (i0 + k)],     usum[k]);
+            output_pixel(&dest[2 * (i0 + k) + 1], vsum[k]);
         }
-
-        output_pixel(&dest[2*i]  , u);
-        output_pixel(&dest[2*i+1], v);
     }
 }
 
@@ -1789,25 +1805,6 @@ yuv2rgb_write(uint8_t *_dest, int i, int Y1, int Y2,
     }
 }
 
-#define VFILTER_SPAN 128
-
-/**
- * Sum the vertical filter taps of n samples from start onto init, one tap at 
a time so the
- * loop vectorizes. The products are unsigned, so the sums wrap instead of 
overflowing.
- */
-static av_always_inline void vfilter_span(int *dst, const int16_t **src, const 
int16_t *filter,
-                                          int filter_size, int start, int n, 
int init)
-{
-    for (int k = 0; k < n; k++)
-        dst[k] = init;
-    for (int j = 0; j < filter_size; j++) {
-        const int16_t *s = src[j] + start;
-        const unsigned f = filter[j];
-        for (int k = 0; k < n; k++)
-            dst[k] += s[k] * f;
-    }
-}
-
 static av_always_inline void
 yuv2rgb_X_c_template(SwsInternal *c, const int16_t *lumFilter,
                      const int16_t **lumSrc, int lumFilterSize,
-- 
2.54.0


>From 713838fcbdbf11481409940358f6dd44dbd1e7b7 Mon Sep 17 00:00:00 2001
From: Nathan Moinvaziri <[email protected]>
Date: Sun, 18 Oct 2026 13:20:43 -0700
Subject: [PATCH 4/4] swscale/output: sum the vertical filter of 16-bit packed
 RGB tap by tap

The rgb48 and rgba64 writers summed every 32-bit tap per output pair.
Summing spans one tap at a time keeps the output identical and makes
scaling to rgb48le about 25% faster.
---
 libswscale/output.c | 135 ++++++++++++++++++++++++--------------------
 1 file changed, 74 insertions(+), 61 deletions(-)

diff --git a/libswscale/output.c b/libswscale/output.c
index d7d4bda176e..43dd812702c 100644
--- a/libswscale/output.c
+++ b/libswscale/output.c
@@ -547,6 +547,21 @@ static av_always_inline void vfilter_span(int *dst, const 
int16_t **src, const i
     }
 }
 
+/** vfilter_span() for the 32-bit intermediates of the high bit depth paths. */
+static av_always_inline void vfilter_span32(unsigned *dst, const int32_t **src,
+                                            const int16_t *filter, int 
filter_size,
+                                            int start, int n, unsigned init)
+{
+    for (int k = 0; k < n; k++)
+        dst[k] = init;
+    for (int j = 0; j < filter_size; j++) {
+        const int32_t *s = src[j] + start;
+        const unsigned f = filter[j];
+        for (int k = 0; k < n; k++)
+            dst[k] += s[k] * f;
+    }
+}
+
 #define output_pixel(pos, val) \
     if (big_endian) { \
         AV_WB16(pos, av_clip_uintp2(val >> shift, output_bits) << 
output_shift); \
@@ -1141,76 +1156,74 @@ yuv2rgba64_X_c_template(SwsInternal *c, const int16_t 
*lumFilter,
                        int y, enum AVPixelFormat target, int hasAlpha, int 
eightbytes,
                        int is_be)
 {
-    int i;
+    const int pairs = (dstW + 1) >> 1;
     int A1 = 0xffff<<14, A2 = 0xffff<<14;
+    unsigned ysum[2 * VFILTER_SPAN], usum[VFILTER_SPAN], vsum[VFILTER_SPAN];
+    unsigned asum[2 * VFILTER_SPAN];
 
-    for (i = 0; i < ((dstW + 1) >> 1); i++) {
-        int j;
-        unsigned Y1 = -0x40000000;
-        unsigned Y2 = -0x40000000;
-        unsigned U  = -(128 << 23); // 19
-        unsigned V  = -(128 << 23);
-        int R, G, B;
+    for (int i0 = 0; i0 < pairs; i0 += VFILTER_SPAN) {
+        const int n = FFMIN(VFILTER_SPAN, pairs - i0);
 
-        for (j = 0; j < lumFilterSize; j++) {
-            Y1 += lumSrc[j][i * 2]     * (unsigned)lumFilter[j];
-            Y2 += lumSrc[j][i * 2 + 1] * (unsigned)lumFilter[j];
-        }
-        for (j = 0; j < chrFilterSize; j++) {;
-            U += chrUSrc[j][i] * (unsigned)chrFilter[j];
-            V += chrVSrc[j][i] * (unsigned)chrFilter[j];
-        }
+        vfilter_span32(ysum, lumSrc,  lumFilter, lumFilterSize, 2 * i0, 2 * n, 
-0x40000000);
+        vfilter_span32(usum, chrUSrc, chrFilter, chrFilterSize, i0, n, -(128 
<< 23)); // 19
+        vfilter_span32(vsum, chrVSrc, chrFilter, chrFilterSize, i0, n, -(128 
<< 23));
+        if (hasAlpha)
+            vfilter_span32(asum, alpSrc, lumFilter, lumFilterSize, 2 * i0, 2 * 
n, -0x40000000);
 
-        if (hasAlpha) {
-            A1 = -0x40000000;
-            A2 = -0x40000000;
-            for (j = 0; j < lumFilterSize; j++) {
-                A1 += alpSrc[j][i * 2]     * (unsigned)lumFilter[j];
-                A2 += alpSrc[j][i * 2 + 1] * (unsigned)lumFilter[j];
+        for (int k = 0; k < n; k++) {
+            unsigned Y1 = ysum[2 * k];
+            unsigned Y2 = ysum[2 * k + 1];
+            unsigned U  = usum[k];
+            unsigned V  = vsum[k];
+            int R, G, B;
+
+            if (hasAlpha) {
+                A1 = asum[2 * k];
+                A2 = asum[2 * k + 1];
+                A1 >>= 1;
+                A1 += 0x20002000;
+                A2 >>= 1;
+                A2 += 0x20002000;
             }
-            A1 >>= 1;
-            A1 += 0x20002000;
-            A2 >>= 1;
-            A2 += 0x20002000;
-        }
 
-        // 8 bits: 12+15=27; 16 bits: 12+19=31
-        Y1 = (int)Y1 >> 14; // 10
-        Y1 += 0x10000;
-        Y2 = (int)Y2 >> 14;
-        Y2 += 0x10000;
-        U  = (int)U >> 14;
-        V  = (int)V >> 14;
+            // 8 bits: 12+15=27; 16 bits: 12+19=31
+            Y1 = (int)Y1 >> 14; // 10
+            Y1 += 0x10000;
+            Y2 = (int)Y2 >> 14;
+            Y2 += 0x10000;
+            U  = (int)U >> 14;
+            V  = (int)V >> 14;
 
-        // 8 bits: 27 -> 17 bits, 16 bits: 31 - 14 = 17 bits
-        Y1 -= c->yuv2rgb_y_offset;
-        Y2 -= c->yuv2rgb_y_offset;
-        Y1 *= c->yuv2rgb_y_coeff;
-        Y2 *= c->yuv2rgb_y_coeff;
-        Y1 += (1 << 13) - (1 << 29); // 21
-        Y2 += (1 << 13) - (1 << 29);
-        // 8 bits: 17 + 13 bits = 30 bits, 16 bits: 17 + 13 bits = 30 bits
+            // 8 bits: 27 -> 17 bits, 16 bits: 31 - 14 = 17 bits
+            Y1 -= c->yuv2rgb_y_offset;
+            Y2 -= c->yuv2rgb_y_offset;
+            Y1 *= c->yuv2rgb_y_coeff;
+            Y2 *= c->yuv2rgb_y_coeff;
+            Y1 += (1 << 13) - (1 << 29); // 21
+            Y2 += (1 << 13) - (1 << 29);
+            // 8 bits: 17 + 13 bits = 30 bits, 16 bits: 17 + 13 bits = 30 bits
 
-        R = V * c->yuv2rgb_v2r_coeff;
-        G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff;
-        B =                            U * c->yuv2rgb_u2b_coeff;
+            R = V * c->yuv2rgb_v2r_coeff;
+            G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff;
+            B =                            U * c->yuv2rgb_u2b_coeff;
 
-        // 8 bits: 30 - 22 = 8 bits, 16 bits: 30 bits - 14 = 16 bits
-        output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y1) >> 14) + 
(1<<15), 16));
-        output_pixel(&dest[1], av_clip_uintp2(((int)(  G + Y1) >> 14) + 
(1<<15), 16));
-        output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y1) >> 14) + 
(1<<15), 16));
-        if (eightbytes) {
-            output_pixel(&dest[3], av_clip_uintp2(A1      , 30) >> 14);
-            output_pixel(&dest[4], av_clip_uintp2(((int)(R_B + Y2) >> 14) + 
(1<<15), 16));
-            output_pixel(&dest[5], av_clip_uintp2(((int)(  G + Y2) >> 14) + 
(1<<15), 16));
-            output_pixel(&dest[6], av_clip_uintp2(((int)(B_R + Y2) >> 14) + 
(1<<15), 16));
-            output_pixel(&dest[7], av_clip_uintp2(A2      , 30) >> 14);
-            dest += 8;
-        } else {
-            output_pixel(&dest[3], av_clip_uintp2(((int)(R_B + Y2) >> 14) + 
(1<<15), 16));
-            output_pixel(&dest[4], av_clip_uintp2(((int)(  G + Y2) >> 14) + 
(1<<15), 16));
-            output_pixel(&dest[5], av_clip_uintp2(((int)(B_R + Y2) >> 14) + 
(1<<15), 16));
-            dest += 6;
+            // 8 bits: 30 - 22 = 8 bits, 16 bits: 30 bits - 14 = 16 bits
+            output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y1) >> 14) + 
(1<<15), 16));
+            output_pixel(&dest[1], av_clip_uintp2(((int)(  G + Y1) >> 14) + 
(1<<15), 16));
+            output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y1) >> 14) + 
(1<<15), 16));
+            if (eightbytes) {
+                output_pixel(&dest[3], av_clip_uintp2(A1      , 30) >> 14);
+                output_pixel(&dest[4], av_clip_uintp2(((int)(R_B + Y2) >> 14) 
+ (1<<15), 16));
+                output_pixel(&dest[5], av_clip_uintp2(((int)(  G + Y2) >> 14) 
+ (1<<15), 16));
+                output_pixel(&dest[6], av_clip_uintp2(((int)(B_R + Y2) >> 14) 
+ (1<<15), 16));
+                output_pixel(&dest[7], av_clip_uintp2(A2      , 30) >> 14);
+                dest += 8;
+            } else {
+                output_pixel(&dest[3], av_clip_uintp2(((int)(R_B + Y2) >> 14) 
+ (1<<15), 16));
+                output_pixel(&dest[4], av_clip_uintp2(((int)(  G + Y2) >> 14) 
+ (1<<15), 16));
+                output_pixel(&dest[5], av_clip_uintp2(((int)(B_R + Y2) >> 14) 
+ (1<<15), 16));
+                dest += 6;
+            }
         }
     }
 }
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to