2 * Westwood Studios VQA Video Decoder
3 * Copyright (c) 2003 The FFmpeg Project
5 * This file is part of FFmpeg.
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.
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.
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
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
;
99 uint32_t palette
[PALETTE_COUNT
];
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 */
107 unsigned char *codebook
; /* the current codebook */
109 unsigned char *next_codebook_buffer
; /* accumulator for next codebook */
110 int next_codebook_buffer_index
;
112 unsigned char *decode_buffer
;
113 int decode_buffer_size
;
115 /* number of frames to go before replacing codebook */
116 int partial_countdown
;
121 static av_cold
int vqa_decode_init(AVCodecContext
*avctx
)
123 VqaContext
*s
= avctx
->priv_data
;
124 int i
, j
, codebook_index
, ret
;
127 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
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
);
135 /* load up the VQA parameters from the header */
136 s
->vqa_version
= s
->avctx
->extradata
[0];
137 switch (s
->vqa_version
) {
142 avpriv_report_missing_feature(avctx
, "VQA Version %d", s
->vqa_version
);
143 return AVERROR_PATCHWELCOME
;
145 avpriv_request_sample(avctx
, "VQA Version %i", s
->vqa_version
);
146 return AVERROR_PATCHWELCOME
;
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;
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];
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
;
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
;
170 /* allocate codebooks */
171 s
->codebook_size
= MAX_CODEBOOK_SIZE
;
172 s
->codebook
= av_malloc(s
->codebook_size
);
175 s
->next_codebook_buffer
= av_malloc(s
->codebook_size
);
176 if (!s
->next_codebook_buffer
)
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
)
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
;
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
;
198 s
->next_codebook_buffer_index
= 0;
202 av_freep(&s
->codebook
);
203 av_freep(&s
->next_codebook_buffer
);
204 av_freep(&s
->decode_buffer
);
205 return AVERROR(ENOMEM
);
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; \
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; \
225 static int decode_format80(VqaContext
*s
, int src_size
,
226 unsigned char *dest
, int dest_size
, int check_size
) {
229 int count
, opcode
, start
;
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
);
239 /* 0x80 means that frame is finished */
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
;
249 if (opcode
== 0xFF) {
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
);
256 for (i
= 0; i
< count
; i
++)
257 dest
[dest_index
+ i
] = dest
[src_pos
+ i
];
260 } else if (opcode
== 0xFE) {
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
);
266 memset(&dest
[dest_index
], color
, count
);
269 } else if ((opcode
& 0xC0) == 0xC0) {
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
);
276 for (i
= 0; i
< count
; i
++)
277 dest
[dest_index
+ i
] = dest
[src_pos
+ i
];
280 } else if (opcode
> 0x80) {
282 count
= opcode
& 0x3F;
283 av_dlog(s
->avctx
, "(4) copy %X bytes from source to dest\n", count
);
285 bytestream2_get_buffer(&s
->gb
, &dest
[dest_index
], count
);
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
);
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
];
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 */
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
);
312 return 0; // let's display what we decoded anyway
315 static int vqa_decode_chunk(VqaContext
*s
, AVFrame
*frame
)
317 unsigned int chunk_type
;
318 unsigned int chunk_size
;
320 unsigned int index
= 0;
322 unsigned char r
, g
, b
;
337 int vector_index
= 0;
341 int hibytes
= s
->decode_buffer_size
/ 2;
343 /* first, traverse through the frame and find the subchunks */
344 while (bytestream2_get_bytes_left(&s
->gb
) >= 8) {
346 chunk_type
= bytestream2_get_be32u(&s
->gb
);
347 index
= bytestream2_tell(&s
->gb
);
348 chunk_size
= bytestream2_get_be32u(&s
->gb
);
350 switch (chunk_type
) {
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,
390 byte_skip
= chunk_size
& 0x01;
391 bytestream2_skip(&s
->gb
, chunk_size
+ byte_skip
);
394 /* next, deal with the palette */
395 if ((cpl0_chunk
!= -1) && (cplz_chunk
!= -1)) {
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
;
402 /* decompress the palette chunk */
403 if (cplz_chunk
!= -1) {
405 /* yet to be handled */
409 /* convert the RGB palette into the machine's endian format */
410 if (cpl0_chunk
!= -1) {
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",
418 return AVERROR_INVALIDDATA
;
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;
430 /* next, look for a full codebook */
431 if ((cbf0_chunk
!= -1) && (cbfz_chunk
!= -1)) {
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
;
438 /* decompress the full codebook chunk */
439 if (cbfz_chunk
!= -1) {
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)
448 /* copy a full codebook */
449 if (cbf0_chunk
!= -1) {
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",
457 return AVERROR_INVALIDDATA
;
460 bytestream2_get_buffer(&s
->gb
, s
->codebook
, chunk_size
);
463 /* decode the frame */
464 if (vptz_chunk
== -1) {
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
;
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)
477 /* render the final PAL8 frame */
478 if (s
->vector_height
== 4)
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
;
486 /* get the vector index, the method for which varies according to
487 * VQA file version */
488 switch (s
->vqa_version
) {
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) {
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];
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
;
518 /* not implemented yet */
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];
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
;
540 if (cbp0_chunk
!= -1) {
542 bytestream2_seek(&s
->gb
, cbp0_chunk
, SEEK_SET
);
543 chunk_size
= bytestream2_get_be32(&s
->gb
);
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",
548 return AVERROR_INVALIDDATA
;
551 /* accumulate partial codebook */
552 bytestream2_get_buffer(&s
->gb
, &s
->next_codebook_buffer
[s
->next_codebook_buffer_index
],
554 s
->next_codebook_buffer_index
+= chunk_size
;
556 s
->partial_countdown
--;
557 if (s
->partial_countdown
<= 0) {
559 /* time to replace codebook */
560 memcpy(s
->codebook
, s
->next_codebook_buffer
,
561 s
->next_codebook_buffer_index
);
563 /* reset accounting */
564 s
->next_codebook_buffer_index
= 0;
565 s
->partial_countdown
= s
->partial_count
;
569 if (cbpz_chunk
!= -1) {
571 bytestream2_seek(&s
->gb
, cbpz_chunk
, SEEK_SET
);
572 chunk_size
= bytestream2_get_be32(&s
->gb
);
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",
577 return AVERROR_INVALIDDATA
;
580 /* accumulate partial codebook */
581 bytestream2_get_buffer(&s
->gb
, &s
->next_codebook_buffer
[s
->next_codebook_buffer_index
],
583 s
->next_codebook_buffer_index
+= chunk_size
;
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)
593 /* reset accounting */
594 s
->next_codebook_buffer_index
= 0;
595 s
->partial_countdown
= s
->partial_count
;
602 static int vqa_decode_frame(AVCodecContext
*avctx
,
603 void *data
, int *got_frame
,
606 VqaContext
*s
= avctx
->priv_data
;
607 AVFrame
*frame
= data
;
610 if ((res
= ff_get_buffer(avctx
, frame
, 0)) < 0)
613 bytestream2_init(&s
->gb
, avpkt
->data
, avpkt
->size
);
614 if ((res
= vqa_decode_chunk(s
, frame
)) < 0)
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;
623 /* report that the buffer was completely consumed */
627 static av_cold
int vqa_decode_end(AVCodecContext
*avctx
)
629 VqaContext
*s
= avctx
->priv_data
;
631 av_freep(&s
->codebook
);
632 av_freep(&s
->next_codebook_buffer
);
633 av_freep(&s
->decode_buffer
);
638 AVCodec ff_vqa_decoder
= {
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
,