Statistics
| Branch: | Revision:

ffmpeg / libavcodec / smc.c @ 2029f312

History | View | Annotate | Download (16.4 KB)

1
/*
2
 * Quicktime Graphics (SMC) Video Decoder
3
 * Copyright (C) 2003 the ffmpeg project
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg 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 GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 *
21
 */
22

    
23
/**
24
 * @file smc.c
25
 * QT SMC Video Decoder by Mike Melanson (melanson@pcisys.net)
26
 * For more information about the SMC format, visit:
27
 *   http://www.pcisys.net/~melanson/codecs/
28
 *
29
 * The SMC decoder outputs PAL8 colorspace data.
30
 */
31

    
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36

    
37
#include "avcodec.h"
38
#include "dsputil.h"
39

    
40
#define CPAIR 2
41
#define CQUAD 4
42
#define COCTET 8
43

    
44
#define COLORS_PER_TABLE 256
45

    
46
typedef struct SmcContext {
47

    
48
    AVCodecContext *avctx;
49
    DSPContext dsp;
50
    AVFrame frame;
51

    
52
    unsigned char *buf;
53
    int size;
54

    
55
    /* SMC color tables */
56
    unsigned char color_pairs[COLORS_PER_TABLE * CPAIR];
57
    unsigned char color_quads[COLORS_PER_TABLE * CQUAD];
58
    unsigned char color_octets[COLORS_PER_TABLE * COCTET];
59

    
60
} SmcContext;
61

    
62
#define GET_BLOCK_COUNT() \
63
  (opcode & 0x10) ? (1 + s->buf[stream_ptr++]) : 1 + (opcode & 0x0F);
64

    
65
#define ADVANCE_BLOCK() \
66
{ \
67
    pixel_ptr += 4; \
68
    if (pixel_ptr >= width) \
69
    { \
70
        pixel_ptr = 0; \
71
        row_ptr += stride * 4; \
72
    } \
73
    total_blocks--; \
74
    if (total_blocks < 0) \
75
    { \
76
        av_log(s->avctx, AV_LOG_INFO, "warning: block counter just went negative (this should not happen)\n"); \
77
        return; \
78
    } \
79
}
80

    
81
static void smc_decode_stream(SmcContext *s)
82
{
83
    int width = s->avctx->width;
84
    int height = s->avctx->height;
85
    int stride = s->frame.linesize[0];
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
    unsigned char *pixels = s->frame.data[0];
97

    
98
    int image_size = height * s->frame.linesize[0];
99
    int row_ptr = 0;
100
    int pixel_ptr = 0;
101
    int pixel_x, pixel_y;
102
    int row_inc = stride - 4;
103
    int block_ptr;
104
    int prev_block_ptr;
105
    int prev_block_ptr1, prev_block_ptr2;
106
    int prev_block_flag;
107
    int total_blocks;
108
    int color_table_index;  /* indexes to color pair, quad, or octet tables */
109
    int pixel;
110

    
111
    int color_pair_index = 0;
112
    int color_quad_index = 0;
113
    int color_octet_index = 0;
114

    
115
    /* make the palette available */
116
    memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
117
    if (s->avctx->palctrl->palette_changed) {
118
        s->frame.palette_has_changed = 1;
119
        s->avctx->palctrl->palette_changed = 0;
120
    }
121

    
122
    chunk_size = AV_RB32(&s->buf[stream_ptr]) & 0x00FFFFFF;
123
    stream_ptr += 4;
124
    if (chunk_size != s->size)
125
        av_log(s->avctx, AV_LOG_INFO, "warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
126
            chunk_size, s->size);
127

    
128
    chunk_size = s->size;
129
    total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
130

    
131
    /* traverse through the blocks */
132
    while (total_blocks) {
133
        /* sanity checks */
134
        /* make sure stream ptr hasn't gone out of bounds */
135
        if (stream_ptr > chunk_size) {
136
            av_log(s->avctx, AV_LOG_INFO, "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 >= image_size) {
142
            av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
143
                row_ptr, image_size);
144
            return;
145
        }
146

    
147
        opcode = s->buf[stream_ptr++];
148
        switch (opcode & 0xF0) {
149
        /* skip n blocks */
150
        case 0x00:
151
        case 0x10:
152
            n_blocks = GET_BLOCK_COUNT();
153
            while (n_blocks--) {
154
                ADVANCE_BLOCK();
155
            }
156
            break;
157

    
158
        /* repeat last block n times */
159
        case 0x20:
160
        case 0x30:
161
            n_blocks = GET_BLOCK_COUNT();
162

    
163
            /* sanity check */
164
            if ((row_ptr == 0) && (pixel_ptr == 0)) {
165
                av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
166
                    opcode & 0xF0);
167
                break;
168
            }
169

    
170
            /* figure out where the previous block started */
171
            if (pixel_ptr == 0)
172
                prev_block_ptr1 =
173
                    (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
174
            else
175
                prev_block_ptr1 = row_ptr + pixel_ptr - 4;
176

    
177
            while (n_blocks--) {
178
                block_ptr = row_ptr + pixel_ptr;
179
                prev_block_ptr = prev_block_ptr1;
180
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
181
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
182
                        pixels[block_ptr++] = pixels[prev_block_ptr++];
183
                    }
184
                    block_ptr += row_inc;
185
                    prev_block_ptr += row_inc;
186
                }
187
                ADVANCE_BLOCK();
188
            }
189
            break;
190

    
191
        /* repeat previous pair of blocks n times */
192
        case 0x40:
193
        case 0x50:
194
            n_blocks = GET_BLOCK_COUNT();
195
            n_blocks *= 2;
196

    
197
            /* sanity check */
198
            if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
199
                av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
200
                    opcode & 0xF0);
