mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-21 19:51:49 +00:00
VIDEO: Add YUV422 and YUV444 to Theora decoder
This commit is contained in:
parent
1555870eb5
commit
237cb4d52a
@ -252,6 +252,58 @@ void YUVToRGBManager::convert444(Graphics::Surface *dst, YUVToRGBManager::Lumina
|
||||
convertYUV444ToRGB<uint32>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
}
|
||||
|
||||
template<typename PixelInt>
|
||||
void convertYUV422ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
int halfWidth = yWidth >> 1;
|
||||
|
||||
// Keep the tables in pointers here to avoid a dereference on each pixel
|
||||
const int16 *Cr_r_tab = colorTab;
|
||||
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->getRGBToPix();
|
||||
|
||||
for (int h = 0; h < yHeight; h++) {
|
||||
for (int w = 0; w < halfWidth; w++) {
|
||||
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;
|
||||
|
||||
PUT_PIXEL(*ySrc, dstPtr);
|
||||
ySrc++;
|
||||
dstPtr += sizeof(PixelInt);
|
||||
PUT_PIXEL(*ySrc, dstPtr);
|
||||
ySrc++;
|
||||
dstPtr += sizeof(PixelInt);
|
||||
}
|
||||
|
||||
dstPtr += dstPitch - yWidth * sizeof(PixelInt);
|
||||
ySrc += yPitch - yWidth;
|
||||
uSrc += uvPitch - halfWidth;
|
||||
vSrc += uvPitch - halfWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void YUVToRGBManager::convert422(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->getPixels());
|
||||
assert(dst->format.bytesPerPixel == 2 || dst->format.bytesPerPixel == 4);
|
||||
assert(ySrc && uSrc && vSrc);
|
||||
assert((yWidth & 1) == 0);
|
||||
|
||||
const YUVToRGBLookup *lookup = getLookup(dst->format, scale);
|
||||
|
||||
// Use a templated function to avoid an if check on every pixel
|
||||
if (dst->format.bytesPerPixel == 2)
|
||||
convertYUV422ToRGB<uint16>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
else
|
||||
convertYUV422ToRGB<uint32>((byte *)dst->getPixels(), dst->pitch, lookup, _colorTab, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch);
|
||||
}
|
||||
|
||||
template<typename PixelInt>
|
||||
void convertYUV420ToRGB(byte *dstPtr, int dstPitch, const YUVToRGBLookup *lookup, int16 *colorTab, const byte *ySrc, const byte *uSrc, const byte *vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) {
|
||||
int halfHeight = yHeight >> 1;
|
||||
|
@ -68,6 +68,21 @@ public:
|
||||
*/
|
||||
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 YUV422 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
|
||||
* @param yWidth the width of the y surface (must be divisible by 2)
|
||||
* @param yHeight the height of the y surface
|
||||
* @param yPitch the pitch of the y surface
|
||||
* @param uvPitch the pitch of the u and v surfaces
|
||||
*/
|
||||
void convert422(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
|
||||
*
|
||||
|
@ -257,8 +257,9 @@ Common::Rational TheoraDecoder::getFrameRate() const {
|
||||
TheoraDecoder::TheoraVideoTrack::TheoraVideoTrack(th_info &theoraInfo, th_setup_info *theoraSetup) {
|
||||
_theoraDecode = th_decode_alloc(&theoraInfo, theoraSetup);
|
||||
|
||||
if (theoraInfo.pixel_fmt != TH_PF_420)
|
||||
error("Only theora YUV420 is supported");
|
||||
if (theoraInfo.pixel_fmt != TH_PF_420 && theoraInfo.pixel_fmt != TH_PF_422 && theoraInfo.pixel_fmt != TH_PF_444) {
|
||||
error("Found unknown Theora format (must be YUV420, YUV422 or YUV444)");
|
||||
}
|
||||
|
||||
int postProcessingMax;
|
||||
th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &postProcessingMax, sizeof(postProcessingMax));
|
||||
@ -272,6 +273,7 @@ TheoraDecoder::TheoraVideoTrack::TheoraVideoTrack(th_info &theoraInfo, th_setup_
|
||||
_surfaceHeight = theoraInfo.frame_height;
|
||||
|
||||
_pixelFormat = g_system->getScreenFormat();
|
||||
_theoraPixelFormat = theoraInfo.pixel_fmt;
|
||||
|
||||
// Default to a 32bpp format, if in 8bpp mode
|
||||
if (_pixelFormat.bytesPerPixel == 1)
|
||||
@ -342,11 +344,11 @@ void TheoraDecoder::TheoraVideoTrack::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuf
|
||||
assert((YUVBuffer[kBufferU].width & 1) == 0);
|
||||
assert((YUVBuffer[kBufferV].width & 1) == 0);
|
||||
|
||||
// UV images have to have a quarter of the Y image resolution
|
||||
assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1);
|
||||
assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1);
|
||||
assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1);
|
||||
assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1);
|
||||
// UV components must be half or equal the Y component
|
||||
assert((YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1) || (YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width));
|
||||
assert((YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1) || (YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width));
|
||||
assert((YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1) || (YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height));
|
||||
assert((YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1) || (YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height));
|
||||
|
||||
if (!_surface) {
|
||||
_surface = new Graphics::Surface();
|
||||
@ -360,7 +362,19 @@ void TheoraDecoder::TheoraVideoTrack::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuf
|
||||
_surface->getBasePtr(_x, _y), _surface->format);
|
||||
}
|
||||
|
||||
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);
|
||||
switch (_theoraPixelFormat) {
|
||||
case TH_PF_420:
|
||||
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);
|
||||
break;
|
||||
case TH_PF_422:
|
||||
YUVToRGBMan.convert422(_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);
|
||||
break;
|
||||
case TH_PF_444:
|
||||
YUVToRGBMan.convert444(_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);
|
||||
break;
|
||||
default:
|
||||
error("Unsupported Theora pixel format");
|
||||
}
|
||||
}
|
||||
|
||||
static vorbis_info *info = 0;
|
||||
|
@ -112,6 +112,7 @@ private:
|
||||
uint16 _surfaceHeight;
|
||||
|
||||
th_dec_ctx *_theoraDecode;
|
||||
th_pixel_fmt _theoraPixelFormat;
|
||||
|
||||
void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user