Statistics
| Branch: | Revision:

ffmpeg / libavcodec / smc.c @ 2912e87a

History | View | Annotate | Download (16.2 KB)

1
/*
2
 * Quicktime Graphics (SMC) Video Decoder
3
 * Copyright (C) 2003 the ffmpeg project
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav 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
 * Libav 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 Libav; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21

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

    
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34

    
35
#include "libavutil/intreadwrite.h"
36
#include "avcodec.h"
37

    
38
#define CPAIR 2
39
#define CQUAD 4
40
#define COCTET 8
41

    
42
#define COLORS_PER_TABLE 256
43

    
44
typedef struct SmcContext {
45

    
46
    AVCodecContext *avctx;
47
    AVFrame frame;
48

    
49
    const unsigned char *buf;
50
    int size;
51

    
52
    /* SMC color tables */
53
    unsigned char color_pairs[COLORS_PER_TABLE * CPAIR];
54
    unsigned char color_quads[COLORS_PER_TABLE * CQUAD];
55
    unsigned char color_octets[COLORS_PER_TABLE * COCTET];
56

    
57
} SmcContext;
58

    
59
#define GET_BLOCK_COUNT() \
60
  (opcode & 0x10) ? (1 + s->buf[stream_ptr++]) : 1 + (opcode & 0x0F);
61

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

    
78
static void smc_decode_stream(SmcContext *s)
79
{
80
    int width = s->avctx->width;
81
    int height = s->avctx->height;
82
    int stride = s->frame.linesize[0];
83
    int i;
84
    int stream_ptr = 0;
85
    int chunk_size;
86
    unsigned char opcode;
87
    int n_blocks;
88
    unsigned int color_flags;
89
    unsigned int color_flags_a;
90
    unsigned int color_flags_b;
91
    unsigned int flag_mask;
92

    
93
    unsigned char *pixels = s->frame.data[0];
94

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

    
108
    int color_pair_index = 0;
109
    int color_quad_index = 0;
110
    int color_octet_index = 0;
111

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

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

    
125
    chunk_size = s->size;
126
    total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
127

    
128
    /* traverse through the blocks */
129
    while (total_blocks) {
130
        /* sanity checks */
131
        /* make sure stream ptr hasn't gone out of bounds */
132
        if (stream_ptr > chunk_size) {
133
            av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)\n",
134
                stream_ptr, chunk_size);
135
            return;
136
        }
137
        /* make sure the row pointer hasn't gone wild */
138
        if (row_ptr >= image_size) {
139
            av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
140
                row_ptr, image_size);
141
            return;
142
        }
143

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

    
155
        /* repeat last block n times */
156
        case 0x20:
157
        case 0x30:
158
            n_blocks = GET_BLOCK_COUNT();
159

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

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

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

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

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

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

    
210
            if (pixel_ptr == 0)
211
                prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
212
            else
213
                prev_block_ptr2 = row_ptr + pixel_ptr - 4;
214

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
401
        /* 16-color block encoding (every pixel is a different color) */
402
        case 0xE0:
403
            n_blocks = (opcode & 0x0F) + 1;
404

    
405
            while (n_blocks--) {
406
                block_ptr = row_ptr + pixel_ptr;
407
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
408
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
409
                        pixels[block_ptr++] = s->buf[stream_ptr++];
410
                    }
411
                    block_ptr += row_inc;
412
                }
413
                ADVANCE_BLOCK();
414
            }
415
            break;
416

    
417
        case 0xF0:
418
            av_log(s->avctx, AV_LOG_INFO, "0xF0 opcode seen in SMC chunk (contact the developers)\n");
419
            break;
420
        }
421
    }
422
}
423

    
424
static av_cold int smc_decode_init(AVCodecContext *avctx)
425
{
426
    SmcContext *s = avctx->priv_data;
427

    
428
    s->avctx = avctx;
429
    avctx->pix_fmt = PIX_FMT_PAL8;
430

    
431
    s->frame.data[0] = NULL;
432

    
433
    return 0;
434
}
435

    
436
static int smc_decode_frame(AVCodecContext *avctx,
437
                             void *data, int *data_size,
438
                             AVPacket *avpkt)
439
{
440
    const uint8_t *buf = avpkt->data;
441
    int buf_size = avpkt->size;
442
    SmcContext *s = avctx->priv_data;
443

    
444
    s->buf = buf;
445
    s->size = buf_size;
446

    
447
    s->frame.reference = 1;
448
    s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
449
                            FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE;
450
    if (avctx->reget_buffer(avctx, &s->frame)) {
451
        av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
452
        return -1;
453
    }
454

    
455
    smc_decode_stream(s);
456

    
457
    *data_size = sizeof(AVFrame);
458
    *(AVFrame*)data = s->frame;
459

    
460
    /* always report that the buffer was completely consumed */
461
    return buf_size;
462
}
463

    
464
static av_cold int smc_decode_end(AVCodecContext *avctx)
465
{
466
    SmcContext *s = avctx->priv_data;
467

    
468
    if (s->frame.data[0])
469
        avctx->release_buffer(avctx, &s->frame);
470

    
471
    return 0;
472
}
473

    
474
AVCodec ff_smc_decoder = {
475
    "smc",
476
    AVMEDIA_TYPE_VIDEO,
477
    CODEC_ID_SMC,
478
    sizeof(SmcContext),
479
    smc_decode_init,
480
    NULL,
481
    smc_decode_end,
482
    smc_decode_frame,
483
    CODEC_CAP_DR1,
484
    .long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
485
};