Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Cinepak 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 | * Cinepak video decoder | ||
25 | * @author Ewald Snel <ewald@rambo.its.tudelft.nl> | ||
26 | * | ||
27 | * @see For more information on the Cinepak algorithm, visit: | ||
28 | * http://www.csse.monash.edu.au/~timf/ | ||
29 | * @see For more information on the quirky data inside Sega FILM/CPK files, visit: | ||
30 | * http://wiki.multimedia.cx/index.php?title=Sega_FILM | ||
31 | * | ||
32 | * Cinepak colorspace support (c) 2013 Rl, Aetey Global Technologies AB | ||
33 | * @author Cinepak colorspace, Rl, Aetey Global Technologies AB | ||
34 | */ | ||
35 | |||
36 | #include <stdio.h> | ||
37 | #include <string.h> | ||
38 | |||
39 | #include "libavutil/common.h" | ||
40 | #include "libavutil/intreadwrite.h" | ||
41 | #include "avcodec.h" | ||
42 | #include "codec_internal.h" | ||
43 | #include "decode.h" | ||
44 | |||
45 | |||
46 | typedef uint8_t cvid_codebook[12]; | ||
47 | |||
48 | #define MAX_STRIPS 32 | ||
49 | |||
50 | typedef struct cvid_strip { | ||
51 | uint16_t id; | ||
52 | uint16_t x1, y1; | ||
53 | uint16_t x2, y2; | ||
54 | cvid_codebook v4_codebook[256]; | ||
55 | cvid_codebook v1_codebook[256]; | ||
56 | } cvid_strip; | ||
57 | |||
58 | typedef struct CinepakContext { | ||
59 | |||
60 | AVCodecContext *avctx; | ||
61 | AVFrame *frame; | ||
62 | |||
63 | const unsigned char *data; | ||
64 | int size; | ||
65 | |||
66 | int width, height; | ||
67 | |||
68 | int palette_video; | ||
69 | cvid_strip strips[MAX_STRIPS]; | ||
70 | |||
71 | int sega_film_skip_bytes; | ||
72 | |||
73 | uint32_t pal[256]; | ||
74 | } CinepakContext; | ||
75 | |||
76 | 2384 | static void cinepak_decode_codebook (cvid_codebook *codebook, | |
77 | int chunk_id, int size, const uint8_t *data) | ||
78 | { | ||
79 | 2384 | const uint8_t *eod = (data + size); | |
80 | uint32_t flag, mask; | ||
81 | int i, n; | ||
82 | uint8_t *p; | ||
83 | |||
84 | /* check if this chunk contains 4- or 6-element vectors */ | ||
85 |
2/2✓ Branch 0 taken 416 times.
✓ Branch 1 taken 1968 times.
|
2384 | n = (chunk_id & 0x04) ? 4 : 6; |
86 | 2384 | flag = 0; | |
87 | 2384 | mask = 0; | |
88 | |||
89 | 2384 | p = codebook[0]; | |
90 |
2/2✓ Branch 0 taken 455222 times.
✓ Branch 1 taken 1667 times.
|
456889 | for (i=0; i < 256; i++) { |
91 |
4/4✓ Branch 0 taken 292735 times.
✓ Branch 1 taken 162487 times.
✓ Branch 2 taken 9271 times.
✓ Branch 3 taken 283464 times.
|
455222 | if ((chunk_id & 0x01) && !(mask >>= 1)) { |
92 |
2/2✓ Branch 0 taken 127 times.
✓ Branch 1 taken 9144 times.
|
9271 | if ((data + 4) > eod) |
93 | 127 | break; | |
94 | |||
95 | 9144 | flag = AV_RB32 (data); | |
96 | 9144 | data += 4; | |
97 | 9144 | mask = 0x80000000; | |
98 | } | ||
99 | |||
100 |
4/4✓ Branch 0 taken 292608 times.
✓ Branch 1 taken 162487 times.
✓ Branch 2 taken 110427 times.
✓ Branch 3 taken 182181 times.
|
727419 | if (!(chunk_id & 0x01) || (flag & mask)) { |
101 | int k, kk; | ||
102 | |||
103 |
2/2✓ Branch 0 taken 590 times.
✓ Branch 1 taken 272324 times.
|
272914 | if ((data + n) > eod) |
104 | 590 | break; | |
105 | |||
106 |
2/2✓ Branch 0 taken 1089296 times.
✓ Branch 1 taken 272324 times.
|
1361620 | for (k = 0; k < 4; ++k) { |
107 | 1089296 | int r = *data++; | |
108 |
2/2✓ Branch 0 taken 3267888 times.
✓ Branch 1 taken 1089296 times.
|
4357184 | for (kk = 0; kk < 3; ++kk) |
109 | 3267888 | *p++ = r; | |
110 | } | ||
111 |
2/2✓ Branch 0 taken 249669 times.
✓ Branch 1 taken 22655 times.
|
272324 | if (n == 6) { |
112 | int r, g, b, u, v; | ||
113 | 249669 | u = *(int8_t *)data++; | |
114 | 249669 | v = *(int8_t *)data++; | |
115 | 249669 | p -= 12; | |
116 |
2/2✓ Branch 0 taken 998676 times.
✓ Branch 1 taken 249669 times.
|
1248345 | for(k=0; k<4; ++k) { |
117 | 998676 | r = *p++ + v*2; | |
118 | 998676 | g = *p++ - (u/2) - v; | |
119 | 998676 | b = *p + u*2; | |
120 | 998676 | p -= 2; | |
121 | 998676 | *p++ = av_clip_uint8(r); | |
122 | 998676 | *p++ = av_clip_uint8(g); | |
123 | 998676 | *p++ = av_clip_uint8(b); | |
124 | } | ||
125 | } | ||
126 | } else { | ||
127 | 182181 | p += 12; | |
128 | } | ||
129 | } | ||
130 | 2384 | } | |
131 | |||
132 | 1192 | static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip, | |
133 | int chunk_id, int size, const uint8_t *data) | ||
134 | { | ||
135 | 1192 | const uint8_t *eod = (data + size); | |
136 | uint32_t flag, mask; | ||
137 | uint8_t *cb0, *cb1, *cb2, *cb3; | ||
138 | int x, y; | ||
139 | char *ip0, *ip1, *ip2, *ip3; | ||
140 | |||
141 | 1192 | flag = 0; | |
142 | 1192 | mask = 0; | |
143 | |||
144 |
2/2✓ Branch 0 taken 21662 times.
✓ Branch 1 taken 1189 times.
|
22851 | for (y=strip->y1; y < strip->y2; y+=4) { |
145 | |||
146 | /* take care of y dimension not being multiple of 4, such streams exist */ | ||
147 | 43324 | ip0 = ip1 = ip2 = ip3 = s->frame->data[0] + | |
148 |
2/2✓ Branch 0 taken 1658 times.
✓ Branch 1 taken 20004 times.
|
21662 | (s->palette_video?strip->x1:strip->x1*3) + (y * s->frame->linesize[0]); |
149 |
1/2✓ Branch 0 taken 21662 times.
✗ Branch 1 not taken.
|
21662 | if(s->avctx->height - y > 1) { |
150 | 21662 | ip1 = ip0 + s->frame->linesize[0]; | |
151 |
1/2✓ Branch 0 taken 21662 times.
✗ Branch 1 not taken.
|
21662 | if(s->avctx->height - y > 2) { |
152 | 21662 | ip2 = ip1 + s->frame->linesize[0]; | |
153 |
2/2✓ Branch 0 taken 21354 times.
✓ Branch 1 taken 308 times.
|
21662 | if(s->avctx->height - y > 3) { |
154 | 21354 | ip3 = ip2 + s->frame->linesize[0]; | |
155 | } | ||
156 | } | ||
157 | } | ||
158 | /* to get the correct picture for not-multiple-of-4 cases let us fill each | ||
159 | * block from the bottom up, thus possibly overwriting the bottommost line | ||
160 | * more than once but ending with the correct data in place | ||
161 | * (instead of in-loop checking) */ | ||
162 | |||
163 |
2/2✓ Branch 0 taken 1481920 times.
✓ Branch 1 taken 21659 times.
|
1503579 | for (x=strip->x1; x < strip->x2; x+=4) { |
164 |
4/4✓ Branch 0 taken 1168298 times.
✓ Branch 1 taken 313622 times.
✓ Branch 2 taken 38088 times.
✓ Branch 3 taken 1130210 times.
|
1481920 | if ((chunk_id & 0x01) && !(mask >>= 1)) { |
165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38088 times.
|
38088 | if ((data + 4) > eod) |
166 | ✗ | return AVERROR_INVALIDDATA; | |
167 | |||
168 | 38088 | flag = AV_RB32 (data); | |
169 | 38088 | data += 4; | |
170 | 38088 | mask = 0x80000000; | |
171 | } | ||
172 | |||
173 |
4/4✓ Branch 0 taken 1168298 times.
✓ Branch 1 taken 313622 times.
✓ Branch 2 taken 693343 times.
✓ Branch 3 taken 474955 times.
|
1481920 | if (!(chunk_id & 0x01) || (flag & mask)) { |
174 |
4/4✓ Branch 0 taken 1005540 times.
✓ Branch 1 taken 1425 times.
✓ Branch 2 taken 30275 times.
✓ Branch 3 taken 975265 times.
|
1006965 | if (!(chunk_id & 0x02) && !(mask >>= 1)) { |
175 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30275 times.
|
30275 | if ((data + 4) > eod) |
176 | ✗ | return AVERROR_INVALIDDATA; | |
177 | |||
178 | 30275 | flag = AV_RB32 (data); | |
179 | 30275 | data += 4; | |
180 | 30275 | mask = 0x80000000; | |
181 | } | ||
182 | |||
183 |
4/4✓ Branch 0 taken 1005540 times.
✓ Branch 1 taken 1425 times.
✓ Branch 2 taken 323204 times.
✓ Branch 3 taken 682336 times.
|
1331594 | if ((chunk_id & 0x02) || (~flag & mask)) { |
184 | uint8_t *p; | ||
185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 324629 times.
|
324629 | if (data >= eod) |
186 | ✗ | return AVERROR_INVALIDDATA; | |
187 | |||
188 | 324629 | p = strip->v1_codebook[*data++]; | |
189 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 324629 times.
|
324629 | if (s->palette_video) { |
190 | ✗ | ip3[0] = ip3[1] = ip2[0] = ip2[1] = p[6]; | |
191 | ✗ | ip3[2] = ip3[3] = ip2[2] = ip2[3] = p[9]; | |
192 | ✗ | ip1[0] = ip1[1] = ip0[0] = ip0[1] = p[0]; | |
193 | ✗ | ip1[2] = ip1[3] = ip0[2] = ip0[3] = p[3]; | |
194 | } else { | ||
195 | 324629 | p += 6; | |
196 | 324629 | memcpy(ip3 + 0, p, 3); memcpy(ip3 + 3, p, 3); | |
197 | 324629 | memcpy(ip2 + 0, p, 3); memcpy(ip2 + 3, p, 3); | |
198 | 324629 | p += 3; /* ... + 9 */ | |
199 | 324629 | memcpy(ip3 + 6, p, 3); memcpy(ip3 + 9, p, 3); | |
200 | 324629 | memcpy(ip2 + 6, p, 3); memcpy(ip2 + 9, p, 3); | |
201 | 324629 | p -= 9; /* ... + 0 */ | |
202 | 324629 | memcpy(ip1 + 0, p, 3); memcpy(ip1 + 3, p, 3); | |
203 | 324629 | memcpy(ip0 + 0, p, 3); memcpy(ip0 + 3, p, 3); | |
204 | 324629 | p += 3; /* ... + 3 */ | |
205 | 324629 | memcpy(ip1 + 6, p, 3); memcpy(ip1 + 9, p, 3); | |
206 | 324629 | memcpy(ip0 + 6, p, 3); memcpy(ip0 + 9, p, 3); | |
207 | } | ||
208 | |||
209 |
1/2✓ Branch 0 taken 682336 times.
✗ Branch 1 not taken.
|
682336 | } else if (flag & mask) { |
210 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 682333 times.
|
682336 | if ((data + 4) > eod) |
211 | 3 | return AVERROR_INVALIDDATA; | |
212 | |||
213 | 682333 | cb0 = strip->v4_codebook[*data++]; | |
214 | 682333 | cb1 = strip->v4_codebook[*data++]; | |
215 | 682333 | cb2 = strip->v4_codebook[*data++]; | |
216 | 682333 | cb3 = strip->v4_codebook[*data++]; | |
217 |
2/2✓ Branch 0 taken 66297 times.
✓ Branch 1 taken 616036 times.
|
682333 | if (s->palette_video) { |
218 | uint8_t *p; | ||
219 | 66297 | p = ip3; | |
220 | 66297 | *p++ = cb2[6]; | |
221 | 66297 | *p++ = cb2[9]; | |
222 | 66297 | *p++ = cb3[6]; | |
223 | 66297 | *p = cb3[9]; | |
224 | 66297 | p = ip2; | |
225 | 66297 | *p++ = cb2[0]; | |
226 | 66297 | *p++ = cb2[3]; | |
227 | 66297 | *p++ = cb3[0]; | |
228 | 66297 | *p = cb3[3]; | |
229 | 66297 | p = ip1; | |
230 | 66297 | *p++ = cb0[6]; | |
231 | 66297 | *p++ = cb0[9]; | |
232 | 66297 | *p++ = cb1[6]; | |
233 | 66297 | *p = cb1[9]; | |
234 | 66297 | p = ip0; | |
235 | 66297 | *p++ = cb0[0]; | |
236 | 66297 | *p++ = cb0[3]; | |
237 | 66297 | *p++ = cb1[0]; | |
238 | 66297 | *p = cb1[3]; | |
239 | } else { | ||
240 | 616036 | memcpy(ip3 + 0, cb2 + 6, 6); | |
241 | 616036 | memcpy(ip3 + 6, cb3 + 6, 6); | |
242 | 616036 | memcpy(ip2 + 0, cb2 + 0, 6); | |
243 | 616036 | memcpy(ip2 + 6, cb3 + 0, 6); | |
244 | 616036 | memcpy(ip1 + 0, cb0 + 6, 6); | |
245 | 616036 | memcpy(ip1 + 6, cb1 + 6, 6); | |
246 | 616036 | memcpy(ip0 + 0, cb0 + 0, 6); | |
247 | 616036 | memcpy(ip0 + 6, cb1 + 0, 6); | |
248 | } | ||
249 | |||
250 | } | ||
251 | } | ||
252 | |||
253 |
2/2✓ Branch 0 taken 66297 times.
✓ Branch 1 taken 1415620 times.
|
1481917 | if (s->palette_video) { |
254 | 66297 | ip0 += 4; ip1 += 4; | |
255 | 66297 | ip2 += 4; ip3 += 4; | |
256 | } else { | ||
257 | 1415620 | ip0 += 12; ip1 += 12; | |
258 | 1415620 | ip2 += 12; ip3 += 12; | |
259 | } | ||
260 | } | ||
261 | } | ||
262 | |||
263 | 1189 | return 0; | |
264 | } | ||
265 | |||
266 | 1192 | static int cinepak_decode_strip (CinepakContext *s, | |
267 | cvid_strip *strip, const uint8_t *data, int size) | ||
268 | { | ||
269 | 1192 | const uint8_t *eod = (data + size); | |
270 | int chunk_id, chunk_size; | ||
271 | |||
272 | /* coordinate sanity checks */ | ||
273 |
1/2✓ Branch 0 taken 1192 times.
✗ Branch 1 not taken.
|
1192 | if (strip->x2 > s->width || |
274 |
1/2✓ Branch 0 taken 1192 times.
✗ Branch 1 not taken.
|
1192 | strip->y2 > s->height || |
275 |
2/4✓ Branch 0 taken 1192 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1192 times.
|
1192 | strip->x1 >= strip->x2 || strip->y1 >= strip->y2) |
276 | ✗ | return AVERROR_INVALIDDATA; | |
277 | |||
278 |
1/2✓ Branch 0 taken 3576 times.
✗ Branch 1 not taken.
|
3576 | while ((data + 4) <= eod) { |
279 | 3576 | chunk_id = data[0]; | |
280 | 3576 | chunk_size = AV_RB24 (&data[1]) - 4; | |
281 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3576 times.
|
3576 | if(chunk_size < 0) |
282 | ✗ | return AVERROR_INVALIDDATA; | |
283 | |||
284 | 3576 | data += 4; | |
285 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3573 times.
|
3576 | chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size; |
286 | |||
287 |
3/4✓ Branch 0 taken 1192 times.
✓ Branch 1 taken 1192 times.
✓ Branch 2 taken 1192 times.
✗ Branch 3 not taken.
|
3576 | switch (chunk_id) { |
288 | |||
289 | 1192 | case 0x20: | |
290 | case 0x21: | ||
291 | case 0x24: | ||
292 | case 0x25: | ||
293 | 1192 | cinepak_decode_codebook (strip->v4_codebook, chunk_id, | |
294 | chunk_size, data); | ||
295 | 1192 | break; | |
296 | |||
297 | 1192 | case 0x22: | |
298 | case 0x23: | ||
299 | case 0x26: | ||
300 | case 0x27: | ||
301 | 1192 | cinepak_decode_codebook (strip->v1_codebook, chunk_id, | |
302 | chunk_size, data); | ||
303 | 1192 | break; | |
304 | |||
305 | 1192 | case 0x30: | |
306 | case 0x31: | ||
307 | case 0x32: | ||
308 | 1192 | return cinepak_decode_vectors (s, strip, chunk_id, | |
309 | chunk_size, data); | ||
310 | } | ||
311 | |||
312 | 2384 | data += chunk_size; | |
313 | } | ||
314 | |||
315 | ✗ | return AVERROR_INVALIDDATA; | |
316 | } | ||
317 | |||
318 | 626 | static int cinepak_predecode_check (CinepakContext *s) | |
319 | { | ||
320 | int num_strips; | ||
321 | int encoded_buf_size; | ||
322 | |||
323 | 626 | num_strips = AV_RB16 (&s->data[8]); | |
324 | 626 | encoded_buf_size = AV_RB24(&s->data[1]); | |
325 | |||
326 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 626 times.
|
626 | if (s->size < encoded_buf_size * (int64_t)(100 - s->avctx->discard_damaged_percentage) / 100) |
327 | ✗ | return AVERROR_INVALIDDATA; | |
328 | |||
329 | /* if this is the first frame, check for deviant Sega FILM data */ | ||
330 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 618 times.
|
626 | if (s->sega_film_skip_bytes == -1) { |
331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (!encoded_buf_size) { |
332 | ✗ | avpriv_request_sample(s->avctx, "encoded_buf_size 0"); | |
333 | ✗ | return AVERROR_PATCHWELCOME; | |
334 | } | ||
335 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
8 | if (encoded_buf_size != s->size && (s->size % encoded_buf_size) != 0) { |
336 | /* If the encoded frame size differs from the frame size as indicated | ||
337 | * by the container file, this data likely comes from a Sega FILM/CPK file. | ||
338 | * If the frame header is followed by the bytes FE 00 00 06 00 00 then | ||
339 | * this is probably one of the two known files that have 6 extra bytes | ||
340 | * after the frame header. Else, assume 2 extra bytes. The container | ||
341 | * size also cannot be a multiple of the encoded size. */ | ||
342 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (s->size >= 16 && |
343 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | (s->data[10] == 0xFE) && |
344 | ✗ | (s->data[11] == 0x00) && | |
345 | ✗ | (s->data[12] == 0x00) && | |
346 | ✗ | (s->data[13] == 0x06) && | |
347 | ✗ | (s->data[14] == 0x00) && | |
348 | ✗ | (s->data[15] == 0x00)) | |
349 | ✗ | s->sega_film_skip_bytes = 6; | |
350 | else | ||
351 | 1 | s->sega_film_skip_bytes = 2; | |
352 | } else | ||
353 | 7 | s->sega_film_skip_bytes = 0; | |
354 | } | ||
355 | |||
356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 626 times.
|
626 | if (s->size < 10 + s->sega_film_skip_bytes + num_strips * 12) |
357 | ✗ | return AVERROR_INVALIDDATA; | |
358 | |||
359 |
1/2✓ Branch 0 taken 626 times.
✗ Branch 1 not taken.
|
626 | if (num_strips) { |
360 | 626 | const uint8_t *data = s->data + 10 + s->sega_film_skip_bytes; | |
361 | 626 | int strip_size = AV_RB24 (data + 1); | |
362 |
2/4✓ Branch 0 taken 626 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 626 times.
|
626 | if (strip_size < 12 || strip_size > encoded_buf_size) |
363 | ✗ | return AVERROR_INVALIDDATA; | |
364 | } | ||
365 | |||
366 | 626 | return 0; | |
367 | } | ||
368 | |||
369 | 626 | static int cinepak_decode (CinepakContext *s) | |
370 | { | ||
371 | 626 | const uint8_t *eod = (s->data + s->size); | |
372 | int i, result, strip_size, frame_flags, num_strips; | ||
373 | 626 | int y0 = 0; | |
374 | |||
375 | 626 | frame_flags = s->data[0]; | |
376 | 626 | num_strips = AV_RB16 (&s->data[8]); | |
377 | |||
378 | 626 | s->data += 10 + s->sega_film_skip_bytes; | |
379 | |||
380 | 626 | num_strips = FFMIN(num_strips, MAX_STRIPS); | |
381 | |||
382 | 626 | s->frame->flags &= ~AV_FRAME_FLAG_KEY; | |
383 | |||
384 |
2/2✓ Branch 0 taken 1192 times.
✓ Branch 1 taken 623 times.
|
1815 | for (i=0; i < num_strips; i++) { |
385 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1192 times.
|
1192 | if ((s->data + 12) > eod) |
386 | ✗ | return AVERROR_INVALIDDATA; | |
387 | |||
388 | 1192 | s->strips[i].id = s->data[0]; | |
389 | /* zero y1 means "relative to the previous stripe" */ | ||
390 |
1/2✓ Branch 0 taken 1192 times.
✗ Branch 1 not taken.
|
1192 | if (!(s->strips[i].y1 = AV_RB16 (&s->data[4]))) |
391 | 1192 | s->strips[i].y2 = (s->strips[i].y1 = y0) + AV_RB16 (&s->data[8]); | |
392 | else | ||
393 | ✗ | s->strips[i].y2 = AV_RB16 (&s->data[8]); | |
394 | 1192 | s->strips[i].x1 = AV_RB16 (&s->data[6]); | |
395 | 1192 | s->strips[i].x2 = AV_RB16 (&s->data[10]); | |
396 | |||
397 |
2/2✓ Branch 0 taken 146 times.
✓ Branch 1 taken 1046 times.
|
1192 | if (s->strips[i].id == 0x10) |
398 | 146 | s->frame->flags |= AV_FRAME_FLAG_KEY; | |
399 | |||
400 | 1192 | strip_size = AV_RB24 (&s->data[1]) - 12; | |
401 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1192 times.
|
1192 | if (strip_size < 0) |
402 | ✗ | return AVERROR_INVALIDDATA; | |
403 | 1192 | s->data += 12; | |
404 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1189 times.
|
1192 | strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size; |
405 | |||
406 |
4/4✓ Branch 0 taken 566 times.
✓ Branch 1 taken 626 times.
✓ Branch 2 taken 77 times.
✓ Branch 3 taken 489 times.
|
1192 | if ((i > 0) && !(frame_flags & 0x01)) { |
407 | 77 | memcpy (s->strips[i].v4_codebook, s->strips[i-1].v4_codebook, | |
408 | sizeof(s->strips[i].v4_codebook)); | ||
409 | 77 | memcpy (s->strips[i].v1_codebook, s->strips[i-1].v1_codebook, | |
410 | sizeof(s->strips[i].v1_codebook)); | ||
411 | } | ||
412 | |||
413 | 1192 | result = cinepak_decode_strip (s, &s->strips[i], s->data, strip_size); | |
414 | |||
415 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1189 times.
|
1192 | if (result != 0) |
416 | 3 | return result; | |
417 | |||
418 | 1189 | s->data += strip_size; | |
419 | 1189 | y0 = s->strips[i].y2; | |
420 | } | ||
421 | 623 | return 0; | |
422 | } | ||
423 | |||
424 | 22 | static av_cold int cinepak_decode_init(AVCodecContext *avctx) | |
425 | { | ||
426 | 22 | CinepakContext *s = avctx->priv_data; | |
427 | |||
428 | 22 | s->avctx = avctx; | |
429 | 22 | s->width = (avctx->width + 3) & ~3; | |
430 | 22 | s->height = (avctx->height + 3) & ~3; | |
431 | |||
432 | 22 | s->sega_film_skip_bytes = -1; /* uninitialized state */ | |
433 | |||
434 | // check for paletted data | ||
435 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
|
22 | if (avctx->bits_per_coded_sample != 8) { |
436 | 20 | s->palette_video = 0; | |
437 | 20 | avctx->pix_fmt = AV_PIX_FMT_RGB24; | |
438 | } else { | ||
439 | 2 | s->palette_video = 1; | |
440 | 2 | avctx->pix_fmt = AV_PIX_FMT_PAL8; | |
441 | } | ||
442 | |||
443 | 22 | s->frame = av_frame_alloc(); | |
444 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | if (!s->frame) |
445 | ✗ | return AVERROR(ENOMEM); | |
446 | |||
447 | 22 | return 0; | |
448 | } | ||
449 | |||
450 | 626 | static int cinepak_decode_frame(AVCodecContext *avctx, AVFrame *rframe, | |
451 | int *got_frame, AVPacket *avpkt) | ||
452 | { | ||
453 | 626 | const uint8_t *buf = avpkt->data; | |
454 | 626 | int ret = 0, buf_size = avpkt->size; | |
455 | 626 | CinepakContext *s = avctx->priv_data; | |
456 | int num_strips; | ||
457 | |||
458 | 626 | s->data = buf; | |
459 | 626 | s->size = buf_size; | |
460 | |||
461 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 626 times.
|
626 | if (s->size < 10) |
462 | ✗ | return AVERROR_INVALIDDATA; | |
463 | |||
464 | 626 | num_strips = AV_RB16 (&s->data[8]); | |
465 | |||
466 | //Empty frame, do not waste time | ||
467 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 626 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
626 | if (!num_strips && (!s->palette_video || !av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL))) |
468 | ✗ | return buf_size; | |
469 | |||
470 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 626 times.
|
626 | if ((ret = cinepak_predecode_check(s)) < 0) { |
471 | ✗ | av_log(avctx, AV_LOG_ERROR, "cinepak_predecode_check failed\n"); | |
472 | ✗ | return ret; | |
473 | } | ||
474 | |||
475 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 626 times.
|
626 | if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) |
476 | ✗ | return ret; | |
477 | |||
478 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 570 times.
|
626 | if (s->palette_video) { |
479 | #if FF_API_PALETTE_HAS_CHANGED | ||
480 | FF_DISABLE_DEPRECATION_WARNINGS | ||
481 | 56 | s->frame->palette_has_changed = | |
482 | #endif | ||
483 | 56 | ff_copy_palette(s->pal, avpkt, avctx); | |
484 | #if FF_API_PALETTE_HAS_CHANGED | ||
485 | FF_ENABLE_DEPRECATION_WARNINGS | ||
486 | #endif | ||
487 | } | ||
488 | |||
489 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 623 times.
|
626 | if ((ret = cinepak_decode(s)) < 0) { |
490 | 3 | av_log(avctx, AV_LOG_ERROR, "cinepak_decode failed\n"); | |
491 | } | ||
492 | |||
493 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 570 times.
|
626 | if (s->palette_video) |
494 | 56 | memcpy (s->frame->data[1], s->pal, AVPALETTE_SIZE); | |
495 | |||
496 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 626 times.
|
626 | if ((ret = av_frame_ref(rframe, s->frame)) < 0) |
497 | ✗ | return ret; | |
498 | |||
499 | 626 | *got_frame = 1; | |
500 | |||
501 | /* report that the buffer was completely consumed */ | ||
502 | 626 | return buf_size; | |
503 | } | ||
504 | |||
505 | 22 | static av_cold int cinepak_decode_end(AVCodecContext *avctx) | |
506 | { | ||
507 | 22 | CinepakContext *s = avctx->priv_data; | |
508 | |||
509 | 22 | av_frame_free(&s->frame); | |
510 | |||
511 | 22 | return 0; | |
512 | } | ||
513 | |||
514 | const FFCodec ff_cinepak_decoder = { | ||
515 | .p.name = "cinepak", | ||
516 | CODEC_LONG_NAME("Cinepak"), | ||
517 | .p.type = AVMEDIA_TYPE_VIDEO, | ||
518 | .p.id = AV_CODEC_ID_CINEPAK, | ||
519 | .priv_data_size = sizeof(CinepakContext), | ||
520 | .init = cinepak_decode_init, | ||
521 | .close = cinepak_decode_end, | ||
522 | FF_CODEC_DECODE_CB(cinepak_decode_frame), | ||
523 | .p.capabilities = AV_CODEC_CAP_DR1, | ||
524 | }; | ||
525 |