/src/ffmpeg/libavcodec/pafvideo.c
Line | Count | Source |
1 | | /* |
2 | | * Packed Animation File video decoder |
3 | | * Copyright (c) 2012 Paul B Mahol |
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 | | #include "libavutil/attributes.h" |
23 | | #include "libavutil/imgutils.h" |
24 | | #include "libavutil/mem.h" |
25 | | |
26 | | #include "avcodec.h" |
27 | | #include "bytestream.h" |
28 | | #include "copy_block.h" |
29 | | #include "codec_internal.h" |
30 | | #include "decode.h" |
31 | | |
32 | | |
33 | | static const uint8_t block_sequences[16][8] = { |
34 | | { 0, 0, 0, 0, 0, 0, 0, 0 }, |
35 | | { 2, 0, 0, 0, 0, 0, 0, 0 }, |
36 | | { 5, 7, 0, 0, 0, 0, 0, 0 }, |
37 | | { 5, 0, 0, 0, 0, 0, 0, 0 }, |
38 | | { 6, 0, 0, 0, 0, 0, 0, 0 }, |
39 | | { 5, 7, 5, 7, 0, 0, 0, 0 }, |
40 | | { 5, 7, 5, 0, 0, 0, 0, 0 }, |
41 | | { 5, 7, 6, 0, 0, 0, 0, 0 }, |
42 | | { 5, 5, 0, 0, 0, 0, 0, 0 }, |
43 | | { 3, 0, 0, 0, 0, 0, 0, 0 }, |
44 | | { 6, 6, 0, 0, 0, 0, 0, 0 }, |
45 | | { 2, 4, 0, 0, 0, 0, 0, 0 }, |
46 | | { 2, 4, 5, 7, 0, 0, 0, 0 }, |
47 | | { 2, 4, 5, 0, 0, 0, 0, 0 }, |
48 | | { 2, 4, 6, 0, 0, 0, 0, 0 }, |
49 | | { 2, 4, 5, 7, 5, 7, 0, 0 }, |
50 | | }; |
51 | | |
52 | | typedef struct PAFVideoDecContext { |
53 | | AVFrame *pic; |
54 | | GetByteContext gb; |
55 | | |
56 | | int width; |
57 | | int height; |
58 | | |
59 | | int current_frame; |
60 | | uint8_t *frame[4]; |
61 | | int dirty[4]; |
62 | | int frame_size; |
63 | | int video_size; |
64 | | |
65 | | uint8_t *opcodes; |
66 | | } PAFVideoDecContext; |
67 | | |
68 | | static av_cold int paf_video_close(AVCodecContext *avctx) |
69 | 845 | { |
70 | 845 | PAFVideoDecContext *c = avctx->priv_data; |
71 | 845 | int i; |
72 | | |
73 | 845 | av_frame_free(&c->pic); |
74 | | |
75 | 4.22k | for (i = 0; i < 4; i++) |
76 | 3.38k | av_freep(&c->frame[i]); |
77 | | |
78 | 845 | return 0; |
79 | 845 | } |
80 | | |
81 | | static av_cold int paf_video_init(AVCodecContext *avctx) |
82 | 845 | { |
83 | 845 | PAFVideoDecContext *c = avctx->priv_data; |
84 | 845 | int i; |
85 | 845 | int ret; |
86 | | |
87 | 845 | c->width = avctx->width; |
88 | 845 | c->height = avctx->height; |
89 | | |
90 | 845 | if (avctx->height & 3 || avctx->width & 3) { |
91 | 14 | av_log(avctx, AV_LOG_ERROR, |
92 | 14 | "width %d and height %d must be multiplie of 4.\n", |
93 | 14 | avctx->width, avctx->height); |
94 | 14 | return AVERROR_INVALIDDATA; |
95 | 14 | } |
96 | | |
97 | 831 | avctx->pix_fmt = AV_PIX_FMT_PAL8; |
98 | 831 | ret = av_image_check_size2(avctx->width, FFALIGN(avctx->height, 256), avctx->max_pixels, avctx->pix_fmt, 0, avctx); |
99 | 831 | if (ret < 0) |
100 | 141 | return ret; |
101 | | |
102 | 690 | c->pic = av_frame_alloc(); |
103 | 690 | if (!c->pic) |
104 | 0 | return AVERROR(ENOMEM); |
105 | | |
106 | 690 | c->frame_size = avctx->width * FFALIGN(avctx->height, 256); |
107 | 690 | c->video_size = avctx->width * avctx->height; |
108 | 3.45k | for (i = 0; i < 4; i++) { |
109 | 2.76k | c->frame[i] = av_mallocz(c->frame_size); |
110 | 2.76k | if (!c->frame[i]) |
111 | 0 | return AVERROR(ENOMEM); |
112 | 2.76k | } |
113 | | |
114 | 690 | return 0; |
115 | 690 | } |
116 | | |
117 | | static void read4x4block(PAFVideoDecContext *c, uint8_t *dst, int width) |
118 | 128k | { |
119 | 128k | int i; |
120 | | |
121 | 643k | for (i = 0; i < 4; i++) { |
122 | 514k | bytestream2_get_buffer(&c->gb, dst, 4); |
123 | 514k | dst += width; |
124 | 514k | } |
125 | 128k | } |
126 | | |
127 | | static void copy_color_mask(uint8_t *dst, int width, uint8_t mask, uint8_t color) |
128 | 159k | { |
129 | 159k | int i; |
130 | | |
131 | 797k | for (i = 0; i < 4; i++) { |
132 | 637k | if (mask & (1 << 7 - i)) |
133 | 142k | dst[i] = color; |
134 | 637k | if (mask & (1 << 3 - i)) |
135 | 144k | dst[width + i] = color; |
136 | 637k | } |
137 | 159k | } |
138 | | |
139 | | static void copy_src_mask(uint8_t *dst, int width, uint8_t mask, const uint8_t *src) |
140 | 374k | { |
141 | 374k | int i; |
142 | | |
143 | 1.87M | for (i = 0; i < 4; i++) { |
144 | 1.49M | if (mask & (1 << 7 - i)) |
145 | 335k | dst[i] = src[i]; |
146 | 1.49M | if (mask & (1 << 3 - i)) |
147 | 339k | dst[width + i] = src[width + i]; |
148 | 1.49M | } |
149 | 374k | } |
150 | | |
151 | | static void set_src_position(PAFVideoDecContext *c, |
152 | | const uint8_t **p, |
153 | | const uint8_t **pend) |
154 | 1.53M | { |
155 | 1.53M | int val = bytestream2_get_be16(&c->gb); |
156 | 1.53M | int page = val >> 14; |
157 | 1.53M | int x = (val & 0x7F); |
158 | 1.53M | int y = ((val >> 7) & 0x7F); |
159 | | |
160 | 1.53M | *p = c->frame[page] + x * 2 + y * 2 * c->width; |
161 | 1.53M | *pend = c->frame[page] + c->frame_size; |
162 | 1.53M | } |
163 | | |
164 | | static int decode_0(PAFVideoDecContext *c, const uint8_t *pkt, uint8_t code) |
165 | 6.16k | { |
166 | 6.16k | uint32_t opcode_size, offset; |
167 | 6.16k | uint8_t *dst, *dend, mask = 0, color = 0; |
168 | 6.16k | const uint8_t *src, *send, *opcodes; |
169 | 6.16k | int i, j, op = 0; |
170 | | |
171 | 6.16k | i = bytestream2_get_byte(&c->gb); |
172 | 6.16k | if (i) { |
173 | 3.59k | if (code & 0x10) { |
174 | 2.36k | int align; |
175 | | |
176 | 2.36k | align = bytestream2_tell(&c->gb) & 3; |
177 | 2.36k | if (align) |
178 | 1.63k | bytestream2_skip(&c->gb, 4 - align); |
179 | 2.36k | } |
180 | 127k | do { |
181 | 127k | int page, val, x, y; |
182 | 127k | val = bytestream2_get_be16(&c->gb); |
183 | 127k | page = val >> 14; |
184 | 127k | x = (val & 0x7F) * 2; |
185 | 127k | y = ((val >> 7) & 0x7F) * 2; |
186 | 127k | dst = c->frame[page] + x + y * c->width; |
187 | 127k | dend = c->frame[page] + c->frame_size; |
188 | 127k | offset = (x & 0x7F) * 2; |
189 | 127k | j = bytestream2_get_le16(&c->gb) + offset; |
190 | 127k | if (bytestream2_get_bytes_left(&c->gb) < (j - offset) * 16) |
191 | 1.19k | return AVERROR_INVALIDDATA; |
192 | 126k | c->dirty[page] = 1; |
193 | 129k | do { |
194 | 129k | offset++; |
195 | 129k | if (dst + 3 * c->width + 4 > dend) |
196 | 511 | return AVERROR_INVALIDDATA; |
197 | 128k | read4x4block(c, dst, c->width); |
198 | 128k | if ((offset & 0x3F) == 0) |
199 | 240 | dst += c->width * 3; |
200 | 128k | dst += 4; |
201 | 128k | } while (offset < j); |
202 | 126k | } while (--i); |
203 | 3.59k | } |
204 | | |
205 | 4.45k | dst = c->frame[c->current_frame]; |
206 | 4.45k | dend = c->frame[c->current_frame] + c->frame_size; |
207 | 1.29M | do { |
208 | 1.29M | set_src_position(c, &src, &send); |
209 | 1.29M | if ((src + 3 * c->width + 4 > send) || |
210 | 1.29M | (dst + 3 * c->width + 4 > dend) || |
211 | 1.29M | bytestream2_get_bytes_left(&c->gb) < 4) |
212 | 2.75k | return AVERROR_INVALIDDATA; |
213 | 1.28M | copy_block4(dst, src, c->width, c->width, 4); |
214 | 1.28M | i++; |
215 | 1.28M | if ((i & 0x3F) == 0) |
216 | 20.0k | dst += c->width * 3; |
217 | 1.28M | dst += 4; |
218 | 1.28M | } while (i < c->video_size / 16); |
219 | | |
220 | 1.70k | opcode_size = bytestream2_get_le16(&c->gb); |
221 | 1.70k | bytestream2_skip(&c->gb, 2); |
222 | | |
223 | 1.70k | if (bytestream2_get_bytes_left(&c->gb) < opcode_size) |
224 | 611 | return AVERROR_INVALIDDATA; |
225 | | |
226 | 1.09k | opcodes = pkt + bytestream2_tell(&c->gb); |
227 | 1.09k | bytestream2_skipu(&c->gb, opcode_size); |
228 | | |
229 | 1.09k | dst = c->frame[c->current_frame]; |
230 | | |
231 | 31.8k | for (i = 0; i < c->height; i += 4, dst += c->width * 3) |
232 | 323k | for (j = 0; j < c->width; j += 4, dst += 4) { |
233 | 292k | int opcode, k = 0; |
234 | 292k | if (op > opcode_size) |
235 | 326 | return AVERROR_INVALIDDATA; |
236 | 292k | if (j & 4) { |
237 | 133k | opcode = opcodes[op] & 15; |
238 | 133k | op++; |
239 | 158k | } else { |
240 | 158k | opcode = opcodes[op] >> 4; |
241 | 158k | } |
242 | | |
243 | 826k | while (block_sequences[opcode][k]) { |
244 | 534k | offset = c->width * 2; |
245 | 534k | code = block_sequences[opcode][k++]; |
246 | | |
247 | 534k | switch (code) { |
248 | 85.6k | case 2: |
249 | 85.6k | offset = 0; |
250 | 85.6k | av_fallthrough; |
251 | 100k | case 3: |
252 | 100k | color = bytestream2_get_byte(&c->gb); |
253 | 100k | av_fallthrough; |
254 | 159k | case 4: |
255 | 159k | mask = bytestream2_get_byte(&c->gb); |
256 | 159k | copy_color_mask(dst + offset, c->width, mask, color); |
257 | 159k | break; |
258 | 197k | case 5: |
259 | 197k | offset = 0; |
260 | 197k | av_fallthrough; |
261 | 240k | case 6: |
262 | 240k | set_src_position(c, &src, &send); |
263 | 240k | av_fallthrough; |
264 | 375k | case 7: |
265 | 375k | if (src + offset + c->width + 4 > send) |
266 | 226 | return AVERROR_INVALIDDATA; |
267 | 374k | mask = bytestream2_get_byte(&c->gb); |
268 | 374k | copy_src_mask(dst + offset, c->width, mask, src + offset); |
269 | 374k | break; |
270 | 534k | } |
271 | 534k | } |
272 | 292k | } |
273 | | |
274 | 538 | return 0; |
275 | 1.09k | } |
276 | | |
277 | | static int paf_video_decode(AVCodecContext *avctx, AVFrame *rframe, |
278 | | int *got_frame, AVPacket *pkt) |
279 | 330k | { |
280 | 330k | PAFVideoDecContext *c = avctx->priv_data; |
281 | 330k | uint8_t code, *dst, *end; |
282 | 330k | int i, frame, ret; |
283 | | |
284 | 330k | if (pkt->size < 2) |
285 | 61.5k | return AVERROR_INVALIDDATA; |
286 | | |
287 | 268k | bytestream2_init(&c->gb, pkt->data, pkt->size); |
288 | | |
289 | 268k | code = bytestream2_get_byte(&c->gb); |
290 | 268k | if ((code & 0xF) > 4 || (code & 0xF) == 3) { |
291 | 10.8k | avpriv_request_sample(avctx, "unknown/invalid code"); |
292 | 10.8k | return AVERROR_INVALIDDATA; |
293 | 10.8k | } |
294 | | |
295 | 257k | if ((code & 0xF) == 0 && |
296 | 9.53k | c->video_size / 32 - (int64_t)bytestream2_get_bytes_left(&c->gb) > c->video_size / 32 * (int64_t)avctx->discard_damaged_percentage / 100) |
297 | 3.28k | return AVERROR_INVALIDDATA; |
298 | | |
299 | 254k | if ((ret = ff_reget_buffer(avctx, c->pic, 0)) < 0) |
300 | 642 | return ret; |
301 | | |
302 | 253k | if (code & 0x20) { // frame is keyframe |
303 | 5.35k | memset(c->pic->data[1], 0, AVPALETTE_SIZE); |
304 | 5.35k | c->current_frame = 0; |
305 | 5.35k | c->pic->flags |= AV_FRAME_FLAG_KEY; |
306 | 5.35k | c->pic->pict_type = AV_PICTURE_TYPE_I; |
307 | 248k | } else { |
308 | 248k | c->pic->flags &= ~AV_FRAME_FLAG_KEY; |
309 | 248k | c->pic->pict_type = AV_PICTURE_TYPE_P; |
310 | 248k | } |
311 | | |
312 | 253k | if (code & 0x40) { // palette update |
313 | 3.63k | uint32_t *out = (uint32_t *)c->pic->data[1]; |
314 | 3.63k | int index, count; |
315 | | |
316 | 3.63k | index = bytestream2_get_byte(&c->gb); |
317 | 3.63k | count = bytestream2_get_byte(&c->gb) + 1; |
318 | | |
319 | 3.63k | if (index + count > 256) |
320 | 365 | return AVERROR_INVALIDDATA; |
321 | 3.26k | if (bytestream2_get_bytes_left(&c->gb) < 3 * count) |
322 | 1.26k | return AVERROR_INVALIDDATA; |
323 | | |
324 | 2.00k | out += index; |
325 | 11.3k | for (i = 0; i < count; i++) { |
326 | 9.36k | unsigned r, g, b; |
327 | | |
328 | 9.36k | r = bytestream2_get_byteu(&c->gb); |
329 | 9.36k | r = r << 2 | r >> 4; |
330 | 9.36k | g = bytestream2_get_byteu(&c->gb); |
331 | 9.36k | g = g << 2 | g >> 4; |
332 | 9.36k | b = bytestream2_get_byteu(&c->gb); |
333 | 9.36k | b = b << 2 | b >> 4; |
334 | 9.36k | *out++ = (0xFFU << 24) | (r << 16) | (g << 8) | b; |
335 | 9.36k | } |
336 | 2.00k | } |
337 | | |
338 | 252k | c->dirty[c->current_frame] = 1; |
339 | 252k | if (code & 0x20) |
340 | 21.6k | for (i = 0; i < 4; i++) { |
341 | 17.2k | if (c->dirty[i]) |
342 | 5.51k | memset(c->frame[i], 0, c->frame_size); |
343 | 17.2k | c->dirty[i] = 0; |
344 | 17.2k | } |
345 | | |
346 | 252k | switch (code & 0x0F) { |
347 | 6.16k | case 0: |
348 | | /* Block-based motion compensation using 4x4 blocks with either |
349 | | * horizontal or vertical vectors; might incorporate VQ as well. */ |
350 | 6.16k | if ((ret = decode_0(c, pkt->data, code)) < 0) |
351 | 5.62k | return ret; |
352 | 538 | break; |
353 | 2.43k | case 1: |
354 | | /* Uncompressed data. This mode specifies that (width * height) bytes |
355 | | * should be copied directly from the encoded buffer into the output. */ |
356 | 2.43k | dst = c->frame[c->current_frame]; |
357 | | // possibly chunk length data |
358 | 2.43k | bytestream2_skip(&c->gb, 2); |
359 | 2.43k | if (bytestream2_get_bytes_left(&c->gb) < c->video_size) |
360 | 2.20k | return AVERROR_INVALIDDATA; |
361 | 231 | bytestream2_get_bufferu(&c->gb, dst, c->video_size); |
362 | 231 | break; |
363 | 241k | case 2: |
364 | | /* Copy reference frame: Consume the next byte in the stream as the |
365 | | * reference frame (which should be 0, 1, 2, or 3, and should not be |
366 | | * the same as the current frame number). */ |
367 | 241k | frame = bytestream2_get_byte(&c->gb); |
368 | 241k | if (frame > 3) |
369 | 99.5k | return AVERROR_INVALIDDATA; |
370 | 141k | if (frame != c->current_frame) |
371 | 105k | memcpy(c->frame[c->current_frame], c->frame[frame], c->frame_size); |
372 | 141k | break; |
373 | 2.04k | case 4: |
374 | | /* Run length encoding.*/ |
375 | 2.04k | dst = c->frame[c->current_frame]; |
376 | 2.04k | end = dst + c->video_size; |
377 | | |
378 | 2.04k | bytestream2_skip(&c->gb, 2); |
379 | | |
380 | 485k | while (dst < end) { |
381 | 485k | int8_t code; |
382 | 485k | int count; |
383 | | |
384 | 485k | if (bytestream2_get_bytes_left(&c->gb) < 2) |
385 | 1.53k | return AVERROR_INVALIDDATA; |
386 | | |
387 | 484k | code = bytestream2_get_byteu(&c->gb); |
388 | 484k | count = FFABS(code) + 1; |
389 | | |
390 | 484k | if (dst + count > end) |
391 | 290 | return AVERROR_INVALIDDATA; |
392 | 483k | if (code < 0) |
393 | 121k | memset(dst, bytestream2_get_byteu(&c->gb), count); |
394 | 362k | else |
395 | 362k | bytestream2_get_buffer(&c->gb, dst, count); |
396 | 483k | dst += count; |
397 | 483k | } |
398 | 221 | break; |
399 | 221 | default: |
400 | 0 | av_assert0(0); |
401 | 252k | } |
402 | | |
403 | 142k | av_image_copy_plane(c->pic->data[0], c->pic->linesize[0], |
404 | 142k | c->frame[c->current_frame], c->width, |
405 | 142k | c->width, c->height); |
406 | | |
407 | 142k | c->current_frame = (c->current_frame + 1) & 3; |
408 | 142k | if ((ret = av_frame_ref(rframe, c->pic)) < 0) |
409 | 0 | return ret; |
410 | | |
411 | 142k | *got_frame = 1; |
412 | | |
413 | 142k | return pkt->size; |
414 | 142k | } |
415 | | |
416 | | const FFCodec ff_paf_video_decoder = { |
417 | | .p.name = "paf_video", |
418 | | CODEC_LONG_NAME("Amazing Studio Packed Animation File Video"), |
419 | | .p.type = AVMEDIA_TYPE_VIDEO, |
420 | | .p.id = AV_CODEC_ID_PAF_VIDEO, |
421 | | .priv_data_size = sizeof(PAFVideoDecContext), |
422 | | .init = paf_video_init, |
423 | | .close = paf_video_close, |
424 | | FF_CODEC_DECODE_CB(paf_video_decode), |
425 | | .p.capabilities = AV_CODEC_CAP_DR1, |
426 | | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
427 | | }; |