2 * Westwood Studios VQA Video Decoder
3 * Copyright (C) 2003 the ffmpeg project
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * @author Mike Melanson (melanson@pcisys.net)
26 * @see http://wiki.multimedia.cx/index.php?title=VQA
28 * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending
29 * on the type of data in the file.
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
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
39 * Bytes 8-49 are what this decoder expects to see.
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".
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.
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
70 #include "libavutil/intreadwrite.h"
71 #include "libavutil/imgutils.h"
73 #include "bytestream.h"
76 #define PALETTE_COUNT 256
77 #define VQA_HEADER_SIZE 0x2A
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)
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')
94 typedef struct VqaContext
{
96 AVCodecContext
*avctx
;
100 uint32_t palette
[PALETTE_COUNT
];
102 int width
; /* width of a frame */
103 int height
; /* height of a frame */
104 int vector_width
; /* width of individual vector */
105 int vector_height
; /* height of individual vector */
106 int vqa_version
; /* this should be either 1, 2 or 3 */
108 unsigned char *codebook
; /* the current codebook */
110 unsigned char *next_codebook_buffer
; /* accumulator for next codebook */
111 int next_codebook_buffer_index
;
113 unsigned char *decode_buffer
;
114 int decode_buffer_size
;
116 /* number of frames to go before replacing codebook */
117 int partial_countdown
;
122 static av_cold
int vqa_decode_init(AVCodecContext
*avctx
)
124 VqaContext
*s
= avctx
->priv_data
;
125 int i
, j
, codebook_index
, ret
;
128 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
130 /* make sure the extradata made it */
131 if (s
->avctx
->extradata_size
!= VQA_HEADER_SIZE
) {
132 av_log(s
->avctx
, AV_LOG_ERROR
, " VQA video: expected extradata size of %d\n", VQA_HEADER_SIZE
);
133 return AVERROR(EINVAL
);
136 /* load up the VQA parameters from the header */
137 s
->vqa_version
= s
->avctx
->extradata
[0];
138 s
->width
= AV_RL16(&s
->avctx
->extradata
[6]);
139 s
->height
= AV_RL16(&s
->avctx
->extradata
[8]);
140 if ((ret
= av_image_check_size(s
->width
, s
->height
, 0, avctx
)) < 0) {
141 s
->width
= s
->height
= 0;
144 s
->vector_width
= s
->avctx
->extradata
[10];
145 s
->vector_height
= s
->avctx
->extradata
[11];
146 s
->partial_count
= s
->partial_countdown
= s
->avctx
->extradata
[13];
148 /* the vector dimensions have to meet very stringent requirements */
149 if ((s
->vector_width
!= 4) ||
150 ((s
->vector_height
!= 2) && (s
->vector_height
!= 4))) {
151 /* return without further initialization */
152 return AVERROR_INVALIDDATA
;
155 if (s
->width
& (s
->vector_width
- 1) ||
156 s
->height
& (s
->vector_height
- 1)) {
157 av_log(avctx
, AV_LOG_ERROR
, "Image size not multiple of block size\n");
158 return AVERROR_INVALIDDATA
;
161 /* allocate codebooks */
162 s
->codebook_size
= MAX_CODEBOOK_SIZE
;
163 s
->codebook
= av_malloc(s
->codebook_size
);
166 s
->next_codebook_buffer
= av_malloc(s
->codebook_size
);
167 if (!s
->next_codebook_buffer
)
170 /* allocate decode buffer */
171 s
->decode_buffer_size
= (s
->width
/ s
->vector_width
) *
172 (s
->height
/ s
->vector_height
) * 2;
173 s
->decode_buffer
= av_malloc(s
->decode_buffer_size
);
174 if (!s
->decode_buffer
)
177 /* initialize the solid-color vectors */
178 if (s
->vector_height
== 4) {
179 codebook_index
= 0xFF00 * 16;
180 for (i
= 0; i
< 256; i
++)
181 for (j
= 0; j
< 16; j
++)
182 s
->codebook
[codebook_index
++] = i
;
184 codebook_index
= 0xF00 * 8;
185 for (i
= 0; i
< 256; i
++)
186 for (j
= 0; j
< 8; j
++)
187 s
->codebook
[codebook_index
++] = i
;
189 s
->next_codebook_buffer_index
= 0;
191 s
->frame
.data
[0] = NULL
;
195 av_freep(&s
->codebook
);
196 av_freep(&s
->next_codebook_buffer
);
197 av_freep(&s
->decode_buffer
);
198 return AVERROR(ENOMEM
);
201 #define CHECK_COUNT() \
202 if (dest_index + count > dest_size) { \
203 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
204 av_log(NULL, AV_LOG_ERROR, " VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \
205 dest_index, count, dest_size); \
206 return AVERROR_INVALIDDATA; \
209 #define CHECK_COPY(idx) \
210 if (idx < 0 || idx + count > dest_size) { \
211 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
212 av_log(NULL, AV_LOG_ERROR, " VQA video: current src_pos = %d, count = %d, dest_size = %d\n", \
213 src_pos, count, dest_size); \
214 return AVERROR_INVALIDDATA; \
218 static int decode_format80(GetByteContext
*gb
, int src_size
,
219 unsigned char *dest
, int dest_size
, int check_size
) {
222 int count
, opcode
, start
;
227 start
= bytestream2_tell(gb
);
228 while (bytestream2_tell(gb
) - start
< src_size
) {
229 opcode
= bytestream2_get_byte(gb
);
230 av_dlog(NULL
, " opcode %02X: ", opcode
);
232 /* 0x80 means that frame is finished */
236 if (dest_index
>= dest_size
) {
237 av_log(NULL
, AV_LOG_ERROR
, " VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",
238 dest_index
, dest_size
);
239 return AVERROR_INVALIDDATA
;
242 if (opcode
== 0xFF) {
244 count
= bytestream2_get_le16(gb
);
245 src_pos
= bytestream2_get_le16(gb
);
246 av_dlog(NULL
, "(1) copy %X bytes from absolute pos %X\n", count
, src_pos
);
249 for (i
= 0; i
< count
; i
++)
250 dest
[dest_index
+ i
] = dest
[src_pos
+ i
];
253 } else if (opcode
== 0xFE) {
255 count
= bytestream2_get_le16(gb
);
256 color
= bytestream2_get_byte(gb
);
257 av_dlog(NULL
, "(2) set %X bytes to %02X\n", count
, color
);
259 memset(&dest
[dest_index
], color
, count
);
262 } else if ((opcode
& 0xC0) == 0xC0) {
264 count
= (opcode
& 0x3F) + 3;
265 src_pos
= bytestream2_get_le16(gb
);
266 av_dlog(NULL
, "(3) copy %X bytes from absolute pos %X\n", count
, src_pos
);
269 for (i
= 0; i
< count
; i
++)
270 dest
[dest_index
+ i
] = dest
[src_pos
+ i
];
273 } else if (opcode
> 0x80) {
275 count
= opcode
& 0x3F;
276 av_dlog(NULL
, "(4) copy %X bytes from source to dest\n", count
);
278 bytestream2_get_buffer(gb
, &dest
[dest_index
], count
);
283 count
= ((opcode
& 0x70) >> 4) + 3;
284 src_pos
= bytestream2_get_byte(gb
) | ((opcode
& 0x0F) << 8);
285 av_dlog(NULL
, "(5) copy %X bytes from relpos %X\n", count
, src_pos
);
287 CHECK_COPY(dest_index
- src_pos
);
288 for (i
= 0; i
< count
; i
++)
289 dest
[dest_index
+ i
] = dest
[dest_index
- src_pos
+ i
];
294 /* validate that the entire destination buffer was filled; this is
295 * important for decoding frame maps since each vector needs to have a
296 * codebook entry; it is not important for compressed codebooks because
297 * not every entry needs to be filled */
299 if (dest_index
< dest_size
)
300 av_log(NULL
, AV_LOG_ERROR
, " VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
301 dest_index
, dest_size
);
303 return 0; // let's display what we decoded anyway
306 static int vqa_decode_chunk(VqaContext
*s
)
308 unsigned int chunk_type
;
309 unsigned int chunk_size
;
311 unsigned int index
= 0;
313 unsigned char r
, g
, b
;
328 int vector_index
= 0;
332 int hibytes
= s
->decode_buffer_size
/ 2;
334 /* first, traverse through the frame and find the subchunks */
335 while (bytestream2_get_bytes_left(&s
->gb
) >= 8) {
337 chunk_type
= bytestream2_get_be32u(&s
->gb
);
338 index
= bytestream2_tell(&s
->gb
);
339 chunk_size
= bytestream2_get_be32u(&s
->gb
);
341 switch (chunk_type
) {
372 av_log(s
->avctx
, AV_LOG_ERROR
, " VQA video: Found unknown chunk type: %c%c%c%c (%08X)\n",
373 (chunk_type
>> 24) & 0xFF,
374 (chunk_type
>> 16) & 0xFF,
375 (chunk_type
>> 8) & 0xFF,
376 (chunk_type
>> 0) & 0xFF,
381 byte_skip
= chunk_size
& 0x01;
382 bytestream2_skip(&s
->gb
, chunk_size
+ byte_skip
);
385 /* next, deal with the palette */
386 if ((cpl0_chunk
!= -1) && (cplz_chunk
!= -1)) {
388 /* a chunk should not have both chunk types */
389 av_log(s
->avctx
, AV_LOG_ERROR
, " VQA video: problem: found both CPL0 and CPLZ chunks\n");
390 return AVERROR_INVALIDDATA
;
393 /* decompress the palette chunk */
394 if (cplz_chunk
!= -1) {
396 /* yet to be handled */
400 /* convert the RGB palette into the machine's endian format */
401 if (cpl0_chunk
!= -1) {
403 bytestream2_seek(&s
->gb
, cpl0_chunk
, SEEK_SET
);
404 chunk_size
= bytestream2_get_be32(&s
->gb
);
405 /* sanity check the palette size */
406 if (chunk_size
/ 3 > 256 || chunk_size
> bytestream2_get_bytes_left(&s
->gb
)) {
407 av_log(s
->avctx
, AV_LOG_ERROR
, " VQA video: problem: found a palette chunk with %d colors\n",
409 return AVERROR_INVALIDDATA
;
411 for (i
= 0; i
< chunk_size
/ 3; i
++) {
412 /* scale by 4 to transform 6-bit palette -> 8-bit */
413 r
= bytestream2_get_byteu(&s
->gb
) * 4;
414 g
= bytestream2_get_byteu(&s
->gb
) * 4;
415 b
= bytestream2_get_byteu(&s
->gb
) * 4;
416 s
->palette
[i
] = (r
<< 16) | (g
<< 8) | (b
);
420 /* next, look for a full codebook */
421 if ((cbf0_chunk
!= -1) && (cbfz_chunk
!= -1)) {
423 /* a chunk should not have both chunk types */
424 av_log(s
->avctx
, AV_LOG_ERROR
, " VQA video: problem: found both CBF0 and CBFZ chunks\n");
425 return AVERROR_INVALIDDATA
;
428 /* decompress the full codebook chunk */
429 if (cbfz_chunk
!= -1) {
431 bytestream2_seek(&s
->gb
, cbfz_chunk
, SEEK_SET
);
432 chunk_size
= bytestream2_get_be32(&s
->gb
);
433 if ((res
= decode_format80(&s
->gb
, chunk_size
, s
->codebook
,
434 s
->codebook_size
, 0)) < 0)
438 /* copy a full codebook */
439 if (cbf0_chunk
!= -1) {
441 bytestream2_seek(&s
->gb
, cbf0_chunk
, SEEK_SET
);
442 chunk_size
= bytestream2_get_be32(&s
->gb
);
443 /* sanity check the full codebook size */
444 if (chunk_size
> MAX_CODEBOOK_SIZE
) {
445 av_log(s
->avctx
, AV_LOG_ERROR
, " VQA video: problem: CBF0 chunk too large (0x%X bytes)\n",
447 return AVERROR_INVALIDDATA
;
450 bytestream2_get_buffer(&s
->gb
, s
->codebook
, chunk_size
);
453 /* decode the frame */
454 if (vptz_chunk
== -1) {
456 /* something is wrong if there is no VPTZ chunk */
457 av_log(s
->avctx
, AV_LOG_ERROR
, " VQA video: problem: no VPTZ chunk found\n");
458 return AVERROR_INVALIDDATA
;
461 bytestream2_seek(&s
->gb
, vptz_chunk
, SEEK_SET
);
462 chunk_size
= bytestream2_get_be32(&s
->gb
);
463 if ((res
= decode_format80(&s
->gb
, chunk_size
,
464 s
->decode_buffer
, s
->decode_buffer_size
, 1)) < 0)
467 /* render the final PAL8 frame */
468 if (s
->vector_height
== 4)
472 for (y
= 0; y
< s
->height
; y
+= s
->vector_height
) {
473 for (x
= 0; x
< s
->width
; x
+= 4, lobytes
++, hibytes
++) {
474 pixel_ptr
= y
* s
->frame
.linesize
[0] + x
;
476 /* get the vector index, the method for which varies according to
477 * VQA file version */
478 switch (s
->vqa_version
) {
481 lobyte
= s
->decode_buffer
[lobytes
* 2];
482 hibyte
= s
->decode_buffer
[(lobytes
* 2) + 1];
483 vector_index
= ((hibyte
<< 8) | lobyte
) >> 3;
484 vector_index
<<= index_shift
;
485 lines
= s
->vector_height
;
486 /* uniform color fill - a quick hack */
487 if (hibyte
== 0xFF) {
489 s
->frame
.data
[0][pixel_ptr
+ 0] = 255 - lobyte
;
490 s
->frame
.data
[0][pixel_ptr
+ 1] = 255 - lobyte
;
491 s
->frame
.data
[0][pixel_ptr
+ 2] = 255 - lobyte
;
492 s
->frame
.data
[0][pixel_ptr
+ 3] = 255 - lobyte
;
493 pixel_ptr
+= s
->frame
.linesize
[0];
500 lobyte
= s
->decode_buffer
[lobytes
];
501 hibyte
= s
->decode_buffer
[hibytes
];
502 vector_index
= (hibyte
<< 8) | lobyte
;
503 vector_index
<<= index_shift
;
504 lines
= s
->vector_height
;
508 /* not implemented yet */
514 s
->frame
.data
[0][pixel_ptr
+ 0] = s
->codebook
[vector_index
++];
515 s
->frame
.data
[0][pixel_ptr
+ 1] = s
->codebook
[vector_index
++];
516 s
->frame
.data
[0][pixel_ptr
+ 2] = s
->codebook
[vector_index
++];
517 s
->frame
.data
[0][pixel_ptr
+ 3] = s
->codebook
[vector_index
++];
518 pixel_ptr
+= s
->frame
.linesize
[0];
523 /* handle partial codebook */
524 if ((cbp0_chunk
!= -1) && (cbpz_chunk
!= -1)) {
525 /* a chunk should not have both chunk types */
526 av_log(s
->avctx
, AV_LOG_ERROR
, " VQA video: problem: found both CBP0 and CBPZ chunks\n");
527 return AVERROR_INVALIDDATA
;
530 if (cbp0_chunk
!= -1) {
532 bytestream2_seek(&s
->gb
, cbp0_chunk
, SEEK_SET
);
533 chunk_size
= bytestream2_get_be32(&s
->gb
);
535 /* accumulate partial codebook */
536 bytestream2_get_buffer(&s
->gb
, &s
->next_codebook_buffer
[s
->next_codebook_buffer_index
],
538 s
->next_codebook_buffer_index
+= chunk_size
;
540 s
->partial_countdown
--;
541 if (s
->partial_countdown
== 0) {
543 /* time to replace codebook */
544 memcpy(s
->codebook
, s
->next_codebook_buffer
,
545 s
->next_codebook_buffer_index
);
547 /* reset accounting */
548 s
->next_codebook_buffer_index
= 0;
549 s
->partial_countdown
= s
->partial_count
;
553 if (cbpz_chunk
!= -1) {
555 bytestream2_seek(&s
->gb
, cbpz_chunk
, SEEK_SET
);
556 chunk_size
= bytestream2_get_be32(&s
->gb
);
558 /* accumulate partial codebook */
559 bytestream2_get_buffer(&s
->gb
, &s
->next_codebook_buffer
[s
->next_codebook_buffer_index
],
561 s
->next_codebook_buffer_index
+= chunk_size
;
563 s
->partial_countdown
--;
564 if (s
->partial_countdown
== 0) {
567 bytestream2_init(&gb
, s
->next_codebook_buffer
, s
->next_codebook_buffer_index
);
568 /* decompress codebook */
569 if ((res
= decode_format80(&gb
, s
->next_codebook_buffer_index
,
570 s
->codebook
, s
->codebook_size
, 0)) < 0)
573 /* reset accounting */
574 s
->next_codebook_buffer_index
= 0;
575 s
->partial_countdown
= s
->partial_count
;
582 static int vqa_decode_frame(AVCodecContext
*avctx
,
583 void *data
, int *got_frame
,
586 VqaContext
*s
= avctx
->priv_data
;
589 if (s
->frame
.data
[0])
590 avctx
->release_buffer(avctx
, &s
->frame
);
592 if ((res
= ff_get_buffer(avctx
, &s
->frame
)) < 0) {
593 av_log(s
->avctx
, AV_LOG_ERROR
, " VQA Video: get_buffer() failed\n");
597 bytestream2_init(&s
->gb
, avpkt
->data
, avpkt
->size
);
598 if ((res
= vqa_decode_chunk(s
)) < 0)
601 /* make the palette available on the way out */
602 memcpy(s
->frame
.data
[1], s
->palette
, PALETTE_COUNT
* 4);
603 s
->frame
.palette_has_changed
= 1;
606 *(AVFrame
*)data
= s
->frame
;
608 /* report that the buffer was completely consumed */
612 static av_cold
int vqa_decode_end(AVCodecContext
*avctx
)
614 VqaContext
*s
= avctx
->priv_data
;
616 av_freep(&s
->codebook
);
617 av_freep(&s
->next_codebook_buffer
);
618 av_freep(&s
->decode_buffer
);
620 if (s
->frame
.data
[0])
621 avctx
->release_buffer(avctx
, &s
->frame
);
626 AVCodec ff_vqa_decoder
= {
628 .type
= AVMEDIA_TYPE_VIDEO
,
629 .id
= AV_CODEC_ID_WS_VQA
,
630 .priv_data_size
= sizeof(VqaContext
),
631 .init
= vqa_decode_init
,
632 .close
= vqa_decode_end
,
633 .decode
= vqa_decode_frame
,
634 .capabilities
= CODEC_CAP_DR1
,
635 .long_name
= NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"),