aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Bouclet2017-10-08 08:54:40 +0200
committerBastien Bouclet2017-10-08 08:54:40 +0200
commit6e6fab5b837af2ee9cf7b96d43f6b1ed353405f4 (patch)
tree2db18807a5b52a3bf3a12361dfacbe1ec8dc5a82
parent51275ea7a91880a19c86ac079ab4462c489a5f19 (diff)
downloadscummvm-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.cpp53
-rw-r--r--video/bink_decoder.h5
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.