diff options
-rw-r--r-- | engines/glk/picture.cpp | 1 | ||||
-rw-r--r-- | engines/groovie/roq.cpp | 5 | ||||
-rw-r--r-- | engines/titanic/support/image_decoders.cpp | 13 | ||||
-rw-r--r-- | graphics/yuv_to_rgb.h | 3 | ||||
-rw-r--r-- | image/codecs/mjpeg.cpp | 6 | ||||
-rw-r--r-- | image/jpeg.cpp | 114 | ||||
-rw-r--r-- | image/jpeg.h | 16 |
7 files changed, 108 insertions, 50 deletions
diff --git a/engines/glk/picture.cpp b/engines/glk/picture.cpp index a47d8bf3d6..306444449c 100644 --- a/engines/glk/picture.cpp +++ b/engines/glk/picture.cpp @@ -125,6 +125,7 @@ Picture *Pictures::load(uint32 id) { palette = png.getPalette(); palCount = png.getPaletteColorCount(); } else if (f.open(Common::String::format("pic%u.jpg", id))) { + jpg.setOutputPixelFormat(g_system->getScreenFormat()); jpg.loadStream(f); img = jpg.getSurface(); } else if (f.open(Common::String::format("pic%u.raw", id))) { diff --git a/engines/groovie/roq.cpp b/engines/groovie/roq.cpp index c1b6c44c4d..2e9a394c53 100644 --- a/engines/groovie/roq.cpp +++ b/engines/groovie/roq.cpp @@ -470,6 +470,7 @@ bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) { debugC(5, kDebugVideo, "Groovie::ROQ: Processing still (JPEG) block"); Image::JPEGDecoder jpg; + jpg.setOutputPixelFormat(_vm->_pixelFormat); uint32 startPos = _file->pos(); Common::SeekableSubReadStream subStream(_file, startPos, startPos + blockHeader.size, DisposeAfterUse::NO); @@ -478,7 +479,9 @@ bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) { const Graphics::Surface *srcSurf = jpg.getSurface(); _currBuf->free(); delete _currBuf; - _currBuf = srcSurf->convertTo(_vm->_pixelFormat); + + _currBuf = new Graphics::Surface(); + _currBuf->copyFrom(*srcSurf); _file->seek(startPos + blockHeader.size); return true; diff --git a/engines/titanic/support/image_decoders.cpp b/engines/titanic/support/image_decoders.cpp index 3819b85116..7c902b2c6d 100644 --- a/engines/titanic/support/image_decoders.cpp +++ b/engines/titanic/support/image_decoders.cpp @@ -20,6 +20,7 @@ * */ +#include "common/system.h" #include "titanic/support/image_decoders.h" namespace Titanic { @@ -29,7 +30,8 @@ void CJPEGDecode::decode(OSVideoSurface &surface, const CString &name) { StdCWadFile file; file.open(name); - // Use the ScucmmVM deoder to decode it + // Use the ScummVM decoder to decode it + setOutputPixelFormat(g_system->getScreenFormat()); loadStream(*file.readStream()); const Graphics::Surface *srcSurf = getSurface(); @@ -38,15 +40,14 @@ void CJPEGDecode::decode(OSVideoSurface &surface, const CString &name) { || surface.getHeight() != srcSurf->h) surface.recreate(srcSurf->w, srcSurf->h, 16); - // Convert the decoded surface to the correct pixel format, and then copy it over + // Copy the decoded surface surface.lock(); - Graphics::Surface *convertedSurface = srcSurf->convertTo(surface._rawSurface->format); - Common::copy((byte *)convertedSurface->getPixels(), (byte *)convertedSurface->getPixels() + + assert(srcSurf->format == surface._rawSurface->format); + + Common::copy((const byte *)srcSurf->getPixels(), (const byte *)srcSurf->getPixels() + surface.getPitch() * surface.getHeight(), (byte *)surface._rawSurface->getPixels()); - convertedSurface->free(); - delete convertedSurface; surface.unlock(); } diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h index a1e61ec705..3d11f35048 100644 --- a/graphics/yuv_to_rgb.h +++ b/graphics/yuv_to_rgb.h @@ -24,9 +24,6 @@ * @file * YUV to RGB conversion. * - * Used in graphics: - * - JPEGDecoder - * * Used in video: * - BinkDecoder * - Indeo3Decoder diff --git a/image/codecs/mjpeg.cpp b/image/codecs/mjpeg.cpp index 6e7faf1045..c5f815342b 100644 --- a/image/codecs/mjpeg.cpp +++ b/image/codecs/mjpeg.cpp @@ -200,6 +200,7 @@ const Graphics::Surface *MJPEGDecoder::decodeFrame(Common::SeekableReadStream &s Common::MemoryReadStream convertedStream(data, outputSize, DisposeAfterUse::YES); JPEGDecoder jpeg; + jpeg.setOutputPixelFormat(_pixelFormat); if (!jpeg.loadStream(convertedStream)) { warning("Failed to decode MJPEG frame"); @@ -211,7 +212,10 @@ const Graphics::Surface *MJPEGDecoder::decodeFrame(Common::SeekableReadStream &s delete _surface; } - _surface = jpeg.getSurface()->convertTo(_pixelFormat); + _surface = new Graphics::Surface(); + _surface->copyFrom(*jpeg.getSurface()); + + assert(_surface->format == _pixelFormat); return _surface; } diff --git a/image/jpeg.cpp b/image/jpeg.cpp index 1ce45f2539..5cc348fdfe 100644 --- a/image/jpeg.cpp +++ b/image/jpeg.cpp @@ -30,6 +30,7 @@ #include "common/endian.h" #include "common/stream.h" #include "common/textconsole.h" +#include "common/util.h" #include "graphics/pixelformat.h" #ifdef USE_JPEG @@ -44,13 +45,24 @@ extern "C" { namespace Image { -JPEGDecoder::JPEGDecoder() : _surface(), _colorSpace(kColorSpaceRGBA) { +JPEGDecoder::JPEGDecoder() : + _surface(), + _colorSpace(kColorSpaceRGB), + _requestedPixelFormat(getByteOrderRgbPixelFormat()) { } JPEGDecoder::~JPEGDecoder() { destroy(); } +Graphics::PixelFormat JPEGDecoder::getByteOrderRgbPixelFormat() const { +#ifdef SCUMM_BIG_ENDIAN + return Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0); +#else + return Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0); +#endif +} + const Graphics::Surface *JPEGDecoder::getSurface() const { return &_surface; } @@ -171,6 +183,44 @@ void outputMessage(j_common_ptr cinfo) { debug(3, "libjpeg: %s", buffer); } +J_COLOR_SPACE fromScummvmPixelFormat(const Graphics::PixelFormat &format) { + struct PixelFormatMapping { + Graphics::PixelFormat pixelFormat; + J_COLOR_SPACE bigEndianColorSpace; + J_COLOR_SPACE littleEndianColorSpace; + }; + + static const PixelFormatMapping mappings[] = { +#ifdef JCS_EXTENSIONS + { Graphics::PixelFormat(4, 8, 8, 8, 0, 24, 16, 8, 0), JCS_EXT_RGBX, JCS_EXT_XBGR }, + { Graphics::PixelFormat(4, 8, 8, 8, 0, 0, 8, 16, 24), JCS_EXT_XBGR, JCS_EXT_RGBX }, + { Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 24), JCS_EXT_XRGB, JCS_EXT_BGRX }, + { Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0), JCS_EXT_BGRX, JCS_EXT_XRGB }, + { Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0), JCS_EXT_RGB, JCS_EXT_BGR }, + { Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0), JCS_EXT_BGR, JCS_EXT_RGB }, +#endif +#ifdef JCS_ALPHA_EXTENSIONS + { Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), JCS_EXT_RGBA, JCS_EXT_ABGR }, + { Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), JCS_EXT_ABGR, JCS_EXT_RGBA }, + { Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), JCS_EXT_ARGB, JCS_EXT_BGRA }, + { Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0), JCS_EXT_BGRA, JCS_EXT_ARGB }, +#endif + { Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), JCS_RGB565, JCS_RGB565 } + }; + + for (uint i = 0; i < ARRAYSIZE(mappings); i++) { + if (mappings[i].pixelFormat == format) { +#ifdef SCUMM_BIG_ENDIAN + return mappings[i].bigEndianColorSpace; +#else + return mappings[i].littleEndianColorSpace; +#endif + } + } + + return JCS_UNKNOWN; +} + } // End of anonymous namespace #endif @@ -198,10 +248,19 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) { // We can request YUV output because Groovie requires it switch (_colorSpace) { - case kColorSpaceRGBA: - cinfo.out_color_space = JCS_RGB; - break; + case kColorSpaceRGB: { + J_COLOR_SPACE colorSpace = fromScummvmPixelFormat(_requestedPixelFormat); + + if (colorSpace == JCS_UNKNOWN) { + // When libjpeg-turbo is not available or an unhandled pixel + // format was requested, ask libjpeg to decode to byte order RGB + // as it's always available. + colorSpace = JCS_RGB; + } + cinfo.out_color_space = colorSpace; + break; + } case kColorSpaceYUV: cinfo.out_color_space = JCS_YCbCr; break; @@ -212,11 +271,16 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) { // Allocate buffers for the output data switch (_colorSpace) { - case kColorSpaceRGBA: - // We use RGBA8888 in this scenario - _surface.create(cinfo.output_width, cinfo.output_height, Graphics::PixelFormat(4, 8, 8, 8, 0, 24, 16, 8, 0)); + case kColorSpaceRGB: { + Graphics::PixelFormat outputPixelFormat; + if (cinfo.out_color_space == JCS_RGB) { + outputPixelFormat = getByteOrderRgbPixelFormat(); + } else { + outputPixelFormat = _requestedPixelFormat; + } + _surface.create(cinfo.output_width, cinfo.output_height, outputPixelFormat); break; - + } case kColorSpaceYUV: // We use YUV with 3 bytes per pixel otherwise. // This is pretty ugly since our PixelFormat cannot express YUV... @@ -225,8 +289,7 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) { } // Allocate buffer for one scanline - assert(cinfo.output_components == 3); - JDIMENSION pitch = cinfo.output_width * cinfo.output_components; + JDIMENSION pitch = cinfo.output_width * _surface.format.bytesPerPixel; assert(_surface.pitch >= pitch); JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, pitch, 1); @@ -236,38 +299,17 @@ bool JPEGDecoder::loadStream(Common::SeekableReadStream &stream) { jpeg_read_scanlines(&cinfo, buffer, 1); - const byte *src = buffer[0]; - switch (_colorSpace) { - case kColorSpaceRGBA: { - for (int remaining = cinfo.output_width; remaining > 0; --remaining) { - byte r = *src++; - byte g = *src++; - byte b = *src++; - // We need to insert a alpha value of 255 (opaque) here. -#ifdef SCUMM_BIG_ENDIAN - *dst++ = r; - *dst++ = g; - *dst++ = b; - *dst++ = 0xFF; -#else - *dst++ = 0xFF; - *dst++ = b; - *dst++ = g; - *dst++ = r; -#endif - } - } break; - - case kColorSpaceYUV: - memcpy(dst, src, pitch); - break; - } + memcpy(dst, buffer[0], pitch); } // We are done with decompressing, thus free all the data jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); + if (_colorSpace == kColorSpaceRGB && _surface.format != _requestedPixelFormat) { + _surface.convertToInPlace(_requestedPixelFormat); // Slow path + } + return true; #else return false; diff --git a/image/jpeg.h b/image/jpeg.h index ac0d22d129..08b5c01dc4 100644 --- a/image/jpeg.h +++ b/image/jpeg.h @@ -60,11 +60,11 @@ public: // Special API for JPEG enum ColorSpace { /** - * Output 32bit RGBA data. + * Output RGB data in the pixel format specified using `setOutputPixelFormat`. * * This is the default output. */ - kColorSpaceRGBA, + kColorSpaceRGB, /** * Output (interleaved) YUV data. @@ -86,15 +86,25 @@ public: * Request the output color space. This can be used to obtain raw YUV * data from the JPEG file. But this might not work for all files! * - * The decoder itself defaults to RGBA. + * The decoder itself defaults to RGB. * * @param outSpace The color space to output. */ void setOutputColorSpace(ColorSpace outSpace) { _colorSpace = outSpace; } + /** + * Request the output pixel format. The JPEG decoder provides high performance + * color conversion routines for some pixel formats. This setting allows to use + * them and avoid costly subsequent color conversion. + */ + void setOutputPixelFormat(const Graphics::PixelFormat &format) { _requestedPixelFormat = format; } + private: Graphics::Surface _surface; ColorSpace _colorSpace; + Graphics::PixelFormat _requestedPixelFormat; + + Graphics::PixelFormat getByteOrderRgbPixelFormat() const; }; } // End of namespace Image |