Mercurial > mplayer.hg
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 } |