Commit 88e6193e00 for ffmpeg

commit 88e6193e00c7ce2c86f857b502c2fec9376636bf
Author: Michael Niedermayer <michael@niedermayer.cc>
Date:   Sat Nov 7 22:08:08 2026 +0100

    swscale: write the last pixel of odd width rows in the planar to packed YUV converters

    Fixes: hEgEOrq8XP97

    Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25034

    Unwritten last pixel Replicated through UnModified FFmpeg with rawvideo output

diff --git a/libswscale/rgb2rgb.h b/libswscale/rgb2rgb.h
index 6f16f95fa6..db648f2d66 100644
--- a/libswscale/rgb2rgb.h
+++ b/libswscale/rgb2rgb.h
@@ -144,16 +144,18 @@ extern void (*yuyvtoyuv422)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const u
 void ff_sws_rgb2rgb_init(void);

 /**
- * Packs the chroma positions from..to-1 of one line as YUYV when
- * luma_first is set and as UYVY otherwise.
+ * Packs one line of width pixels, starting at chroma position from, as YUYV
+ * when luma_first is set and as UYVY otherwise. The luma of an odd last
+ * pixel is repeated.
  */
 static inline void ff_pack_yuv422_line(uint8_t *dst, const uint8_t *ysrc,
                                        const uint8_t *usrc, const uint8_t *vsrc,
-                                       int from, int to, int luma_first)
+                                       int from, int width, int luma_first)
 {
-    for (int i = from; i < to; i++) {
+    for (int i = from; 2 * i < width; i++) {
+        const int y1 = 2 * i + 1 < width ? 2 * i + 1 : 2 * i;
         dst[4 * i +     !luma_first] = ysrc[2 * i];
-        dst[4 * i + 2 + !luma_first] = ysrc[2 * i + 1];
+        dst[4 * i + 2 + !luma_first] = ysrc[y1];
         dst[4 * i +      luma_first] = usrc[i];
         dst[4 * i + 2 +  luma_first] = vsrc[i];
     }
diff --git a/libswscale/rgb2rgb_template.c b/libswscale/rgb2rgb_template.c
index d857b74afb..81515904f3 100644
--- a/libswscale/rgb2rgb_template.c
+++ b/libswscale/rgb2rgb_template.c
@@ -399,7 +399,7 @@ static inline void yuvPlanartoyuy2_c(const uint8_t *ysrc, const uint8_t *usrc,
             uc     += 2;
             vc     += 2;
         }
-        ff_pack_yuv422_line(dst, ysrc, usrc, vsrc, chromWidth & ~1, chromWidth, 1);
+        ff_pack_yuv422_line(dst, ysrc, usrc, vsrc, chromWidth & ~1, width, 1);

 #else
         int *idst = (int32_t *)dst;
@@ -417,6 +417,7 @@ static inline void yuvPlanartoyuy2_c(const uint8_t *ysrc, const uint8_t *usrc,
             uc++;
             vc++;
         }
+        ff_pack_yuv422_line(dst, ysrc, usrc, vsrc, chromWidth, width, 1);
 #endif
         if ((y & (vertLumPerChroma - 1)) == vertLumPerChroma - 1) {
             usrc += chromStride;
@@ -460,7 +461,7 @@ static inline void yuvPlanartouyvy_c(const uint8_t *ysrc, const uint8_t *usrc,
             uc     += 2;
             vc     += 2;
         }
-        ff_pack_yuv422_line(dst, ysrc, usrc, vsrc, chromWidth & ~1, chromWidth, 0);
+        ff_pack_yuv422_line(dst, ysrc, usrc, vsrc, chromWidth & ~1, width, 0);

 #else
         int *idst = (int32_t *)dst;
@@ -478,6 +479,7 @@ static inline void yuvPlanartouyvy_c(const uint8_t *ysrc, const uint8_t *usrc,
             uc++;
             vc++;
         }
+        ff_pack_yuv422_line(dst, ysrc, usrc, vsrc, chromWidth, width, 0);
 #endif
         if ((y & (vertLumPerChroma - 1)) == vertLumPerChroma - 1) {
             usrc += chromStride;
diff --git a/libswscale/x86/rgb2rgb.c b/libswscale/x86/rgb2rgb.c
index f22a919575..aecdaf7a69 100644
--- a/libswscale/x86/rgb2rgb.c
+++ b/libswscale/x86/rgb2rgb.c
@@ -24,6 +24,7 @@
  */

 #include <stdint.h>
+#include <string.h>

 #include "config.h"
 #include "libavutil/attributes.h"
@@ -1158,7 +1159,7 @@ static inline void yuvPlanartoyuy2_line_mmxext(uint8_t *dst, const uint8_t *ysrc
         "cmp                        %4, %%"FF_REG_a" \n\t"
         " jb                        1b               \n\t"
         ::"r"(dst), "r"(ysrc), "r"(usrc), "r"(vsrc), "g" (chromWidth)
-        : "%"FF_REG_a
+        : "%"FF_REG_a, "memory"
     );
 }

@@ -1196,7 +1197,7 @@ static inline void yuvPlanartouyvy_line_mmxext(uint8_t *dst, const uint8_t *ysrc
         "cmp                       %4, %%"FF_REG_a" \n\t"
         " jb                       1b               \n\t"
         ::"r"(dst), "r"(ysrc), "r"(usrc), "r"(vsrc), "g" (chromWidth)
-        : "%"FF_REG_a
+        : "%"FF_REG_a, "memory"
     );
 }

@@ -1210,12 +1211,19 @@ static inline void yuvPlanartopacked_mmxext(void (*pack_line)(uint8_t *, const u
     for (int y = 0; y < height; y++) {
         //FIXME handle 2 lines at once (fewer prefetches, reuse some chroma, but very likely memory-limited anyway)
         if (chromWidth < 8) {
-            ff_pack_yuv422_line(dst, ysrc, usrc, vsrc, 0, chromWidth, luma_first);
+            ff_pack_yuv422_line(dst, ysrc, usrc, vsrc, 0, width, luma_first);
         } else {
             pack_line(dst, ysrc, usrc, vsrc, chromWidth & ~7);
-            if (chromWidth & 7) {
-                x86_reg i = chromWidth - 8;
-                pack_line(dst + 4 * i, ysrc + 2 * i, usrc + i, vsrc + i, 8);
+            if (width & 15) {
+                x86_reg i = ((width + 1) >> 1) - 8;
+                const uint8_t *y = ysrc + 2 * i;
+                uint8_t last[16];
+                if (width & 1) {
+                    memcpy(last, y, 15);
+                    last[15] = last[14];
+                    y = last;
+                }
+                pack_line(dst + 4 * i, y, usrc + i, vsrc + i, 8);
             }
         }
         if ((y&(vertLumPerChroma-1)) == vertLumPerChroma-1) {