diff options
author | Bastien Bouclet | 2017-10-08 08:54:40 +0200 |
---|---|---|
committer | Bastien Bouclet | 2017-10-08 08:54:40 +0200 |
commit | 6e6fab5b837af2ee9cf7b96d43f6b1ed353405f4 (patch) | |
tree | 2db18807a5b52a3bf3a12361dfacbe1ec8dc5a82 | |
parent | 51275ea7a91880a19c86ac079ab4462c489a5f19 (diff) | |
download | scummvm-rg350-6e6fab5b837af2ee9cf7b96d43f6b1ed353405f4.tar.gz scummvm-rg350-6e6fab5b837af2ee9cf7b96d43f6b1ed353405f4.tar.bz2 scummvm-rg350-6e6fab5b837af2ee9cf7b96d43f6b1ed353405f4.zip |
VIDEO: BINK: Fix plane data clobbering caused by incorrect pitch value
When decoding blocks, the YUV planes' pitches were computed using the
target video surface size instead of the block based size, resulting in
decoded plane data being overwritten for some video sizes.
Affected videos are LEOS-11102.bik and LEOS-11152.bik from Myst III.
-rw-r--r-- | video/bink_decoder.cpp | 53 | ||||
-rw-r--r-- | video/bink_decoder.h | 5 |
2 files changed, 33 insertions, 25 deletions
diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index 7f2bedfbf4..fbf75b48ee 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -286,28 +286,31 @@ BinkDecoder::BinkVideoTrack::BinkVideoTrack(uint32 width, uint32 height, const G _surface.h = height; _surface.w = width; - // Give the planes a bit extra space - width = _surface.w + 32; - height = _surface.h + 32; - - _curPlanes[0] = new byte[ width * height ]; // Y - _curPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution - _curPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution - _curPlanes[3] = new byte[ width * height ]; // A - _oldPlanes[0] = new byte[ width * height ]; // Y - _oldPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution - _oldPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution - _oldPlanes[3] = new byte[ width * height ]; // A + // Compute the video dimensions in blocks + _yBlockWidth = (width + 7) >> 3; + _yBlockHeight = (height + 7) >> 3; + _uvBlockWidth = (width + 15) >> 4; + _uvBlockHeight = (height + 15) >> 4; + + // The planes are sized according to the number of blocks + _curPlanes[0] = new byte[_yBlockWidth * 8 * _yBlockHeight * 8]; // Y + _curPlanes[1] = new byte[_uvBlockWidth * 8 * _uvBlockHeight * 8]; // U, 1/4 resolution + _curPlanes[2] = new byte[_uvBlockWidth * 8 * _uvBlockHeight * 8]; // V, 1/4 resolution + _curPlanes[3] = new byte[_yBlockWidth * 8 * _yBlockHeight * 8]; // A + _oldPlanes[0] = new byte[_yBlockWidth * 8 * _yBlockHeight * 8]; // Y + _oldPlanes[1] = new byte[_uvBlockWidth * 8 * _uvBlockHeight * 8]; // U, 1/4 resolution + _oldPlanes[2] = new byte[_uvBlockWidth * 8 * _uvBlockHeight * 8]; // V, 1/4 resolution + _oldPlanes[3] = new byte[_yBlockWidth * 8 * _yBlockHeight * 8]; // A // Initialize the video with solid black - memset(_curPlanes[0], 0, width * height ); - memset(_curPlanes[1], 0, (width >> 1) * (height >> 1)); - memset(_curPlanes[2], 0, (width >> 1) * (height >> 1)); - memset(_curPlanes[3], 255, width * height ); - memset(_oldPlanes[0], 0, width * height ); - memset(_oldPlanes[1], 0, (width >> 1) * (height >> 1)); - memset(_oldPlanes[2], 0, (width >> 1) * (height >> 1)); - memset(_oldPlanes[3], 255, width * height ); + memset(_curPlanes[0], 0, _yBlockWidth * 8 * _yBlockHeight * 8); + memset(_curPlanes[1], 0, _uvBlockWidth * 8 * _uvBlockHeight * 8); + memset(_curPlanes[2], 0, _uvBlockWidth * 8 * _uvBlockHeight * 8); + memset(_curPlanes[3], 255, _yBlockWidth * 8 * _yBlockHeight * 8); + memset(_oldPlanes[0], 0, _yBlockWidth * 8 * _yBlockHeight * 8); + memset(_oldPlanes[1], 0, _uvBlockWidth * 8 * _uvBlockHeight * 8); + memset(_oldPlanes[2], 0, _uvBlockWidth * 8 * _uvBlockHeight * 8); + memset(_oldPlanes[3], 255, _yBlockWidth * 8 * _yBlockHeight * 8); initBundles(); initHuffman(); @@ -357,7 +360,7 @@ void BinkDecoder::BinkVideoTrack::decodePacket(VideoFrame &frame) { // to allow for odd-sized videos. assert(_curPlanes[0] && _curPlanes[1] && _curPlanes[2]); YUVToRGBMan.convert420(&_surface, Graphics::YUVToRGBManager::kScaleITU, _curPlanes[0], _curPlanes[1], _curPlanes[2], - _surfaceWidth, _surfaceHeight, _surfaceWidth, _surfaceWidth >> 1); + _surfaceWidth, _surfaceHeight, _yBlockWidth * 8, _uvBlockWidth * 8); // And swap the planes with the reference planes for (int i = 0; i < 4; i++) @@ -367,10 +370,10 @@ void BinkDecoder::BinkVideoTrack::decodePacket(VideoFrame &frame) { } void BinkDecoder::BinkVideoTrack::decodePlane(VideoFrame &video, int planeIdx, bool isChroma) { - uint32 blockWidth = isChroma ? ((_surface.w + 15) >> 4) : ((_surface.w + 7) >> 3); - uint32 blockHeight = isChroma ? ((_surface.h + 15) >> 4) : ((_surface.h + 7) >> 3); - uint32 width = isChroma ? (_surface.w >> 1) : _surface.w; - uint32 height = isChroma ? (_surface.h >> 1) : _surface.h; + uint32 blockWidth = isChroma ? _uvBlockWidth : _yBlockWidth; + uint32 blockHeight = isChroma ? _uvBlockHeight : _yBlockHeight; + uint32 width = blockWidth * 8; + uint32 height = blockHeight * 8; DecodeContext ctx; diff --git a/video/bink_decoder.h b/video/bink_decoder.h index 8a67913a03..68dd994115 100644 --- a/video/bink_decoder.h +++ b/video/bink_decoder.h @@ -254,6 +254,11 @@ private: /** Value of the last decoded high nibble in color data types. */ int _colLastVal; + uint32 _yBlockWidth; ///< Width of the Y plane in blocks + uint32 _yBlockHeight; ///< Height of the Y plane in blocks + uint32 _uvBlockWidth; ///< Width of the U and V planes in blocks + uint32 _uvBlockHeight; ///< Height of the U and V planes in blocks + byte *_curPlanes[4]; ///< The 4 color planes, YUVA, current frame. byte *_oldPlanes[4]; ///< The 4 color planes, YUVA, last frame. |