]> git.sesse.net Git - ffmpeg/blob - libavcodec/smc.c
watch those hard tabs
[ffmpeg] / libavcodec / smc.c
1 /*
2  * Quicktime Graphics (SMC) Video Decoder
3  * Copyright (C) 2003 the ffmpeg project
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 /**
22  * @file smc.c
23  * QT SMC Video Decoder by Mike Melanson (melanson@pcisys.net)
24  * For more information about the SMC format, visit:
25  *   http://www.pcisys.net/~melanson/codecs/
26  *
27  * The SMC decoder outputs PAL8 colorspace data.
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34
35 #include "common.h"
36 #include "avcodec.h"
37 #include "dsputil.h"
38
39 #define CPAIR 2
40 #define CQUAD 4
41 #define COCTET 8
42
43 #define COLORS_PER_TABLE 256
44
45 typedef struct SmcContext {
46
47     AVCodecContext *avctx;
48     DSPContext dsp;
49     AVFrame frame;
50
51     unsigned char *buf;
52     int size;
53
54     /* SMC color tables */
55     unsigned char color_pairs[COLORS_PER_TABLE * CPAIR];
56     unsigned char color_quads[COLORS_PER_TABLE * CQUAD];
57     unsigned char color_octets[COLORS_PER_TABLE * COCTET];
58
59 } SmcContext;
60
61 #define BE_16(x)  ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])
62 #define BE_32(x)  ((((uint8_t*)(x))[0] << 24) | \
63                    (((uint8_t*)(x))[1] << 16) | \
64                    (((uint8_t*)(x))[2] << 8) | \
65                     ((uint8_t*)(x))[3])
66 #define GET_BLOCK_COUNT() \
67   (opcode & 0x10) ? (1 + s->buf[stream_ptr++]) : 1 + (opcode & 0x0F);
68
69 #define ADVANCE_BLOCK() \
70 { \
71     pixel_ptr += 4; \
72     if (pixel_ptr >= width) \
73     { \
74         pixel_ptr = 0; \
75         row_ptr += stride * 4; \
76     } \
77     total_blocks--; \
78     if (total_blocks < 0) \
79     { \
80         printf("warning: block counter just went negative (this should not happen)\n"); \
81         return; \
82     } \
83 }
84
85 static void smc_decode_stream(SmcContext *s)
86 {
87     int width = s->avctx->width;
88     int height = s->avctx->height;
89     int stride = s->frame.linesize[0];
90     int i;
91     int stream_ptr = 0;
92     int chunk_size;
93     unsigned char opcode;
94     int n_blocks;
95     unsigned int color_flags;
96     unsigned int color_flags_a;
97     unsigned int color_flags_b;
98     unsigned int flag_mask;
99
100     unsigned char *pixels = s->frame.data[0];
101
102     int image_size = height * s->frame.linesize[0];
103     int row_ptr = 0;
104     int pixel_ptr = 0;
105     int pixel_x, pixel_y;
106     int row_inc = stride - 4;
107     int block_ptr;
108     int prev_block_ptr;
109     int prev_block_ptr1, prev_block_ptr2;
110     int prev_block_flag;
111     int total_blocks;
112     int color_table_index;  /* indexes to color pair, quad, or octet tables */
113     int pixel;
114
115     int color_pair_index = 0;
116     int color_quad_index = 0;
117     int color_octet_index = 0;
118
119     /* make the palette available */
120     memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
121     if (s->avctx->palctrl->palette_changed) {
122         s->frame.palette_has_changed = 1;
123         s->avctx->palctrl->palette_changed = 0;
124     }
125
126     chunk_size = BE_32(&s->buf[stream_ptr]) & 0x00FFFFFF;
127     stream_ptr += 4;
128     if (chunk_size != s->size)
129         printf("warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
130             chunk_size, s->size);
131
132     chunk_size = s->size;
133     total_blocks = (s->avctx->width * s->avctx->height) / (4 * 4);
134
135     /* traverse through the blocks */
136     while (total_blocks) {
137         /* sanity checks */
138         /* make sure stream ptr hasn't gone out of bounds */
139         if (stream_ptr > chunk_size) {
140             printf("SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)\n",
141                 stream_ptr, chunk_size);
142             return;
143         }
144         /* make sure the row pointer hasn't gone wild */
145         if (row_ptr >= image_size) {
146             printf("SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
147                 row_ptr, image_size);
148             return;
149         }
150
151         opcode = s->buf[stream_ptr++];
152         switch (opcode & 0xF0) {
153         /* skip n blocks */
154         case 0x00:
155         case 0x10:
156             n_blocks = GET_BLOCK_COUNT();
157             while (n_blocks--) {
158                 ADVANCE_BLOCK();
159             }
160             break;
161
162         /* repeat last block n times */
163         case 0x20:
164         case 0x30:
165             n_blocks = GET_BLOCK_COUNT();
166
167             /* sanity check */
168             if ((row_ptr == 0) && (pixel_ptr == 0)) {
169                 printf("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 = 
177                     (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
178             else
179                 prev_block_ptr1 = row_ptr + pixel_ptr - 4;
180
181             while (n_blocks--) {
182                 block_ptr = row_ptr + pixel_ptr;
183                 prev_block_ptr = prev_block_ptr1;
184                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
185                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
186                         pixels[block_ptr++] = pixels[prev_block_ptr++];
187                     }
188                     block_ptr += row_inc;
189                     prev_block_ptr += row_inc;
190                 }
191                 ADVANCE_BLOCK();
192             }
193             break;
194
195         /* repeat previous pair of blocks n times */
196         case 0x40:
197         case 0x50:
198             n_blocks = GET_BLOCK_COUNT();
199             n_blocks *= 2;
200
201             /* sanity check */
202             if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
203                 printf("encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
204                     opcode & 0xF0);
205                 break;
206             }
207
208             /* figure out where the previous 2 blocks started */
209             if (pixel_ptr == 0)
210                 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + 
211                     s->avctx->width - 4 * 2;
212             else if (pixel_ptr == 4)
213                 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
214             else
215                 prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
216
217             if (pixel_ptr == 0)
218                 prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
219             else
220                 prev_block_ptr2 = row_ptr + pixel_ptr - 4;
221
222             prev_block_flag = 0;
223             while (n_blocks--) {
224                 block_ptr = row_ptr + pixel_ptr;
225                 if (prev_block_flag)
226                     prev_block_ptr = prev_block_ptr2;
227                 else
228                     prev_block_ptr = prev_block_ptr1;
229                 prev_block_flag = !prev_block_flag;
230
231                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
232                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
233                         pixels[block_ptr++] = pixels[prev_block_ptr++];
234                     }
235                     block_ptr += row_inc;
236                     prev_block_ptr += row_inc;
237                 }
238                 ADVANCE_BLOCK();
239             }
240             break;
241
242         /* 1-color block encoding */
243         case 0x60:
244         case 0x70:
245             n_blocks = GET_BLOCK_COUNT();
246             pixel = s->buf[stream_ptr++];
247
248             while (n_blocks--) {
249                 block_ptr = row_ptr + pixel_ptr;
250                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
251                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
252                         pixels[block_ptr++] = pixel;
253                     }
254                     block_ptr += row_inc;
255                 }
256                 ADVANCE_BLOCK();
257             }
258             break;
259
260         /* 2-color block encoding */
261         case 0x80:
262         case 0x90:
263             n_blocks = (opcode & 0x0F) + 1;
264
265             /* figure out which color pair to use to paint the 2-color block */
266             if ((opcode & 0xF0) == 0x80) {
267                 /* fetch the next 2 colors from bytestream and store in next
268                  * available entry in the color pair table */
269                 for (i = 0; i < CPAIR; i++) {
270                     pixel = s->buf[stream_ptr++];
271                     color_table_index = CPAIR * color_pair_index + i;
272                     s->color_pairs[color_table_index] = pixel;
273                 }
274                 /* this is the base index to use for this block */
275                 color_table_index = CPAIR * color_pair_index;
276                 color_pair_index++;
277                 /* wraparound */
278                 if (color_pair_index == COLORS_PER_TABLE)
279                     color_pair_index = 0;
280             } else
281                 color_table_index = CPAIR * s->buf[stream_ptr++];
282
283             while (n_blocks--) {
284                 color_flags = BE_16(&s->buf[stream_ptr]);
285                 stream_ptr += 2;
286                 flag_mask = 0x8000;
287                 block_ptr = row_ptr + pixel_ptr;
288                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
289                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
290                         if (color_flags & flag_mask)
291                             pixel = color_table_index + 1;
292                         else
293                             pixel = color_table_index;
294                         flag_mask >>= 1;
295                         pixels[block_ptr++] = s->color_pairs[pixel];
296                     }
297                     block_ptr += row_inc;
298                 }
299                 ADVANCE_BLOCK();
300             }
301             break;
302
303         /* 4-color block encoding */
304         case 0xA0:
305         case 0xB0:
306             n_blocks = (opcode & 0x0F) + 1;
307
308             /* figure out which color quad to use to paint the 4-color block */
309             if ((opcode & 0xF0) == 0xA0) {
310                 /* fetch the next 4 colors from bytestream and store in next
311                  * available entry in the color quad table */
312                 for (i = 0; i < CQUAD; i++) {
313                     pixel = s->buf[stream_ptr++];
314                     color_table_index = CQUAD * color_quad_index + i;
315                     s->color_quads[color_table_index] = pixel;
316                 }
317                 /* this is the base index to use for this block */
318                 color_table_index = CQUAD * color_quad_index;
319                 color_quad_index++;
320                 /* wraparound */
321                 if (color_quad_index == COLORS_PER_TABLE)
322                     color_quad_index = 0;
323             } else
324                 color_table_index = CQUAD * s->buf[stream_ptr++];
325
326             while (n_blocks--) {
327                 color_flags = BE_32(&s->buf[stream_ptr]);
328                 stream_ptr += 4;
329                 /* flag mask actually acts as a bit shift count here */
330                 flag_mask = 30;
331                 block_ptr = row_ptr + pixel_ptr;
332                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
333                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
334                         pixel = color_table_index + 
335                             ((color_flags >> flag_mask) & 0x03);
336                         flag_mask -= 2;
337                         pixels[block_ptr++] = s->color_quads[pixel];
338                     }
339                     block_ptr += row_inc;
340                 }
341                 ADVANCE_BLOCK();
342             }
343             break;
344
345         /* 8-color block encoding */
346         case 0xC0:
347         case 0xD0:
348             n_blocks = (opcode & 0x0F) + 1;
349
350             /* figure out which color octet to use to paint the 8-color block */
351             if ((opcode & 0xF0) == 0xC0) {
352                 /* fetch the next 8 colors from bytestream and store in next
353                  * available entry in the color octet table */
354                 for (i = 0; i < COCTET; i++) {
355                     pixel = s->buf[stream_ptr++];
356                     color_table_index = COCTET * color_octet_index + i;
357                     s->color_octets[color_table_index] = pixel;
358                 }
359                 /* this is the base index to use for this block */
360                 color_table_index = COCTET * color_octet_index;
361                 color_octet_index++;
362                 /* wraparound */
363                 if (color_octet_index == COLORS_PER_TABLE)
364                     color_octet_index = 0;
365             } else
366                 color_table_index = COCTET * s->buf[stream_ptr++];
367
368             while (n_blocks--) {
369                 /*
370                   For this input of 6 hex bytes:
371                     01 23 45 67 89 AB
372                   Mangle it to this output:
373                     flags_a = xx012456, flags_b = xx89A37B
374                 */
375                 /* build the color flags */
376                 color_flags_a = color_flags_b = 0;
377                 color_flags_a =
378                     (s->buf[stream_ptr + 0] << 16) |
379                     ((s->buf[stream_ptr + 1] & 0xF0) << 8) |
380                     ((s->buf[stream_ptr + 2] & 0xF0) << 4) |
381                     ((s->buf[stream_ptr + 2] & 0x0F) << 4) |
382                     ((s->buf[stream_ptr + 3] & 0xF0) >> 4);
383                 color_flags_b =
384                     (s->buf[stream_ptr + 4] << 16) |
385                     ((s->buf[stream_ptr + 5] & 0xF0) << 8) |
386                     ((s->buf[stream_ptr + 1] & 0x0F) << 8) |
387                     ((s->buf[stream_ptr + 3] & 0x0F) << 4) |
388                     (s->buf[stream_ptr + 5] & 0x0F);
389                 stream_ptr += 6;
390
391                 color_flags = color_flags_a;
392                 /* flag mask actually acts as a bit shift count here */
393                 flag_mask = 21;
394                 block_ptr = row_ptr + pixel_ptr;
395                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
396                     /* reload flags at third row (iteration pixel_y == 2) */
397                     if (pixel_y == 2) {
398                         color_flags = color_flags_b;
399                         flag_mask = 21;
400                     }
401                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
402                         pixel = color_table_index + 
403                             ((color_flags >> flag_mask) & 0x07);
404                         flag_mask -= 3;
405                         pixels[block_ptr++] = s->color_octets[pixel];
406                     }
407                     block_ptr += row_inc;
408                 }
409                 ADVANCE_BLOCK();
410             }
411             break;
412
413         /* 16-color block encoding (every pixel is a different color) */
414         case 0xE0:
415             n_blocks = (opcode & 0x0F) + 1;
416
417             while (n_blocks--) {
418                 block_ptr = row_ptr + pixel_ptr;
419                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
420                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
421                         pixels[block_ptr++] = s->buf[stream_ptr++];
422                     }
423                     block_ptr += row_inc;
424                 }
425                 ADVANCE_BLOCK();
426             }
427             break;
428
429         case 0xF0:
430             printf("0xF0 opcode seen in SMC chunk (xine developers would like to know)\n");
431             break;
432         }
433     }
434 }
435
436 static int smc_decode_init(AVCodecContext *avctx)
437 {
438     SmcContext *s = (SmcContext *)avctx->priv_data;
439
440     s->avctx = avctx;
441     avctx->pix_fmt = PIX_FMT_PAL8;
442     avctx->has_b_frames = 0;
443     dsputil_init(&s->dsp, avctx);
444
445     s->frame.data[0] = NULL;
446
447     return 0;
448 }
449
450 static int smc_decode_frame(AVCodecContext *avctx,
451                              void *data, int *data_size,
452                              uint8_t *buf, int buf_size)
453 {
454     SmcContext *s = (SmcContext *)avctx->priv_data;
455
456     /* no supplementary picture */
457     if (buf_size == 0)
458         return 0;
459
460     s->buf = buf;
461     s->size = buf_size;
462
463     s->frame.reference = 1;
464     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | 
465                             FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE;
466     if (avctx->reget_buffer(avctx, &s->frame)) {
467         printf ("reget_buffer() failed\n");
468         return -1;
469     }
470
471     smc_decode_stream(s);
472
473     *data_size = sizeof(AVFrame);
474     *(AVFrame*)data = s->frame;
475
476     /* always report that the buffer was completely consumed */
477     return buf_size;
478 }
479
480 static int smc_decode_end(AVCodecContext *avctx)
481 {
482     SmcContext *s = (SmcContext *)avctx->priv_data;
483
484     if (s->frame.data[0])
485         avctx->release_buffer(avctx, &s->frame);
486
487     return 0;
488 }
489
490 AVCodec smc_decoder = {
491     "smc",
492     CODEC_TYPE_VIDEO,
493     CODEC_ID_SMC,
494     sizeof(SmcContext),
495     smc_decode_init,
496     NULL,
497     smc_decode_end,
498     smc_decode_frame,
499     CODEC_CAP_DR1,
500 };