aboutsummaryrefslogtreecommitdiff
path: root/graphics/yuv_to_rgb.cpp
diff options
context:
space:
mode:
authorMatthew Hoops2012-04-14 17:06:31 -0400
committerMatthew Hoops2012-04-14 17:06:31 -0400
commit473a09786d0688e7ab9689be4f6e60172a288cb2 (patch)
treea882b293fe948ce72ed4b3f6aafccde6482a3ce5 /graphics/yuv_to_rgb.cpp
parent870ab35f5b184bc7af950437de4e5cb4f2afeddd (diff)
downloadscummvm-rg350-473a09786d0688e7ab9689be4f6e60172a288cb2.tar.gz
scummvm-rg350-473a09786d0688e7ab9689be4f6e60172a288cb2.tar.bz2
scummvm-rg350-473a09786d0688e7ab9689be4f6e60172a288cb2.zip
GRAPHICS: Make YUV410 conversion code use bilinear interpolation
SVQ1 no longer looks blocky and now looks a lot closer to what QuickTime outputs
Diffstat (limited to 'graphics/yuv_to_rgb.cpp')
-rw-r--r--graphics/yuv_to_rgb.cpp65
1 files changed, 36 insertions, 29 deletions
diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp
index e0af267106..0abebf99a8 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;
}
}