comparison libmpcodecs/native/qtsmc.c @ 5602:628c85c15c7b

moved to libmpcodecs/native/
author arpi
date Sat, 13 Apr 2002 18:03:02 +0000
parents qtsmc.c@b3d18d070ec1
children
comparison
equal deleted inserted replaced
5601:fd85802f755b 5602:628c85c15c7b
1 /*
2 Apple Graphics (SMC) Decoder for MPlayer
3 by Mike Melanson
4 Special thanks for Roberto Togni <rtogni@bresciaonline.it> for
5 tracking down the final, nagging bugs.
6
7 The description of the decoding algorithm can be found here:
8 http://www.pcisys.net/~melanson/codecs/
9 */
10
11 #include <stdlib.h>
12 #include "config.h"
13 #include "bswap.h"
14 #include "mp_msg.h"
15
16 #define BE_16(x) (be2me_16(*(unsigned short *)(x)))
17 #define BE_32(x) (be2me_32(*(unsigned int *)(x)))
18
19 #define COLORS_PER_TABLE 256
20 #define BYTES_PER_COLOR 4
21
22 #define CPAIR 2
23 #define CQUAD 4
24 #define COCTET 8
25
26 static unsigned char *color_pairs;
27 static unsigned char *color_quads;
28 static unsigned char *color_octets;
29
30 static int color_pair_index;
31 static int color_quad_index;
32 static int color_octet_index;
33
34 static int smc_initialized;
35
36 // returns 0 if successfully initialized (enough memory was available),
37 // non-zero on failure
38 int qt_init_decode_smc(void)
39 {
40 // be pessimistic to start
41 smc_initialized = 0;
42
43 // allocate memory for the 3 palette tables
44 if ((color_pairs = (unsigned char *)malloc(
45 COLORS_PER_TABLE * BYTES_PER_COLOR * 2)) == 0)
46 return 1;
47 if ((color_quads = (unsigned char *)malloc(
48 COLORS_PER_TABLE * BYTES_PER_COLOR * 4)) == 0)
49 return 1;
50 if ((color_octets = (unsigned char *)malloc(
51 COLORS_PER_TABLE * BYTES_PER_COLOR * 8)) == 0)
52 return 1;
53
54 // if execution got this far, initialization succeeded
55 smc_initialized = 1;
56 return 0;
57 }
58
59 #define GET_BLOCK_COUNT \
60 (opcode & 0x10) ? (1 + encoded[stream_ptr++]) : 1 + (opcode & 0x0F);
61 #define ADVANCE_BLOCK() \
62 { \
63 pixel_ptr += block_x_inc; \
64 if (pixel_ptr >= byte_width) \
65 { \
66 pixel_ptr = 0; \
67 row_ptr += block_y_inc * 4; \
68 } \
69 total_blocks--; \
70 if (total_blocks < 0) \
71 { \
72 mp_msg(MSGT_DECVIDEO, MSGL_WARN, "block counter just went negative (this should not happen)\n"); \
73 return; \
74 } \
75 }
76
77 void qt_decode_smc(
78 unsigned char *encoded,
79 int encoded_size,
80 unsigned char *decoded,
81 int pixel_width,
82 int pixel_height,
83 unsigned char *palette_map,
84 int bytes_per_pixel)
85 {
86 int i;
87 int stream_ptr = 0;
88 int chunk_size;
89 unsigned char opcode;
90 int n_blocks;
91 unsigned int color_flags;
92 unsigned int color_flags_a;
93 unsigned int color_flags_b;
94 unsigned int flag_mask;
95
96 int byte_width = pixel_width * bytes_per_pixel; // width of a row in bytes
97 int byte_height = pixel_height * byte_width; // max image size, basically
98 int row_ptr = 0;
99 int pixel_ptr = 0;
100 int pixel_x, pixel_y;
101 int row_inc = bytes_per_pixel * (pixel_width - 4);
102 int block_x_inc = bytes_per_pixel * 4;
103 int block_y_inc = bytes_per_pixel * pixel_width;
104 int block_ptr;
105 int prev_block_ptr;
106 int prev_block_ptr1, prev_block_ptr2;
107 int prev_block_flag;
108 int total_blocks;
109 int color_table_index; // indexes to color pair, quad, or octet tables
110 int color_index; // indexes into palette map
111
112 if (!smc_initialized)
113 return;
114
115 // reset color tables
116 color_pair_index = 0;
117 color_quad_index = 0;
118 color_octet_index = 0;
119
120 chunk_size = BE_32(&encoded[stream_ptr]) & 0x00FFFFFF;
121 stream_ptr += 4;
122 if (chunk_size != encoded_size)
123 mp_msg(MSGT_DECVIDEO, MSGL_WARN, "MOV chunk size != encoded chunk size; using MOV chunk size\n");
124
125 chunk_size = encoded_size;
126 total_blocks = (pixel_width * pixel_height) / (4 * 4);
127
128 // traverse through the blocks
129 while (total_blocks)
130 {
131 // sanity checks
132 // make sure stream ptr hasn't gone out of bounds
133 if (stream_ptr > chunk_size)
134 {
135 mp_msg(MSGT_DECVIDEO, MSGL_ERR,
136 "SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)\n",
137 stream_ptr, chunk_size);
138 return;
139 }
140 // make sure the row pointer hasn't gone wild
141 if (row_ptr >= byte_height)
142 {
143 mp_msg(MSGT_DECVIDEO, MSGL_ERR,
144 "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
145 row_ptr, byte_height);
146 return;
147 }
148
149 opcode = encoded[stream_ptr++];
150 switch (opcode & 0xF0)
151 {
152 // skip n blocks
153 case 0x00:
154 case 0x10:
155 n_blocks = GET_BLOCK_COUNT;
156 while (n_blocks--)
157 ADVANCE_BLOCK();
158 break;
159
160 // repeat last block n times
161 case 0x20:
162 case 0x30:
163 n_blocks = GET_BLOCK_COUNT;
164
165 // sanity check
166 if ((row_ptr == 0) && (pixel_ptr == 0))
167 {
168 mp_msg(MSGT_DECVIDEO, MSGL_WARN,
169 "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
170 opcode & 0xF0);
171 break;
172 }
173
174 // figure out where the previous block started
175 if (pixel_ptr == 0)
176 prev_block_ptr1 = (row_ptr - block_y_inc * 4) +
177 byte_width - block_x_inc;
178 else
179 prev_block_ptr1 = row_ptr + pixel_ptr - block_x_inc;
180
181 while (n_blocks--)
182 {
183 block_ptr = row_ptr + pixel_ptr;
184 prev_block_ptr = prev_block_ptr1;
185 for (pixel_y = 0; pixel_y < 4; pixel_y++)
186 {
187 for (pixel_x = 0; pixel_x < 4; pixel_x++)
188 {
189 decoded[block_ptr++] = decoded[prev_block_ptr++];
190 decoded[block_ptr++] = decoded[prev_block_ptr++];
191 decoded[block_ptr++] = decoded[prev_block_ptr++];
192 if (bytes_per_pixel == 4) /* 32bpp */
193 {
194 block_ptr++;
195 prev_block_ptr++;
196 }
197 }
198 block_ptr += row_inc;
199 prev_block_ptr += row_inc;
200 }
201 ADVANCE_BLOCK();
202 }
203 break;
204
205 // repeat previous pair of blocks n times
206 case 0x40:
207 case 0x50:
208 n_blocks = GET_BLOCK_COUNT;
209 n_blocks *= 2;
210
211 // sanity check
212 if ((row_ptr == 0) && (pixel_ptr < 2 * block_x_inc))
213 {
214 mp_msg(MSGT_DECVIDEO, MSGL_WARN,
215 "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
216 opcode & 0xF0);
217 break;
218 }
219
220 // figure out where the previous 2 blocks started
221 if (pixel_ptr == 0)
222 prev_block_ptr1 = (row_ptr - block_y_inc * 4) +
223 byte_width - block_x_inc * 2;
224 else if (pixel_ptr == block_x_inc)
225 prev_block_ptr1 = (row_ptr - block_y_inc * 4) +
226 byte_width - block_x_inc;
227 else
228 prev_block_ptr1 = row_ptr + pixel_ptr - block_x_inc * 2;
229
230 if (pixel_ptr == 0)
231 prev_block_ptr2 = (row_ptr - block_y_inc * 4) +
232 (byte_width - block_x_inc);
233 else
234 prev_block_ptr2 = row_ptr + pixel_ptr - block_x_inc;
235
236 prev_block_flag = 0;
237 while (n_blocks--)
238 {
239 block_ptr = row_ptr + pixel_ptr;
240 if (prev_block_flag)
241 prev_block_ptr = prev_block_ptr2;
242 else
243 prev_block_ptr = prev_block_ptr1;
244 prev_block_flag = !prev_block_flag;
245
246 for (pixel_y = 0; pixel_y < 4; pixel_y++)
247 {
248 for (pixel_x = 0; pixel_x < 4; pixel_x++)
249 {
250 decoded[block_ptr++] = decoded[prev_block_ptr++];
251 decoded[block_ptr++] = decoded[prev_block_ptr++];
252 decoded[block_ptr++] = decoded[prev_block_ptr++];
253 if (bytes_per_pixel == 4) /* 32bpp */
254 {
255 block_ptr++;
256 prev_block_ptr++;
257 }
258 }
259 block_ptr += row_inc;
260 prev_block_ptr += row_inc;
261 }
262 ADVANCE_BLOCK();
263 }
264 break;
265
266 // 1-color block encoding
267 case 0x60:
268 case 0x70:
269 n_blocks = GET_BLOCK_COUNT;
270 color_index = encoded[stream_ptr++] * 4;
271
272 while (n_blocks--)
273 {
274 block_ptr = row_ptr + pixel_ptr;
275 for (pixel_y = 0; pixel_y < 4; pixel_y++)
276 {
277 for (pixel_x = 0; pixel_x < 4; pixel_x++)
278 {
279 decoded[block_ptr++] = palette_map[color_index + 0];
280 decoded[block_ptr++] = palette_map[color_index + 1];
281 decoded[block_ptr++] = palette_map[color_index + 2];
282 if (bytes_per_pixel == 4) /* 32bpp */
283 block_ptr++;
284 }
285 block_ptr += row_inc;
286 }
287 ADVANCE_BLOCK();
288 }
289 break;
290
291 // 2-color block encoding
292 case 0x80:
293 case 0x90:
294 n_blocks = (opcode & 0x0F) + 1;
295
296 // figure out which color pair to use to paint the 2-color block
297 if ((opcode & 0xF0) == 0x80)
298 {
299 // fetch the next 2 colors from bytestream and store in next
300 // available entry in the color pair table
301 for (i = 0; i < CPAIR; i++)
302 {
303 color_index = encoded[stream_ptr++] * BYTES_PER_COLOR;
304 color_table_index = CPAIR * BYTES_PER_COLOR * color_pair_index +
305 (i * BYTES_PER_COLOR);
306 color_pairs[color_table_index + 0] = palette_map[color_index + 0];
307 color_pairs[color_table_index + 1] = palette_map[color_index + 1];
308 color_pairs[color_table_index + 2] = palette_map[color_index + 2];
309 }
310 // this is the base index to use for this block
311 color_table_index = CPAIR * BYTES_PER_COLOR * color_pair_index;
312 color_pair_index++;
313 if (color_pair_index == COLORS_PER_TABLE)
314 color_pair_index = 0;
315 }
316 else
317 color_table_index = CPAIR * BYTES_PER_COLOR * encoded[stream_ptr++];
318
319 while (n_blocks--)
320 {
321 color_flags = BE_16(&encoded[stream_ptr]);
322 stream_ptr += 2;
323 flag_mask = 0x8000;
324 block_ptr = row_ptr + pixel_ptr;
325 for (pixel_y = 0; pixel_y < 4; pixel_y++)
326 {
327 for (pixel_x = 0; pixel_x < 4; pixel_x++)
328 {
329 if (color_flags & flag_mask)
330 color_index = color_table_index + BYTES_PER_COLOR;
331 else
332 color_index = color_table_index;
333 flag_mask >>= 1;
334
335 decoded[block_ptr++] = color_pairs[color_index + 0];
336 decoded[block_ptr++] = color_pairs[color_index + 1];
337 decoded[block_ptr++] = color_pairs[color_index + 2];
338 if (bytes_per_pixel == 4) /* 32bpp */
339 block_ptr++;
340 }
341 block_ptr += row_inc;
342 }
343 ADVANCE_BLOCK();
344 }
345 break;
346
347 // 4-color block encoding
348 case 0xA0:
349 case 0xB0:
350 n_blocks = (opcode & 0x0F) + 1;
351
352 // figure out which color quad to use to paint the 4-color block
353 if ((opcode & 0xF0) == 0xA0)
354 {
355 // fetch the next 4 colors from bytestream and store in next
356 // available entry in the color quad table
357 for (i = 0; i < CQUAD; i++)
358 {
359 color_index = encoded[stream_ptr++] * BYTES_PER_COLOR;
360 color_table_index = CQUAD * BYTES_PER_COLOR * color_quad_index +
361 (i * BYTES_PER_COLOR);
362 color_quads[color_table_index + 0] = palette_map[color_index + 0];
363 color_quads[color_table_index + 1] = palette_map[color_index + 1];
364 color_quads[color_table_index + 2] = palette_map[color_index + 2];
365 }
366 // this is the base index to use for this block
367 color_table_index = CQUAD * BYTES_PER_COLOR * color_quad_index;
368 color_quad_index++;
369 if (color_quad_index == COLORS_PER_TABLE)
370 color_quad_index = 0;
371 }
372 else
373 color_table_index = CQUAD * BYTES_PER_COLOR * encoded[stream_ptr++];
374
375 while (n_blocks--)
376 {
377 color_flags = BE_32(&encoded[stream_ptr]);
378 stream_ptr += 4;
379 // flag mask actually acts as a bit shift count here
380 flag_mask = 30;
381 block_ptr = row_ptr + pixel_ptr;
382 for (pixel_y = 0; pixel_y < 4; pixel_y++)
383 {
384 for (pixel_x = 0; pixel_x < 4; pixel_x++)
385 {
386 color_index = color_table_index + (BYTES_PER_COLOR *
387 ((color_flags >> flag_mask) & 0x03));
388 flag_mask -= 2;
389
390 decoded[block_ptr++] = color_quads[color_index + 0];
391 decoded[block_ptr++] = color_quads[color_index + 1];
392 decoded[block_ptr++] = color_quads[color_index + 2];
393 if (bytes_per_pixel == 4) /* 32bpp */
394 block_ptr++;
395 }
396 block_ptr += row_inc;
397 }
398 ADVANCE_BLOCK();
399 }
400 break;
401
402 // 8-color block encoding
403 case 0xC0:
404 case 0xD0:
405 n_blocks = (opcode & 0x0F) + 1;
406
407 // figure out which color octet to use to paint the 8-color block
408 if ((opcode & 0xF0) == 0xC0)
409 {
410 // fetch the next 8 colors from bytestream and store in next
411 // available entry in the color octet table
412 for (i = 0; i < COCTET; i++)
413 {
414 color_index = encoded[stream_ptr++] * BYTES_PER_COLOR;
415 color_table_index = COCTET * BYTES_PER_COLOR * color_octet_index +
416 (i * BYTES_PER_COLOR);
417 color_octets[color_table_index + 0] = palette_map[color_index + 0];
418 color_octets[color_table_index + 1] = palette_map[color_index + 1];
419 color_octets[color_table_index + 2] = palette_map[color_index + 2];
420 }
421 // this is the base index to use for this block
422 color_table_index = COCTET * BYTES_PER_COLOR * color_octet_index;
423 color_octet_index++;
424 if (color_octet_index == COLORS_PER_TABLE)
425 color_octet_index = 0;
426 }
427 else
428 color_table_index = COCTET * BYTES_PER_COLOR * encoded[stream_ptr++];
429
430 while (n_blocks--)
431 {
432 /*
433 For this input:
434 01 23 45 67 89 AB
435 This is the output:
436 flags_a = xx012456, flags_b = xx89A37B
437 */
438 // build the color flags
439 color_flags_a = color_flags_b = 0;
440 color_flags_a =
441 (encoded[stream_ptr + 0] << 16) |
442 ((encoded[stream_ptr + 1] & 0xF0) << 8) |
443 ((encoded[stream_ptr + 2] & 0xF0) << 4) |
444 ((encoded[stream_ptr + 2] & 0x0F) << 4) |
445 ((encoded[stream_ptr + 3] & 0xF0) >> 4);
446 color_flags_b =
447 (encoded[stream_ptr + 4] << 16) |
448 ((encoded[stream_ptr + 5] & 0xF0) << 8) |
449 ((encoded[stream_ptr + 1] & 0x0F) << 8) |
450 ((encoded[stream_ptr + 3] & 0x0F) << 4) |
451 (encoded[stream_ptr + 5] & 0x0F);
452 stream_ptr += 6;
453
454 color_flags = color_flags_a;
455 // flag mask actually acts as a bit shift count here
456 flag_mask = 21;
457 block_ptr = row_ptr + pixel_ptr;
458 for (pixel_y = 0; pixel_y < 4; pixel_y++)
459 {
460 // reload flags at third row (iteration pixel_y == 2)
461 if (pixel_y == 2)
462 {
463 color_flags = color_flags_b;
464 flag_mask = 21;
465 }
466 for (pixel_x = 0; pixel_x < 4; pixel_x++)
467 {
468 color_index = color_table_index + (BYTES_PER_COLOR *
469 ((color_flags >> flag_mask) & 0x07));
470 flag_mask -= 3;
471
472 decoded[block_ptr++] = color_octets[color_index + 0];
473 decoded[block_ptr++] = color_octets[color_index + 1];
474 decoded[block_ptr++] = color_octets[color_index + 2];
475 if (bytes_per_pixel == 4) /* 32bpp */
476 block_ptr++;
477 }
478 block_ptr += row_inc;
479 }
480 ADVANCE_BLOCK();
481 }
482 break;
483
484 // 16-color block encoding (every pixel is a different color)
485 case 0xE0:
486 n_blocks = (opcode & 0x0F) + 1;
487
488 while (n_blocks--)
489 {
490 block_ptr = row_ptr + pixel_ptr;
491 for (pixel_y = 0; pixel_y < 4; pixel_y++)
492 {
493 for (pixel_x = 0; pixel_x < 4; pixel_x++)
494 {
495 color_index = encoded[stream_ptr++] * BYTES_PER_COLOR;
496 decoded[block_ptr++] = palette_map[color_index + 0];
497 decoded[block_ptr++] = palette_map[color_index + 1];
498 decoded[block_ptr++] = palette_map[color_index + 2];
499 if (bytes_per_pixel == 4) /* 32bpp */
500 block_ptr++;
501 }
502 block_ptr += row_inc;
503 }
504 ADVANCE_BLOCK();
505 }
506 break;
507
508 case 0xF0:
509 mp_msg(MSGT_DECVIDEO, MSGL_HINT, "0xF0 opcode seen in SMC chunk (MPlayer developers would like to know)\n");
510 break;
511 }
512 }
513 }