diff options
author | Matthew Hoops | 2012-09-18 15:54:45 -0400 |
---|---|---|
committer | Matthew Hoops | 2012-09-18 16:50:01 -0400 |
commit | 09269fce8c61b8193b25266b681c7849a6ad058d (patch) | |
tree | d5bb74ccb845d878a5bf09713c8aaf75bf07aaec | |
parent | 065b996d1551c9fb2ba927dac47a5fb907ac8d8e (diff) | |
download | scummvm-rg350-09269fce8c61b8193b25266b681c7849a6ad058d.tar.gz scummvm-rg350-09269fce8c61b8193b25266b681c7849a6ad058d.tar.bz2 scummvm-rg350-09269fce8c61b8193b25266b681c7849a6ad058d.zip |
GRAPHICS: Implement different luminance ranges
Bink and Theora are now much improved
-rw-r--r-- | graphics/decoders/jpeg.cpp | 2 | ||||
-rw-r--r-- | graphics/yuv_to_rgb.cpp | 100 | ||||
-rw-r--r-- | graphics/yuv_to_rgb.h | 18 | ||||
-rw-r--r-- | video/bink_decoder.cpp | 2 | ||||
-rw-r--r-- | video/codecs/svq1.cpp | 2 | ||||
-rw-r--r-- | video/psx_decoder.cpp | 2 | ||||
-rw-r--r-- | video/theora_decoder.cpp | 2 |
7 files changed, 81 insertions, 47 deletions
diff --git a/graphics/decoders/jpeg.cpp b/graphics/decoders/jpeg.cpp index 77ca316c6d..748275b84b 100644 --- a/graphics/decoders/jpeg.cpp +++ b/graphics/decoders/jpeg.cpp @@ -81,7 +81,7 @@ const Surface *JPEGDecoder::getSurface() const { const Graphics::Surface *uComponent = getComponent(2); const Graphics::Surface *vComponent = getComponent(3); - YUVToRGBMan.convert444(_rgbSurface, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch); + YUVToRGBMan.convert444(_rgbSurface, Graphics::YUVToRGBManager::kScaleFull, (byte *)yComponent->pixels, (byte *)uComponent->pixels, (byte *)vComponent->pixels, yComponent->w, yComponent->h, yComponent->pitch, uComponent->pitch); return _rgbSurface; } diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp index 1afd0d295b..6043315a13 100644 --- a/graphics/yuv_to_rgb.cpp +++ b/graphics/yuv_to_rgb.cpp @@ -94,40 +94,67 @@ namespace Graphics { class YUVToRGBLookup { public: - YUVToRGBLookup(Graphics::PixelFormat format); - ~YUVToRGBLookup(); + YUVToRGBLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale); - uint32 *_rgbToPix; + Graphics::PixelFormat getFormat() const { return _format; } + YUVToRGBManager::LuminanceScale getScale() const { return _scale; } + const uint32 *getRGBToPix() const { return _rgbToPix; } + +private: + Graphics::PixelFormat _format; + YUVToRGBManager::LuminanceScale _scale; + uint32 _rgbToPix[3 * 768]; // 9216 bytes }; -YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format) { - _rgbToPix = new uint32[3 * 768]; // 9216 bytes +YUVToRGBLookup::YUVToRGBLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale) { + _format = format; + _scale = scale; uint32 *r_2_pix_alloc = &_rgbToPix[0 * 768]; uint32 *g_2_pix_alloc = &_rgbToPix[1 * 768]; uint32 *b_2_pix_alloc = &_rgbToPix[2 * 768]; - // Set up entries 0-255 in rgb-to-pixel value tables. - for (int i = 0; i < 256; i++) { - r_2_pix_alloc[i + 256] = format.RGBToColor(i, 0, 0); - g_2_pix_alloc[i + 256] = format.RGBToColor(0, i, 0); - b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, i); - } + if (scale == YUVToRGBManager::kScaleFull) { + // Set up entries 0-255 in rgb-to-pixel value tables. + for (int i = 0; i < 256; i++) { + r_2_pix_alloc[i + 256] = format.RGBToColor(i, 0, 0); + g_2_pix_alloc[i + 256] = format.RGBToColor(0, i, 0); + b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, i); + } - // Spread out the values we have to the rest of the array so that we do - // not need to check for overflow. - for (int i = 0; i < 256; i++) { - r_2_pix_alloc[i] = r_2_pix_alloc[256]; - r_2_pix_alloc[i + 512] = r_2_pix_alloc[511]; - g_2_pix_alloc[i] = g_2_pix_alloc[256]; - g_2_pix_alloc[i + 512] = g_2_pix_alloc[511]; - b_2_pix_alloc[i] = b_2_pix_alloc[256]; - b_2_pix_alloc[i + 512] = b_2_pix_alloc[511]; - } -} + // Spread out the values we have to the rest of the array so that we do + // not need to check for overflow. + for (int i = 0; i < 256; i++) { + r_2_pix_alloc[i] = r_2_pix_alloc[256]; + r_2_pix_alloc[i + 512] = r_2_pix_alloc[511]; + g_2_pix_alloc[i] = g_2_pix_alloc[256]; + g_2_pix_alloc[i + 512] = g_2_pix_alloc[511]; + b_2_pix_alloc[i] = b_2_pix_alloc[256]; + b_2_pix_alloc[i + 512] = b_2_pix_alloc[511]; + } + } else { + // Set up entries 16-235 in rgb-to-pixel value tables + for (int i = 16; i < 236; i++) { + int scaledValue = (i - 16) * 255 / 219; + r_2_pix_alloc[i + 256] = format.RGBToColor(scaledValue, 0, 0); + g_2_pix_alloc[i + 256] = format.RGBToColor(0, scaledValue, 0); + b_2_pix_alloc[i + 256] = format.RGBToColor(0, 0, scaledValue); + } + + // Spread out the values we have to the rest of the array so that we do + // not need to check for overflow. We have to do it here in two steps. + for (int i = 0; i < 256 + 16; i++) { + r_2_pix_alloc[i] = r_2_pix_alloc[256 + 16]; + g_2_pix_alloc[i] = g_2_pix_alloc[256 + 16]; + b_2_pix_alloc[i] = b_2_pix_alloc[256 + 16]; + } -YUVToRGBLookup::~YUVToRGBLookup() { - delete[] _rgbToPix; + for (int i = 256 + 236; i < 768; i++) { + r_2_pix_alloc[i] = r_2_pix_alloc[256 + 236 - 1]; + g_2_pix_alloc[i] = g_2_pix_alloc[256 + 236 - 1]; + b_2_pix_alloc[i] = b_2_pix_alloc[256 + 236 - 1]; + } + } } YUVToRGBManager::YUVToRGBManager() { @@ -156,13 +183,12 @@ YUVToRGBManager::~YUVToRGBManager() { delete _lookup; } -const YUVToRGBLookup *YUVToRGBManager::getLookup(Graphics::PixelFormat format) { - if (_lastFormat == format) +const YUVToRGBLookup *YUVToRGBManager::getLookup(Graphics::PixelFormat format, YUVToRGBManager::LuminanceScale scale) { + if (_lookup && _lookup->getFormat() == format && _lookup->getScale() == scale) return _lookup; delete _lookup; - _lookup = new YUVToRGBLookup(format); - _lastFormat = format; + _lookup = new YUVToRGBLookup(format, scale); return _lookup; } @@ -177,7 +203,7 @@ void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup const int16 *Cr_g_tab = Cr_r_tab + 256; const int16 *Cb_g_tab = Cr_g_tab + 256; const int16 *Cb_b_tab = Cb_g_tab + 256; - const uint32 *rgbToPix = lookup->_rgbToPix; + const uint32 *rgbToPix = lookup->getRGBToPix(); for (int h = 0; h < yHeight; h++) { for (int w = 0; w < yWidth; w++) { @@ -201,13 +227,13 @@ void convertYUV444ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup } } -void YUVToRGBManager::convert444(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void YUVToRGBManager::convert444(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); assert(ySrc && uSrc && vSrc); - const YUVToRGBLookup *lookup = getLookup(dst->format); + const YUVToRGBLookup *lookup = getLookup(dst->format, scale); // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) @@ -226,7 +252,7 @@ void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup const int16 *Cr_g_tab = Cr_r_tab + 256; const int16 *Cb_g_tab = Cr_g_tab + 256; const int16 *Cb_b_tab = Cb_g_tab + 256; - const uint32 *rgbToPix = lookup->_rgbToPix; + const uint32 *rgbToPix = lookup->getRGBToPix(); for (int h = 0; h < halfHeight; h++) { for (int w = 0; w < halfWidth; w++) { @@ -255,7 +281,7 @@ void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup } } -void YUVToRGBManager::convert420(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void YUVToRGBManager::convert420(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); @@ -263,7 +289,7 @@ void YUVToRGBManager::convert420(Graphics::Surface *dst, const byte *ySrc, const assert((yWidth & 1) == 0); assert((yHeight & 1) == 0); - const YUVToRGBLookup *lookup = getLookup(dst->format); + const YUVToRGBLookup *lookup = getLookup(dst->format, scale); // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) @@ -303,7 +329,7 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup const int16 *Cr_g_tab = Cr_r_tab + 256; const int16 *Cb_g_tab = Cr_g_tab + 256; const int16 *Cb_b_tab = Cb_g_tab + 256; - const uint32 *rgbToPix = lookup->_rgbToPix; + const uint32 *rgbToPix = lookup->getRGBToPix(); int quarterWidth = yWidth >> 2; @@ -340,7 +366,7 @@ void convertYUV410ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup #undef DO_INTERPOLATION #undef DO_YUV410_PIXEL -void YUVToRGBManager::convert410(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { +void YUVToRGBManager::convert410(Graphics::Surface *dst, YUVToRGBManager::LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks assert(dst && dst->pixels); assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4); @@ -348,7 +374,7 @@ void YUVToRGBManager::convert410(Graphics::Surface *dst, const byte *ySrc, const assert((yWidth & 3) == 0); assert((yHeight & 3) == 0); - const YUVToRGBLookup *lookup = getLookup(dst->format); + const YUVToRGBLookup *lookup = getLookup(dst->format, scale); // Use a templated function to avoid an if check on every pixel if (dst->format.bytesPerPixel == 2) diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index 3af3fe87e4..68a0449d2c 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -41,10 +41,17 @@ class YUVToRGBLookup; class YUVToRGBManager : public Common::Singleton<YUVToRGBManager> { public: + /** The scale of the luminance values */ + enum LuminanceScale { + kScaleFull, /** Luminance values range from [0, 255] */ + kScaleITU /** Luminance values range from [16, 235], the range from ITU-R BT.601 */ + }; + /** * Convert a YUV444 image to an RGB surface * * @param dst the destination surface + * @param scale the scale of the luminance values * @param ySrc the source of the y component * @param uSrc the source of the u component * @param vSrc the source of the v component @@ -53,12 +60,13 @@ public: * @param yPitch the pitch of the y surface * @param uvPitch the pitch of the u and v surfaces */ - void convert444(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + void convert444(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); /** * Convert a YUV420 image to an RGB surface * * @param dst the destination surface + * @param scale the scale of the luminance values * @param ySrc the source of the y component * @param uSrc the source of the u component * @param vSrc the source of the v component @@ -67,7 +75,7 @@ public: * @param yPitch the pitch of the y surface * @param uvPitch the pitch of the u and v surfaces */ - void convert420(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + void convert420(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); /** * Convert a YUV410 image to an RGB surface @@ -78,6 +86,7 @@ public: * image (filled with 0x80). This is required in order to speed up this function. * * @param dst the destination surface + * @param scale the scale of the luminance values * @param ySrc the source of the y component * @param uSrc the source of the u component * @param vSrc the source of the v component @@ -86,16 +95,15 @@ public: * @param yPitch the pitch of the y surface * @param uvPitch the pitch of the u and v surfaces */ - void convert410(Graphics::Surface *dst, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); + void convert410(Graphics::Surface *dst, LuminanceScale scale, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch); private: friend class Common::Singleton<SingletonBaseType>; YUVToRGBManager(); ~YUVToRGBManager(); - const YUVToRGBLookup *getLookup(Graphics::PixelFormat format); + const YUVToRGBLookup *getLookup(Graphics::PixelFormat format, LuminanceScale scale); - Graphics::PixelFormat _lastFormat; YUVToRGBLookup *_lookup; int16 _colorTab[4 * 256]; // 2048 bytes }; diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index 65f0f6c0af..37e12624b8 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -348,7 +348,7 @@ void BinkDecoder::BinkVideoTrack::decodePacket(VideoFrame &frame) { // The width used here is the surface-width, and not the video-width // to allow for odd-sized videos. assert(_curPlanes[0] && _curPlanes[1] && _curPlanes[2]); - YUVToRGBMan.convert420(&_surface, _curPlanes[0], _curPlanes[1], _curPlanes[2], + YUVToRGBMan.convert420(&_surface, Graphics::YUVToRGBManager::kScaleITU, _curPlanes[0], _curPlanes[1], _curPlanes[2], _surfaceWidth, _surfaceHeight, _surfaceWidth, _surfaceWidth >> 1); // And swap the planes with the reference planes diff --git a/video/codecs/svq1.cpp b/video/codecs/svq1.cpp index 41bd1dc507..5f0f76ffb6 100644 --- a/video/codecs/svq1.cpp +++ b/video/codecs/svq1.cpp @@ -256,7 +256,7 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st _surface->h = _height; } - YUVToRGBMan.convert410(_surface, current[0], current[1], current[2], yWidth, yHeight, yWidth, uvWidth); + YUVToRGBMan.convert410(_surface, Graphics::YUVToRGBManager::kScaleFull, current[0], current[1], current[2], yWidth, yHeight, yWidth, uvWidth); // Store the current surfaces for later and free the old ones for (int i = 0; i < 3; i++) { diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp index 7cdc53d511..f19802f349 100644 --- a/video/psx_decoder.cpp +++ b/video/psx_decoder.cpp @@ -483,7 +483,7 @@ void PSXStreamDecoder::PSXVideoTrack::decodeFrame(Common::SeekableReadStream *fr decodeMacroBlock(&bits, mbX, mbY, scale, version); // Output data onto the frame - YUVToRGBMan.convert420(_surface, _yBuffer, _cbBuffer, _crBuffer, _surface->w, _surface->h, _macroBlocksW * 16, _macroBlocksW * 8); + YUVToRGBMan.convert420(_surface, Graphics::YUVToRGBManager::kScaleFull, _yBuffer, _cbBuffer, _crBuffer, _surface->w, _surface->h, _macroBlocksW * 16, _macroBlocksW * 8); _curFrame++; diff --git a/video/theora_decoder.cpp b/video/theora_decoder.cpp index 8b579321ac..bf953b0de9 100644 --- a/video/theora_decoder.cpp +++ b/video/theora_decoder.cpp @@ -328,7 +328,7 @@ void TheoraDecoder::TheoraVideoTrack::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuf assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1); assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1); - YUVToRGBMan.convert420(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride); + YUVToRGBMan.convert420(&_surface, Graphics::YUVToRGBManager::kScaleITU, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride); } static vorbis_info *info = 0; |