1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 // Based on the TrueMotion 1 decoder by Alex Beregszaszi & Mike Melanson in FFmpeg
24 
25 #include "common/scummsys.h"
26 #include "image/codecs/truemotion1.h"
27 
28 #ifdef IMAGE_CODECS_TRUEMOTION1_H
29 
30 #include "image/codecs/truemotion1data.h"
31 #include "common/stream.h"
32 #include "common/textconsole.h"
33 #include "common/rect.h"
34 #include "common/util.h"
35 
36 namespace Image {
37 
38 enum {
39 	FLAG_SPRITE = (1 << 5),
40 	FLAG_KEYFRAME = (1 << 4),
41 	FLAG_INTERFRAME = (1 << 3),
42 	FLAG_INTERPOLATED = (1 << 2)
43 };
44 
45 enum {
46 	ALGO_NOP = 0,
47 	ALGO_RGB16V = 1,
48 	ALGO_RGB16H = 2,
49 	ALGO_RGB24H = 3
50 };
51 
52 // these are the various block sizes that can occupy a 4x4 block
53 enum {
54 	BLOCK_2x2 = 0,
55 	BLOCK_2x4 = 1,
56 	BLOCK_4x2 = 2,
57 	BLOCK_4x4 = 3
58 };
59 
60 // { valid for metatype }, algorithm, num of deltas, vert res, horiz res
61 struct CompressionType {
62 	int algorithm;
63 	int blockWidth; // vres
64 	int blockHeight; // hres
65 	int blockType;
66 };
67 
68 static const CompressionType compressionTypes[17] = {
69 	{ ALGO_NOP,	0, 0, 0 },
70 
71 	{ ALGO_RGB16V, 4, 4, BLOCK_4x4 },
72 	{ ALGO_RGB16H, 4, 4, BLOCK_4x4 },
73 	{ ALGO_RGB16V, 4, 2, BLOCK_4x2 },
74 	{ ALGO_RGB16H, 4, 2, BLOCK_4x2 },
75 
76 	{ ALGO_RGB16V, 2, 4, BLOCK_2x4 },
77 	{ ALGO_RGB16H, 2, 4, BLOCK_2x4 },
78 	{ ALGO_RGB16V, 2, 2, BLOCK_2x2 },
79 	{ ALGO_RGB16H, 2, 2, BLOCK_2x2 },
80 
81 	{ ALGO_NOP,	4, 4, BLOCK_4x4 },
82 	{ ALGO_RGB24H, 4, 4, BLOCK_4x4 },
83 	{ ALGO_NOP,	4, 2, BLOCK_4x2 },
84 	{ ALGO_RGB24H, 4, 2, BLOCK_4x2 },
85 
86 	{ ALGO_NOP,	2, 4, BLOCK_2x4 },
87 	{ ALGO_RGB24H, 2, 4, BLOCK_2x4 },
88 	{ ALGO_NOP,	2, 2, BLOCK_2x2 },
89 	{ ALGO_RGB24H, 2, 2, BLOCK_2x2 }
90 };
91 
TrueMotion1Decoder()92 TrueMotion1Decoder::TrueMotion1Decoder() {
93 	_surface = 0;
94 	_vertPred = 0;
95 
96 	_buf = _mbChangeBits = _indexStream = 0;
97 	_lastDeltaset = _lastVectable = -1;
98 }
99 
~TrueMotion1Decoder()100 TrueMotion1Decoder::~TrueMotion1Decoder() {
101 	if (_surface) {
102 		_surface->free();
103 		delete _surface;
104 	}
105 
106 	delete[] _vertPred;
107 }
108 
selectDeltaTables(int deltaTableIndex)109 void TrueMotion1Decoder::selectDeltaTables(int deltaTableIndex) {
110 	if (deltaTableIndex > 3)
111 		return;
112 
113 	for (byte i = 0; i < 8; i++) {
114 		_ydt[i] = ydts[deltaTableIndex][i];
115 		_cdt[i] = cdts[deltaTableIndex][i];
116 
117 		// Y skinny deltas need to be halved for some reason; maybe the
118 		// skinny Y deltas should be modified
119 		// Drop the lsb before dividing by 2-- net effect: round down
120 		// when dividing a negative number (e.g., -3/2 = -2, not -1)
121 		_ydt[i] &= 0xFFFE;
122 		_ydt[i] /= 2;
123 	}
124 }
125 
makeYdt16Entry(int p1,int p2)126 int TrueMotion1Decoder::makeYdt16Entry(int p1, int p2) {
127 #ifdef SCUMM_BIG_ENDIAN
128 	// Swap the values on BE systems. FFmpeg does this too.
129 	SWAP<int>(p1, p2);
130 #endif
131 
132 	int lo = _ydt[p1];
133 	lo += (lo << 6) + (lo << 11);
134 	int hi = _ydt[p2];
135 	hi += (hi << 6) + (hi << 11);
136 	return lo + (hi << 16);
137 }
138 
makeCdt16Entry(int p1,int p2)139 int TrueMotion1Decoder::makeCdt16Entry(int p1, int p2) {
140 	int b = _cdt[p2];
141 	int r = _cdt[p1] << 11;
142 	int lo = b + r;
143 	return lo + (lo << 16);
144 }
145 
genVectorTable16(const byte * selVectorTable)146 void TrueMotion1Decoder::genVectorTable16(const byte *selVectorTable) {
147 	memset(&_yPredictorTable, 0, sizeof(PredictorTableEntry) * 1024);
148 	memset(&_cPredictorTable, 0, sizeof(PredictorTableEntry) * 1024);
149 
150 	for (int i = 0; i < 1024; i += 4) {
151 		int len = *selVectorTable++ / 2;
152 		for (int j = 0; j < len; j++) {
153 			byte deltaPair = *selVectorTable++;
154 			_yPredictorTable[i + j].color = makeYdt16Entry(deltaPair >> 4, deltaPair & 0xf);
155 			_cPredictorTable[i + j].color = makeCdt16Entry(deltaPair >> 4, deltaPair & 0xf);
156 		}
157 
158 		_yPredictorTable[i + (len - 1)].getNextIndex = true;
159 		_cPredictorTable[i + (len - 1)].getNextIndex = true;
160 	}
161 }
162 
decodeHeader(Common::SeekableReadStream & stream)163 void TrueMotion1Decoder::decodeHeader(Common::SeekableReadStream &stream) {
164 	_buf = new byte[stream.size()];
165 	stream.read(_buf, stream.size());
166 
167 	byte headerBuffer[128];  // logical maximum size of the header
168 	const byte *selVectorTable;
169 
170 	_header.headerSize = ((_buf[0] >> 5) | (_buf[0] << 3)) & 0x7f;
171 
172 	if (_buf[0] < 0x10)
173 		error("Invalid TrueMotion1 header size %d", _header.headerSize);
174 
175 	// unscramble the header bytes with a XOR operation
176 	memset(headerBuffer, 0, 128);
177 	for (int i = 1; i < _header.headerSize; i++)
178 		headerBuffer[i - 1] = _buf[i] ^ _buf[i + 1];
179 
180 	_header.compression = headerBuffer[0];
181 	_header.deltaset = headerBuffer[1];
182 	_header.vectable = headerBuffer[2];
183 	_header.ysize = READ_LE_UINT16(&headerBuffer[3]);
184 	_header.xsize = READ_LE_UINT16(&headerBuffer[5]);
185 	_header.checksum = READ_LE_UINT16(&headerBuffer[7]);
186 	_header.version = headerBuffer[9];
187 	_header.headerType = headerBuffer[10];
188 	_header.flags = headerBuffer[11];
189 	_header.control = headerBuffer[12];
190 
191 	if (!_vertPred) {
192 		// there is a vertical predictor for each pixel in a line; each vertical
193 		// predictor is 0 to start with
194 		_vertPred = new uint32[_header.xsize];
195 	}
196 
197 	if (!_surface) {
198 		_surface = new Graphics::Surface();
199 		_surface->create(_header.xsize, _header.ysize, getPixelFormat());
200 	}
201 
202 	// There is 1 change bit per 4 pixels, so each change byte represents
203 	// 32 pixels; divide width by 4 to obtain the number of change bits and
204 	// then round up to the nearest byte.
205 	_mbChangeBitsRowSize = ((_header.xsize >> 2) + 7) >> 3;
206 
207 	// Version 2
208 	if (_header.version >= 2) {
209 		if (_header.headerType > 3) {
210 			error("Invalid header type %d", _header.headerType);
211 		} else if (_header.headerType == 2 || _header.headerType == 3) {
212 			_flags = _header.flags;
213 			if (!(_flags & FLAG_INTERFRAME))
214 				_flags |= FLAG_KEYFRAME;
215 		} else
216 			_flags = FLAG_KEYFRAME;
217 	} else // Version 1
218 		_flags = FLAG_KEYFRAME;
219 
220 	if (_flags & FLAG_SPRITE) {
221 		error("SPRITE frame found, please report the sample to the developers");
222 	} else if (_header.headerType < 2 && _header.xsize < 213 && _header.ysize >= 176) {
223 		_flags |= FLAG_INTERPOLATED;
224 		error("INTERPOLATION selected, please report the sample to the developers");
225 	}
226 
227 	if (_header.compression >= 17)
228 		error("Invalid TrueMotion1 compression type %d", _header.compression);
229 
230 	if (_header.deltaset != _lastDeltaset || _header.vectable != _lastVectable)
231 		selectDeltaTables(_header.deltaset);
232 
233 	if ((_header.compression & 1) && _header.headerType)
234 		selVectorTable = pc_tbl2;
235 	else if (_header.vectable < 4)
236 		selVectorTable = tables[_header.vectable - 1];
237 	else
238 		error("Invalid vector table id %d", _header.vectable);
239 
240 	if (_header.deltaset != _lastDeltaset || _header.vectable != _lastVectable)
241 		genVectorTable16(selVectorTable);
242 
243 	// set up pointers to the other key data chunks
244 	_mbChangeBits = _buf + _header.headerSize;
245 
246 	if (_flags & FLAG_KEYFRAME) {
247 		// no change bits specified for a keyframe; only index bytes
248 		_indexStream = _mbChangeBits;
249 	} else {
250 		// one change bit per 4x4 block
251 		_indexStream = _mbChangeBits + _mbChangeBitsRowSize * (_header.ysize >> 2);
252 	}
253 
254 	_indexStreamSize = stream.size() - (_indexStream - _buf);
255 
256 	_lastDeltaset = _header.deltaset;
257 	_lastVectable = _header.vectable;
258 	_blockWidth = compressionTypes[_header.compression].blockWidth;
259 	_blockHeight = compressionTypes[_header.compression].blockHeight;
260 	_blockType = compressionTypes[_header.compression].blockType;
261 }
262 
263 #define GET_NEXT_INDEX() \
264 do { \
265 	if (indexStreamIndex >= _indexStreamSize) \
266 		error("TrueMotion1 decoder went out of bounds"); \
267 	index = _indexStream[indexStreamIndex++] * 4; \
268 } while (0) \
269 
270 #define APPLY_C_PREDICTOR() \
271 	predictor_pair = _cPredictorTable[index].color; \
272 	horizPred += predictor_pair; \
273 	if (_cPredictorTable[index].getNextIndex) { \
274 		GET_NEXT_INDEX(); \
275 		if (!index) { \
276 			GET_NEXT_INDEX(); \
277 			predictor_pair = _cPredictorTable[index].color; \
278 			horizPred += predictor_pair * 5; \
279 			if (_cPredictorTable[index].getNextIndex) \
280 				GET_NEXT_INDEX(); \
281 			else \
282 				index++; \
283 		} \
284 	} else \
285 		index++
286 
287 #define APPLY_Y_PREDICTOR() \
288 	predictor_pair = _yPredictorTable[index].color; \
289 	horizPred += predictor_pair; \
290 	if (_yPredictorTable[index].getNextIndex) { \
291 		GET_NEXT_INDEX(); \
292 		if (!index) { \
293 			GET_NEXT_INDEX(); \
294 			predictor_pair = _yPredictorTable[index].color; \
295 			horizPred += predictor_pair * 5; \
296 			if (_yPredictorTable[index].getNextIndex) \
297 				GET_NEXT_INDEX(); \
298 			else \
299 				index++; \
300 		} \
301 	} else \
302 		index++
303 
304 #define OUTPUT_PIXEL_PAIR() \
305 	*currentPixelPair = *vertPred + horizPred; \
306 	*vertPred++ = *currentPixelPair++
307 
decode16()308 void TrueMotion1Decoder::decode16() {
309 	uint32 predictor_pair;
310 	bool keyframe = _flags & FLAG_KEYFRAME;
311 	int indexStreamIndex = 0;
312 
313 	// these variables are for managing the main index stream
314 	int index;
315 
316 	// clean out the line buffer
317 	memset(_vertPred, 0, _header.xsize * 4);
318 
319 	GET_NEXT_INDEX();
320 
321 	for (int y = 0; y < _header.ysize; y++) {
322 		// re-init variables for the next line iteration
323 		uint32 horizPred = 0;
324 		uint32 *currentPixelPair = (uint32 *)_surface->getBasePtr(0, y);
325 		uint32 *vertPred = _vertPred;
326 		int mbChangeIndex = 0;
327 		byte mbChangeByte = _mbChangeBits[mbChangeIndex++];
328 		byte mbChangeByteMask = 1;
329 
330 		for (int pixelsLeft = _header.xsize; pixelsLeft > 0; pixelsLeft -= 4) {
331 			if (keyframe || (mbChangeByte & mbChangeByteMask) == 0) {
332 				switch (y & 3) {
333 				case 0:
334 					// if macroblock width is 2, apply C-Y-C-Y; else
335 					// apply C-Y-Y
336 					if (_blockWidth == 2) {
337 						APPLY_C_PREDICTOR();
338 						APPLY_Y_PREDICTOR();
339 						OUTPUT_PIXEL_PAIR();
340 						APPLY_C_PREDICTOR();
341 						APPLY_Y_PREDICTOR();
342 						OUTPUT_PIXEL_PAIR();
343 					} else {
344 						APPLY_C_PREDICTOR();
345 						APPLY_Y_PREDICTOR();
346 						OUTPUT_PIXEL_PAIR();
347 						APPLY_Y_PREDICTOR();
348 						OUTPUT_PIXEL_PAIR();
349 					}
350 					break;
351 				case 1:
352 				case 3:
353 					// always apply 2 Y predictors on these iterations
354 					APPLY_Y_PREDICTOR();
355 					OUTPUT_PIXEL_PAIR();
356 					APPLY_Y_PREDICTOR();
357 					OUTPUT_PIXEL_PAIR();
358 					break;
359 				case 2:
360 					// this iteration might be C-Y-C-Y, Y-Y, or C-Y-Y
361 					// depending on the macroblock type
362 					if (_blockType == BLOCK_2x2) {
363 						APPLY_C_PREDICTOR();
364 						APPLY_Y_PREDICTOR();
365 						OUTPUT_PIXEL_PAIR();
366 						APPLY_C_PREDICTOR();
367 						APPLY_Y_PREDICTOR();
368 						OUTPUT_PIXEL_PAIR();
369 					} else if (_blockType == BLOCK_4x2) {
370 						APPLY_C_PREDICTOR();
371 						APPLY_Y_PREDICTOR();
372 						OUTPUT_PIXEL_PAIR();
373 						APPLY_Y_PREDICTOR();
374 						OUTPUT_PIXEL_PAIR();
375 					} else {
376 						APPLY_Y_PREDICTOR();
377 						OUTPUT_PIXEL_PAIR();
378 						APPLY_Y_PREDICTOR();
379 						OUTPUT_PIXEL_PAIR();
380 					}
381 					break;
382 				}
383 			} else {
384 				// skip (copy) four pixels, but reassign the horizontal
385 				// predictor
386 				*vertPred++ = *currentPixelPair++;
387 				horizPred = *currentPixelPair - *vertPred;
388 				*vertPred++ = *currentPixelPair++;
389 			}
390 
391 			if (!keyframe) {
392 				mbChangeByteMask <<= 1;
393 
394 				// next byte
395 				if (!mbChangeByteMask) {
396 					mbChangeByte = _mbChangeBits[mbChangeIndex++];
397 					mbChangeByteMask = 1;
398 				}
399 			}
400 		}
401 
402 		// next change row
403 		if (((y + 1) & 3) == 0)
404 			_mbChangeBits += _mbChangeBitsRowSize;
405 	}
406 }
407 
decodeFrame(Common::SeekableReadStream & stream)408 const Graphics::Surface *TrueMotion1Decoder::decodeFrame(Common::SeekableReadStream &stream) {
409 	decodeHeader(stream);
410 
411 	if (compressionTypes[_header.compression].algorithm == ALGO_NOP) {
412 		delete[] _buf;
413 		return 0;
414 	}
415 
416 	if (compressionTypes[_header.compression].algorithm == ALGO_RGB24H) {
417 		warning("Unhandled TrueMotion1 24bpp frame");
418 		delete[] _buf;
419 		return 0;
420 	} else
421 		decode16();
422 
423 	delete[] _buf;
424 
425 	return _surface;
426 }
427 
428 } // End of namespace Image
429 
430 #endif
431