blob: 0e70be1000a1f45a1b84671966bffb3ca6c53f83
1 | /* |
2 | * Westwood Studios VQA 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 | * VQA Video Decoder |
25 | * @author Mike Melanson (melanson@pcisys.net) |
26 | * @see http://wiki.multimedia.cx/index.php?title=VQA |
27 | * |
28 | * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending |
29 | * on the type of data in the file. |
30 | * |
31 | * This decoder needs the 42-byte VQHD header from the beginning |
32 | * of the VQA file passed through the extradata field. The VQHD header |
33 | * is laid out as: |
34 | * |
35 | * bytes 0-3 chunk fourcc: 'VQHD' |
36 | * bytes 4-7 chunk size in big-endian format, should be 0x0000002A |
37 | * bytes 8-49 VQHD chunk data |
38 | * |
39 | * Bytes 8-49 are what this decoder expects to see. |
40 | * |
41 | * Briefly, VQA is a vector quantized animation format that operates in a |
42 | * VGA palettized colorspace. It operates on pixel vectors (blocks) |
43 | * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector |
44 | * codebooks, palette information, and code maps for rendering vectors onto |
45 | * frames. Any of these components can also be compressed with a run-length |
46 | * encoding (RLE) algorithm commonly referred to as "format80". |
47 | * |
48 | * VQA takes a novel approach to rate control. Each group of n frames |
49 | * (usually, n = 8) relies on a different vector codebook. Rather than |
50 | * transporting an entire codebook every 8th frame, the new codebook is |
51 | * broken up into 8 pieces and sent along with the compressed video chunks |
52 | * for each of the 8 frames preceding the 8 frames which require the |
53 | * codebook. A full codebook is also sent on the very first frame of a |
54 | * file. This is an interesting technique, although it makes random file |
55 | * seeking difficult despite the fact that the frames are all intracoded. |
56 | * |
57 | * V1,2 VQA uses 12-bit codebook indexes. If the 12-bit indexes were |
58 | * packed into bytes and then RLE compressed, bytewise, the results would |
59 | * be poor. That is why the coding method divides each index into 2 parts, |
60 | * the top 4 bits and the bottom 8 bits, then RL encodes the 4-bit pieces |
61 | * together and the 8-bit pieces together. If most of the vectors are |
62 | * clustered into one group of 256 vectors, most of the 4-bit index pieces |
63 | * should be the same. |
64 | */ |
65 | |
66 | #include <stdio.h> |
67 | #include <stdlib.h> |
68 | #include <string.h> |
69 | |
70 | #include "libavutil/intreadwrite.h" |
71 | #include "libavutil/imgutils.h" |
72 | #include "avcodec.h" |
73 | #include "bytestream.h" |
74 | #include "internal.h" |
75 | |
76 | #define PALETTE_COUNT 256 |
77 | #define VQA_HEADER_SIZE 0x2A |
78 | |
79 | /* allocate the maximum vector space, regardless of the file version: |
80 | * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */ |
81 | #define MAX_CODEBOOK_VECTORS 0xFF00 |
82 | #define SOLID_PIXEL_VECTORS 0x100 |
83 | #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS) |
84 | #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4) |
85 | |
86 | #define CBF0_TAG MKBETAG('C', 'B', 'F', '0') |
87 | #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z') |
88 | #define CBP0_TAG MKBETAG('C', 'B', 'P', '0') |
89 | #define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z') |
90 | #define CPL0_TAG MKBETAG('C', 'P', 'L', '0') |
91 | #define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z') |
92 | #define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z') |
93 | |
94 | typedef struct VqaContext { |
95 | |
96 | AVCodecContext *avctx; |
97 | GetByteContext gb; |
98 | |
99 | uint32_t palette[PALETTE_COUNT]; |
100 | |
101 | int width; /* width of a frame */ |
102 | int height; /* height of a frame */ |
103 | int vector_width; /* width of individual vector */ |
104 | int vector_height; /* height of individual vector */ |
105 | int vqa_version; /* this should be either 1, 2 or 3 */ |
106 | |
107 | unsigned char *codebook; /* the current codebook */ |
108 | int codebook_size; |
109 | unsigned char *next_codebook_buffer; /* accumulator for next codebook */ |
110 | int next_codebook_buffer_index; |
111 | |
112 | unsigned char *decode_buffer; |
113 | int decode_buffer_size; |
114 | |
115 | /* number of frames to go before replacing codebook */ |
116 | int partial_countdown; |
117 | int partial_count; |
118 | |
119 | } VqaContext; |
120 | |
121 | static av_cold int vqa_decode_init(AVCodecContext *avctx) |
122 | { |
123 | VqaContext *s = avctx->priv_data; |
124 | int i, j, codebook_index, ret; |
125 | |
126 | s->avctx = avctx; |
127 | avctx->pix_fmt = AV_PIX_FMT_PAL8; |
128 | |
129 | /* make sure the extradata made it */ |
130 | if (s->avctx->extradata_size != VQA_HEADER_SIZE) { |
131 | av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n", VQA_HEADER_SIZE); |
132 | return AVERROR(EINVAL); |
133 | } |
134 | |
135 | /* load up the VQA parameters from the header */ |
136 | s->vqa_version = s->avctx->extradata[0]; |
137 | switch (s->vqa_version) { |
138 | case 1: |
139 | case 2: |
140 | break; |
141 | case 3: |
142 | avpriv_report_missing_feature(avctx, "VQA Version %d", s->vqa_version); |
143 | return AVERROR_PATCHWELCOME; |
144 | default: |
145 | avpriv_request_sample(avctx, "VQA Version %i", s->vqa_version); |
146 | return AVERROR_PATCHWELCOME; |
147 | } |
148 | s->width = AV_RL16(&s->avctx->extradata[6]); |
149 | s->height = AV_RL16(&s->avctx->extradata[8]); |
150 | if ((ret = av_image_check_size(s->width, s->height, 0, avctx)) < 0) { |
151 | s->width= s->height= 0; |
152 | return ret; |
153 | } |
154 | s->vector_width = s->avctx->extradata[10]; |
155 | s->vector_height = s->avctx->extradata[11]; |
156 | s->partial_count = s->partial_countdown = s->avctx->extradata[13]; |
157 | |
158 | /* the vector dimensions have to meet very stringent requirements */ |
159 | if ((s->vector_width != 4) || |
160 | ((s->vector_height != 2) && (s->vector_height != 4))) { |
161 | /* return without further initialization */ |
162 | return AVERROR_INVALIDDATA; |
163 | } |
164 | |
165 | if (s->width % s->vector_width || s->height % s->vector_height) { |
166 | av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n"); |
167 | return AVERROR_INVALIDDATA; |
168 | } |
169 | |
170 | /* allocate codebooks */ |
171 | s->codebook_size = MAX_CODEBOOK_SIZE; |
172 | s->codebook = av_malloc(s->codebook_size); |
173 | if (!s->codebook) |
174 | goto fail; |
175 | s->next_codebook_buffer = av_malloc(s->codebook_size); |
176 | if (!s->next_codebook_buffer) |
177 | goto fail; |
178 | |
179 | /* allocate decode buffer */ |
180 | s->decode_buffer_size = (s->width / s->vector_width) * |
181 | (s->height / s->vector_height) * 2; |
182 | s->decode_buffer = av_mallocz(s->decode_buffer_size); |
183 | if (!s->decode_buffer) |
184 | goto fail; |
185 | |
186 | /* initialize the solid-color vectors */ |
187 | if (s->vector_height == 4) { |
188 | codebook_index = 0xFF00 * 16; |
189 | for (i = 0; i < 256; i++) |
190 | for (j = 0; j < 16; j++) |
191 | s->codebook[codebook_index++] = i; |
192 | } else { |
193 | codebook_index = 0xF00 * 8; |
194 | for (i = 0; i < 256; i++) |
195 | for (j = 0; j < 8; j++) |
196 | s->codebook[codebook_index++] = i; |
197 | } |
198 | s->next_codebook_buffer_index = 0; |
199 | |
200 | return 0; |
201 | fail: |
202 | av_freep(&s->codebook); |
203 | av_freep(&s->next_codebook_buffer); |
204 | av_freep(&s->decode_buffer); |
205 | return AVERROR(ENOMEM); |
206 | } |
207 | |
208 | #define CHECK_COUNT() \ |
209 | if (dest_index + count > dest_size) { \ |
210 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \ |
211 | av_log(s->avctx, AV_LOG_ERROR, "current dest_index = %d, count = %d, dest_size = %d\n", \ |
212 | dest_index, count, dest_size); \ |
213 | return AVERROR_INVALIDDATA; \ |
214 | } |
215 | |
216 | #define CHECK_COPY(idx) \ |
217 | if (idx < 0 || idx + count > dest_size) { \ |
218 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \ |
219 | av_log(s->avctx, AV_LOG_ERROR, "current src_pos = %d, count = %d, dest_size = %d\n", \ |
220 | src_pos, count, dest_size); \ |
221 | return AVERROR_INVALIDDATA; \ |
222 | } |
223 | |
224 | |
225 | static int decode_format80(VqaContext *s, int src_size, |
226 | unsigned char *dest, int dest_size, int check_size) { |
227 | |
228 | int dest_index = 0; |
229 | int count, opcode, start; |
230 | int src_pos; |
231 | unsigned char color; |
232 | int i; |
233 | |
234 | if (src_size < 0 || src_size > bytestream2_get_bytes_left(&s->gb)) { |
235 | av_log(s->avctx, AV_LOG_ERROR, "Chunk size %d is out of range\n", |
236 | src_size); |
237 | return AVERROR_INVALIDDATA; |
238 | } |
239 | |
240 | start = bytestream2_tell(&s->gb); |
241 | while (bytestream2_tell(&s->gb) - start < src_size) { |
242 | opcode = bytestream2_get_byte(&s->gb); |
243 | ff_tlog(s->avctx, "opcode %02X: ", opcode); |
244 | |
245 | /* 0x80 means that frame is finished */ |
246 | if (opcode == 0x80) |
247 | break; |
248 | |
249 | if (dest_index >= dest_size) { |
250 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n", |
251 | dest_index, dest_size); |
252 | return AVERROR_INVALIDDATA; |
253 | } |
254 | |
255 | if (opcode == 0xFF) { |
256 | |
257 | count = bytestream2_get_le16(&s->gb); |
258 | src_pos = bytestream2_get_le16(&s->gb); |
259 | ff_tlog(s->avctx, "(1) copy %X bytes from absolute pos %X\n", count, src_pos); |
260 | CHECK_COUNT(); |
261 | CHECK_COPY(src_pos); |
262 | for (i = 0; i < count; i++) |
263 | dest[dest_index + i] = dest[src_pos + i]; |
264 | dest_index += count; |
265 | |
266 | } else if (opcode == 0xFE) { |
267 | |
268 | count = bytestream2_get_le16(&s->gb); |
269 | color = bytestream2_get_byte(&s->gb); |
270 | ff_tlog(s->avctx, "(2) set %X bytes to %02X\n", count, color); |
271 | CHECK_COUNT(); |
272 | memset(&dest[dest_index], color, count); |
273 | dest_index += count; |
274 | |
275 | } else if ((opcode & 0xC0) == 0xC0) { |
276 | |
277 | count = (opcode & 0x3F) + 3; |
278 | src_pos = bytestream2_get_le16(&s->gb); |
279 | ff_tlog(s->avctx, "(3) copy %X bytes from absolute pos %X\n", count, src_pos); |
280 | CHECK_COUNT(); |
281 | CHECK_COPY(src_pos); |
282 | for (i = 0; i < count; i++) |
283 | dest[dest_index + i] = dest[src_pos + i]; |
284 | dest_index += count; |
285 | |
286 | } else if (opcode > 0x80) { |
287 | |
288 | count = opcode & 0x3F; |
289 | ff_tlog(s->avctx, "(4) copy %X bytes from source to dest\n", count); |
290 | CHECK_COUNT(); |
291 | bytestream2_get_buffer(&s->gb, &dest[dest_index], count); |
292 | dest_index += count; |
293 | |
294 | } else { |
295 | |
296 | count = ((opcode & 0x70) >> 4) + 3; |
297 | src_pos = bytestream2_get_byte(&s->gb) | ((opcode & 0x0F) << 8); |
298 | ff_tlog(s->avctx, "(5) copy %X bytes from relpos %X\n", count, src_pos); |
299 | CHECK_COUNT(); |
300 | CHECK_COPY(dest_index - src_pos); |
301 | for (i = 0; i < count; i++) |
302 | dest[dest_index + i] = dest[dest_index - src_pos + i]; |
303 | dest_index += count; |
304 | } |
305 | } |
306 | |
307 | /* validate that the entire destination buffer was filled; this is |
308 | * important for decoding frame maps since each vector needs to have a |
309 | * codebook entry; it is not important for compressed codebooks because |
310 | * not every entry needs to be filled */ |
311 | if (check_size) |
312 | if (dest_index < dest_size) { |
313 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n", |
314 | dest_index, dest_size); |
315 | memset(dest + dest_index, 0, dest_size - dest_index); |
316 | } |
317 | |
318 | return 0; // let's display what we decoded anyway |
319 | } |
320 | |
321 | static int vqa_decode_chunk(VqaContext *s, AVFrame *frame) |
322 | { |
323 | unsigned int chunk_type; |
324 | unsigned int chunk_size; |
325 | int byte_skip; |
326 | unsigned int index = 0; |
327 | int i; |
328 | unsigned char r, g, b; |
329 | int index_shift; |
330 | int res; |
331 | |
332 | int cbf0_chunk = -1; |
333 | int cbfz_chunk = -1; |
334 | int cbp0_chunk = -1; |
335 | int cbpz_chunk = -1; |
336 | int cpl0_chunk = -1; |
337 | int cplz_chunk = -1; |
338 | int vptz_chunk = -1; |
339 | |
340 | int x, y; |
341 | int lines = 0; |
342 | int pixel_ptr; |
343 | int vector_index = 0; |
344 | int lobyte = 0; |
345 | int hibyte = 0; |
346 | int lobytes = 0; |
347 | int hibytes = s->decode_buffer_size / 2; |
348 | |
349 | /* first, traverse through the frame and find the subchunks */ |
350 | while (bytestream2_get_bytes_left(&s->gb) >= 8) { |
351 | |
352 | chunk_type = bytestream2_get_be32u(&s->gb); |
353 | index = bytestream2_tell(&s->gb); |
354 | chunk_size = bytestream2_get_be32u(&s->gb); |
355 | |
356 | switch (chunk_type) { |
357 | |
358 | case CBF0_TAG: |
359 | cbf0_chunk = index; |
360 | break; |
361 | |
362 | case CBFZ_TAG: |
363 | cbfz_chunk = index; |
364 | break; |
365 | |
366 | case CBP0_TAG: |
367 | cbp0_chunk = index; |
368 | break; |
369 | |
370 | case CBPZ_TAG: |
371 | cbpz_chunk = index; |
372 | break; |
373 | |
374 | case CPL0_TAG: |
375 | cpl0_chunk = index; |
376 | break; |
377 | |
378 | case CPLZ_TAG: |
379 | cplz_chunk = index; |
380 | break; |
381 | |
382 | case VPTZ_TAG: |
383 | vptz_chunk = index; |
384 | break; |
385 | |
386 | default: |
387 | av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n", |
388 | av_fourcc2str(av_bswap32(chunk_type)), chunk_type); |
389 | break; |
390 | } |
391 | |
392 | byte_skip = chunk_size & 0x01; |
393 | bytestream2_skip(&s->gb, chunk_size + byte_skip); |
394 | } |
395 | |
396 | /* next, deal with the palette */ |
397 | if ((cpl0_chunk != -1) && (cplz_chunk != -1)) { |
398 | |
399 | /* a chunk should not have both chunk types */ |
400 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CPL0 and CPLZ chunks\n"); |
401 | return AVERROR_INVALIDDATA; |
402 | } |
403 | |
404 | /* decompress the palette chunk */ |
405 | if (cplz_chunk != -1) { |
406 | |
407 | /* yet to be handled */ |
408 | |
409 | } |
410 | |
411 | /* convert the RGB palette into the machine's endian format */ |
412 | if (cpl0_chunk != -1) { |
413 | |
414 | bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET); |
415 | chunk_size = bytestream2_get_be32(&s->gb); |
416 | /* sanity check the palette size */ |
417 | if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) { |
418 | av_log(s->avctx, AV_LOG_ERROR, "problem: found a palette chunk with %d colors\n", |
419 | chunk_size / 3); |
420 | return AVERROR_INVALIDDATA; |
421 | } |
422 | for (i = 0; i < chunk_size / 3; i++) { |
423 | /* scale by 4 to transform 6-bit palette -> 8-bit */ |
424 | r = bytestream2_get_byteu(&s->gb) * 4; |
425 | g = bytestream2_get_byteu(&s->gb) * 4; |
426 | b = bytestream2_get_byteu(&s->gb) * 4; |
427 | s->palette[i] = 0xFFU << 24 | r << 16 | g << 8 | b; |
428 | s->palette[i] |= s->palette[i] >> 6 & 0x30303; |
429 | } |
430 | } |
431 | |
432 | /* next, look for a full codebook */ |
433 | if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { |
434 | |
435 | /* a chunk should not have both chunk types */ |
436 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n"); |
437 | return AVERROR_INVALIDDATA; |
438 | } |
439 | |
440 | /* decompress the full codebook chunk */ |
441 | if (cbfz_chunk != -1) { |
442 | |
443 | bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET); |
444 | chunk_size = bytestream2_get_be32(&s->gb); |
445 | if ((res = decode_format80(s, chunk_size, s->codebook, |
446 | s->codebook_size, 0)) < 0) |
447 | return res; |
448 | } |
449 | |
450 | /* copy a full codebook */ |
451 | if (cbf0_chunk != -1) { |
452 | |
453 | bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET); |
454 | chunk_size = bytestream2_get_be32(&s->gb); |
455 | /* sanity check the full codebook size */ |
456 | if (chunk_size > MAX_CODEBOOK_SIZE) { |
457 | av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n", |
458 | chunk_size); |
459 | return AVERROR_INVALIDDATA; |
460 | } |
461 | |
462 | bytestream2_get_buffer(&s->gb, s->codebook, chunk_size); |
463 | } |
464 | |
465 | /* decode the frame */ |
466 | if (vptz_chunk == -1) { |
467 | |
468 | /* something is wrong if there is no VPTZ chunk */ |
469 | av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n"); |
470 | return AVERROR_INVALIDDATA; |
471 | } |
472 | |
473 | bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET); |
474 | chunk_size = bytestream2_get_be32(&s->gb); |
475 | if ((res = decode_format80(s, chunk_size, |
476 | s->decode_buffer, s->decode_buffer_size, 1)) < 0) |
477 | return res; |
478 | |
479 | /* render the final PAL8 frame */ |
480 | if (s->vector_height == 4) |
481 | index_shift = 4; |
482 | else |
483 | index_shift = 3; |
484 | for (y = 0; y < s->height; y += s->vector_height) { |
485 | for (x = 0; x < s->width; x += 4, lobytes++, hibytes++) { |
486 | pixel_ptr = y * frame->linesize[0] + x; |
487 | |
488 | /* get the vector index, the method for which varies according to |
489 | * VQA file version */ |
490 | switch (s->vqa_version) { |
491 | |
492 | case 1: |
493 | lobyte = s->decode_buffer[lobytes * 2]; |
494 | hibyte = s->decode_buffer[(lobytes * 2) + 1]; |
495 | vector_index = ((hibyte << 8) | lobyte) >> 3; |
496 | vector_index <<= index_shift; |
497 | lines = s->vector_height; |
498 | /* uniform color fill - a quick hack */ |
499 | if (hibyte == 0xFF) { |
500 | while (lines--) { |
501 | frame->data[0][pixel_ptr + 0] = 255 - lobyte; |
502 | frame->data[0][pixel_ptr + 1] = 255 - lobyte; |
503 | frame->data[0][pixel_ptr + 2] = 255 - lobyte; |
504 | frame->data[0][pixel_ptr + 3] = 255 - lobyte; |
505 | pixel_ptr += frame->linesize[0]; |
506 | } |
507 | lines=0; |
508 | } |
509 | break; |
510 | |
511 | case 2: |
512 | lobyte = s->decode_buffer[lobytes]; |
513 | hibyte = s->decode_buffer[hibytes]; |
514 | vector_index = (hibyte << 8) | lobyte; |
515 | vector_index <<= index_shift; |
516 | lines = s->vector_height; |
517 | break; |
518 | |
519 | case 3: |
520 | /* not implemented yet */ |
521 | lines = 0; |
522 | break; |
523 | } |
524 | |
525 | while (lines--) { |
526 | frame->data[0][pixel_ptr + 0] = s->codebook[vector_index++]; |
527 | frame->data[0][pixel_ptr + 1] = s->codebook[vector_index++]; |
528 | frame->data[0][pixel_ptr + 2] = s->codebook[vector_index++]; |
529 | frame->data[0][pixel_ptr + 3] = s->codebook[vector_index++]; |
530 | pixel_ptr += frame->linesize[0]; |
531 | } |
532 | } |
533 | } |
534 | |
535 | /* handle partial codebook */ |
536 | if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) { |
537 | /* a chunk should not have both chunk types */ |
538 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBP0 and CBPZ chunks\n"); |
539 | return AVERROR_INVALIDDATA; |
540 | } |
541 | |
542 | if (cbp0_chunk != -1) { |
543 | |
544 | bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET); |
545 | chunk_size = bytestream2_get_be32(&s->gb); |
546 | |
547 | if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { |
548 | av_log(s->avctx, AV_LOG_ERROR, "cbp0 chunk too large (%u bytes)\n", |
549 | chunk_size); |
550 | return AVERROR_INVALIDDATA; |
551 | } |
552 | |
553 | /* accumulate partial codebook */ |
554 | bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], |
555 | chunk_size); |
556 | s->next_codebook_buffer_index += chunk_size; |
557 | |
558 | s->partial_countdown--; |
559 | if (s->partial_countdown <= 0) { |
560 | |
561 | /* time to replace codebook */ |
562 | memcpy(s->codebook, s->next_codebook_buffer, |
563 | s->next_codebook_buffer_index); |
564 | |
565 | /* reset accounting */ |
566 | s->next_codebook_buffer_index = 0; |
567 | s->partial_countdown = s->partial_count; |
568 | } |
569 | } |
570 | |
571 | if (cbpz_chunk != -1) { |
572 | |
573 | bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET); |
574 | chunk_size = bytestream2_get_be32(&s->gb); |
575 | |
576 | if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { |
577 | av_log(s->avctx, AV_LOG_ERROR, "cbpz chunk too large (%u bytes)\n", |
578 | chunk_size); |
579 | return AVERROR_INVALIDDATA; |
580 | } |
581 | |
582 | /* accumulate partial codebook */ |
583 | bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], |
584 | chunk_size); |
585 | s->next_codebook_buffer_index += chunk_size; |
586 | |
587 | s->partial_countdown--; |
588 | if (s->partial_countdown <= 0) { |
589 | bytestream2_init(&s->gb, s->next_codebook_buffer, s->next_codebook_buffer_index); |
590 | /* decompress codebook */ |
591 | if ((res = decode_format80(s, s->next_codebook_buffer_index, |
592 | s->codebook, s->codebook_size, 0)) < 0) |
593 | return res; |
594 | |
595 | /* reset accounting */ |
596 | s->next_codebook_buffer_index = 0; |
597 | s->partial_countdown = s->partial_count; |
598 | } |
599 | } |
600 | |
601 | return 0; |
602 | } |
603 | |
604 | static int vqa_decode_frame(AVCodecContext *avctx, |
605 | void *data, int *got_frame, |
606 | AVPacket *avpkt) |
607 | { |
608 | VqaContext *s = avctx->priv_data; |
609 | AVFrame *frame = data; |
610 | int res; |
611 | |
612 | if ((res = ff_get_buffer(avctx, frame, 0)) < 0) |
613 | return res; |
614 | |
615 | bytestream2_init(&s->gb, avpkt->data, avpkt->size); |
616 | if ((res = vqa_decode_chunk(s, frame)) < 0) |
617 | return res; |
618 | |
619 | /* make the palette available on the way out */ |
620 | memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4); |
621 | frame->palette_has_changed = 1; |
622 | |
623 | *got_frame = 1; |
624 | |
625 | /* report that the buffer was completely consumed */ |
626 | return avpkt->size; |
627 | } |
628 | |
629 | static av_cold int vqa_decode_end(AVCodecContext *avctx) |
630 | { |
631 | VqaContext *s = avctx->priv_data; |
632 | |
633 | av_freep(&s->codebook); |
634 | av_freep(&s->next_codebook_buffer); |
635 | av_freep(&s->decode_buffer); |
636 | |
637 | return 0; |
638 | } |
639 | |
640 | AVCodec ff_vqa_decoder = { |
641 | .name = "vqavideo", |
642 | .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"), |
643 | .type = AVMEDIA_TYPE_VIDEO, |
644 | .id = AV_CODEC_ID_WS_VQA, |
645 | .priv_data_size = sizeof(VqaContext), |
646 | .init = vqa_decode_init, |
647 | .close = vqa_decode_end, |
648 | .decode = vqa_decode_frame, |
649 | .capabilities = AV_CODEC_CAP_DR1, |
650 | }; |
651 |