201
                break;
202
            }
203

    
204
            /* figure out where the previous 2 blocks started */
205
            if (pixel_ptr == 0)
206
                prev_block_ptr1 = (row_ptr - s->avctx->width * 4) +
207
                    s->avctx->width - 4 * 2;
208
            else if (pixel_ptr == 4)
209
                prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
210
            else
211
                prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
212

    
213
            if (pixel_ptr == 0)
214
                prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
215
            else
216
                prev_block_ptr2 = row_ptr + pixel_ptr - 4;
217

    
218
            prev_block_flag = 0;
219
            while (n_blocks--) {
220
                block_ptr = row_ptr + pixel_ptr;
221
                if (prev_block_flag)
222
                    prev_block_ptr = prev_block_ptr2;
223
                else
224
                    prev_block_ptr = prev_block_ptr1;
225
                prev_block_flag = !prev_block_flag;
226

    
227
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
228
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
229
                        pixels[block_ptr++] = pixels[prev_block_ptr++];
230
                    }
231
                    block_ptr += row_inc;
232
                    prev_block_ptr += row_inc;
233
                }
234
                ADVANCE_BLOCK();
235
            }
236
            break;
237

    
238
        /* 1-color block encoding */
239
        case 0x60:
240
        case 0x70:
241
            n_blocks = GET_BLOCK_COUNT();
242
            pixel = s->buf[stream_ptr++];
243

    
244
            while (n_blocks--) {
245
                block_ptr = row_ptr + pixel_ptr;
246
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
247
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
248
                        pixels[block_ptr++] = pixel;
249
                    }
250
                    block_ptr += row_inc;
251
                }
252
                ADVANCE_BLOCK();
253
            }
254
            break;
255

    
256
        /* 2-color block encoding */
257
        case 0x80:
258
        case 0x90:
259
            n_blocks = (opcode & 0x0F) + 1;
260

    
261
            /* figure out which color pair to use to paint the 2-color block */
262
            if ((opcode & 0xF0) == 0x80) {
263
                /* fetch the next 2 colors from bytestream and store in next
264
                 * available entry in the color pair table */
265
                for (i = 0; i < CPAIR; i++) {
266
                    pixel = s->buf[stream_ptr++];
267
                    color_table_index = CPAIR * color_pair_index + i;
268
                    s->color_pairs[color_table_index] = pixel;
269
                }
270
                /* this is the base index to use for this block */
271
                color_table_index = CPAIR * color_pair_index;
272
                color_pair_index++;
273
                /* wraparound */
274
                if (color_pair_index == COLORS_PER_TABLE)
275
                    color_pair_index = 0;
276
            } else
