1 | /*
|
---|
2 | * Westwood Studios VQA Video Decoder
|
---|
3 | * Copyright (C) 2003 the ffmpeg project
|
---|
4 | *
|
---|
5 | * This library is free software; you can redistribute it and/or
|
---|
6 | * modify it under the terms of the GNU Lesser General Public
|
---|
7 | * License as published by the Free Software Foundation; either
|
---|
8 | * version 2 of the License, or (at your option) any later version.
|
---|
9 | *
|
---|
10 | * This library is distributed in the hope that it will be useful,
|
---|
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
13 | * Lesser General Public License for more details.
|
---|
14 | *
|
---|
15 | * You should have received a copy of the GNU Lesser General Public
|
---|
16 | * License along with this library; if not, write to the Free Software
|
---|
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
---|
18 | *
|
---|
19 | */
|
---|
20 |
|
---|
21 | /**
|
---|
22 | * @file vqavideo.c
|
---|
23 | * VQA Video Decoder by Mike Melanson ([email protected])
|
---|
24 | * For more information about the RPZA format, visit:
|
---|
25 | * http://www.pcisys.net/~melanson/codecs/
|
---|
26 | *
|
---|
27 | * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending
|
---|
28 | * on the type of data in the file.
|
---|
29 | *
|
---|
30 | * This decoder needs the 42-byte VQHD header from the beginning
|
---|
31 | * of the VQA file passed through the extradata field. The VQHD header
|
---|
32 | * is laid out as:
|
---|
33 | *
|
---|
34 | * bytes 0-3 chunk fourcc: 'VQHD'
|
---|
35 | * bytes 4-7 chunk size in big-endian format, should be 0x0000002A
|
---|
36 | * bytes 8-49 VQHD chunk data
|
---|
37 | *
|
---|
38 | * Bytes 8-49 are what this decoder expects to see.
|
---|
39 | *
|
---|
40 | * Briefly, VQA is a vector quantized animation format that operates in a
|
---|
41 | * VGA palettized colorspace. It operates on pixel vectors (blocks)
|
---|
42 | * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector
|
---|
43 | * codebooks, palette information, and code maps for rendering vectors onto
|
---|
44 | * frames. Any of these components can also be compressed with a run-length
|
---|
45 | * encoding (RLE) algorithm commonly referred to as "format80".
|
---|
46 | *
|
---|
47 | * VQA takes a novel approach to rate control. Each group of n frames
|
---|
48 | * (usually, n = 8) relies on a different vector codebook. Rather than
|
---|
49 | * transporting an entire codebook every 8th frame, the new codebook is
|
---|
50 | * broken up into 8 pieces and sent along with the compressed video chunks
|
---|
51 | * for each of the 8 frames preceding the 8 frames which require the
|
---|
52 | * codebook. A full codebook is also sent on the very first frame of a
|
---|
53 | * file. This is an interesting technique, although it makes random file
|
---|
54 | * seeking difficult despite the fact that the frames are all intracoded.
|
---|
55 | *
|
---|
56 | * V1,2 VQA uses 12-bit codebook indices. If the 12-bit indices were
|
---|
57 | * packed into bytes and then RLE compressed, bytewise, the results would
|
---|
58 | * be poor. That is why the coding method divides each index into 2 parts,
|
---|
59 | * the top 4 bits and the bottom 8 bits, then RL encodes the 4-bit pieces
|
---|
60 | * together and the 8-bit pieces together. If most of the vectors are
|
---|
61 | * clustered into one group of 256 vectors, most of the 4-bit index pieces
|
---|
62 | * should be the same.
|
---|
63 | */
|
---|
64 |
|
---|
65 | #include <stdio.h>
|
---|
66 | #include <stdlib.h>
|
---|
67 | #include <string.h>
|
---|
68 | #include <unistd.h>
|
---|
69 |
|
---|
70 | #include "common.h"
|
---|
71 | #include "avcodec.h"
|
---|
72 | #include "dsputil.h"
|
---|
73 |
|
---|
74 | #define PALETTE_COUNT 256
|
---|
75 | #define VQA_HEADER_SIZE 0x2A
|
---|
76 | #define CHUNK_PREAMBLE_SIZE 8
|
---|
77 |
|
---|
78 | /* allocate the maximum vector space, regardless of the file version:
|
---|
79 | * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */
|
---|
80 | #define MAX_CODEBOOK_VECTORS 0xFF00
|
---|
81 | #define SOLID_PIXEL_VECTORS 0x100
|
---|
82 | #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS)
|
---|
83 | #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4)
|
---|
84 |
|
---|
85 | #define CBF0_TAG MKBETAG('C', 'B', 'F', '0')
|
---|
86 | #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z')
|
---|
87 | #define CBP0_TAG MKBETAG('C', 'B', 'P', '0')
|
---|
88 | #define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z')
|
---|
89 | #define CPL0_TAG MKBETAG('C', 'P', 'L', '0')
|
---|
90 | #define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z')
|
---|
91 | #define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z')
|
---|
92 |
|
---|
93 | #define VQA_DEBUG 0
|
---|
94 |
|
---|
95 | #if VQA_DEBUG
|
---|
96 | #define vqa_debug printf
|
---|
97 | #else
|
---|
98 | static inline void vqa_debug(const char *format, ...) { }
|
---|
99 | #endif
|
---|
100 |
|
---|
101 | typedef struct VqaContext {
|
---|
102 |
|
---|
103 | AVCodecContext *avctx;
|
---|
104 | DSPContext dsp;
|
---|
105 | AVFrame frame;
|
---|
106 |
|
---|
107 | unsigned char *buf;
|
---|
108 | int size;
|
---|
109 |
|
---|
110 | unsigned int palette[PALETTE_COUNT];
|
---|
111 |
|
---|
112 | int width; /* width of a frame */
|
---|
113 | int height; /* height of a frame */
|
---|
114 | int vector_width; /* width of individual vector */
|
---|
115 | int vector_height; /* height of individual vector */
|
---|
116 | int vqa_version; /* this should be either 1, 2 or 3 */
|
---|
117 |
|
---|
118 | unsigned char *codebook; /* the current codebook */
|
---|
119 | int codebook_size;
|
---|
120 | unsigned char *next_codebook_buffer; /* accumulator for next codebook */
|
---|
121 | int next_codebook_buffer_index;
|
---|
122 |
|
---|
123 | unsigned char *decode_buffer;
|
---|
124 | int decode_buffer_size;
|
---|
125 |
|
---|
126 | /* number of frames to go before replacing codebook */
|
---|
127 | int partial_countdown;
|
---|
128 | int partial_count;
|
---|
129 |
|
---|
130 | } VqaContext;
|
---|
131 |
|
---|
132 | static int vqa_decode_init(AVCodecContext *avctx)
|
---|
133 | {
|
---|
134 | VqaContext *s = (VqaContext *)avctx->priv_data;
|
---|
135 | unsigned char *vqa_header;
|
---|
136 | int i, j, codebook_index;;
|
---|
137 |
|
---|
138 | s->avctx = avctx;
|
---|
139 | avctx->pix_fmt = PIX_FMT_PAL8;
|
---|
140 | avctx->has_b_frames = 0;
|
---|
141 | dsputil_init(&s->dsp, avctx);
|
---|
142 |
|
---|
143 | /* make sure the extradata made it */
|
---|
144 | if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
|
---|
145 | av_log(s->avctx, AV_LOG_ERROR, " VQA video: expected extradata size of %d\n", VQA_HEADER_SIZE);
|
---|
146 | return -1;
|
---|
147 | }
|
---|
148 |
|
---|
149 | /* load up the VQA parameters from the header */
|
---|
150 | vqa_header = (unsigned char *)s->avctx->extradata;
|
---|
151 | s->vqa_version = vqa_header[0];
|
---|
152 | s->width = LE_16(&vqa_header[6]);
|
---|
153 | s->height = LE_16(&vqa_header[8]);
|
---|
154 | if(avcodec_check_dimensions(avctx, s->width, s->height)){
|
---|
155 | s->width= s->height= 0;
|
---|
156 | return -1;
|
---|
157 | }
|
---|
158 | s->vector_width = vqa_header[10];
|
---|
159 | s->vector_height = vqa_header[11];
|
---|
160 | s->partial_count = s->partial_countdown = vqa_header[13];
|
---|
161 |
|
---|
162 | /* the vector dimensions have to meet very stringent requirements */
|
---|
163 | if ((s->vector_width != 4) ||
|
---|
164 | ((s->vector_height != 2) && (s->vector_height != 4))) {
|
---|
165 | /* return without further initialization */
|
---|
166 | return -1;
|
---|
167 | }
|
---|
168 |
|
---|
169 | /* allocate codebooks */
|
---|
170 | s->codebook_size = MAX_CODEBOOK_SIZE;
|
---|
171 | s->codebook = av_malloc(s->codebook_size);
|
---|
172 | s->next_codebook_buffer = av_malloc(s->codebook_size);
|
---|
173 |
|
---|
174 | /* initialize the solid-color vectors */
|
---|
175 | if (s->vector_height == 4) {
|
---|
176 | codebook_index = 0xFF00 * 16;
|
---|
177 | for (i = 0; i < 256; i++)
|
---|
178 | for (j = 0; j < 16; j++)
|
---|
179 | s->codebook[codebook_index++] = i;
|
---|
180 | } else {
|
---|
181 | codebook_index = 0xF00 * 8;
|
---|
182 | for (i = 0; i < 256; i++)
|
---|
183 | for (j = 0; j < 8; j++)
|
---|
184 | s->codebook[codebook_index++] = i;
|
---|
185 | }
|
---|
186 | s->next_codebook_buffer_index = 0;
|
---|
187 |
|
---|
188 | /* allocate decode buffer */
|
---|
189 | s->decode_buffer_size = (s->width / s->vector_width) *
|
---|
190 | (s->height / s->vector_height) * 2;
|
---|
191 | s->decode_buffer = av_malloc(s->decode_buffer_size);
|
---|
192 |
|
---|
193 | s->frame.data[0] = NULL;
|
---|
194 |
|
---|
195 | return 0;
|
---|
196 | }
|
---|
197 |
|
---|
198 | #define CHECK_COUNT() \
|
---|
199 | if (dest_index + count > dest_size) { \
|
---|
200 | av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
|
---|
201 | av_log(NULL, AV_LOG_ERROR, " VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \
|
---|
202 | dest_index, count, dest_size); \
|
---|
203 | return; \
|
---|
204 | }
|
---|
205 |
|
---|
206 | static void decode_format80(unsigned char *src, int src_size,
|
---|
207 | unsigned char *dest, int dest_size, int check_size) {
|
---|
208 |
|
---|
209 | int src_index = 0;
|
---|
210 | int dest_index = 0;
|
---|
211 | int count;
|
---|
212 | int src_pos;
|
---|
213 | unsigned char color;
|
---|
214 | int i;
|
---|
215 |
|
---|
216 | while (src_index < src_size) {
|
---|
217 |
|
---|
218 | vqa_debug(" opcode %02X: ", src[src_index]);
|
---|
219 |
|
---|
220 | /* 0x80 means that frame is finished */
|
---|
221 | if (src[src_index] == 0x80)
|
---|
222 | return;
|
---|
223 |
|
---|
224 | if (dest_index >= dest_size) {
|
---|
225 | av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",
|
---|
226 | dest_index, dest_size);
|
---|
227 | return;
|
---|
228 | }
|
---|
229 |
|
---|
230 | if (src[src_index] == 0xFF) {
|
---|
231 |
|
---|
232 | src_index++;
|
---|
233 | count = LE_16(&src[src_index]);
|
---|
234 | src_index += 2;
|
---|
235 | src_pos = LE_16(&src[src_index]);
|
---|
236 | src_index += 2;
|
---|
237 | vqa_debug("(1) copy %X bytes from absolute pos %X\n", count, src_pos);
|
---|
238 | CHECK_COUNT();
|
---|
239 | for (i = 0; i < count; i++)
|
---|
240 | dest[dest_index + i] = dest[src_pos + i];
|
---|
241 | dest_index += count;
|
---|
242 |
|
---|
243 | } else if (src[src_index] == 0xFE) {
|
---|
244 |
|
---|
245 | src_index++;
|
---|
246 | count = LE_16(&src[src_index]);
|
---|
247 | src_index += 2;
|
---|
248 | color = src[src_index++];
|
---|
249 | vqa_debug("(2) set %X bytes to %02X\n", count, color);
|
---|
250 | CHECK_COUNT();
|
---|
251 | memset(&dest[dest_index], color, count);
|
---|
252 | dest_index += count;
|
---|
253 |
|
---|
254 | } else if ((src[src_index] & 0xC0) == 0xC0) {
|
---|
255 |
|
---|
256 | count = (src[src_index++] & 0x3F) + 3;
|
---|
257 | src_pos = LE_16(&src[src_index]);
|
---|
258 | src_index += 2;
|
---|
259 | vqa_debug("(3) copy %X bytes from absolute pos %X\n", count, src_pos);
|
---|
260 | CHECK_COUNT();
|
---|
261 | for (i = 0; i < count; i++)
|
---|
262 | dest[dest_index + i] = dest[src_pos + i];
|
---|
263 | dest_index += count;
|
---|
264 |
|
---|
265 | } else if (src[src_index] > 0x80) {
|
---|
266 |
|
---|
267 | count = src[src_index++] & 0x3F;
|
---|
268 | vqa_debug("(4) copy %X bytes from source to dest\n", count);
|
---|
269 | CHECK_COUNT();
|
---|
270 | memcpy(&dest[dest_index], &src[src_index], count);
|
---|
271 | src_index += count;
|
---|
272 | dest_index += count;
|
---|
273 |
|
---|
274 | } else {
|
---|
275 |
|
---|
276 | count = ((src[src_index] & 0x70) >> 4) + 3;
|
---|
277 | src_pos = BE_16(&src[src_index]) & 0x0FFF;
|
---|
278 | src_index += 2;
|
---|
279 | vqa_debug("(5) copy %X bytes from relpos %X\n", count, src_pos);
|
---|
280 | CHECK_COUNT();
|
---|
281 | for (i = 0; i < count; i++)
|
---|
282 | dest[dest_index + i] = dest[dest_index - src_pos + i];
|
---|
283 | dest_index += count;
|
---|
284 | }
|
---|
285 | }
|
---|
286 |
|
---|
287 | /* validate that the entire destination buffer was filled; this is
|
---|
288 | * important for decoding frame maps since each vector needs to have a
|
---|
289 | * codebook entry; it is not important for compressed codebooks because
|
---|
290 | * not every entry needs to be filled */
|
---|
291 | if (check_size)
|
---|
292 | if (dest_index < dest_size)
|
---|
293 | av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
|
---|
294 | dest_index, dest_size);
|
---|
295 | }
|
---|
296 |
|
---|
297 | static void vqa_decode_chunk(VqaContext *s)
|
---|
298 | {
|
---|
299 | unsigned int chunk_type;
|
---|
300 | unsigned int chunk_size;
|
---|
301 | int byte_skip;
|
---|
302 | unsigned int index = 0;
|
---|
303 | int i;
|
---|
304 | unsigned char r, g, b;
|
---|
305 | int index_shift;
|
---|
306 |
|
---|
307 | int cbf0_chunk = -1;
|
---|
308 | int cbfz_chunk = -1;
|
---|
309 | int cbp0_chunk = -1;
|
---|
310 | int cbpz_chunk = -1;
|
---|
311 | int cpl0_chunk = -1;
|
---|
312 | int cplz_chunk = -1;
|
---|
313 | int vptz_chunk = -1;
|
---|
314 |
|
---|
315 | int x, y;
|
---|
316 | int lines = 0;
|
---|
317 | int pixel_ptr;
|
---|
318 | int vector_index = 0;
|
---|
319 | int lobyte = 0;
|
---|
320 | int hibyte = 0;
|
---|
321 | int lobytes = 0;
|
---|
322 | int hibytes = s->decode_buffer_size / 2;
|
---|
323 |
|
---|
324 | /* first, traverse through the frame and find the subchunks */
|
---|
325 | while (index < s->size) {
|
---|
326 |
|
---|
327 | chunk_type = BE_32(&s->buf[index]);
|
---|
328 | chunk_size = BE_32(&s->buf[index + 4]);
|
---|
329 |
|
---|
330 | switch (chunk_type) {
|
---|
331 |
|
---|
332 | case CBF0_TAG:
|
---|
333 | cbf0_chunk = index;
|
---|
334 | break;
|
---|
335 |
|
---|
336 | case CBFZ_TAG:
|
---|
337 | cbfz_chunk = index;
|
---|
338 | break;
|
---|
339 |
|
---|
340 | case CBP0_TAG:
|
---|
341 | cbp0_chunk = index;
|
---|
342 | break;
|
---|
343 |
|
---|
344 | case CBPZ_TAG:
|
---|
345 | cbpz_chunk = index;
|
---|
346 | break;
|
---|
347 |
|
---|
348 | case CPL0_TAG:
|
---|
349 | cpl0_chunk = index;
|
---|
350 | break;
|
---|
351 |
|
---|
352 | case CPLZ_TAG:
|
---|
353 | cplz_chunk = index;
|
---|
354 | break;
|
---|
355 |
|
---|
356 | case VPTZ_TAG:
|
---|
357 | vptz_chunk = index;
|
---|
358 | break;
|
---|
359 |
|
---|
360 | default:
|
---|
361 | av_log(s->avctx, AV_LOG_ERROR, " VQA video: Found unknown chunk type: %c%c%c%c (%08X)\n",
|
---|
362 | (chunk_type >> 24) & 0xFF,
|
---|
363 | (chunk_type >> 16) & 0xFF,
|
---|
364 | (chunk_type >> 8) & 0xFF,
|
---|
365 | (chunk_type >> 0) & 0xFF,
|
---|
366 | chunk_type);
|
---|
367 | break;
|
---|
368 | }
|
---|
369 |
|
---|
370 | byte_skip = chunk_size & 0x01;
|
---|
371 | index += (CHUNK_PREAMBLE_SIZE + chunk_size + byte_skip);
|
---|
372 | }
|
---|
373 |
|
---|
374 | /* next, deal with the palette */
|
---|
375 | if ((cpl0_chunk != -1) && (cplz_chunk != -1)) {
|
---|
376 |
|
---|
377 | /* a chunk should not have both chunk types */
|
---|
378 | av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CPL0 and CPLZ chunks\n");
|
---|
379 | return;
|
---|
380 | }
|
---|
381 |
|
---|
382 | /* decompress the palette chunk */
|
---|
383 | if (cplz_chunk != -1) {
|
---|
384 |
|
---|
385 | /* yet to be handled */
|
---|
386 |
|
---|
387 | }
|
---|
388 |
|
---|
389 | /* convert the RGB palette into the machine's endian format */
|
---|
390 | if (cpl0_chunk != -1) {
|
---|
391 |
|
---|
392 | chunk_size = BE_32(&s->buf[cpl0_chunk + 4]);
|
---|
393 | /* sanity check the palette size */
|
---|
394 | if (chunk_size / 3 > 256) {
|
---|
395 | av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found a palette chunk with %d colors\n",
|
---|
396 | chunk_size / 3);
|
---|
397 | return;
|
---|
398 | }
|
---|
399 | cpl0_chunk += CHUNK_PREAMBLE_SIZE;
|
---|
400 | for (i = 0; i < chunk_size / 3; i++) {
|
---|
401 | /* scale by 4 to transform 6-bit palette -> 8-bit */
|
---|
402 | r = s->buf[cpl0_chunk++] * 4;
|
---|
403 | g = s->buf[cpl0_chunk++] * 4;
|
---|
404 | b = s->buf[cpl0_chunk++] * 4;
|
---|
405 | s->palette[i] = (r << 16) | (g << 8) | (b);
|
---|
406 | }
|
---|
407 | }
|
---|
408 |
|
---|
409 | /* next, look for a full codebook */
|
---|
410 | if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
|
---|
411 |
|
---|
412 | /* a chunk should not have both chunk types */
|
---|
413 | av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBF0 and CBFZ chunks\n");
|
---|
414 | return;
|
---|
415 | }
|
---|
416 |
|
---|
417 | /* decompress the full codebook chunk */
|
---|
418 | if (cbfz_chunk != -1) {
|
---|
419 |
|
---|
420 | chunk_size = BE_32(&s->buf[cbfz_chunk + 4]);
|
---|
421 | cbfz_chunk += CHUNK_PREAMBLE_SIZE;
|
---|
422 | decode_format80(&s->buf[cbfz_chunk], chunk_size,
|
---|
423 | s->codebook, s->codebook_size, 0);
|
---|
424 | }
|
---|
425 |
|
---|
426 | /* copy a full codebook */
|
---|
427 | if (cbf0_chunk != -1) {
|
---|
428 |
|
---|
429 | chunk_size = BE_32(&s->buf[cbf0_chunk + 4]);
|
---|
430 | /* sanity check the full codebook size */
|
---|
431 | if (chunk_size > MAX_CODEBOOK_SIZE) {
|
---|
432 | av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: CBF0 chunk too large (0x%X bytes)\n",
|
---|
433 | chunk_size);
|
---|
434 | return;
|
---|
435 | }
|
---|
436 | cbf0_chunk += CHUNK_PREAMBLE_SIZE;
|
---|
437 |
|
---|
438 | memcpy(s->codebook, &s->buf[cbf0_chunk], chunk_size);
|
---|
439 | }
|
---|
440 |
|
---|
441 | /* decode the frame */
|
---|
442 | if (vptz_chunk == -1) {
|
---|
443 |
|
---|
444 | /* something is wrong if there is no VPTZ chunk */
|
---|
445 | av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: no VPTZ chunk found\n");
|
---|
446 | return;
|
---|
447 | }
|
---|
448 |
|
---|
449 | chunk_size = BE_32(&s->buf[vptz_chunk + 4]);
|
---|
450 | vptz_chunk += CHUNK_PREAMBLE_SIZE;
|
---|
451 | decode_format80(&s->buf[vptz_chunk], chunk_size,
|
---|
452 | s->decode_buffer, s->decode_buffer_size, 1);
|
---|
453 |
|
---|
454 | /* render the final PAL8 frame */
|
---|
455 | if (s->vector_height == 4)
|
---|
456 | index_shift = 4;
|
---|
457 | else
|
---|
458 | index_shift = 3;
|
---|
459 | for (y = 0; y < s->frame.linesize[0] * s->height;
|
---|
460 | y += s->frame.linesize[0] * s->vector_height) {
|
---|
461 |
|
---|
462 | for (x = y; x < y + s->width; x += 4, lobytes++, hibytes++) {
|
---|
463 | pixel_ptr = x;
|
---|
464 |
|
---|
465 | /* get the vector index, the method for which varies according to
|
---|
466 | * VQA file version */
|
---|
467 | switch (s->vqa_version) {
|
---|
468 |
|
---|
469 | case 1:
|
---|
470 | /* still need sample media for this case (only one game, "Legend of
|
---|
471 | * Kyrandia III : Malcolm's Revenge", is known to use this version) */
|
---|
472 | lines = 0;
|
---|
473 | break;
|
---|
474 |
|
---|
475 | case 2:
|
---|
476 | lobyte = s->decode_buffer[lobytes];
|
---|
477 | hibyte = s->decode_buffer[hibytes];
|
---|
478 | vector_index = (hibyte << 8) | lobyte;
|
---|
479 | vector_index <<= index_shift;
|
---|
480 | lines = s->vector_height;
|
---|
481 | break;
|
---|
482 |
|
---|
483 | case 3:
|
---|
484 | /* not implemented yet */
|
---|
485 | lines = 0;
|
---|
486 | break;
|
---|
487 | }
|
---|
488 |
|
---|
489 | while (lines--) {
|
---|
490 | s->frame.data[0][pixel_ptr + 0] = s->codebook[vector_index++];
|
---|
491 | s->frame.data[0][pixel_ptr + 1] = s->codebook[vector_index++];
|
---|
492 | s->frame.data[0][pixel_ptr + 2] = s->codebook[vector_index++];
|
---|
493 | s->frame.data[0][pixel_ptr + 3] = s->codebook[vector_index++];
|
---|
494 | pixel_ptr += s->frame.linesize[0];
|
---|
495 | }
|
---|
496 | }
|
---|
497 | }
|
---|
498 |
|
---|
499 | /* handle partial codebook */
|
---|
500 | if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
|
---|
501 | /* a chunk should not have both chunk types */
|
---|
502 | av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBP0 and CBPZ chunks\n");
|
---|
503 | return;
|
---|
504 | }
|
---|
505 |
|
---|
506 | if (cbp0_chunk != -1) {
|
---|
507 |
|
---|
508 | chunk_size = BE_32(&s->buf[cbp0_chunk + 4]);
|
---|
509 | cbp0_chunk += CHUNK_PREAMBLE_SIZE;
|
---|
510 |
|
---|
511 | /* accumulate partial codebook */
|
---|
512 | memcpy(&s->next_codebook_buffer[s->next_codebook_buffer_index],
|
---|
513 | &s->buf[cbp0_chunk], chunk_size);
|
---|
514 | s->next_codebook_buffer_index += chunk_size;
|
---|
515 |
|
---|
516 | s->partial_countdown--;
|
---|
517 | if (s->partial_countdown == 0) {
|
---|
518 |
|
---|
519 | /* time to replace codebook */
|
---|
520 | memcpy(s->codebook, s->next_codebook_buffer,
|
---|
521 | s->next_codebook_buffer_index);
|
---|
522 |
|
---|
523 | /* reset accounting */
|
---|
524 | s->next_codebook_buffer_index = 0;
|
---|
525 | s->partial_countdown = s->partial_count;
|
---|
526 | }
|
---|
527 | }
|
---|
528 |
|
---|
529 | if (cbpz_chunk != -1) {
|
---|
530 |
|
---|
531 | chunk_size = BE_32(&s->buf[cbpz_chunk + 4]);
|
---|
532 | cbpz_chunk += CHUNK_PREAMBLE_SIZE;
|
---|
533 |
|
---|
534 | /* accumulate partial codebook */
|
---|
535 | memcpy(&s->next_codebook_buffer[s->next_codebook_buffer_index],
|
---|
536 | &s->buf[cbpz_chunk], chunk_size);
|
---|
537 | s->next_codebook_buffer_index += chunk_size;
|
---|
538 |
|
---|
539 | s->partial_countdown--;
|
---|
540 | if (s->partial_countdown == 0) {
|
---|
541 |
|
---|
542 | /* decompress codebook */
|
---|
543 | decode_format80(s->next_codebook_buffer,
|
---|
544 | s->next_codebook_buffer_index,
|
---|
545 | s->codebook, s->codebook_size, 0);
|
---|
546 |
|
---|
547 | /* reset accounting */
|
---|
548 | s->next_codebook_buffer_index = 0;
|
---|
549 | s->partial_countdown = s->partial_count;
|
---|
550 | }
|
---|
551 | }
|
---|
552 | }
|
---|
553 |
|
---|
554 | static int vqa_decode_frame(AVCodecContext *avctx,
|
---|
555 | void *data, int *data_size,
|
---|
556 | uint8_t *buf, int buf_size)
|
---|
557 | {
|
---|
558 | VqaContext *s = (VqaContext *)avctx->priv_data;
|
---|
559 |
|
---|
560 | s->buf = buf;
|
---|
561 | s->size = buf_size;
|
---|
562 |
|
---|
563 | if (s->frame.data[0])
|
---|
564 | avctx->release_buffer(avctx, &s->frame);
|
---|
565 |
|
---|
566 | if (avctx->get_buffer(avctx, &s->frame)) {
|
---|
567 | av_log(s->avctx, AV_LOG_ERROR, " VQA Video: get_buffer() failed\n");
|
---|
568 | return -1;
|
---|
569 | }
|
---|
570 |
|
---|
571 | vqa_decode_chunk(s);
|
---|
572 |
|
---|
573 | /* make the palette available on the way out */
|
---|
574 | memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
|
---|
575 | s->frame.palette_has_changed = 1;
|
---|
576 |
|
---|
577 | *data_size = sizeof(AVFrame);
|
---|
578 | *(AVFrame*)data = s->frame;
|
---|
579 |
|
---|
580 | /* report that the buffer was completely consumed */
|
---|
581 | return buf_size;
|
---|
582 | }
|
---|
583 |
|
---|
584 | static int vqa_decode_end(AVCodecContext *avctx)
|
---|
585 | {
|
---|
586 | VqaContext *s = (VqaContext *)avctx->priv_data;
|
---|
587 |
|
---|
588 | av_free(s->codebook);
|
---|
589 | av_free(s->next_codebook_buffer);
|
---|
590 | av_free(s->decode_buffer);
|
---|
591 |
|
---|
592 | if (s->frame.data[0])
|
---|
593 | avctx->release_buffer(avctx, &s->frame);
|
---|
594 |
|
---|
595 | return 0;
|
---|
596 | }
|
---|
597 |
|
---|
598 | AVCodec vqa_decoder = {
|
---|
599 | "vqavideo",
|
---|
600 | CODEC_TYPE_VIDEO,
|
---|
601 | CODEC_ID_WS_VQA,
|
---|
602 | sizeof(VqaContext),
|
---|
603 | vqa_decode_init,
|
---|
604 | NULL,
|
---|
605 | vqa_decode_end,
|
---|
606 | vqa_decode_frame,
|
---|
607 | CODEC_CAP_DR1,
|
---|
608 | };
|
---|