FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/smc.c
Date: 2021-09-24 20:55:06
Exec Total Coverage
Lines: 174 220 79.1%
Branches: 102 151 67.5%

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 uint8_t color_pairs[COLORS_PER_TABLE * CPAIR];
56 uint8_t color_quads[COLORS_PER_TABLE * CQUAD];
57 uint8_t 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(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_ERROR, "block counter just went negative (this should not happen)\n"); \
77 return AVERROR_INVALIDDATA; \
78 } \
79 }
80
81 120 static int smc_decode_stream(SmcContext *s)
82 {
83 120 GetByteContext *gb = &s->gb;
84 120 int width = s->avctx->width;
85 120 int height = s->avctx->height;
86 120 int stride = s->frame->linesize[0];
87 int i;
88 int chunk_size;
89 120 int buf_size = bytestream2_size(gb);
90 uint8_t opcode;
91 int n_blocks;
92 unsigned int color_flags;
93 unsigned int color_flags_a;
94 unsigned int color_flags_b;
95 unsigned int flag_mask;
96
97 120 uint8_t * const pixels = s->frame->data[0];
98
99 120 int image_size = height * s->frame->linesize[0];
100 120 int row_ptr = 0;
101 120 int pixel_ptr = 0;
102 int pixel_x, pixel_y;
103 120 int row_inc = stride - 4;
104 int block_ptr;
105 int prev_block_ptr;
106 int prev_block_ptr1, prev_block_ptr2;
107 int prev_block_flag;
108 int total_blocks;
109 int color_table_index; /* indexes to color pair, quad, or octet tables */
110 int pixel;
111
112 120 int color_pair_index = 0;
113 120 int color_quad_index = 0;
114 120 int color_octet_index = 0;
115
116 /* make the palette available */
117 120 memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
118
119 120 bytestream2_skip(gb, 1);
120 120 chunk_size = bytestream2_get_be24(gb);
121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (chunk_size != buf_size)
122 av_log(s->avctx, AV_LOG_WARNING, "MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
123 chunk_size, buf_size);
124
125 120 chunk_size = buf_size;
126 120 total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
127
128 /* traverse through the blocks */
129
2/2
✓ Branch 0 taken 130697 times.
✓ Branch 1 taken 120 times.
130817 while (total_blocks) {
130 /* sanity checks */
131 /* make sure the row pointer hasn't gone wild */
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130697 times.
130697 if (row_ptr >= image_size) {
133 av_log(s->avctx, AV_LOG_ERROR, "just went out of bounds (row ptr = %d, height = %d)\n",
134 row_ptr, image_size);
135 return AVERROR_INVALIDDATA;
136 }
137
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 130697 times.
130697 if (bytestream2_get_bytes_left(gb) < 1) {
138 av_log(s->avctx, AV_LOG_ERROR, "input too small\n");
139 return AVERROR_INVALIDDATA;
140 }
141
142 130697 opcode = bytestream2_get_byteu(gb);
143
7/9
✓ Branch 0 taken 28630 times.
✓ Branch 1 taken 1068 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11688 times.
✓ Branch 4 taken 17912 times.
✓ Branch 5 taken 35882 times.
✓ Branch 6 taken 33474 times.
✓ Branch 7 taken 2043 times.
✗ Branch 8 not taken.
130697 switch (opcode & 0xF0) {
144 /* skip n blocks */
145 28630 case 0x00:
146 case 0x10:
147
2/2
✓ Branch 0 taken 11959 times.
✓ Branch 1 taken 16671 times.
28630 n_blocks = GET_BLOCK_COUNT();
148
2/2
✓ Branch 0 taken 418385 times.
✓ Branch 1 taken 28630 times.
447015 while (n_blocks--) {
149
3/4
✓ Branch 0 taken 6375 times.
✓ Branch 1 taken 412010 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 418385 times.
418385 ADVANCE_BLOCK();
150 }
151 28630 break;
152
153 /* repeat last block n times */
154 1068 case 0x20:
155 case 0x30:
156
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1057 times.
1068 n_blocks = GET_BLOCK_COUNT();
157
158 /* sanity check */
159
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1068 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1068 if ((row_ptr == 0) && (pixel_ptr == 0)) {
160 av_log(s->avctx, AV_LOG_ERROR, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
161 opcode & 0xF0);
162 return AVERROR_INVALIDDATA;
163 }
164
165 /* figure out where the previous block started */
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1068 times.
1068 if (pixel_ptr == 0)
167 prev_block_ptr1 =
168 (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
169 else
170 1068 prev_block_ptr1 = row_ptr + pixel_ptr - 4;
171
172
2/2
✓ Branch 0 taken 2325 times.
✓ Branch 1 taken 1068 times.
3393 while (n_blocks--) {
173 2325 block_ptr = row_ptr + pixel_ptr;
174 2325 prev_block_ptr = prev_block_ptr1;
175
2/2
✓ Branch 0 taken 9300 times.
✓ Branch 1 taken 2325 times.
11625 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
176
2/2
✓ Branch 0 taken 37200 times.
✓ Branch 1 taken 9300 times.
46500 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
177 37200 pixels[block_ptr++] = pixels[prev_block_ptr++];
178 }
179 9300 block_ptr += row_inc;
180 9300 prev_block_ptr += row_inc;
181 }
182
3/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 2294 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2325 times.
2325 ADVANCE_BLOCK();
183 }
184 1068 break;
185
186 /* repeat previous pair of blocks n times */
187 case 0x40:
188 case 0x50:
189 n_blocks = GET_BLOCK_COUNT();
190 n_blocks *= 2;
191
192 /* sanity check */
193 if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
194 av_log(s->avctx, AV_LOG_ERROR, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
195 opcode & 0xF0);
196 return AVERROR_INVALIDDATA;
197 }
198
199 /* figure out where the previous 2 blocks started */
200 if (pixel_ptr == 0)
201 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) +
202 s->avctx->width - 4 * 2;
203 else if (pixel_ptr == 4)
204 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
205 else
206 prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
207
208 if (pixel_ptr == 0)
209 prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
210 else
211 prev_block_ptr2 = row_ptr + pixel_ptr - 4;
212
213 prev_block_flag = 0;
214 while (n_blocks--) {
215 block_ptr = row_ptr + pixel_ptr;
216 if (prev_block_flag)
217 prev_block_ptr = prev_block_ptr2;
218 else
219 prev_block_ptr = prev_block_ptr1;
220 prev_block_flag = !prev_block_flag;
221
222 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
223 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
224 pixels[block_ptr++] = pixels[prev_block_ptr++];
225 }
226 block_ptr += row_inc;
227 prev_block_ptr += row_inc;
228 }
229 ADVANCE_BLOCK();
230 }
231 break;
232
233 /* 1-color block encoding */
234 11688 case 0x60:
235 case 0x70:
236
2/2
✓ Branch 0 taken 1082 times.
✓ Branch 1 taken 10606 times.
11688 n_blocks = GET_BLOCK_COUNT();
237 11688 pixel = bytestream2_get_byte(gb);
238
239
2/2
✓ Branch 0 taken 50417 times.
✓ Branch 1 taken 11688 times.
62105 while (n_blocks--) {
240 50417 block_ptr = row_ptr + pixel_ptr;
241
2/2
✓ Branch 0 taken 201668 times.
✓ Branch 1 taken 50417 times.
252085 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
242
2/2
✓ Branch 0 taken 806672 times.
✓ Branch 1 taken 201668 times.
1008340 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
243 806672 pixels[block_ptr++] = pixel;
244 }
245 201668 block_ptr += row_inc;
246 }
247
3/4
✓ Branch 0 taken 631 times.
✓ Branch 1 taken 49786 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50417 times.
50417 ADVANCE_BLOCK();
248 }
249 11688 break;
250
251 /* 2-color block encoding */
252 17912 case 0x80:
253 case 0x90:
254 17912 n_blocks = (opcode & 0x0F) + 1;
255
256 /* figure out which color pair to use to paint the 2-color block */
257
2/2
✓ Branch 0 taken 5271 times.
✓ Branch 1 taken 12641 times.
17912 if ((opcode & 0xF0) == 0x80) {
258 /* fetch the next 2 colors from bytestream and store in next
259 * available entry in the color pair table */
260
2/2
✓ Branch 0 taken 10542 times.
✓ Branch 1 taken 5271 times.
15813 for (i = 0; i < CPAIR; i++) {
261 10542 pixel = bytestream2_get_byte(gb);
262 10542 color_table_index = CPAIR * color_pair_index + i;
263 10542 s->color_pairs[color_table_index] = pixel;
264 }
265 /* this is the base index to use for this block */
266 5271 color_table_index = CPAIR * color_pair_index;
267 5271 color_pair_index++;
268 /* wraparound */
269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5271 times.
5271 if (color_pair_index == COLORS_PER_TABLE)
270 color_pair_index = 0;
271 } else
272 12641 color_table_index = CPAIR * bytestream2_get_byte(gb);
273
274
2/2
✓ Branch 0 taken 18944 times.
✓ Branch 1 taken 17912 times.
36856 while (n_blocks--) {
275 18944 color_flags = bytestream2_get_be16(gb);
276 18944 flag_mask = 0x8000;
277 18944 block_ptr = row_ptr + pixel_ptr;
278
2/2
✓ Branch 0 taken 75776 times.
✓ Branch 1 taken 18944 times.
94720 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
279
2/2
✓ Branch 0 taken 303104 times.
✓ Branch 1 taken 75776 times.
378880 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
280
2/2
✓ Branch 0 taken 121822 times.
✓ Branch 1 taken 181282 times.
303104 if (color_flags & flag_mask)
281 121822 pixel = color_table_index + 1;
282 else
283 181282 pixel = color_table_index;
284 303104 flag_mask >>= 1;
285 303104 pixels[block_ptr++] = s->color_pairs[pixel];
286 }
287 75776 block_ptr += row_inc;
288 }
289
3/4
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 18903 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18944 times.
18944 ADVANCE_BLOCK();
290 }
291 17912 break;
292
293 /* 4-color block encoding */
294 35882 case 0xA0:
295 case 0xB0:
296 35882 n_blocks = (opcode & 0x0F) + 1;
297
298 /* figure out which color quad to use to paint the 4-color block */
299
2/2
✓ Branch 0 taken 14534 times.
✓ Branch 1 taken 21348 times.
35882 if ((opcode & 0xF0) == 0xA0) {
300 /* fetch the next 4 colors from bytestream and store in next
301 * available entry in the color quad table */
302
2/2
✓ Branch 0 taken 58136 times.
✓ Branch 1 taken 14534 times.
72670 for (i = 0; i < CQUAD; i++) {
303 58136 pixel = bytestream2_get_byte(gb);
304 58136 color_table_index = CQUAD * color_quad_index + i;
305 58136 s->color_quads[color_table_index] = pixel;
306 }
307 /* this is the base index to use for this block */
308 14534 color_table_index = CQUAD * color_quad_index;
309 14534 color_quad_index++;
310 /* wraparound */
311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14534 times.
14534 if (color_quad_index == COLORS_PER_TABLE)
312 color_quad_index = 0;
313 } else
314 21348 color_table_index = CQUAD * bytestream2_get_byte(gb);
315
316
2/2
✓ Branch 0 taken 41159 times.
✓ Branch 1 taken 35882 times.
77041 while (n_blocks--) {
317 41159 color_flags = bytestream2_get_be32(gb);
318 /* flag mask actually acts as a bit shift count here */
319 41159 flag_mask = 30;
320 41159 block_ptr = row_ptr + pixel_ptr;
321
2/2
✓ Branch 0 taken 164636 times.
✓ Branch 1 taken 41159 times.
205795 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
322
2/2
✓ Branch 0 taken 658544 times.
✓ Branch 1 taken 164636 times.
823180 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
323 658544 pixel = color_table_index +
324 658544 ((color_flags >> flag_mask) & 0x03);
325 658544 flag_mask -= 2;
326 658544 pixels[block_ptr++] = s->color_quads[pixel];
327 }
328 164636 block_ptr += row_inc;
329 }
330
3/4
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 41081 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 41159 times.
41159 ADVANCE_BLOCK();
331 }
332 35882 break;
333
334 /* 8-color block encoding */
335 33474 case 0xC0:
336 case 0xD0:
337 33474 n_blocks = (opcode & 0x0F) + 1;
338
339 /* figure out which color octet to use to paint the 8-color block */
340
2/2
✓ Branch 0 taken 10987 times.
✓ Branch 1 taken 22487 times.
33474 if ((opcode & 0xF0) == 0xC0) {
341 /* fetch the next 8 colors from bytestream and store in next
342 * available entry in the color octet table */
343
2/2
✓ Branch 0 taken 87896 times.
✓ Branch 1 taken 10987 times.
98883 for (i = 0; i < COCTET; i++) {
344 87896 pixel = bytestream2_get_byte(gb);
345 87896 color_table_index = COCTET * color_octet_index + i;
346 87896 s->color_octets[color_table_index] = pixel;
347 }
348 /* this is the base index to use for this block */
349 10987 color_table_index = COCTET * color_octet_index;
350 10987 color_octet_index++;
351 /* wraparound */
352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10987 times.
10987 if (color_octet_index == COLORS_PER_TABLE)
353 color_octet_index = 0;
354 } else
355 22487 color_table_index = COCTET * bytestream2_get_byte(gb);
356
357
2/2
✓ Branch 0 taken 42573 times.
✓ Branch 1 taken 33474 times.
76047 while (n_blocks--) {
358 /*
359 For this input of 6 hex bytes:
360 01 23 45 67 89 AB
361 Mangle it to this output:
362 flags_a = xx012456, flags_b = xx89A37B
363 */
364 /* build the color flags */
365 42573 int val1 = bytestream2_get_be16(gb);
366 42573 int val2 = bytestream2_get_be16(gb);
367 42573 int val3 = bytestream2_get_be16(gb);
368 42573 color_flags_a = ((val1 & 0xFFF0) << 8) | (val2 >> 4);
369 42573 color_flags_b = ((val3 & 0xFFF0) << 8) |
370 42573 ((val1 & 0x0F) << 8) | ((val2 & 0x0F) << 4) | (val3 & 0x0F);
371
372 42573 color_flags = color_flags_a;
373 /* flag mask actually acts as a bit shift count here */
374 42573 flag_mask = 21;
375 42573 block_ptr = row_ptr + pixel_ptr;
376
2/2
✓ Branch 0 taken 170292 times.
✓ Branch 1 taken 42573 times.
212865 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
377 /* reload flags at third row (iteration pixel_y == 2) */
378
2/2
✓ Branch 0 taken 42573 times.
✓ Branch 1 taken 127719 times.
170292 if (pixel_y == 2) {
379 42573 color_flags = color_flags_b;
380 42573 flag_mask = 21;
381 }
382
2/2
✓ Branch 0 taken 681168 times.
✓ Branch 1 taken 170292 times.
851460 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
383 681168 pixel = color_table_index +
384 681168 ((color_flags >> flag_mask) & 0x07);
385 681168 flag_mask -= 3;
386 681168 pixels[block_ptr++] = s->color_octets[pixel];
387 }
388 170292 block_ptr += row_inc;
389 }
390
3/4
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 42529 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42573 times.
42573 ADVANCE_BLOCK();
391 }
392 33474 break;
393
394 /* 16-color block encoding (every pixel is a different color) */
395 2043 case 0xE0:
396 case 0xF0:
397 2043 n_blocks = (opcode & 0x0F) + 1;
398
399
2/2
✓ Branch 0 taken 2197 times.
✓ Branch 1 taken 2043 times.
4240 while (n_blocks--) {
400 2197 block_ptr = row_ptr + pixel_ptr;
401
2/2
✓ Branch 0 taken 8788 times.
✓ Branch 1 taken 2197 times.
10985 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
402
2/2
✓ Branch 0 taken 35152 times.
✓ Branch 1 taken 8788 times.
43940 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
403 35152 pixels[block_ptr++] = bytestream2_get_byte(gb);
404 }
405 8788 block_ptr += row_inc;
406 }
407
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2197 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2197 times.
2197 ADVANCE_BLOCK();
408 }
409 2043 break;
410 }
411 }
412
413 120 return 0;
414 }
415
416 2 static av_cold int smc_decode_init(AVCodecContext *avctx)
417 {
418 2 SmcContext *s = avctx->priv_data;
419
420 2 s->avctx = avctx;
421 2 avctx->pix_fmt = AV_PIX_FMT_PAL8;
422
423 2 s->frame = av_frame_alloc();
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!s->frame)
425 return AVERROR(ENOMEM);
426
427 2 return 0;
428 }
429
430 120 static int smc_decode_frame(AVCodecContext *avctx,
431 void *data, int *got_frame,
432 AVPacket *avpkt)
433 {
434 120 const uint8_t *buf = avpkt->data;
435 120 int buf_size = avpkt->size;
436 120 SmcContext *s = avctx->priv_data;
437 int ret;
438 120 int total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
439
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (total_blocks / 1024 > avpkt->size)
441 return AVERROR_INVALIDDATA;
442
443 120 bytestream2_init(&s->gb, buf, buf_size);
444
445
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
120 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
446 return ret;
447
448 120 s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
449
450 120 ret = smc_decode_stream(s);
451
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (ret < 0)
452 return ret;
453
454 120 *got_frame = 1;
455
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
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 const 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 };
483