GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/smc.c Lines: 173 221 78.3 %
Date: 2021-04-14 23:45:22 Branches: 101 150 67.3 %

Line Branch Exec Source
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
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
#include "bytestream.h"
38
#include "decode.h"
39
#include "internal.h"
40
41
#define CPAIR 2
42
#define CQUAD 4
43
#define COCTET 8
44
45
#define COLORS_PER_TABLE 256
46
47
typedef struct SmcContext {
48
49
    AVCodecContext *avctx;
50
    AVFrame *frame;
51
52
    GetByteContext gb;
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
    uint32_t pal[256];
60
} SmcContext;
61
62
#define GET_BLOCK_COUNT() \
63
  (opcode & 0x10) ? (1 + bytestream2_get_byte(&s->gb)) : 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 < !!n_blocks) \
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
120
static void smc_decode_stream(SmcContext *s)
82
{
83
120
    int width = s->avctx->width;
84
120
    int height = s->avctx->height;
85
120
    int stride = s->frame->linesize[0];
86
    int i;
87
    int chunk_size;
88
120
    int buf_size = bytestream2_size(&s->gb);
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
120
    unsigned char * const pixels = s->frame->data[0];
97
98
120
    int image_size = height * s->frame->linesize[0];
99
120
    int row_ptr = 0;
100
120
    int pixel_ptr = 0;
101
    int pixel_x, pixel_y;
102
120
    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
120
    int color_pair_index = 0;
112
120
    int color_quad_index = 0;
113
120
    int color_octet_index = 0;
114
115
    /* make the palette available */
116
120
    memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
117
118
120
    bytestream2_skip(&s->gb, 1);
119
120
    chunk_size = bytestream2_get_be24(&s->gb);
120
120
    if (chunk_size != buf_size)
121
        av_log(s->avctx, AV_LOG_INFO, "warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
122
            chunk_size, buf_size);
123
124
120
    chunk_size = buf_size;
125
120
    total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
126
127
    /* traverse through the blocks */
128
120
    while (total_blocks) {
129
        /* sanity checks */
130
        /* make sure the row pointer hasn't gone wild */
131
130697
        if (row_ptr >= image_size) {
132
            av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
133
                row_ptr, image_size);
134
            return;
135
        }
136
130697
        if (bytestream2_get_bytes_left(&s->gb) < 1) {
137
            av_log(s->avctx, AV_LOG_ERROR, "input too small\n");
138
            return;
139
        }
140
141
130697
        opcode = bytestream2_get_byte(&s->gb);
142


130697
        switch (opcode & 0xF0) {
143
        /* skip n blocks */
144
28630
        case 0x00:
145
        case 0x10:
146
28630
            n_blocks = GET_BLOCK_COUNT();
147
447015
            while (n_blocks--) {
148

418385
                ADVANCE_BLOCK();
149
            }
150
28630
            break;
151
152
        /* repeat last block n times */
153
1068
        case 0x20:
154
        case 0x30:
155
1068
            n_blocks = GET_BLOCK_COUNT();
156
157
            /* sanity check */
158

1068
            if ((row_ptr == 0) && (pixel_ptr == 0)) {
159
                av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
160
                    opcode & 0xF0);
161
                return;
162
            }
163
164
            /* figure out where the previous block started */
165
1068
            if (pixel_ptr == 0)
166
                prev_block_ptr1 =
167
                    (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
168
            else
169
1068
                prev_block_ptr1 = row_ptr + pixel_ptr - 4;
170
171
3393
            while (n_blocks--) {
172
2325
                block_ptr = row_ptr + pixel_ptr;
173
2325
                prev_block_ptr = prev_block_ptr1;
174
11625
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
175
46500
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
176
37200
                        pixels[block_ptr++] = pixels[prev_block_ptr++];
177
                    }
178
9300
                    block_ptr += row_inc;
179
9300
                    prev_block_ptr += row_inc;
180
                }
181

2325
                ADVANCE_BLOCK();
182
            }
183
1068
            break;
184
185
        /* repeat previous pair of blocks n times */
186
        case 0x40:
187
        case 0x50:
188
            n_blocks = GET_BLOCK_COUNT();
189
            n_blocks *= 2;
190
191
            /* sanity check */
192
            if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
193
                av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
194
                    opcode & 0xF0);
195
                return;
196
            }
197
198
            /* figure out where the previous 2 blocks started */
199
            if (pixel_ptr == 0)
200
                prev_block_ptr1 = (row_ptr - s->avctx->width * 4) +
201
                    s->avctx->width - 4 * 2;
202
            else if (pixel_ptr == 4)
203
                prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
204
            else
205
                prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
206
207
            if (pixel_ptr == 0)
208
                prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
209
            else
210
                prev_block_ptr2 = row_ptr + pixel_ptr - 4;
211
212
            prev_block_flag = 0;
213
            while (n_blocks--) {
214
                block_ptr = row_ptr + pixel_ptr;
215
                if (prev_block_flag)
216
                    prev_block_ptr = prev_block_ptr2;
217
                else
218
                    prev_block_ptr = prev_block_ptr1;
219
                prev_block_flag = !prev_block_flag;
220
221
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
222
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
223
                        pixels[block_ptr++] = pixels[prev_block_ptr++];
224
                    }
