~ubuntu-branches/ubuntu/hardy/avidemux/hardy

« back to all changes in this revision

Viewing changes to avidemux/ADM_libraries/ADM_lavcodec/smc.c

  • Committer: Bazaar Package Importer
  • Author(s): Matvey Kozhev
  • Date: 2007-12-18 13:53:04 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20071218135304-cdqec2lg2bglyz15
Tags: 1:2.4~preview3-0.0ubuntu1
* Upload to Ubuntu. (LP: #163287, LP: #126572)
* debian/changelog: re-added Ubuntu releases.
* debian/control:
  - Require debhelper >= 5.0.51 (for dh_icons) and imagemagick.
  - Build-depend on libsdl1.2-dev instead of libsdl-dev.
  - Build against newer libx264-dev. (LP: #138854)
  - Removed libamrnb-dev, not in Ubuntu yet.
* debian/rules:
  - Install all icon sizes, using convert (upstream installs none).
  - Added missing calls to dh_installmenu, dh_installman, dh_icons and
    dh_desktop.
* debian/menu, debian/avidemux-qt.menu:
  - Corrected package and executable names.
* debian/avidemux-common.install: Install icons.
* debian/avidemux.common.manpages: Install man/avidemux.1.
* debian/links, debian/avidemux-cli.links, debian/avidemux-gtk.links:
  - Link manpages to avidemux.1.gz.
* debian/install, debian/avidemux-qt.install, debian/avidemux-gtk.desktop,
  debian/avidemux-qt.desktop: Install desktop files.

Show diffs side-by-side

added added

removed removed

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