1/* 2 * Westwood Studios VQA Video Decoder 3 * Copyright (C) 2003 the ffmpeg project 4 * 5 * This file is part of Libav. 6 * 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. 11 * 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. 16 * 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 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 75#define PALETTE_COUNT 256 76#define VQA_HEADER_SIZE 0x2A 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 93typedef struct VqaContext { 94 95 AVCodecContext *avctx; 96 AVFrame frame; 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 121static av_cold int vqa_decode_init(AVCodecContext *avctx) 122{ 123 VqaContext *s = avctx->priv_data; 124 int i, j, codebook_index; 125 126 s->avctx = avctx; 127 avctx->pix_fmt = 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, " VQA video: expected extradata size of %d\n", VQA_HEADER_SIZE); 132 return -1; 133 } 134 135 /* load up the VQA parameters from the header */ 136 s->vqa_version = s->avctx->extradata[0]; 137 s->width = AV_RL16(&s->avctx->extradata[6]); 138 s->height = AV_RL16(&s->avctx->extradata[8]); 139 if(av_image_check_size(s->width, s->height, 0, avctx)){ 140 s->width= s->height= 0; 141 return -1; 142 } 143 s->vector_width = s->avctx->extradata[10]; 144 s->vector_height = s->avctx->extradata[11]; 145 s->partial_count = s->partial_countdown = s->avctx->extradata[13]; 146 147 /* the vector dimensions have to meet very stringent requirements */ 148 if ((s->vector_width != 4) || 149 ((s->vector_height != 2) && (s->vector_height != 4))) { 150 /* return without further initialization */ 151 return -1; 152 } 153 154 if (s->width & (s->vector_width - 1) || 155 s->height & (s->vector_height - 1)) { 156 av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n"); 157 return AVERROR_INVALIDDATA; 158 } 159 160 /* allocate codebooks */ 161 s->codebook_size = MAX_CODEBOOK_SIZE; 162 s->codebook = av_malloc(s->codebook_size); 163 s->next_codebook_buffer = av_malloc(s->codebook_size); 164 165 /* initialize the solid-color vectors */ 166 if (s->vector_height == 4) { 167 codebook_index = 0xFF00 * 16; 168 for (i = 0; i < 256; i++) 169 for (j = 0; j < 16; j++) 170 s->codebook[codebook_index++] = i; 171 } else { 172 codebook_index = 0xF00 * 8; 173 for (i = 0; i < 256; i++) 174 for (j = 0; j < 8; j++) 175 s->codebook[codebook_index++] = i; 176 } 177 s->next_codebook_buffer_index = 0; 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_malloc(s->decode_buffer_size); 183 184 s->frame.data[0] = NULL; 185 186 return 0; 187} 188 189#define CHECK_COUNT() \ 190 if (dest_index + count > dest_size) { \ 191 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \ 192 av_log(NULL, AV_LOG_ERROR, " VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \ 193 dest_index, count, dest_size); \ 194 return AVERROR_INVALIDDATA; \ 195 } 196 197#define CHECK_COPY(idx) \ 198 if (idx < 0 || idx + count > dest_size) { \ 199 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \ 200 av_log(NULL, AV_LOG_ERROR, " VQA video: current src_pos = %d, count = %d, dest_size = %d\n", \ 201 src_pos, count, dest_size); \ 202 return AVERROR_INVALIDDATA; \ 203 } 204 205 206static int decode_format80(GetByteContext *gb, int src_size, 207 unsigned char *dest, int dest_size, int check_size) { 208 209 int dest_index = 0; 210 int count, opcode, start; 211 int src_pos; 212 unsigned char color; 213 int i; 214 215 start = bytestream2_tell(gb); 216 while (bytestream2_tell(gb) - start < src_size) { 217 opcode = bytestream2_get_byte(gb); 218 av_dlog(NULL, " opcode %02X: ", opcode); 219 220 /* 0x80 means that frame is finished */ 221 if (opcode == 0x80) 222 return 0; 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 AVERROR_INVALIDDATA; 228 } 229 230 if (opcode == 0xFF) { 231 232 count = bytestream2_get_le16(gb); 233 src_pos = bytestream2_get_le16(gb); 234 av_dlog(NULL, "(1) copy %X bytes from absolute pos %X\n", count, src_pos); 235 CHECK_COUNT(); 236 CHECK_COPY(src_pos); 237 for (i = 0; i < count; i++) 238 dest[dest_index + i] = dest[src_pos + i]; 239 dest_index += count; 240 241 } else if (opcode == 0xFE) { 242 243 count = bytestream2_get_le16(gb); 244 color = bytestream2_get_byte(gb); 245 av_dlog(NULL, "(2) set %X bytes to %02X\n", count, color); 246 CHECK_COUNT(); 247 memset(&dest[dest_index], color, count); 248 dest_index += count; 249 250 } else if ((opcode & 0xC0) == 0xC0) { 251 252 count = (opcode & 0x3F) + 3; 253 src_pos = bytestream2_get_le16(gb); 254 av_dlog(NULL, "(3) copy %X bytes from absolute pos %X\n", count, src_pos); 255 CHECK_COUNT(); 256 CHECK_COPY(src_pos); 257 for (i = 0; i < count; i++) 258 dest[dest_index + i] = dest[src_pos + i]; 259 dest_index += count; 260 261 } else if (opcode > 0x80) { 262 263 count = opcode & 0x3F; 264 av_dlog(NULL, "(4) copy %X bytes from source to dest\n", count); 265 CHECK_COUNT(); 266 bytestream2_get_buffer(gb, &dest[dest_index], count); 267 dest_index += count; 268 269 } else { 270 271 count = ((opcode & 0x70) >> 4) + 3; 272 src_pos = bytestream2_get_byte(gb) | ((opcode & 0x0F) << 8); 273 av_dlog(NULL, "(5) copy %X bytes from relpos %X\n", count, src_pos); 274 CHECK_COUNT(); 275 CHECK_COPY(dest_index - src_pos); 276 for (i = 0; i < count; i++) 277 dest[dest_index + i] = dest[dest_index - src_pos + i]; 278 dest_index += count; 279 } 280 } 281 282 /* validate that the entire destination buffer was filled; this is 283 * important for decoding frame maps since each vector needs to have a 284 * codebook entry; it is not important for compressed codebooks because 285 * not every entry needs to be filled */ 286 if (check_size) 287 if (dest_index < dest_size) 288 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n", 289 dest_index, dest_size); 290 291 return 0; // let's display what we decoded anyway 292} 293 294static int vqa_decode_chunk(VqaContext *s) 295{ 296 unsigned int chunk_type; 297 unsigned int chunk_size; 298 int byte_skip; 299 unsigned int index = 0; 300 int i; 301 unsigned char r, g, b; 302 int index_shift; 303 int res; 304 305 int cbf0_chunk = -1; 306 int cbfz_chunk = -1; 307 int cbp0_chunk = -1; 308 int cbpz_chunk = -1; 309 int cpl0_chunk = -1; 310 int cplz_chunk = -1; 311 int vptz_chunk = -1; 312 313 int x, y; 314 int lines = 0; 315 int pixel_ptr; 316 int vector_index = 0; 317 int lobyte = 0; 318 int hibyte = 0; 319 int lobytes = 0; 320 int hibytes = s->decode_buffer_size / 2; 321 322 /* first, traverse through the frame and find the subchunks */ 323 while (bytestream2_get_bytes_left(&s->gb) >= 8) { 324 325 chunk_type = bytestream2_get_be32u(&s->gb); 326 index = bytestream2_tell(&s->gb); 327 chunk_size = bytestream2_get_be32u(&s->gb); 328 329 switch (chunk_type) { 330 331 case CBF0_TAG: 332 cbf0_chunk = index; 333 break; 334 335 case CBFZ_TAG: 336 cbfz_chunk = index; 337 break; 338 339 case CBP0_TAG: 340 cbp0_chunk = index; 341 break; 342 343 case CBPZ_TAG: 344 cbpz_chunk = index; 345 break; 346 347 case CPL0_TAG: 348 cpl0_chunk = index; 349 break; 350 351 case CPLZ_TAG: 352 cplz_chunk = index; 353 break; 354 355 case VPTZ_TAG: 356 vptz_chunk = index; 357 break; 358 359 default: 360 av_log(s->avctx, AV_LOG_ERROR, " VQA video: Found unknown chunk type: %c%c%c%c (%08X)\n", 361 (chunk_type >> 24) & 0xFF, 362 (chunk_type >> 16) & 0xFF, 363 (chunk_type >> 8) & 0xFF, 364 (chunk_type >> 0) & 0xFF, 365 chunk_type); 366 break; 367 } 368 369 byte_skip = chunk_size & 0x01; 370 bytestream2_skip(&s->gb, chunk_size + byte_skip); 371 } 372 373 /* next, deal with the palette */ 374 if ((cpl0_chunk != -1) && (cplz_chunk != -1)) { 375 376 /* a chunk should not have both chunk types */ 377 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CPL0 and CPLZ chunks\n"); 378 return AVERROR_INVALIDDATA; 379 } 380 381 /* decompress the palette chunk */ 382 if (cplz_chunk != -1) { 383 384/* yet to be handled */ 385 386 } 387 388 /* convert the RGB palette into the machine's endian format */ 389 if (cpl0_chunk != -1) { 390 391 bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET); 392 chunk_size = bytestream2_get_be32(&s->gb); 393 /* sanity check the palette size */ 394 if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) { 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 AVERROR_INVALIDDATA; 398 } 399 for (i = 0; i < chunk_size / 3; i++) { 400 /* scale by 4 to transform 6-bit palette -> 8-bit */ 401 r = bytestream2_get_byteu(&s->gb) * 4; 402 g = bytestream2_get_byteu(&s->gb) * 4; 403 b = bytestream2_get_byteu(&s->gb) * 4; 404 s->palette[i] = (r << 16) | (g << 8) | (b); 405 } 406 } 407 408 /* next, look for a full codebook */ 409 if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { 410 411 /* a chunk should not have both chunk types */ 412 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBF0 and CBFZ chunks\n"); 413 return AVERROR_INVALIDDATA; 414 } 415 416 /* decompress the full codebook chunk */ 417 if (cbfz_chunk != -1) { 418 419 bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET); 420 chunk_size = bytestream2_get_be32(&s->gb); 421 if ((res = decode_format80(&s->gb, chunk_size, s->codebook, 422 s->codebook_size, 0)) < 0) 423 return res; 424 } 425 426 /* copy a full codebook */ 427 if (cbf0_chunk != -1) { 428 429 bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET); 430 chunk_size = bytestream2_get_be32(&s->gb); 431 /* sanity check the full codebook size */ 432 if (chunk_size > MAX_CODEBOOK_SIZE) { 433 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: CBF0 chunk too large (0x%X bytes)\n", 434 chunk_size); 435 return AVERROR_INVALIDDATA; 436 } 437 438 bytestream2_get_buffer(&s->gb, s->codebook, 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 AVERROR_INVALIDDATA; 447 } 448 449 bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET); 450 chunk_size = bytestream2_get_be32(&s->gb); 451 if ((res = decode_format80(&s->gb, chunk_size, 452 s->decode_buffer, s->decode_buffer_size, 1)) < 0) 453 return res; 454 455 /* render the final PAL8 frame */ 456 if (s->vector_height == 4) 457 index_shift = 4; 458 else 459 index_shift = 3; 460 for (y = 0; y < s->frame.linesize[0] * s->height; 461 y += s->frame.linesize[0] * s->vector_height) { 462 463 for (x = y; x < y + s->width; x += 4, lobytes++, hibytes++) { 464 pixel_ptr = x; 465 466 /* get the vector index, the method for which varies according to 467 * VQA file version */ 468 switch (s->vqa_version) { 469 470 case 1: 471 lobyte = s->decode_buffer[lobytes * 2]; 472 hibyte = s->decode_buffer[(lobytes * 2) + 1]; 473 vector_index = ((hibyte << 8) | lobyte) >> 3; 474 vector_index <<= index_shift; 475 lines = s->vector_height; 476 /* uniform color fill - a quick hack */ 477 if (hibyte == 0xFF) { 478 while (lines--) { 479 s->frame.data[0][pixel_ptr + 0] = 255 - lobyte; 480 s->frame.data[0][pixel_ptr + 1] = 255 - lobyte; 481 s->frame.data[0][pixel_ptr + 2] = 255 - lobyte; 482 s->frame.data[0][pixel_ptr + 3] = 255 - lobyte; 483 pixel_ptr += s->frame.linesize[0]; 484 } 485 lines=0; 486 } 487 break; 488 489 case 2: 490 lobyte = s->decode_buffer[lobytes]; 491 hibyte = s->decode_buffer[hibytes]; 492 vector_index = (hibyte << 8) | lobyte; 493 vector_index <<= index_shift; 494 lines = s->vector_height; 495 break; 496 497 case 3: 498/* not implemented yet */ 499 lines = 0; 500 break; 501 } 502 503 while (lines--) { 504 s->frame.data[0][pixel_ptr + 0] = s->codebook[vector_index++]; 505 s->frame.data[0][pixel_ptr + 1] = s->codebook[vector_index++]; 506 s->frame.data[0][pixel_ptr + 2] = s->codebook[vector_index++]; 507 s->frame.data[0][pixel_ptr + 3] = s->codebook[vector_index++]; 508 pixel_ptr += s->frame.linesize[0]; 509 } 510 } 511 } 512 513 /* handle partial codebook */ 514 if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) { 515 /* a chunk should not have both chunk types */ 516 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBP0 and CBPZ chunks\n"); 517 return AVERROR_INVALIDDATA; 518 } 519 520 if (cbp0_chunk != -1) { 521 522 bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET); 523 chunk_size = bytestream2_get_be32(&s->gb); 524 525 /* accumulate partial codebook */ 526 bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], 527 chunk_size); 528 s->next_codebook_buffer_index += chunk_size; 529 530 s->partial_countdown--; 531 if (s->partial_countdown == 0) { 532 533 /* time to replace codebook */ 534 memcpy(s->codebook, s->next_codebook_buffer, 535 s->next_codebook_buffer_index); 536 537 /* reset accounting */ 538 s->next_codebook_buffer_index = 0; 539 s->partial_countdown = s->partial_count; 540 } 541 } 542 543 if (cbpz_chunk != -1) { 544 545 bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET); 546 chunk_size = bytestream2_get_be32(&s->gb); 547 548 /* accumulate partial codebook */ 549 bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], 550 chunk_size); 551 s->next_codebook_buffer_index += chunk_size; 552 553 s->partial_countdown--; 554 if (s->partial_countdown == 0) { 555 GetByteContext gb; 556 557 bytestream2_init(&gb, s->next_codebook_buffer, s->next_codebook_buffer_index); 558 /* decompress codebook */ 559 if ((res = decode_format80(&gb, s->next_codebook_buffer_index, 560 s->codebook, s->codebook_size, 0)) < 0) 561 return res; 562 563 /* reset accounting */ 564 s->next_codebook_buffer_index = 0; 565 s->partial_countdown = s->partial_count; 566 } 567 } 568 569 return 0; 570} 571 572static int vqa_decode_frame(AVCodecContext *avctx, 573 void *data, int *data_size, 574 AVPacket *avpkt) 575{ 576 VqaContext *s = avctx->priv_data; 577 int res; 578 579 if (s->frame.data[0]) 580 avctx->release_buffer(avctx, &s->frame); 581 582 if (avctx->get_buffer(avctx, &s->frame)) { 583 av_log(s->avctx, AV_LOG_ERROR, " VQA Video: get_buffer() failed\n"); 584 return -1; 585 } 586 587 bytestream2_init(&s->gb, avpkt->data, avpkt->size); 588 if ((res = vqa_decode_chunk(s)) < 0) 589 return res; 590 591 /* make the palette available on the way out */ 592 memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4); 593 s->frame.palette_has_changed = 1; 594 595 *data_size = sizeof(AVFrame); 596 *(AVFrame*)data = s->frame; 597 598 /* report that the buffer was completely consumed */ 599 return avpkt->size; 600} 601 602static av_cold int vqa_decode_end(AVCodecContext *avctx) 603{ 604 VqaContext *s = avctx->priv_data; 605 606 av_free(s->codebook); 607 av_free(s->next_codebook_buffer); 608 av_free(s->decode_buffer); 609 610 if (s->frame.data[0]) 611 avctx->release_buffer(avctx, &s->frame); 612 613 return 0; 614} 615 616AVCodec ff_vqa_decoder = { 617 .name = "vqavideo", 618 .type = AVMEDIA_TYPE_VIDEO, 619 .id = CODEC_ID_WS_VQA, 620 .priv_data_size = sizeof(VqaContext), 621 .init = vqa_decode_init, 622 .close = vqa_decode_end, 623 .decode = vqa_decode_frame, 624 .capabilities = CODEC_CAP_DR1, 625 .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"), 626}; 627