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