[FFmpeg-devel] [PATCH 05/12] swscale/internal: fix and expose xyz12Torgb48 and rgb48Toxyz12

Niklas Haas ffmpeg at haasn.xyz
Sat Oct 5 22:23:56 EEST 2024


From: Niklas Haas <git at haasn.dev>

In the process of refactoring the signature to be more generically useful,
this fixes an 11-year-old bug where the functions (incorrectly) did nothing
when the stride was negative, since the stride was being used as the loop
bounds for x.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git at haasn.dev>
---
 libswscale/swscale.c                | 98 +++++++++++++++--------------
 libswscale/swscale_internal.h       |  6 ++
 tests/ref/fate/filter-pixfmts-vflip |  4 +-
 3 files changed, 60 insertions(+), 48 deletions(-)

diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index 8b6a3a84b4..b9ec976be0 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -636,29 +636,31 @@ static int check_image_pointers(const uint8_t * const data[4], enum AVPixelForma
     return 1;
 }
 
-static void xyz12Torgb48(struct SwsContext *c, uint16_t *dst,
-                         const uint16_t *src, int stride, int h)
+void ff_xyz12Torgb48(const SwsContext *c, uint8_t *dst, int dst_stride,
+                     const uint8_t *src, int src_stride, int w, int h)
 {
-    int xp,yp;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->srcFormat);
 