277
                color_table_index = CPAIR * s->buf[stream_ptr++];
278

    
279
            while (n_blocks--) {
280
                color_flags = AV_RB16(&s->buf[stream_ptr]);
281
                stream_ptr += 2;
282
                flag_mask = 0x8000;
283
                block_ptr = row_ptr + pixel_ptr;
284
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
285
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
286
                        if (color_flags & flag_mask)
287
                            pixel = color_table_index + 1;
288
                        else
289
                            pixel = color_table_index;
290
                        flag_mask >>= 1;
291
                        pixels[block_ptr++] = s->color_pairs[pixel];
292
                    }
293
                    block_ptr += row_inc;
294
                }
295
                ADVANCE_BLOCK();
296
            }
297
            break;
298

    
299
        /* 4-color block encoding */
300
        case 0xA0:
301
        case 0xB0:
302
            n_blocks = (opcode & 0x0F) + 1;
303

    
304
            /* figure out which color quad to use to paint the 4-color block */
305
            if ((opcode & 0xF0) == 0xA0) {
306
                /* fetch the next 4 colors from bytestream and store in next
307
                 * available entry in the color quad table */
308
                for (i = 0; i < CQUAD; i++) {
309
                    pixel = s->buf[stream_ptr++];
310
                    color_table_index = CQUAD * color_quad_index + i;
311
                    s->color_quads[color_table_index] = pixel;
312
                }
313
                /* this is the base index to use for this block */
314
                color_table_index = CQUAD * color_quad_index;
315
                color_quad_index++;
316
                /* wraparound */
317
                if (color_quad_index == COLORS_PER_TABLE)
318
                    color_quad_index = 0;
319
            } else
320
                color_table_index = CQUAD * s->buf[stream_ptr++];
321

    
322
            while (n_blocks--) {
323
                color_flags = AV_RB32(&s->buf[stream_ptr]);
324
                stream_ptr += 4;
325
                /* flag mask actually acts as a bit shift count here */
326
                flag_mask = 30;
327
                block_ptr = row_ptr + pixel_ptr;
328
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
329
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
330
                        pixel = color_table_index +
331
                            ((color_flags >> flag_mask) & 0x03);
332
                        flag_mask -= 2;
333
                        pixels[block_ptr++] = s->color_quads[pixel];
334
                    }
335
                    block_ptr += row_inc;
336
                }
337
                ADVANCE_BLOCK();
338
            }
339
            break;
340

    
341
        /* 8-color block encoding */
342
        case 0xC0:
343
        case 0xD0:
344
            n_blocks = (opcode & 0x0F) + 1;
345

    
346
            /* figure out which color octet to use to paint the 8-color block */
347
            if ((opcode & 0xF0) == 0xC0) {
348
                /* fetch the next 8 colors from bytestream and store in next
349
                 * available entry in the color octet table */
350
                for (i = 0; i < COCTET; i++) {
351
                    pixel = s->buf[stream_ptr++];
352
                    color_table_index = COCTET * color_octet_index + i;
353
                    s->color_octets[color_table_index] = pixel;
354
                }
355
                /* this is the base index to use for this block */
356
                color_table_index = COCTET * color_octet_index;
357
                color_octet_index++;
358
                /* wraparound */
359
                if (color_octet_index == COLORS_PER_TABLE)
360
                    color_octet_index = 0;
361
            } else
362
                color_table_index = COCTET * s->buf[stream_ptr++];
