Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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 | start = bytestream2_tell(&s->gb); | |
235 | while (bytestream2_tell(&s->gb) - start < src_size) { | |
236 | opcode = bytestream2_get_byte(&s->gb); | |
237 | av_dlog(s->avctx, "opcode %02X: ", opcode); | |
238 | ||
239 | /* 0x80 means that frame is finished */ | |
240 | if (opcode == 0x80) | |
241 | break; | |
242 | ||
243 | if (dest_index >= dest_size) { | |
244 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n", | |
245 | dest_index, dest_size); | |
246 | return AVERROR_INVALIDDATA; | |
247 | } | |
248 | ||
249 | if (opcode == 0xFF) { | |
250 | ||
251 | count = bytestream2_get_le16(&s->gb); | |
252 | src_pos = bytestream2_get_le16(&s->gb); | |
253 | av_dlog(s->avctx, "(1) copy %X bytes from absolute pos %X\n", count, src_pos); | |
254 | CHECK_COUNT(); | |
255 | CHECK_COPY(src_pos); | |
256 | for (i = 0; i < count; i++) | |
257 | dest[dest_index + i] = dest[src_pos + i]; | |
258 | dest_index += count; | |
259 | ||
260 | } else if (opcode == 0xFE) { | |
261 | ||
262 | count = bytestream2_get_le16(&s->gb); | |
263 | color = bytestream2_get_byte(&s->gb); | |
264 | av_dlog(s->avctx, "(2) set %X bytes to %02X\n", count, color); | |
265 | CHECK_COUNT(); | |
266 | memset(&dest[dest_index], color, count); | |
267 | dest_index += count; | |
268 | ||
269 | } else if ((opcode & 0xC0) == 0xC0) { | |
270 | ||
271 | count = (opcode & 0x3F) + 3; | |
272 | src_pos = bytestream2_get_le16(&s->gb); | |
273 | av_dlog(s->avctx, "(3) copy %X bytes from absolute pos %X\n", count, src_pos); | |
274 | CHECK_COUNT(); | |
275 | CHECK_COPY(src_pos); | |
276 | for (i = 0; i < count; i++) | |
277 | dest[dest_index + i] = dest[src_pos + i]; | |
278 | dest_index += count; | |
279 | ||
280 | } else if (opcode > 0x80) { | |
281 | ||
282 | count = opcode & 0x3F; | |
283 | av_dlog(s->avctx, "(4) copy %X bytes from source to dest\n", count); | |
284 | CHECK_COUNT(); | |
285 | bytestream2_get_buffer(&s->gb, &dest[dest_index], count); | |
286 | dest_index += count; | |
287 | ||
288 | } else { | |
289 | ||
290 | count = ((opcode & 0x70) >> 4) + 3; | |
291 | src_pos = bytestream2_get_byte(&s->gb) | ((opcode & 0x0F) << 8); | |
292 | av_dlog(s->avctx, "(5) copy %X bytes from relpos %X\n", count, src_pos); | |
293 | CHECK_COUNT(); | |
294 | CHECK_COPY(dest_index - src_pos); | |
295 | for (i = 0; i < count; i++) | |
296 | dest[dest_index + i] = dest[dest_index - src_pos + i]; | |
297 | dest_index += count; | |
298 | } | |
299 | } | |
300 | ||
301 | /* validate that the entire destination buffer was filled; this is | |
302 | * important for decoding frame maps since each vector needs to have a | |
303 | * codebook entry; it is not important for compressed codebooks because | |
304 | * not every entry needs to be filled */ | |
305 | if (check_size) | |
306 | if (dest_index < dest_size) { | |
307 | av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n", | |
308 | dest_index, dest_size); | |
309 | memset(dest + dest_index, 0, dest_size - dest_index); | |
310 | } | |
311 | ||
312 | return 0; // let's display what we decoded anyway | |
313 | } | |
314 | ||
315 | static int vqa_decode_chunk(VqaContext *s, AVFrame *frame) | |
316 | { | |
317 | unsigned int chunk_type; | |
318 | unsigned int chunk_size; | |
319 | int byte_skip; | |
320 | unsigned int index = 0; | |
321 | int i; | |
322 | unsigned char r, g, b; | |
323 | int index_shift; | |
324 | int res; | |
325 | ||
326 | int cbf0_chunk = -1; | |
327 | int cbfz_chunk = -1; | |
328 | int cbp0_chunk = -1; | |
329 | int cbpz_chunk = -1; | |
330 | int cpl0_chunk = -1; | |
331 | int cplz_chunk = -1; | |
332 | int vptz_chunk = -1; | |
333 | ||
334 | int x, y; | |
335 | int lines = 0; | |
336 | int pixel_ptr; | |
337 | int vector_index = 0; | |
338 | int lobyte = 0; | |
339 | int hibyte = 0; | |
340 | int lobytes = 0; | |
341 | int hibytes = s->decode_buffer_size / 2; | |
342 | ||
343 | /* first, traverse through the frame and find the subchunks */ | |
344 | while (bytestream2_get_bytes_left(&s->gb) >= 8) { | |
345 | ||
346 | chunk_type = bytestream2_get_be32u(&s->gb); | |
347 | index = bytestream2_tell(&s->gb); | |
348 | chunk_size = bytestream2_get_be32u(&s->gb); | |
349 | ||
350 | switch (chunk_type) { | |
351 | ||
352 | case CBF0_TAG: | |
353 | cbf0_chunk = index; | |
354 | break; | |
355 | ||
356 | case CBFZ_TAG: | |
357 | cbfz_chunk = index; | |
358 | break; | |
359 | ||
360 | case CBP0_TAG: | |
361 | cbp0_chunk = index; | |
362 | break; | |
363 | ||
364 | case CBPZ_TAG: | |
365 | cbpz_chunk = index; | |
366 | break; | |
367 | ||
368 | case CPL0_TAG: | |
369 | cpl0_chunk = index; | |
370 | break; | |
371 | ||
372 | case CPLZ_TAG: | |
373 | cplz_chunk = index; | |
374 | break; | |
375 | ||
376 | case VPTZ_TAG: | |
377 | vptz_chunk = index; | |
378 | break; | |
379 | ||
380 | default: | |
381 | av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %c%c%c%c (%08X)\n", | |
382 | (chunk_type >> 24) & 0xFF, | |
383 | (chunk_type >> 16) & 0xFF, | |
384 | (chunk_type >> 8) & 0xFF, | |
385 | (chunk_type >> 0) & 0xFF, | |
386 | chunk_type); | |
387 | break; | |
388 | } | |
389 | ||
390 | byte_skip = chunk_size & 0x01; | |
391 | bytestream2_skip(&s->gb, chunk_size + byte_skip); | |
392 | } | |
393 | ||
394 | /* next, deal with the palette */ | |
395 | if ((cpl0_chunk != -1) && (cplz_chunk != -1)) { | |
396 | ||
397 | /* a chunk should not have both chunk types */ | |
398 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CPL0 and CPLZ chunks\n"); | |
399 | return AVERROR_INVALIDDATA; | |
400 | } | |
401 | ||
402 | /* decompress the palette chunk */ | |
403 | if (cplz_chunk != -1) { | |
404 | ||
405 | /* yet to be handled */ | |
406 | ||
407 | } | |
408 | ||
409 | /* convert the RGB palette into the machine's endian format */ | |
410 | if (cpl0_chunk != -1) { | |
411 | ||
412 | bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET); | |
413 | chunk_size = bytestream2_get_be32(&s->gb); | |
414 | /* sanity check the palette size */ | |
415 | if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) { | |
416 | av_log(s->avctx, AV_LOG_ERROR, "problem: found a palette chunk with %d colors\n", | |
417 | chunk_size / 3); | |
418 | return AVERROR_INVALIDDATA; | |
419 | } | |
420 | for (i = 0; i < chunk_size / 3; i++) { | |
421 | /* scale by 4 to transform 6-bit palette -> 8-bit */ | |
422 | r = bytestream2_get_byteu(&s->gb) * 4; | |
423 | g = bytestream2_get_byteu(&s->gb) * 4; | |
424 | b = bytestream2_get_byteu(&s->gb) * 4; | |
425 | s->palette[i] = 0xFFU << 24 | r << 16 | g << 8 | b; | |
426 | s->palette[i] |= s->palette[i] >> 6 & 0x30303; | |
427 | } | |
428 | } | |
429 | ||
430 | /* next, look for a full codebook */ | |
431 | if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { | |
432 | ||
433 | /* a chunk should not have both chunk types */ | |
434 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n"); | |
435 | return AVERROR_INVALIDDATA; | |
436 | } | |
437 | ||
438 | /* decompress the full codebook chunk */ | |
439 | if (cbfz_chunk != -1) { | |
440 | ||
441 | bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET); | |
442 | chunk_size = bytestream2_get_be32(&s->gb); | |
443 | if ((res = decode_format80(s, chunk_size, s->codebook, | |
444 | s->codebook_size, 0)) < 0) | |
445 | return res; | |
446 | } | |
447 | ||
448 | /* copy a full codebook */ | |
449 | if (cbf0_chunk != -1) { | |
450 | ||
451 | bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET); | |
452 | chunk_size = bytestream2_get_be32(&s->gb); | |
453 | /* sanity check the full codebook size */ | |
454 | if (chunk_size > MAX_CODEBOOK_SIZE) { | |
455 | av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n", | |
456 | chunk_size); | |
457 | return AVERROR_INVALIDDATA; | |
458 | } | |
459 | ||
460 | bytestream2_get_buffer(&s->gb, s->codebook, chunk_size); | |
461 | } | |
462 | ||
463 | /* decode the frame */ | |
464 | if (vptz_chunk == -1) { | |
465 | ||
466 | /* something is wrong if there is no VPTZ chunk */ | |
467 | av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n"); | |
468 | return AVERROR_INVALIDDATA; | |
469 | } | |
470 | ||
471 | bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET); | |
472 | chunk_size = bytestream2_get_be32(&s->gb); | |
473 | if ((res = decode_format80(s, chunk_size, | |
474 | s->decode_buffer, s->decode_buffer_size, 1)) < 0) | |
475 | return res; | |
476 | ||
477 | /* render the final PAL8 frame */ | |
478 | if (s->vector_height == 4) | |
479 | index_shift = 4; | |
480 | else | |
481 | index_shift = 3; | |
482 | for (y = 0; y < s->height; y += s->vector_height) { | |
483 | for (x = 0; x < s->width; x += 4, lobytes++, hibytes++) { | |
484 | pixel_ptr = y * frame->linesize[0] + x; | |
485 | ||
486 | /* get the vector index, the method for which varies according to | |
487 | * VQA file version */ | |
488 | switch (s->vqa_version) { | |
489 | ||
490 | case 1: | |
491 | lobyte = s->decode_buffer[lobytes * 2]; | |
492 | hibyte = s->decode_buffer[(lobytes * 2) + 1]; | |
493 | vector_index = ((hibyte << 8) | lobyte) >> 3; | |
494 | vector_index <<= index_shift; | |
495 | lines = s->vector_height; | |
496 | /* uniform color fill - a quick hack */ | |
497 | if (hibyte == 0xFF) { | |
498 | while (lines--) { | |
499 | frame->data[0][pixel_ptr + 0] = 255 - lobyte; | |
500 | frame->data[0][pixel_ptr + 1] = 255 - lobyte; | |
501 | frame->data[0][pixel_ptr + 2] = 255 - lobyte; | |
502 | frame->data[0][pixel_ptr + 3] = 255 - lobyte; | |
503 | pixel_ptr += frame->linesize[0]; | |
504 | } | |
505 | lines=0; | |
506 | } | |
507 | break; | |
508 | ||
509 | case 2: | |
510 | lobyte = s->decode_buffer[lobytes]; | |
511 | hibyte = s->decode_buffer[hibytes]; | |
512 | vector_index = (hibyte << 8) | lobyte; | |
513 | vector_index <<= index_shift; | |
514 | lines = s->vector_height; | |
515 | break; | |
516 | ||
517 | case 3: | |
518 | /* not implemented yet */ | |
519 | lines = 0; | |
520 | break; | |
521 | } | |
522 | ||
523 | while (lines--) { | |
524 | frame->data[0][pixel_ptr + 0] = s->codebook[vector_index++]; | |
525 | frame->data[0][pixel_ptr + 1] = s->codebook[vector_index++]; | |
526 | frame->data[0][pixel_ptr + 2] = s->codebook[vector_index++]; | |
527 | frame->data[0][pixel_ptr + 3] = s->codebook[vector_index++]; | |
528 | pixel_ptr += frame->linesize[0]; | |
529 | } | |
530 | } | |
531 | } | |
532 | ||
533 | /* handle partial codebook */ | |
534 | if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) { | |
535 | /* a chunk should not have both chunk types */ | |
536 | av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBP0 and CBPZ chunks\n"); | |
537 | return AVERROR_INVALIDDATA; | |
538 | } | |
539 | ||
540 | if (cbp0_chunk != -1) { | |
541 | ||
542 | bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET); | |
543 | chunk_size = bytestream2_get_be32(&s->gb); | |
544 | ||
545 | if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { | |
546 | av_log(s->avctx, AV_LOG_ERROR, "cbp0 chunk too large (%u bytes)\n", | |
547 | chunk_size); | |
548 | return AVERROR_INVALIDDATA; | |
549 | } | |
550 | ||
551 | /* accumulate partial codebook */ | |
552 | bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], | |
553 | chunk_size); | |
554 | s->next_codebook_buffer_index += chunk_size; | |
555 | ||
556 | s->partial_countdown--; | |
557 | if (s->partial_countdown <= 0) { | |
558 | ||
559 | /* time to replace codebook */ | |
560 | memcpy(s->codebook, s->next_codebook_buffer, | |
561 | s->next_codebook_buffer_index); | |
562 | ||
563 | /* reset accounting */ | |
564 | s->next_codebook_buffer_index = 0; | |
565 | s->partial_countdown = s->partial_count; | |
566 | } | |
567 | } | |
568 | ||
569 | if (cbpz_chunk != -1) { | |
570 | ||
571 | bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET); | |
572 | chunk_size = bytestream2_get_be32(&s->gb); | |
573 | ||
574 | if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { | |
575 | av_log(s->avctx, AV_LOG_ERROR, "cbpz chunk too large (%u bytes)\n", | |
576 | chunk_size); | |
577 | return AVERROR_INVALIDDATA; | |
578 | } | |
579 | ||
580 | /* accumulate partial codebook */ | |
581 | bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], | |
582 | chunk_size); | |
583 | s->next_codebook_buffer_index += chunk_size; | |
584 | ||
585 | s->partial_countdown--; | |
586 | if (s->partial_countdown <= 0) { | |
587 | bytestream2_init(&s->gb, s->next_codebook_buffer, s->next_codebook_buffer_index); | |
588 | /* decompress codebook */ | |
589 | if ((res = decode_format80(s, s->next_codebook_buffer_index, | |
590 | s->codebook, s->codebook_size, 0)) < 0) | |
591 | return res; | |
592 | ||
593 | /* reset accounting */ | |
594 | s->next_codebook_buffer_index = 0; | |
595 | s->partial_countdown = s->partial_count; | |
596 | } | |
597 | } | |
598 | ||
599 | return 0; | |
600 | } | |
601 | ||
602 | static int vqa_decode_frame(AVCodecContext *avctx, | |
603 | void *data, int *got_frame, | |
604 | AVPacket *avpkt) | |
605 | { | |
606 | VqaContext *s = avctx->priv_data; | |
607 | AVFrame *frame = data; | |
608 | int res; | |
609 | ||
610 | if ((res = ff_get_buffer(avctx, frame, 0)) < 0) | |
611 | return res; | |
612 | ||
613 | bytestream2_init(&s->gb, avpkt->data, avpkt->size); | |
614 | if ((res = vqa_decode_chunk(s, frame)) < 0) | |
615 | return res; | |
616 | ||
617 | /* make the palette available on the way out */ | |
618 | memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4); | |
619 | frame->palette_has_changed = 1; | |
620 | ||
621 | *got_frame = 1; | |
622 | ||
623 | /* report that the buffer was completely consumed */ | |
624 | return avpkt->size; | |
625 | } | |
626 | ||
627 | static av_cold int vqa_decode_end(AVCodecContext *avctx) | |
628 | { | |
629 | VqaContext *s = avctx->priv_data; | |
630 | ||
631 | av_freep(&s->codebook); | |
632 | av_freep(&s->next_codebook_buffer); | |
633 | av_freep(&s->decode_buffer); | |
634 | ||
635 | return 0; | |
636 | } | |
637 | ||
638 | AVCodec ff_vqa_decoder = { | |
639 | .name = "vqavideo", | |
640 | .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"), | |
641 | .type = AVMEDIA_TYPE_VIDEO, | |
642 | .id = AV_CODEC_ID_WS_VQA, | |
643 | .priv_data_size = sizeof(VqaContext), | |
644 | .init = vqa_decode_init, | |
645 | .close = vqa_decode_end, | |
646 | .decode = vqa_decode_frame, | |
647 | .capabilities = CODEC_CAP_DR1, | |
648 | }; |