225
                    block_ptr += row_inc;
226
                    prev_block_ptr += row_inc;
227
                }
228
                ADVANCE_BLOCK();
229
            }
230
            break;
231
232
        /* 1-color block encoding */
233
11688
        case 0x60:
234
        case 0x70:
235
11688
            n_blocks = GET_BLOCK_COUNT();
236
11688
            pixel = bytestream2_get_byte(&s->gb);
237
238
62105
            while (n_blocks--) {
239
50417
                block_ptr = row_ptr + pixel_ptr;
240
252085
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
241
1008340
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
242
806672
                        pixels[block_ptr++] = pixel;
243
                    }
244
201668
                    block_ptr += row_inc;
245
                }
246

50417
                ADVANCE_BLOCK();
247
            }
248
11688
            break;
249
250
        /* 2-color block encoding */
251
17912
        case 0x80:
252
        case 0x90:
253
17912
            n_blocks = (opcode & 0x0F) + 1;
254
255
            /* figure out which color pair to use to paint the 2-color block */
256
17912
            if ((opcode & 0xF0) == 0x80) {
257
                /* fetch the next 2 colors from bytestream and store in next
258
                 * available entry in the color pair table */
259
15813
                for (i = 0; i < CPAIR; i++) {
260
10542
                    pixel = bytestream2_get_byte(&s->gb);
261
10542
                    color_table_index = CPAIR * color_pair_index + i;
262
10542
                    s->color_pairs[color_table_index] = pixel;
263
                }
264
                /* this is the base index to use for this block */
265
5271
                color_table_index = CPAIR * color_pair_index;
266
5271
                color_pair_index++;
267
                /* wraparound */
268
5271
                if (color_pair_index == COLORS_PER_TABLE)
269
                    color_pair_index = 0;
270
            } else
271
12641
                color_table_index = CPAIR * bytestream2_get_byte(&s->gb);
272
273
36856
            while (n_blocks--) {
274
18944
                color_flags = bytestream2_get_be16(&s->gb);
275
18944
                flag_mask = 0x8000;
276
18944
                block_ptr = row_ptr + pixel_ptr;
277
94720
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
278
378880
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
279
303104
                        if (color_flags & flag_mask)
280
121822
                            pixel = color_table_index + 1;
281
                        else
282
181282
                            pixel = color_table_index;
283
303104
                        flag_mask >>= 1;
284
303104
                        pixels[block_ptr++] = s->color_pairs[pixel];
285
                    }
286
75776
                    block_ptr += row_inc;
287
                }
288

18944
                ADVANCE_BLOCK();
289
            }
290
17912
            break;
291
292
        /* 4-color block encoding */
293
35882
        case 0xA0:
294
        case 0xB0:
295
35882
            n_blocks = (opcode & 0x0F) + 1;
296
297
            /* figure out which color quad to use to paint the 4-color block */
298
35882
            if ((opcode & 0xF0) == 0xA0) {
299
                /* fetch the next 4 colors from bytestream and store in next
300
                 * available entry in the color quad table */
301
72670
                for (i = 0; i < CQUAD; i++) {
302
58136
                    pixel = bytestream2_get_byte(&s->gb);
303
58136
                    color_table_index = CQUAD * color_quad_index + i;
304
58136
                    s->color_quads[color_table_index] = pixel;
305
                }
306
                /* this is the base index to use for this block */
307
14534
                color_table_index = CQUAD * color_quad_index;
308
14534
                color_quad_index++;
309
                /* wraparound */
310
14534
                if (color_quad_index == COLORS_PER_TABLE)
311
                    color_quad_index = 0;
312
            } else
313
21348
                color_table_index = CQUAD * bytestream2_get_byte(&s->gb);
314
315
77041
            while (n_blocks--) {
316
41159
                color_flags = bytestream2_get_be32(&s->gb);
317
                /* flag mask actually acts as a bit shift count here */
318
41159
                flag_mask = 30;
319
41159
                block_ptr = row_ptr + pixel_ptr;
320
205795
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
321
823180
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
322
658544
                        pixel = color_table_index +
323
658544
                            ((color_flags >> flag_mask) & 0x03);
324
658544
                        flag_mask -= 2;
325
658544
                        pixels[block_ptr++] = s->color_quads[pixel];
326
                    }
327
164636
                    block_ptr += row_inc;
328
                }
329

41159
                ADVANCE_BLOCK();
330
            }
331
35882
            break;
332
333
        /* 8-color block encoding */
334
33474
        case 0xC0:
335
        case 0xD0:
336
33474
            n_blocks = (opcode & 0x0F) + 1;
337
338
            /* figure out which color octet to use to paint the 8-color block */
