Directory: | ../../../ffmpeg/ |
---|---|
File: | src/libavcodec/smc.c |
Date: | 2022-07-05 19:52:29 |
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 "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 | |||
82 | 120 | static int smc_decode_stream(SmcContext *s) | |
83 | { | ||
84 | 120 | GetByteContext *gb = &s->gb; | |
85 | 120 | int width = s->avctx->width; | |
86 | 120 | int height = s->avctx->height; | |
87 | 120 | int stride = s->frame->linesize[0]; | |
88 | int i; | ||
89 | int chunk_size; | ||
90 | 120 | 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 | 120 | uint8_t * const pixels = s->frame->data[0]; | |
99 | |||
100 | 120 | int image_size = height * s->frame->linesize[0]; | |
101 | 120 | int row_ptr = 0; | |
102 | 120 | int pixel_ptr = 0; | |
103 | int pixel_x, pixel_y; | ||
104 | 120 | 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 | 120 | int color_pair_index = 0; | |
114 | 120 | int color_quad_index = 0; | |
115 | 120 | int color_octet_index = 0; | |
116 | |||
117 | /* make the palette available */ | ||
118 | 120 | memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); | |
119 | |||
120 | 120 | bytestream2_skip(gb, 1); | |
121 | 120 | chunk_size = bytestream2_get_be24(gb); | |
122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
|
120 | 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 | 120 | chunk_size = buf_size; | |
127 | 120 | total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4); | |
128 | |||
129 | /* traverse through the blocks */ | ||
130 |
2/2✓ Branch 0 taken 130697 times.
✓ Branch 1 taken 120 times.
|
130817 | while (total_blocks) { |
131 | /* sanity checks */ | ||
132 | /* make sure the row pointer hasn't gone wild */ | ||
133 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 130697 times.
|
130697 | 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 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 130697 times.
|
130697 | 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 | 130697 | opcode = bytestream2_get_byteu(gb); | |
144 |
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) { |
145 | /* skip n blocks */ | ||
146 | 28630 | case 0x00: | |
147 | case 0x10: | ||
148 |
2/2✓ Branch 0 taken 11959 times.
✓ Branch 1 taken 16671 times.
|
28630 | n_blocks = GET_BLOCK_COUNT(); |
149 |
2/2✓ Branch 0 taken 418385 times.
✓ Branch 1 taken 28630 times.
|
447015 | while (n_blocks--) { |
150 |
3/4✓ Branch 0 taken 6375 times.
✓ Branch 1 taken 412010 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 418385 times.
|
418385 | ADVANCE_BLOCK(); |
151 | } | ||
152 | 28630 | break; | |
153 | |||
154 | /* repeat last block n times */ | ||
155 | 1068 | case 0x20: | |
156 | case 0x30: | ||
157 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1057 times.
|
1068 | n_blocks = GET_BLOCK_COUNT(); |
158 | |||
159 | /* sanity check */ | ||
160 |
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)) { |
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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1068 times.
|
1068 | if (pixel_ptr == 0) |
168 | ✗ | prev_block_ptr1 = | |
169 | ✗ | (row_ptr - s->avctx->width * 4) + s->avctx->width - 4; | |
170 | else | ||
171 | 1068 | prev_block_ptr1 = row_ptr + pixel_ptr - 4; | |
172 | |||
173 |
2/2✓ Branch 0 taken 2325 times.
✓ Branch 1 taken 1068 times.
|
3393 | while (n_blocks--) { |
174 | 2325 | block_ptr = row_ptr + pixel_ptr; | |
175 | 2325 | prev_block_ptr = prev_block_ptr1; | |
176 |
2/2✓ Branch 0 taken 9300 times.
✓ Branch 1 taken 2325 times.
|
11625 | for (pixel_y = 0; pixel_y < 4; pixel_y++) { |
177 |
2/2✓ Branch 0 taken 37200 times.
✓ Branch 1 taken 9300 times.
|
46500 | for (pixel_x = 0; pixel_x < 4; pixel_x++) { |
178 | 37200 | pixels[block_ptr++] = pixels[prev_block_ptr++]; | |
179 | } | ||
180 | 9300 | block_ptr += row_inc; | |
181 | 9300 | prev_block_ptr += row_inc; | |
182 | } | ||
183 |
3/4✓ Branch 0 taken 31 times.
✓ Branch 1 taken 2294 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2325 times.
|
2325 | ADVANCE_BLOCK(); |
184 | } | ||
185 | 1068 | 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 | 11688 | case 0x60: | |
236 | case 0x70: | ||
237 |
2/2✓ Branch 0 taken 1082 times.
✓ Branch 1 taken 10606 times.
|
11688 | n_blocks = GET_BLOCK_COUNT(); |
238 | 11688 | pixel = bytestream2_get_byte(gb); | |
239 | |||
240 |
2/2✓ Branch 0 taken 50417 times.
✓ Branch 1 taken 11688 times.
|
62105 | while (n_blocks--) { |
241 | 50417 | block_ptr = row_ptr + pixel_ptr; | |
242 |
2/2✓ Branch 0 taken 201668 times.
✓ Branch 1 taken 50417 times.
|
252085 | for (pixel_y = 0; pixel_y < 4; pixel_y++) { |
243 |
2/2✓ Branch 0 taken 806672 times.
✓ Branch 1 taken 201668 times.
|
1008340 | for (pixel_x = 0; pixel_x < 4; pixel_x++) { |
244 | 806672 | pixels[block_ptr++] = pixel; | |
245 | } | ||
246 | 201668 | block_ptr += row_inc; | |
247 | } | ||
248 |
3/4✓ Branch 0 taken 631 times.
✓ Branch 1 taken 49786 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50417 times.
|
50417 | ADVANCE_BLOCK(); |
249 | } | ||
250 | 11688 | break; | |
251 | |||
252 | /* 2-color block encoding */ | ||
253 | 17912 | case 0x80: | |
254 | case 0x90: | ||
255 | 17912 | n_blocks = (opcode & 0x0F) + 1; | |
256 | |||
257 | /* figure out which color pair to use to paint the 2-color block */ | ||
258 |
2/2✓ Branch 0 taken 5271 times.
✓ Branch 1 taken 12641 times.
|
17912 | 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 |
2/2✓ Branch 0 taken 10542 times.
✓ Branch 1 taken 5271 times.
|
15813 | for (i = 0; i < CPAIR; i++) { |
262 | 10542 | pixel = bytestream2_get_byte(gb); | |
263 | 10542 | color_table_index = CPAIR * color_pair_index + i; | |
264 | 10542 | s->color_pairs[color_table_index] = pixel; | |
265 | } | ||
266 | /* this is the base index to use for this block */ | ||
267 | 5271 | color_table_index = CPAIR * color_pair_index; | |
268 | 5271 | color_pair_index++; | |
269 | /* wraparound */ | ||
270 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5271 times.
|
5271 | if (color_pair_index == COLORS_PER_TABLE) |
271 | ✗ | color_pair_index = 0; | |
272 | } else | ||
273 | 12641 | color_table_index = CPAIR * bytestream2_get_byte(gb); | |
274 | |||
275 |
2/2✓ Branch 0 taken 18944 times.
✓ Branch 1 taken 17912 times.
|
36856 | while (n_blocks--) { |
276 | 18944 | color_flags = bytestream2_get_be16(gb); | |
277 | 18944 | flag_mask = 0x8000; | |
278 | 18944 | block_ptr = row_ptr + pixel_ptr; | |
279 |
2/2✓ Branch 0 taken 75776 times.
✓ Branch 1 taken 18944 times.
|
94720 | for (pixel_y = 0; pixel_y < 4; pixel_y++) { |
280 |
2/2✓ Branch 0 taken 303104 times.
✓ Branch 1 taken 75776 times.
|
378880 | for (pixel_x = 0; pixel_x < 4; pixel_x++) { |
281 |
2/2✓ Branch 0 taken 121822 times.
✓ Branch 1 taken 181282 times.
|
303104 | if (color_flags & flag_mask) |
282 | 121822 | pixel = color_table_index + 1; | |
283 | else | ||
284 | 181282 | pixel = color_table_index; | |
285 | 303104 | flag_mask >>= 1; | |
286 | 303104 | pixels[block_ptr++] = s->color_pairs[pixel]; | |
287 | } | ||
288 | 75776 | block_ptr += row_inc; | |
289 | } | ||
290 |
3/4✓ Branch 0 taken 41 times.
✓ Branch 1 taken 18903 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18944 times.
|
18944 | ADVANCE_BLOCK(); |
291 | } | ||
292 | 17912 | break; | |
293 | |||
294 | /* 4-color block encoding */ | ||
295 | 35882 | case 0xA0: | |
296 | case 0xB0: | ||
297 | 35882 | n_blocks = (opcode & 0x0F) + 1; | |
298 | |||
299 | /* figure out which color quad to use to paint the 4-color block */ | ||
300 |
2/2✓ Branch 0 taken 14534 times.
✓ Branch 1 taken 21348 times.
|
35882 | 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 |
2/2✓ Branch 0 taken 58136 times.
✓ Branch 1 taken 14534 times.
|
72670 | for (i = 0; i < CQUAD; i++) { |
304 | 58136 | pixel = bytestream2_get_byte(gb); | |
305 | 58136 | color_table_index = CQUAD * color_quad_index + i; | |
306 | 58136 | s->color_quads[color_table_index] = pixel; | |
307 | } | ||
308 | /* this is the base index to use for this block */ | ||
309 | 14534 | color_table_index = CQUAD * color_quad_index; | |
310 | 14534 | color_quad_index++; | |
311 | /* wraparound */ | ||
312 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14534 times.
|
14534 | if (color_quad_index == COLORS_PER_TABLE) |
313 | ✗ | color_quad_index = 0; | |
314 | } else | ||
315 | 21348 | color_table_index = CQUAD * bytestream2_get_byte(gb); | |
316 | |||
317 |
2/2✓ Branch 0 taken 41159 times.
✓ Branch 1 taken 35882 times.
|
77041 | while (n_blocks--) { |
318 | 41159 | color_flags = bytestream2_get_be32(gb); | |
319 | /* flag mask actually acts as a bit shift count here */ | ||
320 | 41159 | flag_mask = 30; | |
321 | 41159 | block_ptr = row_ptr + pixel_ptr; | |
322 |
2/2✓ Branch 0 taken 164636 times.
✓ Branch 1 taken 41159 times.
|
205795 | for (pixel_y = 0; pixel_y < 4; pixel_y++) { |
323 |
2/2✓ Branch 0 taken 658544 times.
✓ Branch 1 taken 164636 times.
|
823180 | for (pixel_x = 0; pixel_x < 4; pixel_x++) { |
324 | 658544 | pixel = color_table_index + | |
325 | 658544 | ((color_flags >> flag_mask) & 0x03); | |
326 | 658544 | flag_mask -= 2; | |
327 | 658544 | pixels[block_ptr++] = s->color_quads[pixel]; | |
328 | } | ||
329 | 164636 | block_ptr += row_inc; | |
330 | } | ||
331 |
3/4✓ Branch 0 taken 78 times.
✓ Branch 1 taken 41081 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 41159 times.
|
41159 | ADVANCE_BLOCK(); |
332 | } | ||
333 | 35882 | break; | |
334 | |||
335 | /* 8-color block encoding */ | ||
336 | 33474 | case 0xC0: | |
337 | case 0xD0: | ||
338 | 33474 | n_blocks = (opcode & 0x0F) + 1; | |
339 | |||
340 | /* figure out which color octet to use to paint the 8-color block */ | ||
341 |
2/2✓ Branch 0 taken 10987 times.
✓ Branch 1 taken 22487 times.
|
33474 | 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 |
2/2✓ Branch 0 taken 87896 times.
✓ Branch 1 taken 10987 times.
|
98883 | for (i = 0; i < COCTET; i++) { |
345 | 87896 | pixel = bytestream2_get_byte(gb); | |
346 | 87896 | color_table_index = COCTET * color_octet_index + i; | |
347 | 87896 | s->color_octets[color_table_index] = pixel; | |
348 | } | ||
349 | /* this is the base index to use for this block */ | ||
350 | 10987 | color_table_index = COCTET * color_octet_index; | |
351 | 10987 | color_octet_index++; | |
352 | /* wraparound */ | ||
353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10987 times.
|
10987 | if (color_octet_index == COLORS_PER_TABLE) |
354 | ✗ | color_octet_index = 0; | |
355 | } else | ||
356 | 22487 | color_table_index = COCTET * bytestream2_get_byte(gb); | |
357 | |||
358 |
2/2✓ Branch 0 taken 42573 times.
✓ Branch 1 taken 33474 times.
|
76047 | 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 | 42573 | int val1 = bytestream2_get_be16(gb); | |
367 | 42573 | int val2 = bytestream2_get_be16(gb); | |
368 | 42573 | int val3 = bytestream2_get_be16(gb); | |
369 | 42573 | color_flags_a = ((val1 & 0xFFF0) << 8) | (val2 >> 4); | |
370 | 42573 | color_flags_b = ((val3 & 0xFFF0) << 8) | | |
371 | 42573 | ((val1 & 0x0F) << 8) | ((val2 & 0x0F) << 4) | (val3 & 0x0F); | |
372 | |||
373 | 42573 | color_flags = color_flags_a; | |
374 | /* flag mask actually acts as a bit shift count here */ | ||
375 | 42573 | flag_mask = 21; | |
376 | 42573 | block_ptr = row_ptr + pixel_ptr; | |
377 |
2/2✓ Branch 0 taken 170292 times.
✓ Branch 1 taken 42573 times.
|
212865 | for (pixel_y = 0; pixel_y < 4; pixel_y++) { |
378 | /* reload flags at third row (iteration pixel_y == 2) */ | ||
379 |
2/2✓ Branch 0 taken 42573 times.
✓ Branch 1 taken 127719 times.
|
170292 | if (pixel_y == 2) { |
380 | 42573 | color_flags = color_flags_b; | |
381 | 42573 | flag_mask = 21; | |
382 | } | ||
383 |
2/2✓ Branch 0 taken 681168 times.
✓ Branch 1 taken 170292 times.
|
851460 | for (pixel_x = 0; pixel_x < 4; pixel_x++) { |
384 | 681168 | pixel = color_table_index + | |
385 | 681168 | ((color_flags >> flag_mask) & 0x07); | |
386 | 681168 | flag_mask -= 3; | |
387 | 681168 | pixels[block_ptr++] = s->color_octets[pixel]; | |
388 | } | ||
389 | 170292 | block_ptr += row_inc; | |
390 | } | ||
391 |
3/4✓ Branch 0 taken 44 times.
✓ Branch 1 taken 42529 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42573 times.
|
42573 | ADVANCE_BLOCK(); |
392 | } | ||
393 | 33474 | break; | |
394 | |||
395 | /* 16-color block encoding (every pixel is a different color) */ | ||
396 | 2043 | case 0xE0: | |
397 | case 0xF0: | ||
398 | 2043 | n_blocks = (opcode & 0x0F) + 1; | |
399 | |||
400 |
2/2✓ Branch 0 taken 2197 times.
✓ Branch 1 taken 2043 times.
|
4240 | while (n_blocks--) { |
401 | 2197 | block_ptr = row_ptr + pixel_ptr; | |
402 |
2/2✓ Branch 0 taken 8788 times.
✓ Branch 1 taken 2197 times.
|
10985 | for (pixel_y = 0; pixel_y < 4; pixel_y++) { |
403 |
2/2✓ Branch 0 taken 35152 times.
✓ Branch 1 taken 8788 times.
|
43940 | for (pixel_x = 0; pixel_x < 4; pixel_x++) { |
404 | 35152 | pixels[block_ptr++] = bytestream2_get_byte(gb); | |
405 | } | ||
406 | 8788 | block_ptr += row_inc; | |
407 | } | ||
408 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 2197 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2197 times.
|
2197 | ADVANCE_BLOCK(); |
409 | } | ||
410 | 2043 | break; | |
411 | } | ||
412 | } | ||
413 | |||
414 | 120 | return 0; | |
415 | } | ||
416 | |||
417 | 2 | static av_cold int smc_decode_init(AVCodecContext *avctx) | |
418 | { | ||
419 | 2 | SmcContext *s = avctx->priv_data; | |
420 | |||
421 | 2 | s->avctx = avctx; | |
422 | 2 | avctx->pix_fmt = AV_PIX_FMT_PAL8; | |
423 | |||
424 | 2 | s->frame = av_frame_alloc(); | |
425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!s->frame) |
426 | ✗ | return AVERROR(ENOMEM); | |
427 | |||
428 | 2 | return 0; | |
429 | } | ||
430 | |||
431 | 120 | static int smc_decode_frame(AVCodecContext *avctx, AVFrame *rframe, | |
432 | int *got_frame, 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(rframe, 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 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 |