363

    
364
            while (n_blocks--) {
365
                /*
366
                  For this input of 6 hex bytes:
367
                    01 23 45 67 89 AB
368
                  Mangle it to this output:
369
                    flags_a = xx012456, flags_b = xx89A37B
370
                */
371
                /* build the color flags */
372
                color_flags_a = color_flags_b = 0;
373
                color_flags_a =
374
                    (s->buf[stream_ptr + 0] << 16) |
375
                    ((s->buf[stream_ptr + 1] & 0xF0) << 8) |
376
                    ((s->buf[stream_ptr + 2] & 0xF0) << 4) |
377
                    ((s->buf[stream_ptr + 2] & 0x0F) << 4) |
378
                    ((s->buf[stream_ptr + 3] & 0xF0) >> 4);
379
                color_flags_b =
380
                    (s->buf[stream_ptr + 4] << 16) |
381
                    ((s->buf[stream_ptr + 5] & 0xF0) << 8) |
382
                    ((s->buf[stream_ptr + 1] & 0x0F) << 8) |
383
                    ((s->buf[stream_ptr + 3] & 0x0F) << 4) |
384
                    (s->buf[stream_ptr + 5] & 0x0F);
385
                stream_ptr += 6;
386

    
387
                color_flags = color_flags_a;
388
                /* flag mask actually acts as a bit shift count here */
389
                flag_mask = 21;
390
                block_ptr = row_ptr + pixel_ptr;
391
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
392
                    /* reload flags at third row (iteration pixel_y == 2) */
393
                    if (pixel_y == 2) {
394
                        color_flags = color_flags_b;
395
                        flag_mask = 21;
396
                    }
397
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
398
                        pixel = color_table_index +
399
                            ((color_flags >> flag_mask) & 0x07);
400
                        flag_mask -= 3;
401
                        pixels[block_ptr++] = s->color_octets[pixel];
402
                    }
403
                    block_ptr += row_inc;
404
                }
405
                ADVANCE_BLOCK();
406
            }
407
            break;
408

    
409
        /* 16-color block encoding (every pixel is a different color) */
410
        case 0xE0:
411
            n_blocks = (opcode & 0x0F) + 1;
412

    
413
            while (n_blocks--) {
414
                block_ptr = row_ptr + pixel_ptr;
415
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
416
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
417
                        pixels[block_ptr++] = s->buf[stream_ptr++];
418
                    }
419
                    block_ptr += row_inc;
420
                }
421
                ADVANCE_BLOCK();
422
            }
423
            break;
424

    
425
        case 0xF0:
426
            av_log(s->avctx, AV_LOG_INFO, "0xF0 opcode seen in SMC chunk (contact the developers)\n");
427
            break;
428
        }
429
    }
430
}
431

    
432
static int smc_decode_init(AVCodecContext *avctx)
433
{
434
    SmcContext *s = avctx->priv_data;
435

    
436
    s->avctx = avctx;
437
    avctx->pix_fmt = PIX_FMT_PAL8;
438
    dsputil_init(&s->dsp, avctx);
439

    
440
    s->frame.data[0] = NULL;
441

    
442
    return 0;
443
}
444

    
445
static int smc_decode_frame(AVCodecContext *avctx,
446
                             void *data, int *data_size,
447
                             uint8_t *buf, int buf_size)
448
{
449
    SmcContext *s = avctx->priv_data;
450

    
451
    s->buf = buf;
452
    s->size = buf_size;
453

    
454
    s->frame.reference = 1;
455
    s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
456
                            FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE;
457
    if (avctx->reget_buffer(avctx, &s->frame)) {
458
        av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
459
        return -1;
460
    }
461

    
462
    smc_decode_stream(s);
463

    
464
    *data_size = sizeof(AVFrame);
465
    *(AVFrame*)data = s->frame;
466

    
467
    /* always report that the buffer was completely consumed */
468
    return buf_size;
469
}
470

    
471
static int smc_decode_end(AVCodecContext *avctx)
472
{
473
    SmcContext *s = avctx->priv_data;
474

    
475
    if (s->frame.data[0])
476
        avctx->release_buffer(avctx, &s->frame);
477

    
478
    return 0;
479
}
480

    
481
AVCodec smc_decoder = {
482
    "smc",
483
    CODEC_TYPE_VIDEO,
484
    CODEC_ID_SMC,
485
    sizeof(SmcContext),
486
    smc_decode_init,
487
    NULL,
488
    smc_decode_end,
489
    smc_decode_frame,
490
    CODEC_CAP_DR1,
491
};