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