iccvid: Implement inverted frame decompressing

Bruno Jesus 00cpxxx at gmail.com
Sun Nov 1 13:02:46 CST 2015


Signed-off-by: Bruno Jesus <00cpxxx at gmail.com>

The game from bug 29852 requests uncompressed video frames with
negative height. This happens because the video files are upside down.
So add this support in the Cinepak codec so that videos are
decompressed correctly (visually tested).

The patch is simple actually, it just changes where to write in the
output buffer and the code was already there under an #ifdef. I double
checked and I think I didn't mess anything up and also tested with
Starship Titanic to ensure standard cinepak is still working.

The tests for this are in msvfw32 so this patch touches both DLLs at
the same time.

Fixes https://bugs.winehq.org/show_bug.cgi?id=29852
-------------- next part --------------
diff --git a/dlls/iccvid/iccvid.c b/dlls/iccvid/iccvid.c
index 5f620b9..e6e4419 100644
--- a/dlls/iccvid/iccvid.c
+++ b/dlls/iccvid/iccvid.c
@@ -141,6 +141,15 @@ int uvr, uvg, uvb;
         }
 }
 
+static inline long get_addr(BOOL inverted, unsigned long x, unsigned long y,
+                       int frm_stride, int bpp, unsigned int out_height)
+{
+    /* Returns the starting position of a line from top-down or bottom-up */
+    if (inverted)
+        return y * frm_stride + x * bpp;
+    else
+        return (out_height - 1 - y) * frm_stride + x * bpp;
+}
 
 #define MAKECOLOUR32(r,g,b) (((r) << 16) | ((g) << 8) | (b))
 /*#define MAKECOLOUR24(r,g,b) (((r) << 16) | ((g) << 8) | (b))*/
@@ -148,16 +157,18 @@ int uvr, uvg, uvb;
 #define MAKECOLOUR15(r,g,b) (((r) >> 3) << 10)| (((g) >> 3) << 5)| (((b) >> 3) << 0)
 
 /* ------------------------------------------------------------------------ */