339
33474
            if ((opcode & 0xF0) == 0xC0) {
340
                /* fetch the next 8 colors from bytestream and store in next
341
                 * available entry in the color octet table */
342
98883
                for (i = 0; i < COCTET; i++) {
343
87896
                    pixel = bytestream2_get_byte(&s->gb);
344
87896
                    color_table_index = COCTET * color_octet_index + i;
345
87896
                    s->color_octets[color_table_index] = pixel;
346
                }
347
                /* this is the base index to use for this block */
348
10987
                color_table_index = COCTET * color_octet_index;
349
10987
                color_octet_index++;
350
                /* wraparound */
351
10987
                if (color_octet_index == COLORS_PER_TABLE)
352
                    color_octet_index = 0;
353
            } else
354
22487
                color_table_index = COCTET * bytestream2_get_byte(&s->gb);
355
356
76047
            while (n_blocks--) {
357
                /*
358
                  For this input of 6 hex bytes:
359
                    01 23 45 67 89 AB
360
                  Mangle it to this output:
361
                    flags_a = xx012456, flags_b = xx89A37B
362
                */
363
                /* build the color flags */
364
42573
                int val1 = bytestream2_get_be16(&s->gb);
365
42573
                int val2 = bytestream2_get_be16(&s->gb);
366
42573
                int val3 = bytestream2_get_be16(&s->gb);
367
42573
                color_flags_a = ((val1 & 0xFFF0) << 8) | (val2 >> 4);
368
42573
                color_flags_b = ((val3 & 0xFFF0) << 8) |
369
42573
                    ((val1 & 0x0F) << 8) | ((val2 & 0x0F) << 4) | (val3 & 0x0F);
370
371
42573
                color_flags = color_flags_a;
372
                /* flag mask actually acts as a bit shift count here */
373
42573
                flag_mask = 21;
374
42573
                block_ptr = row_ptr + pixel_ptr;
375
212865
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
376
                    /* reload flags at third row (iteration pixel_y == 2) */
377
170292
                    if (pixel_y == 2) {
378
42573
                        color_flags = color_flags_b;
379
42573
                        flag_mask = 21;
380
                    }
381
851460
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
382
681168
                        pixel = color_table_index +
383
681168
                            ((color_flags >> flag_mask) & 0x07);
384
681168
                        flag_mask -= 3;
385
681168
                        pixels[block_ptr++] = s->color_octets[pixel];
386
                    }
387
170292
                    block_ptr += row_inc;
388
                }
389

42573
                ADVANCE_BLOCK();
390
            }
391
33474
            break;
392
393
        /* 16-color block encoding (every pixel is a different color) */
394
2043
        case 0xE0:
395
2043
            n_blocks = (opcode & 0x0F) + 1;
396
397
4240
            while (n_blocks--) {
398
2197
                block_ptr = row_ptr + pixel_ptr;
399
10985
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
400
43940
                    for (pixel_x = 0; pixel_x < 4; pixel_x++) {
401
35152
                        pixels[block_ptr++] = bytestream2_get_byte(&s->gb);
402
                    }
403
8788
                    block_ptr += row_inc;
404
                }
405

2197
                ADVANCE_BLOCK();
406
            }
407
2043
            break;
408
409
        case 0xF0:
410
            avpriv_request_sample(s->avctx, "0xF0 opcode");
411
            break;
412
        }
413
130817
    }
414
415
120
    return;
416
}
417
418
2
static av_cold int smc_decode_init(AVCodecContext *avctx)
419
{
420
2
    SmcContext *s = avctx->priv_data;
421
422
2
    s->avctx = avctx;
423
2
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
424
425
2
    s->frame = av_frame_alloc();
426
2
    if (!s->frame)
427
        return AVERROR(ENOMEM);
428
429
2
    return 0;
430
}
431
432
120
static int smc_decode_frame(AVCodecContext *avctx,
433
                             void *data, int *got_frame,
434
                             AVPacket *avpkt)
435
{
436
120
    const uint8_t *buf = avpkt->data;
437
120
    int buf_size = avpkt->size;
438
120
    SmcContext *s = avctx->priv_data;
439
    int ret;
440
120
    int total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
441
442
120
    if (total_blocks / 1024 > avpkt->size)
443
        return AVERROR_INVALIDDATA;
444
445
120
    bytestream2_init(&s->gb, buf, buf_size);
446
447
120
    if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
448
        return ret;
449
450
120
    s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
451
452
120
    smc_decode_stream(s);
453
454
120
    *got_frame      = 1;
455
120
    if ((ret = av_frame_ref(data, s->frame)) < 0)
456
        return ret;
457
458
    /* always report that the buffer was completely consumed */
459
120
    return buf_size;
460
}
461
462
2
static av_cold int smc_decode_end(AVCodecContext *avctx)
463
{
464
2
    SmcContext *s = avctx->priv_data;
465
466
2
    av_frame_free(&s->frame);
467
468
2
    return 0;
469
}
470
471
AVCodec ff_smc_decoder = {
472
    .name           = "smc",
473
    .long_name      = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
474
    .type           = AVMEDIA_TYPE_VIDEO,
475
    .id             = AV_CODEC_ID_SMC,
476
    .priv_data_size = sizeof(SmcContext),
477
    .init           = smc_decode_init,
478
    .close          = smc_decode_end,
479
    .decode         = smc_decode_frame,
480
    .capabilities   = AV_CODEC_CAP_DR1,
481
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
482
};