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