IMAGE: Defer creation of surface until decodeFrame() is called in Indeo codecs

This commit is contained in:
Cameron Cawley 2023-02-22 21:01:34 +00:00 committed by Eugene Sandulenko
parent d90d7a72b6
commit 78faa2ae28
6 changed files with 54 additions and 31 deletions

View File

@ -463,7 +463,10 @@ IVI45DecContext::IVI45DecContext() : _gb(nullptr), _frameNum(0), _frameType(0),
/*------------------------------------------------------------------------*/
IndeoDecoderBase::IndeoDecoderBase(uint16 width, uint16 height, uint bitsPerPixel) : Codec() {
IndeoDecoderBase::IndeoDecoderBase(uint16 width, uint16 height, uint bitsPerPixel) : Codec(), _surface(nullptr) {
_width = width;
_height = height;
_bitsPerPixel = bitsPerPixel;
_pixelFormat = g_system->getScreenFormat();
if (_pixelFormat.bytesPerPixel == 1) {
@ -486,13 +489,15 @@ IndeoDecoderBase::IndeoDecoderBase(uint16 width, uint16 height, uint bitsPerPixe
}
}
_surface.create(width, height, _pixelFormat);
_surface.fillRect(Common::Rect(0, 0, width, height), (bitsPerPixel == 32) ? 0xff : 0);
_ctx._bRefBuf = 3; // buffer 2 is used for scalability mode
}
IndeoDecoderBase::~IndeoDecoderBase() {
_surface.free();
if (_surface) {
_surface->free();
delete _surface;
_surface = nullptr;
}
IVIPlaneDesc::freeBuffers(_ctx._planes);
if (_ctx._mbVlc._custTab._table)
_ctx._mbVlc._custTab.freeVlc();
@ -507,6 +512,12 @@ int IndeoDecoderBase::decodeIndeoFrame() {
AVFrame frameData;
AVFrame *frame = &frameData;
if (!_surface) {
_surface = new Graphics::Surface;
_surface->create(_width, _height, _pixelFormat);
_surface->fillRect(Common::Rect(0, 0, _width, _height), (_bitsPerPixel == 32) ? 0xff : 0);
}
// Decode the header
if (decodePictureHeader() < 0)
return -1;
@ -562,7 +573,7 @@ int IndeoDecoderBase::decodeIndeoFrame() {
if (!isNonNullFrame())
return 0;
assert(_ctx._planes[0]._width <= _surface.w && _ctx._planes[0]._height <= _surface.h);
assert(_ctx._planes[0]._width <= _surface->w && _ctx._planes[0]._height <= _surface->h);
result = frame->setDimensions(_ctx._planes[0]._width, _ctx._planes[0]._height);
if (result < 0)
return result;
@ -583,7 +594,7 @@ int IndeoDecoderBase::decodeIndeoFrame() {
outputPlane(&_ctx._planes[1], frame->_data[2], frame->_linesize[2]);
// Merge the planes into the final surface
YUVToRGBMan.convert410(&_surface, Graphics::YUVToRGBManager::kScaleITU,
YUVToRGBMan.convert410(_surface, Graphics::YUVToRGBManager::kScaleITU,
frame->_data[0], frame->_data[1], frame->_data[2], frame->_width, frame->_height,
frame->_width, frame->_width);

View File

@ -518,8 +518,11 @@ private:
int blkSize);
protected:
IVI45DecContext _ctx;
uint16 _width;
uint16 _height;
uint _bitsPerPixel;
Graphics::PixelFormat _pixelFormat;
Graphics::Surface _surface;
Graphics::Surface *_surface;
/**
* Scan patterns shared between indeo4 and indeo5

View File

@ -39,10 +39,12 @@
namespace Image {
Indeo3Decoder::Indeo3Decoder(uint16 width, uint16 height, uint bitsPerPixel) : _ModPred(0), _corrector_type(0) {
Indeo3Decoder::Indeo3Decoder(uint16 width, uint16 height, uint bitsPerPixel) : _surface(nullptr), _ModPred(0), _corrector_type(0) {
_iv_frame[0].the_buf = 0;
_iv_frame[1].the_buf = 0;
_width = width;
_height = height;
_pixelFormat = g_system->getScreenFormat();
if (_pixelFormat.bytesPerPixel == 1) {
@ -65,16 +67,16 @@ Indeo3Decoder::Indeo3Decoder(uint16 width, uint16 height, uint bitsPerPixel) : _
}
}
_surface = new Graphics::Surface;
_surface->create(width, height, _pixelFormat);
buildModPred();
allocFrames();
}
Indeo3Decoder::~Indeo3Decoder() {
_surface->free();
delete _surface;
if (_surface) {
_surface->free();
delete _surface;
_surface = nullptr;
}
delete[] _iv_frame[0].the_buf;
delete[] _ModPred;
@ -134,8 +136,8 @@ void Indeo3Decoder::buildModPred() {
}
void Indeo3Decoder::allocFrames() {
int32 luma_width = (_surface->w + 3) & (~3);
int32 luma_height = (_surface->h + 3) & (~3);
int32 luma_width = (_width + 3) & (~3);
int32 luma_height = (_height + 3) & (~3);
int32 chroma_width = ((luma_width >> 2) + 3) & (~3);
int32 chroma_height = ((luma_height >> 2) + 3) & (~3);
@ -211,6 +213,11 @@ const Graphics::Surface *Indeo3Decoder::decodeFrame(Common::SeekableReadStream &
_ref_frame = _iv_frame + 1;
}
if (!_surface) {
_surface = new Graphics::Surface;
_surface->create(_width, _height, _pixelFormat);
}
if (flags3 == 0x80)
return _surface;

View File

@ -56,6 +56,8 @@ public:
private:
Graphics::Surface *_surface;
uint16 _width;
uint16 _height;
Graphics::PixelFormat _pixelFormat;
static const int _corrector_type_0[24];

View File

@ -88,7 +88,7 @@ const Graphics::Surface *Indeo4Decoder::decodeFrame(Common::SeekableReadStream &
_ctx._frameData = nullptr;
_ctx._frameSize = 0;
return (err < 0) ? nullptr : &_surface;
return (err < 0) ? nullptr : _surface;
}
int Indeo4Decoder::decodePictureHeader() {
@ -111,11 +111,11 @@ int Indeo4Decoder::decodePictureHeader() {
_ctx._hasBFrames = true;
_ctx._hasTransp = _ctx._gb->getBit();
if (_ctx._hasTransp && _surface.format.aBits() == 0) {
if (_ctx._hasTransp && _surface->format.aBits() == 0) {
// Surface is 4 bytes per pixel, but only RGB. So promote the
// surface to full RGBA, and convert all the existing pixels
_pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
_surface.convertToInPlace(_pixelFormat);
_surface->convertToInPlace(_pixelFormat);
}
// unknown bit: Mac decoder ignores this bit, XANIM returns error
@ -610,16 +610,16 @@ int Indeo4Decoder::decodeRLETransparency(VLC_TYPE (*table)[2]) {
bool runIsOpaque = _ctx._gb->getBit();
bool nextRunIsOpaque = !runIsOpaque;
uint32 *pixel = (uint32 *)_surface.getPixels();
const int surfacePixelPitch = _surface.pitch / _surface.format.bytesPerPixel;
const int surfacePadding = surfacePixelPitch - _surface.w;
const uint32 *endOfVisibleRow = pixel + _surface.w;
const uint32 *endOfVisibleArea = pixel + surfacePixelPitch * _surface.h - surfacePadding;
uint32 *pixel = (uint32 *)_surface->getPixels();
const int surfacePixelPitch = _surface->pitch / _surface->format.bytesPerPixel;
const int surfacePadding = surfacePixelPitch - _surface->w;
const uint32 *endOfVisibleRow = pixel + _surface->w;
const uint32 *endOfVisibleArea = pixel + surfacePixelPitch * _surface->h - surfacePadding;
const int codecAlignedWidth = (_surface.w + 31) & ~31;
const int codecPaddingSize = codecAlignedWidth - _surface.w;
const int codecAlignedWidth = (_surface->w + 31) & ~31;
const int codecPaddingSize = codecAlignedWidth - _surface->w;
int numPixelsToRead = codecAlignedWidth * _surface.h;
int numPixelsToRead = codecAlignedWidth * _surface->h;
int numPixelsToSkip = 0;
while (numPixelsToRead > 0) {
int value = _ctx._gb->getVLC2<1, IVI_VLC_BITS>(table);
@ -716,7 +716,7 @@ int Indeo4Decoder::decodeTransparency() {
if (_ctx._gb->getBit()) { /* @350 */
/* @358 */
_ctx._transKeyColor = _surface.format.ARGBToColor(0, _ctx._gb->getBits<8>(), _ctx._gb->getBits<8>(), _ctx._gb->getBits<8>());
_ctx._transKeyColor = _surface->format.ARGBToColor(0, _ctx._gb->getBits<8>(), _ctx._gb->getBits<8>(), _ctx._gb->getBits<8>());
debug(4, "Indeo4: Key color is %08x", _ctx._transKeyColor);
/* @477 */
}
@ -767,8 +767,8 @@ int Indeo4Decoder::decodeTransparency() {
// necessary for correct decoding of game videos.
assert(!_ctx._usesTiling);
assert(_surface.format.bytesPerPixel == 4);
assert((_surface.pitch % 4) == 0);
assert(_surface->format.bytesPerPixel == 4);
assert((_surface->pitch % 4) == 0);
const uint32 startByte = _ctx._gb->pos() / 8;
@ -781,7 +781,7 @@ int Indeo4Decoder::decodeTransparency() {
// It should only be necessary to draw transparency here since the
// data from the YUV planes gets drawn to the output surface on each
// frame, which resets the surface pixels to be fully opaque
_surface.fillRect(Common::Rect(_surface.w, _surface.h), _ctx._transKeyColor);
_surface->fillRect(Common::Rect(_surface->w, _surface->h), _ctx._transKeyColor);
}
// No alignment here

View File

@ -96,7 +96,7 @@ const Graphics::Surface *Indeo5Decoder::decodeFrame(Common::SeekableReadStream &
_ctx._frameData = nullptr;
_ctx._frameSize = 0;
return (err < 0) ? nullptr : &_surface;
return (err < 0) ? nullptr : _surface;
}
int Indeo5Decoder::decodePictureHeader() {