[Scummvm-cvs-logs] scummvm master -> 473a09786d0688e7ab9689be4f6e60172a288cb2

clone2727 clone2727 at gmail.com
Sat Apr 14 23:20:38 CEST 2012


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
473a09786d GRAPHICS: Make YUV410 conversion code use bilinear interpolation


Commit: 473a09786d0688e7ab9689be4f6e60172a288cb2
    https://github.com/scummvm/scummvm/commit/473a09786d0688e7ab9689be4f6e60172a288cb2
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-04-14T14:06:31-07:00

Commit Message:
GRAPHICS: Make YUV410 conversion code use bilinear interpolation

SVQ1 no longer looks blocky and now looks a lot closer to what QuickTime outputs

Changed paths:
    graphics/yuv_to_rgb.cpp
    graphics/yuv_to_rgb.h
    video/codecs/svq1.cpp



diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp
index e0af267..0abebf9 100644
--- a/graphics/yuv_to_rgb.cpp
+++ b/graphics/yuv_to_rgb.cpp
@@ -300,19 +300,8 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS
 		convertYUV420ToRGB<uint32>((byte *)dst->pixels, dst->pitch, lookup, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
 }
 
-#define OUTPUT_4_PIXEL_COLUMN() \
-	PUT_PIXEL(*ySrc, dstPtr); \
-	PUT_PIXEL(*(ySrc + yPitch), dstPtr + dstPitch); \
-	PUT_PIXEL(*(ySrc + (yPitch << 1)), dstPtr + dstPitch * 2); \
-	PUT_PIXEL(*(ySrc + (yPitch * 3)), dstPtr + dstPitch * 3); \
-	ySrc++; \
-	dstPtr += sizeof(PixelInt)
-
 template<typename PixelInt>
 void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
-	int quarterHeight = yHeight >> 2;
-	int quarterWidth = yWidth >> 2;
-
 	// Keep the tables in pointers here to avoid a dereference on each pixel
 	const int16 *Cr_r_tab = lookup->_colorTab;
 	const int16 *Cr_g_tab = Cr_r_tab + 256;
@@ -320,26 +309,44 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup
 	const int16 *Cb_b_tab = Cb_g_tab + 256;
 	const uint32 *rgbToPix = lookup->_rgbToPix;
 
-	for (int h = 0; h < quarterHeight; h++) {
-		for (int w = 0; w < quarterWidth; w++) {
-			register const uint32 *L;
-
-			int16 cr_r  = Cr_r_tab[*vSrc];
-			int16 crb_g = Cr_g_tab[*vSrc] + Cb_g_tab[*uSrc];
-			int16 cb_b  = Cb_b_tab[*uSrc];
-			++uSrc;
-			++vSrc;
-
-			OUTPUT_4_PIXEL_COLUMN();
-			OUTPUT_4_PIXEL_COLUMN();
-			OUTPUT_4_PIXEL_COLUMN();
-			OUTPUT_4_PIXEL_COLUMN();
+	for (int y = 0; y < yHeight; y++) {
+		for (int x = 0; x < yWidth; x++) {
+			// Perform bilinear interpolation on the the chroma values
+			// Based on the algorithm found here: http://tech-algorithm.com/articles/bilinear-image-scaling/
+			// Feel free to optimize further
+			int targetX = x >> 2;
+			int targetY = y >> 2;
+			int xDiff = x & 3;
+			int yDiff = y & 3;
+			int index = targetY * uvPitch + targetX;
+
+			byte a = uSrc[index];
+			byte b = uSrc[index + 1];
+			byte c = uSrc[index + uvPitch];
+			byte d = uSrc[index + uvPitch + 1];
+
+			byte u = (a * (4 - xDiff) * (4 - yDiff) + b * xDiff * (4 - yDiff) +
+					c * yDiff * (4 - xDiff) + d * xDiff * yDiff) >> 4;
+
+			a = vSrc[index];
+			b = vSrc[index + 1];
+			c = vSrc[index + uvPitch];
+			d = vSrc[index + uvPitch + 1];
+
+			byte v = (a * (4 - xDiff) * (4 - yDiff) + b * xDiff * (4 - yDiff) +
+					c * yDiff * (4 - xDiff) + d * xDiff * yDiff) >> 4;
+
+			int16 cr_r  = Cr_r_tab[v];
+			int16 crb_g = Cr_g_tab[v] + Cb_g_tab[u];
+			int16 cb_b  = Cb_b_tab[u];
+			const uint32 *L;
+
+			PUT_PIXEL(ySrc[x], dstPtr);
+			dstPtr += sizeof(PixelInt);
 		}
 
-		dstPtr += dstPitch * 3;
-		ySrc += (yPitch << 2) - yWidth;
-		uSrc += uvPitch - quarterWidth;
-		vSrc += uvPitch - quarterWidth;
+		dstPtr += dstPitch - yWidth * sizeof(PixelInt);
+		ySrc += yPitch;
 	}
 }
 
diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h
index 52ab2eb..73a2c69 100644
--- a/graphics/yuv_to_rgb.h
+++ b/graphics/yuv_to_rgb.h
@@ -67,6 +67,11 @@ void convertYUV420ToRGB(Graphics::Surface *dst, const byte *ySrc, const byte *uS
 /**
  * Convert a YUV410 image to an RGB surface
  *
+ * Since the chroma has a very low resolution in 410, we perform bilinear scaling
+ * on the two chroma planes to produce the image. The chroma planes must have
+ * at least one extra row that can be read from in order to produce a proper
+ * image (filled with 0x80). This is required in order to speed up this function.
+ *
  * @param dst     the destination surface
  * @param ySrc    the source of the y component
  * @param uSrc    the source of the u component
diff --git a/video/codecs/svq1.cpp b/video/codecs/svq1.cpp
index dc64429..eba0c90 100644
--- a/video/codecs/svq1.cpp
+++ b/video/codecs/svq1.cpp
@@ -191,14 +191,18 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
 	for (int i = 0; i < 3; i++) {
 		int width, height;
 		if (i == 0) {
-			width  = yWidth;
+			width = yWidth;
 			height = yHeight;
+			current[i] = new byte[width * height];
 		} else {
-			width  = uvWidth;
+			width = uvWidth;
 			height = uvHeight;
-		}
 
-		current[i] = new byte[width * height];
+			// Add an extra row's worth of data to not go out-of-bounds in the
+			// color conversion. Then fill that with "empty" data.
+			current[i] = new byte[width * (height + 1)];
+			memset(current[i] + width * height, 0x80, width);
+		}
 
 		if (frameType == 0) { // I Frame
 			// Keyframe (I)






More information about the Scummvm-git-logs mailing list