mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-04 09:18:38 +00:00
GRAPHICS: Implement different luminance ranges
Bink and Theora are now much improved
This commit is contained in:
parent
065b996d15
commit
09269fce8c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
YUVToRGBLookup::~YUVToRGBLookup() {
|
||||
delete[] _rgbToPix;
|
||||
// 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];
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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++) {
|
||||
|
@ -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++;
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user