-    for (yp=0; yp<h; yp++) {
-        for (xp=0; xp+2<stride; xp+=3) {
+    for (int yp = 0; yp < h; yp++) {
+        const uint16_t *src16 = (const uint16_t *) src;
+        uint16_t *dst16 = (uint16_t *) dst;
+
+        for (int xp = 0; xp < 3 * w; xp += 3) {
             int x, y, z, r, g, b;
 
             if (desc->flags & AV_PIX_FMT_FLAG_BE) {
-                x = AV_RB16(src + xp + 0);
-                y = AV_RB16(src + xp + 1);
-                z = AV_RB16(src + xp + 2);
+                x = AV_RB16(src16 + xp + 0);
+                y = AV_RB16(src16 + xp + 1);
+                z = AV_RB16(src16 + xp + 2);
             } else {
-                x = AV_RL16(src + xp + 0);
-                y = AV_RL16(src + xp + 1);
-                z = AV_RL16(src + xp + 2);
+                x = AV_RL16(src16 + xp + 0);
+                y = AV_RL16(src16 + xp + 1);
+                z = AV_RL16(src16 + xp + 2);
             }
 
-            x = c->xyzgamma[x>>4];
-            y = c->xyzgamma[y>>4];
-            z = c->xyzgamma[z>>4];
+            x = c->xyzgamma[x >> 4];
+            y = c->xyzgamma[y >> 4];
+            z = c->xyzgamma[z >> 4];
 
             // convert from XYZlinear to sRGBlinear
             r = c->xyz2rgb_matrix[0][0] * x +
@@ -678,38 +680,41 @@ static void xyz12Torgb48(struct SwsContext *c, uint16_t *dst,
 
             // convert from sRGBlinear to RGB and scale from 12bit to 16bit
             if (desc->flags & AV_PIX_FMT_FLAG_BE) {
-                AV_WB16(dst + xp + 0, c->rgbgamma[r] << 4);
-                AV_WB16(dst + xp + 1, c->rgbgamma[g] << 4);
-                AV_WB16(dst + xp + 2, c->rgbgamma[b] << 4);
+                AV_WB16(dst16 + xp + 0, c->rgbgamma[r] << 4);
+                AV_WB16(dst16 + xp + 1, c->rgbgamma[g] << 4);
+                AV_WB16(dst16 + xp + 2, c->rgbgamma[b] << 4);
             } else {
-                AV_WL16(dst + xp + 0, c->rgbgamma[r] << 4);
-                AV_WL16(dst + xp + 1, c->rgbgamma[g] << 4);
-                AV_WL16(dst + xp + 2, c->rgbgamma[b] << 4);
+                AV_WL16(dst16 + xp + 0, c->rgbgamma[r] << 4);
+                AV_WL16(dst16 + xp + 1, c->rgbgamma[g] << 4);
+                AV_WL16(dst16 + xp + 2, c->rgbgamma[b] << 4);
             }
         }
-        src += stride;
-        dst += stride;
+
+        src += src_stride;
+        dst += dst_stride;
     }
 }
 
-static void rgb48Toxyz12(struct SwsContext *c, uint16_t *dst,
-                         const uint16_t *src, int stride, int h)
+void ff_rgb48Toxyz12(const SwsContext *c, uint8_t *dst, int dst_stride,
+                     const uint8_t *src, int src_stride, int w, int h)
 {
-    int xp,yp;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->dstFormat);
 
-    for (yp=0; yp<h; yp++) {
-        for (xp=0; xp+2<stride; xp+=3) {
+    for (int yp = 0; yp < h; yp++) {
+        uint16_t *src16 = (uint16_t *) src;
+        uint16_t *dst16 = (uint16_t *) dst;
+
+        for (int xp = 0; xp < 3 * w; xp += 3) {
             int x, y, z, r, g, b;
 
             if (desc->flags & AV_PIX_FMT_FLAG_BE) {
-                r = AV_RB16(src + xp + 0);
-                g = AV_RB16(src + xp + 1);
-                b = AV_RB16(src + xp + 2);
+                r = AV_RB16(src16 + xp + 0);
+                g = AV_RB16(src16 + xp + 1);
+                b = AV_RB16(src16 + xp + 2);
             } else {
-                r = AV_RL16(src + xp + 0);
-                g = AV_RL16(src + xp + 1);
-                b = AV_RL16(src + xp + 2);
+                r = AV_RL16(src16 + xp + 0);
+                g = AV_RL16(src16 + xp + 1);
+                b = AV_RL16(src16 + xp + 2);
             }
 
             r = c->rgbgammainv[r>>4];
@@ -734,17 +739,18 @@ static void rgb48Toxyz12(struct SwsContext *c, uint16_t *dst,
 
             // convert from XYZlinear to X'Y'Z' and scale from 12bit to 16bit
             if (desc->flags & AV_PIX_FMT_FLAG_BE) {
-                AV_WB16(dst + xp + 0, c->xyzgammainv[x] << 4);
-                AV_WB16(dst + xp + 1, c->xyzgammainv[y] << 4);
-                AV_WB16(dst + xp + 2, c->xyzgammainv[z] << 4);
+                AV_WB16(dst16 + xp + 0, c->xyzgammainv[x] << 4);
+                AV_WB16(dst16 + xp + 1, c->xyzgammainv[y] << 4);
+                AV_WB16(dst16 + xp + 2, c->xyzgammainv[z] << 4);
             } else {
-                AV_WL16(dst + xp + 0, c->xyzgammainv[x] << 4);
-                AV_WL16(dst + xp + 1, c->xyzgammainv[y] << 4);
-                AV_WL16(dst + xp + 2, c->xyzgammainv[z] << 4);
+                AV_WL16(dst16 + xp + 0, c->xyzgammainv[x] << 4);
+                AV_WL16(dst16 + xp + 1, c->xyzgammainv[y] << 4);
+                AV_WL16(dst16 + xp + 2, c->xyzgammainv[z] << 4);
             }
         }
-        src += stride;
-        dst += stride;
+
+        src += src_stride;
+        dst += dst_stride;
     }
 }
 
@@ -994,7 +1000,7 @@ static int scale_internal(SwsContext *c,
         base = srcStride[0] < 0 ? c->xyz_scratch - srcStride[0] * (srcSliceH-1) :
                                   c->xyz_scratch;
 
-        xyz12Torgb48(c, (uint16_t*)base, (const uint16_t*)src2[0], srcStride[0]/2, srcSliceH);
+        ff_xyz12Torgb48(c, base, srcStride[0], src2[0], srcStride[0], c->srcW, srcSliceH);
         src2[0] = base;
     }
 
@@ -1052,21 +1058,21 @@ static int scale_internal(SwsContext *c,
     }
 
     if (c->dstXYZ && !(c->srcXYZ && c->srcW==c->dstW && c->srcH==c->dstH)) {
-        uint16_t *dst16;
+        uint8_t *dst;
 
         if (scale_dst) {
-            dst16 = (uint16_t *)dst2[0];
+            dst = dst2[0];
         } else {
             int dstY = c->dstY ? c->dstY : srcSliceY + srcSliceH;
 
             av_assert0(dstY >= ret);
             av_assert0(ret >= 0);
             av_assert0(c->dstH >= dstY);
-            dst16 = (uint16_t*)(dst2[0] + (dstY - ret) * dstStride2[0]);
+            dst = dst2[0] + (dstY - ret) * dstStride2[0];
         }
 
         /* replace on the same data */
-        rgb48Toxyz12(c, dst16, dst16, dstStride2[0]/2, ret);
+        ff_rgb48Toxyz12(c, dst, dstStride2[0], dst, dstStride2[0], c->dstW, ret);
     }
 
     /* reset slice direction at end of frame */
diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
index 963879cf9a..17440c99c4 100644
--- a/libswscale/swscale_internal.h
+++ b/libswscale/swscale_internal.h
@@ -1013,6 +1013,12 @@ void ff_copyPlane(const uint8_t *src, int srcStride,
                   int srcSliceY, int srcSliceH, int width,
                   uint8_t *dst, int dstStride);
 
+void ff_xyz12Torgb48(const SwsContext *c, uint8_t *dst, int dst_stride,
+                     const uint8_t *src, int src_stride, int w, int h);
+
+void ff_rgb48Toxyz12(const SwsContext *c, uint8_t *dst, int dst_stride,
+                     const uint8_t *src, int src_stride, int w, int h);
+
 static inline void fillPlane16(uint8_t *plane, int stride, int width, int height, int y,
                                int alpha, int bits, const int big_endian)
 {
diff --git a/tests/ref/fate/filter-pixfmts-vflip b/tests/ref/fate/filter-pixfmts-vflip
index 5ba28917a7..4cc716799f 100644
--- a/tests/ref/fate/filter-pixfmts-vflip
+++ b/tests/ref/fate/filter-pixfmts-vflip
@@ -103,8 +103,8 @@ x2bgr10le           795b66a5fc83cd2cf300aae51c230f80
 x2rgb10le           262c502230cf3724f8e2cf4737f18a42
 xv30le              7e29ee107a1fabf3c7251f337d4b9fe5
 xv36le              bf1cbef0745f90881e15f5c5db3c5949
-xyz12be             810644e008deb231850d779aaa27cc7e
-xyz12le             829701db461b43533cf9241e0743bc61
+xyz12be             23fa9fb36d49dce61e284d41b83e0e6b
+xyz12le             ef73e6d1f932a9a355df1eedd628394f
 y210le              9544c81f8e1fc95e9fa4009dbecfea25
 y212le              c801725ae31e3b8f5be269359d49f191
 ya16be              55b1dbbe4d56ed0d22461685ce85520d
-- 
2.46.1



More information about the ffmpeg-devel mailing list