-static void cvid_v1_32(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb)
+static void cvid_v1_32(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
+    cvid_codebook *cb)
 {
 unsigned long *vptr = (unsigned long *)frm;
-#ifndef ORIGINAL
-int row_inc = -stride/4;
-#else
-int row_inc = stride/4;
-#endif
+int row_inc;
 int x, y;
 
+    if (!inverted)
+        row_inc = -stride/4;
+    else
+        row_inc = stride/4;
+
     /* fill 4x4 block of pixels with colour values from codebook */
     for (y = 0; y < 4; y++)
     {
@@ -169,18 +180,19 @@ int x, y;
 
 
 /* ------------------------------------------------------------------------ */
-static void cvid_v4_32(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0,
-    cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
+static void cvid_v4_32(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
+    cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
 {
 unsigned long *vptr = (unsigned long *)frm;
-#ifndef ORIGINAL
-int row_inc = -stride/4;
-#else
-int row_inc = stride/4;
-#endif
+int row_inc;
 int x, y;
 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
 
+    if (!inverted)
+        row_inc = -stride/4;
+    else
+        row_inc = stride/4;
+
     /* fill 4x4 block of pixels with colour values from codebooks */
     for (y = 0; y < 4; y++)
     {
@@ -192,15 +204,17 @@ cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
 
 
 /* ------------------------------------------------------------------------ */
-static void cvid_v1_24(unsigned char *vptr, unsigned char *limit, int stride, cvid_codebook *cb)
+static void cvid_v1_24(unsigned char *vptr, unsigned char *limit, int stride, BOOL inverted,
+    cvid_codebook *cb)
 {
-#ifndef ORIGINAL
-int row_inc = -stride;
-#else
-int row_inc = stride;
-#endif
+int row_inc;
 int x, y;
 
+    if (!inverted)
+        row_inc = -stride;
+    else
+        row_inc = stride;
+
     /* fill 4x4 block of pixels with colour values from codebook */
     for (y = 0; y < 4; y++)
     {
@@ -216,17 +230,18 @@ int x, y;
 
 
 /* ------------------------------------------------------------------------ */
-static void cvid_v4_24(unsigned char *vptr, unsigned char *limit, int stride, cvid_codebook *cb0,
-    cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
+static void cvid_v4_24(unsigned char *vptr, unsigned char *limit, int stride, BOOL inverted,
+    cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
 {
-#ifndef ORIGINAL
-int row_inc = -stride;
-#else
-int row_inc = stride;
-#endif
+int row_inc;
 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
 int x, y;
 
+    if (!inverted)
+        row_inc = -stride;
+    else
+        row_inc = stride;
+
     /* fill 4x4 block of pixels with colour values from codebooks */
     for (y = 0; y < 4; y++)
     {
@@ -242,16 +257,18 @@ int x, y;
 
 
 /* ------------------------------------------------------------------------ */
-static void cvid_v1_16(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb)
+static void cvid_v1_16(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
+    cvid_codebook *cb)
 {
 unsigned short *vptr = (unsigned short *)frm;
-#ifndef ORIGINAL
-int row_inc = -stride/2;
-#else
-int row_inc = stride/2;
-#endif
+int row_inc;
 int x, y;
 
+    if (!inverted)
+        row_inc = -stride/2;
+    else
+        row_inc = stride/2;
+
     /* fill 4x4 block of pixels with colour values from codebook */
     for (y = 0; y < 4; y++)
     {
@@ -263,18 +280,19 @@ int x, y;
 
 
 /* ------------------------------------------------------------------------ */
-static void cvid_v4_16(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0,
-    cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
+static void cvid_v4_16(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
+    cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
 {
 unsigned short *vptr = (unsigned short *)frm;
-#ifndef ORIGINAL
-int row_inc = -stride/2;
-#else
-int row_inc = stride/2;
-#endif
+int row_inc;
 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
 int x, y;
 
+    if (!inverted)
+        row_inc = -stride/2;
+    else
+        row_inc = stride/2;
+
     /* fill 4x4 block of pixels with colour values from codebooks */
     for (y = 0; y < 4; y++)
     {
@@ -285,16 +303,18 @@ int x, y;
 }
 
 /* ------------------------------------------------------------------------ */
-static void cvid_v1_15(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb)
+static void cvid_v1_15(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
+    cvid_codebook *cb)
 {
 unsigned short *vptr = (unsigned short *)frm;
-#ifndef ORIGINAL
-int row_inc = -stride/2;
-#else
-int row_inc = stride/2;
-#endif
+int row_inc;
 int x, y;
 
+    if (!inverted)
+        row_inc = -stride/2;
+    else
+        row_inc = stride/2;
+
     /* fill 4x4 block of pixels with colour values from codebook */
     for (y = 0; y < 4; y++)
     {
@@ -306,18 +326,19 @@ int x, y;
 
 
 /* ------------------------------------------------------------------------ */
-static void cvid_v4_15(unsigned char *frm, unsigned char *limit, int stride, cvid_codebook *cb0,
-    cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
+static void cvid_v4_15(unsigned char *frm, unsigned char *limit, int stride, BOOL inverted,
+    cvid_codebook *cb0, cvid_codebook *cb1, cvid_codebook *cb2, cvid_codebook *cb3)
 {
 unsigned short *vptr = (unsigned short *)frm;
-#ifndef ORIGINAL
-int row_inc = -stride/2;
-#else
-int row_inc = stride/2;
-#endif
+int row_inc;
 cvid_codebook * cb[] = {cb0,cb1,cb2,cb3};
 int x, y;
 
+    if (!inverted)
+        row_inc = -stride/2;
+    else
+        row_inc = stride/2;
+
     /* fill 4x4 block of pixels with colour values from codebooks */
     for (y = 0; y < 4; y++)
     {
@@ -365,8 +386,9 @@ static void free_cvinfo( cinepak_info *cvinfo )
 }
 
 typedef void (*fn_cvid_v1)(unsigned char *frm, unsigned char *limit,
-                           int stride, cvid_codebook *cb);
-typedef void (*fn_cvid_v4)(unsigned char *frm, unsigned char *limit, int stride,
+                           int stride, BOOL inverted, cvid_codebook *cb);
+typedef void (*fn_cvid_v4)(unsigned char *frm, unsigned char *limit,
+                           int stride, BOOL inverted,
                            cvid_codebook *cb0, cvid_codebook *cb1,
                            cvid_codebook *cb2, cvid_codebook *cb3);
 
@@ -390,7 +412,7 @@ static void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size,
                   x0, y0, x1, y1, ci, flag, mask;
     long top_size, chunk_size;
     unsigned char *frm_ptr;
-    unsigned int i, cur_strip;
+    unsigned int i, cur_strip, addr;
     int d0, d1, d2, d3, frm_stride, bpp = 3;
     fn_cvid_v1 cvid_v1 = cvid_v1_24;
     fn_cvid_v4 cvid_v4 = cvid_v4_24;
@@ -402,10 +424,13 @@ static void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size,
       unsigned short height;
       unsigned short strips;
     } frame;
+    BOOL inverted;
 
     y = 0;
     y_bottom = 0;
     in_buffer = buf;
+    inverted = (int) out_height < 0;
+    if (inverted) out_height = -out_height;
 
     frame.flags = get_byte();
     frame.length = get_byte() << 16;
@@ -601,19 +626,15 @@ static void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size,
                                 d2 = get_byte();
                                 d3 = get_byte();
                                 chunk_size -= 4;
-#ifdef ORIGINAL
-                                cvid_v4(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
-#else
-                                cvid_v4(frm_ptr + ((out_height - 1 - y) * frm_stride + x * bpp), output, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
-#endif
+
+                                addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
+                                cvid_v4(frm_ptr + addr, output, frm_stride, inverted, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
                                 }
                             else        /* 1 byte per block */
                                 {
-#ifdef ORIGINAL
-                                cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte());
-#else
-                                cvid_v1(frm_ptr + ((out_height - 1 - y) * frm_stride + x * bpp), output, frm_stride, v1_codebook + get_byte());
-#endif
+                                addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
+                                cvid_v1(frm_ptr + addr, output, frm_stride, inverted, v1_codebook + get_byte());
+
                                 chunk_size--;
                                 }
 
@@ -657,20 +678,16 @@ static void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size,
                                     d2 = get_byte();
                                     d3 = get_byte();
                                     chunk_size -= 4;
-#ifdef ORIGINAL
-                                    cvid_v4(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
-#else
-                                    cvid_v4(frm_ptr + ((out_height - 1 - y) * frm_stride + x * bpp), output, frm_stride, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
-#endif
+
+                                    addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
+                                    cvid_v4(frm_ptr + addr, output, frm_stride, inverted, v4_codebook+d0, v4_codebook+d1, v4_codebook+d2, v4_codebook+d3);
                                     }
                                 else        /* V1 */
                                     {
                                     chunk_size--;
-#ifdef ORIGINAL
-                                    cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte());
-#else
-                                    cvid_v1(frm_ptr + ((out_height - 1 - y) * frm_stride + x * bpp), output, frm_stride, v1_codebook + get_byte());
-#endif
+
+                                    addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
+                                    cvid_v1(frm_ptr + addr, output, frm_stride, inverted, v1_codebook + get_byte());
                                     }
                                 }        /* else SKIP */
 
@@ -690,11 +707,9 @@ static void decode_cinepak(cinepak_info *cvinfo, unsigned char *buf, int size,
                 case 0x3200:        /* each byte is a V1 codebook */
                     while((chunk_size > 0) && (y < y_bottom))
                         {
-#ifdef ORIGINAL
-                        cvid_v1(frm_ptr + (y * frm_stride + x * bpp), frm_end, frm_stride, v1_codebook + get_byte());
-#else
-                        cvid_v1(frm_ptr + ((out_height - 1 - y) * frm_stride + x * bpp), output, frm_stride, v1_codebook + get_byte());
-#endif
+                        addr = get_addr(inverted, x, y, frm_stride, bpp, out_height);
+                        cvid_v1(frm_ptr + addr, output, frm_stride, inverted, v1_codebook + get_byte());
+
                         chunk_size--;
                         x += 4;
                         if(x >= out_width)
@@ -782,7 +797,11 @@ static LRESULT ICCVID_DecompressQuery( ICCVID_Info *info, LPBITMAPINFO in, LPBIT
         if( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes )
             return ICERR_BADFORMAT;
         if( in->bmiHeader.biHeight != out->bmiHeader.biHeight )
-            return ICERR_BADFORMAT;
+        {
+            if( in->bmiHeader.biHeight != -out->bmiHeader.biHeight )
+                return ICERR_BADFORMAT;
+            TRACE("Detected inverted height for video output\n");
+        }
         if( in->bmiHeader.biWidth != out->bmiHeader.biWidth )
             return ICERR_BADFORMAT;
 
@@ -887,6 +906,7 @@ static LRESULT ICCVID_Decompress( ICCVID_Info *info, ICDECOMPRESS *icd, DWORD si
 
     width  = icd->lpbiInput->biWidth;
     height = icd->lpbiInput->biHeight;
+    if (-icd->lpbiOutput->biHeight == height) height = -height;
 
     decode_cinepak(info->cvinfo, icd->lpInput, icd->lpbiInput->biSizeImage,
                    icd->lpOutput, width, height, info->bits_per_pixel);
@@ -912,6 +932,7 @@ static LRESULT ICCVID_DecompressEx( ICCVID_Info *info, ICDECOMPRESSEX *icd, DWOR
 
     width  = icd->lpbiSrc->biWidth;
     height = icd->lpbiSrc->biHeight;
+    if (-icd->lpbiDst->biHeight == height) height = -height;
 
     decode_cinepak(info->cvinfo, icd->lpSrc, icd->lpbiSrc->biSizeImage,
                    icd->lpDst, width, height, info->bits_per_pixel);
diff --git a/dlls/msvfw32/tests/msvfw.c b/dlls/msvfw32/tests/msvfw.c
index 95f28f3..b3e7b19 100644
--- a/dlls/msvfw32/tests/msvfw.c
+++ b/dlls/msvfw32/tests/msvfw.c
@@ -120,7 +120,7 @@ static void test_Locate(void)
 
         bo.biHeight = -bo.biHeight;
         err = ICDecompressQuery(h, &bi, &bo);
-        todo_wine ok(err == ICERR_OK, "Query cvid->RGB32 height<0: %d\n", err);
+        ok(err == ICERR_OK, "Query cvid->RGB32 height<0: %d\n", err);
         bo.biHeight = -bo.biHeight;
 
         ok(ICClose(h) == ICERR_OK,"ICClose failed\n");
@@ -141,7 +141,7 @@ static void test_Locate(void)
         if (h) ok(ICClose(h) == ICERR_OK,"ICClose failed\n");
         bo.biHeight = - bo.biHeight;
         h = ICLocate(ICTYPE_VIDEO, 0, &bi, &bo, ICMODE_DECOMPRESS);
-        todo_wine ok(h != 0, "cvid->RGB16 height<0 failed\n");
+        ok(h != 0, "cvid->RGB16 height<0 failed\n");
         if (h) ok(ICClose(h) == ICERR_OK,"ICClose failed\n");
         bo.biHeight = - bo.biHeight;
 
@@ -151,7 +151,7 @@ static void test_Locate(void)
         if (h) ok(ICClose(h) == ICERR_OK,"ICClose failed\n");
         bo.biHeight = - bo.biHeight;
         h = ICLocate(ICTYPE_VIDEO, 0, &bi, &bo, ICMODE_DECOMPRESS);
-        todo_wine ok(h != 0, "cvid->RGB32 height<0 failed\n");
+        ok(h != 0, "cvid->RGB32 height<0 failed\n");
         if (h) ok(ICClose(h) == ICERR_OK,"ICClose failed\n");
         bo.biHeight = - bo.biHeight;
 


More information about the wine-patches mailing list