1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Westwood Studios VQA Video Decoder 3cabdff1aSopenharmony_ci * Copyright (c) 2003 Mike Melanson <melanson@pcisys.net> 4cabdff1aSopenharmony_ci * Copyright (c) 2021 Pekka Väänänen <pekka.vaananen@iki.fi> 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * This file is part of FFmpeg. 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 12cabdff1aSopenharmony_ci * 13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16cabdff1aSopenharmony_ci * Lesser General Public License for more details. 17cabdff1aSopenharmony_ci * 18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21cabdff1aSopenharmony_ci */ 22cabdff1aSopenharmony_ci 23cabdff1aSopenharmony_ci/** 24cabdff1aSopenharmony_ci * @file 25cabdff1aSopenharmony_ci * VQA Video Decoder 26cabdff1aSopenharmony_ci * @author Mike Melanson (melanson@pcisys.net) 27cabdff1aSopenharmony_ci * @see http://wiki.multimedia.cx/index.php?title=VQA 28cabdff1aSopenharmony_ci * 29cabdff1aSopenharmony_ci * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending 30cabdff1aSopenharmony_ci * on the type of data in the file. 31cabdff1aSopenharmony_ci * 32cabdff1aSopenharmony_ci * This decoder needs the 42-byte VQHD header from the beginning 33cabdff1aSopenharmony_ci * of the VQA file passed through the extradata field. The VQHD header 34cabdff1aSopenharmony_ci * is laid out as: 35cabdff1aSopenharmony_ci * 36cabdff1aSopenharmony_ci * bytes 0-3 chunk fourcc: 'VQHD' 37cabdff1aSopenharmony_ci * bytes 4-7 chunk size in big-endian format, should be 0x0000002A 38cabdff1aSopenharmony_ci * bytes 8-49 VQHD chunk data 39cabdff1aSopenharmony_ci * 40cabdff1aSopenharmony_ci * Bytes 8-49 are what this decoder expects to see. 41cabdff1aSopenharmony_ci * 42cabdff1aSopenharmony_ci * Briefly, VQA is a vector quantized animation format that operates in a 43cabdff1aSopenharmony_ci * VGA palettized colorspace. It operates on pixel vectors (blocks) 44cabdff1aSopenharmony_ci * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector 45cabdff1aSopenharmony_ci * codebooks, palette information, and code maps for rendering vectors onto 46cabdff1aSopenharmony_ci * frames. Any of these components can also be compressed with a run-length 47cabdff1aSopenharmony_ci * encoding (RLE) algorithm commonly referred to as "format80". 48cabdff1aSopenharmony_ci * 49cabdff1aSopenharmony_ci * VQA takes a novel approach to rate control. Each group of n frames 50cabdff1aSopenharmony_ci * (usually, n = 8) relies on a different vector codebook. Rather than 51cabdff1aSopenharmony_ci * transporting an entire codebook every 8th frame, the new codebook is 52cabdff1aSopenharmony_ci * broken up into 8 pieces and sent along with the compressed video chunks 53cabdff1aSopenharmony_ci * for each of the 8 frames preceding the 8 frames which require the 54cabdff1aSopenharmony_ci * codebook. A full codebook is also sent on the very first frame of a 55cabdff1aSopenharmony_ci * file. This is an interesting technique, although it makes random file 56cabdff1aSopenharmony_ci * seeking difficult despite the fact that the frames are all intracoded. 57cabdff1aSopenharmony_ci * 58cabdff1aSopenharmony_ci * V1,2 VQA uses 12-bit codebook indexes. If the 12-bit indexes were 59cabdff1aSopenharmony_ci * packed into bytes and then RLE compressed, bytewise, the results would 60cabdff1aSopenharmony_ci * be poor. That is why the coding method divides each index into 2 parts, 61cabdff1aSopenharmony_ci * the top 4 bits and the bottom 8 bits, then RL encodes the 4-bit pieces 62cabdff1aSopenharmony_ci * together and the 8-bit pieces together. If most of the vectors are 63cabdff1aSopenharmony_ci * clustered into one group of 256 vectors, most of the 4-bit index pieces 64cabdff1aSopenharmony_ci * should be the same. 65cabdff1aSopenharmony_ci * 66cabdff1aSopenharmony_ci * VQA3 introduces a 15-bit high color codebook, delta coding, replaces 67cabdff1aSopenharmony_ci * the above "split byte" scheme with RLE compression, and extends the 68cabdff1aSopenharmony_ci * "format80" compression with relative references. In VQA3 the whole 69cabdff1aSopenharmony_ci * codebook is always updated as a whole without splitting it into pieces. 70cabdff1aSopenharmony_ci */ 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci#include <stdio.h> 73cabdff1aSopenharmony_ci#include <stdlib.h> 74cabdff1aSopenharmony_ci#include <string.h> 75cabdff1aSopenharmony_ci 76cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 77cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 78cabdff1aSopenharmony_ci#include "avcodec.h" 79cabdff1aSopenharmony_ci#include "bytestream.h" 80cabdff1aSopenharmony_ci#include "codec_internal.h" 81cabdff1aSopenharmony_ci#include "internal.h" 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci#define PALETTE_COUNT 256 84cabdff1aSopenharmony_ci#define VQA_HEADER_SIZE 0x2A 85cabdff1aSopenharmony_ci 86cabdff1aSopenharmony_ci/* allocate the maximum vector space, regardless of the file version: 87cabdff1aSopenharmony_ci * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */ 88cabdff1aSopenharmony_ci#define MAX_CODEBOOK_VECTORS 0xFF00 89cabdff1aSopenharmony_ci#define SOLID_PIXEL_VECTORS 0x100 90cabdff1aSopenharmony_ci#define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS) 91cabdff1aSopenharmony_ci#define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4 * sizeof(uint16_t)) 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci#define CBF0_TAG MKBETAG('C', 'B', 'F', '0') 94cabdff1aSopenharmony_ci#define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z') 95cabdff1aSopenharmony_ci#define CBP0_TAG MKBETAG('C', 'B', 'P', '0') 96cabdff1aSopenharmony_ci#define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z') 97cabdff1aSopenharmony_ci#define CPL0_TAG MKBETAG('C', 'P', 'L', '0') 98cabdff1aSopenharmony_ci#define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z') 99cabdff1aSopenharmony_ci#define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z') 100cabdff1aSopenharmony_ci#define VPTR_TAG MKBETAG('V', 'P', 'T', 'R') 101cabdff1aSopenharmony_ci#define VPRZ_TAG MKBETAG('V', 'P', 'R', 'Z') 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_citypedef struct VqaContext { 104cabdff1aSopenharmony_ci AVFrame *frame; 105cabdff1aSopenharmony_ci AVCodecContext *avctx; 106cabdff1aSopenharmony_ci GetByteContext gb; 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci uint32_t palette[PALETTE_COUNT]; 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_ci int width; /* width of a frame */ 111cabdff1aSopenharmony_ci int height; /* height of a frame */ 112cabdff1aSopenharmony_ci int vector_width; /* width of individual vector */ 113cabdff1aSopenharmony_ci int vector_height; /* height of individual vector */ 114cabdff1aSopenharmony_ci int vqa_version; /* this should be either 1, 2 or 3 */ 115cabdff1aSopenharmony_ci 116cabdff1aSopenharmony_ci unsigned char *codebook; /* the current codebook */ 117cabdff1aSopenharmony_ci int codebook_size; 118cabdff1aSopenharmony_ci unsigned char *next_codebook_buffer; /* accumulator for next codebook */ 119cabdff1aSopenharmony_ci int next_codebook_buffer_index; 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ci unsigned char *decode_buffer; 122cabdff1aSopenharmony_ci int decode_buffer_size; 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci /* number of frames to go before replacing codebook */ 125cabdff1aSopenharmony_ci int partial_countdown; 126cabdff1aSopenharmony_ci int partial_count; 127cabdff1aSopenharmony_ci} VqaContext; 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_cistatic av_cold int vqa_decode_init(AVCodecContext *avctx) 130cabdff1aSopenharmony_ci{ 131cabdff1aSopenharmony_ci VqaContext *s = avctx->priv_data; 132cabdff1aSopenharmony_ci int i, j, codebook_index, ret; 133cabdff1aSopenharmony_ci int colors; 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci s->avctx = avctx; 136cabdff1aSopenharmony_ci 137cabdff1aSopenharmony_ci /* make sure the extradata made it */ 138cabdff1aSopenharmony_ci if (s->avctx->extradata_size != VQA_HEADER_SIZE) { 139cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n", VQA_HEADER_SIZE); 140cabdff1aSopenharmony_ci return AVERROR(EINVAL); 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci /* load up the VQA parameters from the header */ 144cabdff1aSopenharmony_ci s->vqa_version = s->avctx->extradata[0]; 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_ci if (s->vqa_version < 1 || s->vqa_version > 3) { 147cabdff1aSopenharmony_ci avpriv_request_sample(avctx, "VQA Version %i", s->vqa_version); 148cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 149cabdff1aSopenharmony_ci } 150cabdff1aSopenharmony_ci 151cabdff1aSopenharmony_ci s->width = AV_RL16(&s->avctx->extradata[6]); 152cabdff1aSopenharmony_ci s->height = AV_RL16(&s->avctx->extradata[8]); 153cabdff1aSopenharmony_ci if ((ret = ff_set_dimensions(avctx, s->width, s->height)) < 0) { 154cabdff1aSopenharmony_ci s->width= s->height= 0; 155cabdff1aSopenharmony_ci return ret; 156cabdff1aSopenharmony_ci } 157cabdff1aSopenharmony_ci s->vector_width = s->avctx->extradata[10]; 158cabdff1aSopenharmony_ci s->vector_height = s->avctx->extradata[11]; 159cabdff1aSopenharmony_ci s->partial_count = s->partial_countdown = s->avctx->extradata[13]; 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci colors = (s->avctx->extradata[14] << 8) | s->avctx->extradata[15]; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci if (colors > 0) { 164cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_PAL8; 165cabdff1aSopenharmony_ci } else { 166cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_RGB555LE; 167cabdff1aSopenharmony_ci } 168cabdff1aSopenharmony_ci 169cabdff1aSopenharmony_ci /* the vector dimensions have to meet very stringent requirements */ 170cabdff1aSopenharmony_ci if ((s->vector_width != 4) || 171cabdff1aSopenharmony_ci ((s->vector_height != 2) && (s->vector_height != 4))) { 172cabdff1aSopenharmony_ci /* return without further initialization */ 173cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 174cabdff1aSopenharmony_ci } 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci if (s->width % s->vector_width || s->height % s->vector_height) { 177cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n"); 178cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 179cabdff1aSopenharmony_ci } 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci s->frame = av_frame_alloc(); 182cabdff1aSopenharmony_ci if (!s->frame) 183cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 184cabdff1aSopenharmony_ci 185cabdff1aSopenharmony_ci /* allocate codebooks */ 186cabdff1aSopenharmony_ci s->codebook_size = MAX_CODEBOOK_SIZE; 187cabdff1aSopenharmony_ci s->codebook = av_malloc(s->codebook_size); 188cabdff1aSopenharmony_ci if (!s->codebook) 189cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 190cabdff1aSopenharmony_ci s->next_codebook_buffer = av_malloc(s->codebook_size); 191cabdff1aSopenharmony_ci if (!s->next_codebook_buffer) 192cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_ci /* allocate decode buffer */ 195cabdff1aSopenharmony_ci s->decode_buffer_size = (s->width / s->vector_width) * 196cabdff1aSopenharmony_ci (s->height / s->vector_height) * 2; 197cabdff1aSopenharmony_ci s->decode_buffer = av_mallocz(s->decode_buffer_size); 198cabdff1aSopenharmony_ci if (!s->decode_buffer) 199cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_ci /* initialize the solid-color vectors */ 202cabdff1aSopenharmony_ci if (s->vector_height == 4) { 203cabdff1aSopenharmony_ci codebook_index = 0xFF00 * 16; 204cabdff1aSopenharmony_ci for (i = 0; i < 256; i++) 205cabdff1aSopenharmony_ci for (j = 0; j < 16; j++) 206cabdff1aSopenharmony_ci s->codebook[codebook_index++] = i; 207cabdff1aSopenharmony_ci } else { 208cabdff1aSopenharmony_ci codebook_index = 0xF00 * 8; 209cabdff1aSopenharmony_ci for (i = 0; i < 256; i++) 210cabdff1aSopenharmony_ci for (j = 0; j < 8; j++) 211cabdff1aSopenharmony_ci s->codebook[codebook_index++] = i; 212cabdff1aSopenharmony_ci } 213cabdff1aSopenharmony_ci s->next_codebook_buffer_index = 0; 214cabdff1aSopenharmony_ci 215cabdff1aSopenharmony_ci return 0; 216cabdff1aSopenharmony_ci} 217cabdff1aSopenharmony_ci 218cabdff1aSopenharmony_ci#define CHECK_COUNT() \ 219cabdff1aSopenharmony_ci if (dest_index + count > dest_size) { \ 220cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \ 221cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "current dest_index = %d, count = %d, dest_size = %d\n", \ 222cabdff1aSopenharmony_ci dest_index, count, dest_size); \ 223cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; \ 224cabdff1aSopenharmony_ci } 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ci#define CHECK_COPY(idx) \ 227cabdff1aSopenharmony_ci if (idx < 0 || idx + count > dest_size) { \ 228cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \ 229cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "current src_pos = %d, count = %d, dest_size = %d\n", \ 230cabdff1aSopenharmony_ci src_pos, count, dest_size); \ 231cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; \ 232cabdff1aSopenharmony_ci } 233cabdff1aSopenharmony_ci 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_cistatic int decode_format80(VqaContext *s, int src_size, 236cabdff1aSopenharmony_ci unsigned char *dest, int dest_size, int check_size) { 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_ci int dest_index = 0; 239cabdff1aSopenharmony_ci int count, opcode, start; 240cabdff1aSopenharmony_ci int src_pos; 241cabdff1aSopenharmony_ci unsigned char color; 242cabdff1aSopenharmony_ci int i; 243cabdff1aSopenharmony_ci int relative = 0; 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_ci if (src_size < 0 || src_size > bytestream2_get_bytes_left(&s->gb)) { 246cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "Chunk size %d is out of range\n", 247cabdff1aSopenharmony_ci src_size); 248cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 249cabdff1aSopenharmony_ci } 250cabdff1aSopenharmony_ci 251cabdff1aSopenharmony_ci /* the "new" scheme makes references relative to destination pointer */ 252cabdff1aSopenharmony_ci if (bytestream2_peek_byte(&s->gb) == 0x00) { 253cabdff1aSopenharmony_ci relative = 1; 254cabdff1aSopenharmony_ci bytestream2_get_byte(&s->gb); 255cabdff1aSopenharmony_ci ff_tlog(s->avctx, "found new format stream "); 256cabdff1aSopenharmony_ci } 257cabdff1aSopenharmony_ci 258cabdff1aSopenharmony_ci start = bytestream2_tell(&s->gb); 259cabdff1aSopenharmony_ci while (bytestream2_tell(&s->gb) - start < src_size) { 260cabdff1aSopenharmony_ci opcode = bytestream2_get_byte(&s->gb); 261cabdff1aSopenharmony_ci ff_tlog(s->avctx, "opcode %02X: ", opcode); 262cabdff1aSopenharmony_ci 263cabdff1aSopenharmony_ci /* 0x80 means that frame is finished */ 264cabdff1aSopenharmony_ci if (opcode == 0x80) 265cabdff1aSopenharmony_ci break; 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci if (dest_index >= dest_size) { 268cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n", 269cabdff1aSopenharmony_ci dest_index, dest_size); 270cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 271cabdff1aSopenharmony_ci } 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_ci if (opcode == 0xFF) { 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci count = bytestream2_get_le16(&s->gb); 276cabdff1aSopenharmony_ci src_pos = bytestream2_get_le16(&s->gb); 277cabdff1aSopenharmony_ci if (relative) 278cabdff1aSopenharmony_ci src_pos = dest_index - src_pos; 279cabdff1aSopenharmony_ci ff_tlog(s->avctx, "(1) copy %X bytes from pos %X\n", count, src_pos); 280cabdff1aSopenharmony_ci CHECK_COUNT(); 281cabdff1aSopenharmony_ci CHECK_COPY(src_pos); 282cabdff1aSopenharmony_ci for (i = 0; i < count; i++) 283cabdff1aSopenharmony_ci dest[dest_index + i] = dest[src_pos + i]; 284cabdff1aSopenharmony_ci dest_index += count; 285cabdff1aSopenharmony_ci 286cabdff1aSopenharmony_ci } else if (opcode == 0xFE) { 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_ci count = bytestream2_get_le16(&s->gb); 289cabdff1aSopenharmony_ci color = bytestream2_get_byte(&s->gb); 290cabdff1aSopenharmony_ci ff_tlog(s->avctx, "(2) set %X bytes to %02X\n", count, color); 291cabdff1aSopenharmony_ci CHECK_COUNT(); 292cabdff1aSopenharmony_ci memset(&dest[dest_index], color, count); 293cabdff1aSopenharmony_ci dest_index += count; 294cabdff1aSopenharmony_ci 295cabdff1aSopenharmony_ci } else if ((opcode & 0xC0) == 0xC0) { 296cabdff1aSopenharmony_ci 297cabdff1aSopenharmony_ci count = (opcode & 0x3F) + 3; 298cabdff1aSopenharmony_ci src_pos = bytestream2_get_le16(&s->gb); 299cabdff1aSopenharmony_ci if (relative) 300cabdff1aSopenharmony_ci src_pos = dest_index - src_pos; 301cabdff1aSopenharmony_ci ff_tlog(s->avctx, "(3) copy %X bytes from pos %X\n", count, src_pos); 302cabdff1aSopenharmony_ci CHECK_COUNT(); 303cabdff1aSopenharmony_ci CHECK_COPY(src_pos); 304cabdff1aSopenharmony_ci for (i = 0; i < count; i++) 305cabdff1aSopenharmony_ci dest[dest_index + i] = dest[src_pos + i]; 306cabdff1aSopenharmony_ci dest_index += count; 307cabdff1aSopenharmony_ci 308cabdff1aSopenharmony_ci } else if (opcode > 0x80) { 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci count = opcode & 0x3F; 311cabdff1aSopenharmony_ci ff_tlog(s->avctx, "(4) copy %X bytes from source to dest\n", count); 312cabdff1aSopenharmony_ci CHECK_COUNT(); 313cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->gb, &dest[dest_index], count); 314cabdff1aSopenharmony_ci dest_index += count; 315cabdff1aSopenharmony_ci 316cabdff1aSopenharmony_ci } else { 317cabdff1aSopenharmony_ci 318cabdff1aSopenharmony_ci count = ((opcode & 0x70) >> 4) + 3; 319cabdff1aSopenharmony_ci src_pos = bytestream2_get_byte(&s->gb) | ((opcode & 0x0F) << 8); 320cabdff1aSopenharmony_ci ff_tlog(s->avctx, "(5) copy %X bytes from relpos %X\n", count, src_pos); 321cabdff1aSopenharmony_ci CHECK_COUNT(); 322cabdff1aSopenharmony_ci CHECK_COPY(dest_index - src_pos); 323cabdff1aSopenharmony_ci for (i = 0; i < count; i++) 324cabdff1aSopenharmony_ci dest[dest_index + i] = dest[dest_index - src_pos + i]; 325cabdff1aSopenharmony_ci dest_index += count; 326cabdff1aSopenharmony_ci } 327cabdff1aSopenharmony_ci } 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_ci /* validate that the entire destination buffer was filled; this is 330cabdff1aSopenharmony_ci * important for decoding frame maps since each vector needs to have a 331cabdff1aSopenharmony_ci * codebook entry; it is not important for compressed codebooks because 332cabdff1aSopenharmony_ci * not every entry needs to be filled */ 333cabdff1aSopenharmony_ci if (check_size) 334cabdff1aSopenharmony_ci if (dest_index < dest_size) { 335cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n", 336cabdff1aSopenharmony_ci dest_index, dest_size); 337cabdff1aSopenharmony_ci memset(dest + dest_index, 0, dest_size - dest_index); 338cabdff1aSopenharmony_ci } 339cabdff1aSopenharmony_ci 340cabdff1aSopenharmony_ci return 0; // let's display what we decoded anyway 341cabdff1aSopenharmony_ci} 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_cistatic int vqa_decode_frame_pal8(VqaContext *s, AVFrame *frame) 344cabdff1aSopenharmony_ci{ 345cabdff1aSopenharmony_ci unsigned int chunk_type; 346cabdff1aSopenharmony_ci unsigned int chunk_size; 347cabdff1aSopenharmony_ci int byte_skip; 348cabdff1aSopenharmony_ci unsigned int index = 0; 349cabdff1aSopenharmony_ci int i; 350cabdff1aSopenharmony_ci unsigned char r, g, b; 351cabdff1aSopenharmony_ci int index_shift; 352cabdff1aSopenharmony_ci int res; 353cabdff1aSopenharmony_ci 354cabdff1aSopenharmony_ci int cbf0_chunk = -1; 355cabdff1aSopenharmony_ci int cbfz_chunk = -1; 356cabdff1aSopenharmony_ci int cbp0_chunk = -1; 357cabdff1aSopenharmony_ci int cbpz_chunk = -1; 358cabdff1aSopenharmony_ci int cpl0_chunk = -1; 359cabdff1aSopenharmony_ci int cplz_chunk = -1; 360cabdff1aSopenharmony_ci int vptz_chunk = -1; 361cabdff1aSopenharmony_ci 362cabdff1aSopenharmony_ci int x, y; 363cabdff1aSopenharmony_ci int lines = 0; 364cabdff1aSopenharmony_ci int pixel_ptr; 365cabdff1aSopenharmony_ci int vector_index = 0; 366cabdff1aSopenharmony_ci int lobyte = 0; 367cabdff1aSopenharmony_ci int hibyte = 0; 368cabdff1aSopenharmony_ci int lobytes = 0; 369cabdff1aSopenharmony_ci int hibytes = s->decode_buffer_size / 2; 370cabdff1aSopenharmony_ci 371cabdff1aSopenharmony_ci /* first, traverse through the frame and find the subchunks */ 372cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(&s->gb) >= 8) { 373cabdff1aSopenharmony_ci 374cabdff1aSopenharmony_ci chunk_type = bytestream2_get_be32u(&s->gb); 375cabdff1aSopenharmony_ci index = bytestream2_tell(&s->gb); 376cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32u(&s->gb); 377cabdff1aSopenharmony_ci 378cabdff1aSopenharmony_ci switch (chunk_type) { 379cabdff1aSopenharmony_ci 380cabdff1aSopenharmony_ci case CBF0_TAG: 381cabdff1aSopenharmony_ci cbf0_chunk = index; 382cabdff1aSopenharmony_ci break; 383cabdff1aSopenharmony_ci 384cabdff1aSopenharmony_ci case CBFZ_TAG: 385cabdff1aSopenharmony_ci cbfz_chunk = index; 386cabdff1aSopenharmony_ci break; 387cabdff1aSopenharmony_ci 388cabdff1aSopenharmony_ci case CBP0_TAG: 389cabdff1aSopenharmony_ci cbp0_chunk = index; 390cabdff1aSopenharmony_ci break; 391cabdff1aSopenharmony_ci 392cabdff1aSopenharmony_ci case CBPZ_TAG: 393cabdff1aSopenharmony_ci cbpz_chunk = index; 394cabdff1aSopenharmony_ci break; 395cabdff1aSopenharmony_ci 396cabdff1aSopenharmony_ci case CPL0_TAG: 397cabdff1aSopenharmony_ci cpl0_chunk = index; 398cabdff1aSopenharmony_ci break; 399cabdff1aSopenharmony_ci 400cabdff1aSopenharmony_ci case CPLZ_TAG: 401cabdff1aSopenharmony_ci cplz_chunk = index; 402cabdff1aSopenharmony_ci break; 403cabdff1aSopenharmony_ci 404cabdff1aSopenharmony_ci case VPTZ_TAG: 405cabdff1aSopenharmony_ci vptz_chunk = index; 406cabdff1aSopenharmony_ci break; 407cabdff1aSopenharmony_ci 408cabdff1aSopenharmony_ci default: 409cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n", 410cabdff1aSopenharmony_ci av_fourcc2str(av_bswap32(chunk_type)), chunk_type); 411cabdff1aSopenharmony_ci break; 412cabdff1aSopenharmony_ci } 413cabdff1aSopenharmony_ci 414cabdff1aSopenharmony_ci byte_skip = chunk_size & 0x01; 415cabdff1aSopenharmony_ci bytestream2_skip(&s->gb, chunk_size + byte_skip); 416cabdff1aSopenharmony_ci } 417cabdff1aSopenharmony_ci 418cabdff1aSopenharmony_ci /* next, deal with the palette */ 419cabdff1aSopenharmony_ci if ((cpl0_chunk != -1) && (cplz_chunk != -1)) { 420cabdff1aSopenharmony_ci 421cabdff1aSopenharmony_ci /* a chunk should not have both chunk types */ 422cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "problem: found both CPL0 and CPLZ chunks\n"); 423cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 424cabdff1aSopenharmony_ci } 425cabdff1aSopenharmony_ci 426cabdff1aSopenharmony_ci /* decompress the palette chunk */ 427cabdff1aSopenharmony_ci if (cplz_chunk != -1) { 428cabdff1aSopenharmony_ci 429cabdff1aSopenharmony_ci/* yet to be handled */ 430cabdff1aSopenharmony_ci 431cabdff1aSopenharmony_ci } 432cabdff1aSopenharmony_ci 433cabdff1aSopenharmony_ci /* convert the RGB palette into the machine's endian format */ 434cabdff1aSopenharmony_ci if (cpl0_chunk != -1) { 435cabdff1aSopenharmony_ci 436cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET); 437cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 438cabdff1aSopenharmony_ci /* sanity check the palette size */ 439cabdff1aSopenharmony_ci if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) { 440cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "problem: found a palette chunk with %d colors\n", 441cabdff1aSopenharmony_ci chunk_size / 3); 442cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 443cabdff1aSopenharmony_ci } 444cabdff1aSopenharmony_ci for (i = 0; i < chunk_size / 3; i++) { 445cabdff1aSopenharmony_ci /* scale by 4 to transform 6-bit palette -> 8-bit */ 446cabdff1aSopenharmony_ci r = bytestream2_get_byteu(&s->gb) * 4; 447cabdff1aSopenharmony_ci g = bytestream2_get_byteu(&s->gb) * 4; 448cabdff1aSopenharmony_ci b = bytestream2_get_byteu(&s->gb) * 4; 449cabdff1aSopenharmony_ci s->palette[i] = 0xFFU << 24 | r << 16 | g << 8 | b; 450cabdff1aSopenharmony_ci s->palette[i] |= s->palette[i] >> 6 & 0x30303; 451cabdff1aSopenharmony_ci } 452cabdff1aSopenharmony_ci } 453cabdff1aSopenharmony_ci 454cabdff1aSopenharmony_ci /* next, look for a full codebook */ 455cabdff1aSopenharmony_ci if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { 456cabdff1aSopenharmony_ci 457cabdff1aSopenharmony_ci /* a chunk should not have both chunk types */ 458cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n"); 459cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 460cabdff1aSopenharmony_ci } 461cabdff1aSopenharmony_ci 462cabdff1aSopenharmony_ci /* decompress the full codebook chunk */ 463cabdff1aSopenharmony_ci if (cbfz_chunk != -1) { 464cabdff1aSopenharmony_ci 465cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET); 466cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 467cabdff1aSopenharmony_ci if ((res = decode_format80(s, chunk_size, s->codebook, 468cabdff1aSopenharmony_ci s->codebook_size, 0)) < 0) 469cabdff1aSopenharmony_ci return res; 470cabdff1aSopenharmony_ci } 471cabdff1aSopenharmony_ci 472cabdff1aSopenharmony_ci /* copy a full codebook */ 473cabdff1aSopenharmony_ci if (cbf0_chunk != -1) { 474cabdff1aSopenharmony_ci 475cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET); 476cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 477cabdff1aSopenharmony_ci /* sanity check the full codebook size */ 478cabdff1aSopenharmony_ci if (chunk_size > MAX_CODEBOOK_SIZE) { 479cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n", 480cabdff1aSopenharmony_ci chunk_size); 481cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 482cabdff1aSopenharmony_ci } 483cabdff1aSopenharmony_ci 484cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->gb, s->codebook, chunk_size); 485cabdff1aSopenharmony_ci } 486cabdff1aSopenharmony_ci 487cabdff1aSopenharmony_ci /* decode the frame */ 488cabdff1aSopenharmony_ci if (vptz_chunk == -1) { 489cabdff1aSopenharmony_ci 490cabdff1aSopenharmony_ci /* something is wrong if there is no VPTZ chunk */ 491cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n"); 492cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 493cabdff1aSopenharmony_ci } 494cabdff1aSopenharmony_ci 495cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET); 496cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 497cabdff1aSopenharmony_ci if ((res = decode_format80(s, chunk_size, 498cabdff1aSopenharmony_ci s->decode_buffer, s->decode_buffer_size, 1)) < 0) 499cabdff1aSopenharmony_ci return res; 500cabdff1aSopenharmony_ci 501cabdff1aSopenharmony_ci /* render the final PAL8 frame */ 502cabdff1aSopenharmony_ci if (s->vector_height == 4) 503cabdff1aSopenharmony_ci index_shift = 4; 504cabdff1aSopenharmony_ci else 505cabdff1aSopenharmony_ci index_shift = 3; 506cabdff1aSopenharmony_ci for (y = 0; y < s->height; y += s->vector_height) { 507cabdff1aSopenharmony_ci for (x = 0; x < s->width; x += 4, lobytes++, hibytes++) { 508cabdff1aSopenharmony_ci pixel_ptr = y * frame->linesize[0] + x; 509cabdff1aSopenharmony_ci 510cabdff1aSopenharmony_ci /* get the vector index, the method for which varies according to 511cabdff1aSopenharmony_ci * VQA file version */ 512cabdff1aSopenharmony_ci switch (s->vqa_version) { 513cabdff1aSopenharmony_ci 514cabdff1aSopenharmony_ci case 1: 515cabdff1aSopenharmony_ci lobyte = s->decode_buffer[lobytes * 2]; 516cabdff1aSopenharmony_ci hibyte = s->decode_buffer[(lobytes * 2) + 1]; 517cabdff1aSopenharmony_ci vector_index = ((hibyte << 8) | lobyte) >> 3; 518cabdff1aSopenharmony_ci vector_index <<= index_shift; 519cabdff1aSopenharmony_ci lines = s->vector_height; 520cabdff1aSopenharmony_ci /* uniform color fill - a quick hack */ 521cabdff1aSopenharmony_ci if (hibyte == 0xFF) { 522cabdff1aSopenharmony_ci while (lines--) { 523cabdff1aSopenharmony_ci frame->data[0][pixel_ptr + 0] = 255 - lobyte; 524cabdff1aSopenharmony_ci frame->data[0][pixel_ptr + 1] = 255 - lobyte; 525cabdff1aSopenharmony_ci frame->data[0][pixel_ptr + 2] = 255 - lobyte; 526cabdff1aSopenharmony_ci frame->data[0][pixel_ptr + 3] = 255 - lobyte; 527cabdff1aSopenharmony_ci pixel_ptr += frame->linesize[0]; 528cabdff1aSopenharmony_ci } 529cabdff1aSopenharmony_ci lines=0; 530cabdff1aSopenharmony_ci } 531cabdff1aSopenharmony_ci break; 532cabdff1aSopenharmony_ci 533cabdff1aSopenharmony_ci case 2: 534cabdff1aSopenharmony_ci lobyte = s->decode_buffer[lobytes]; 535cabdff1aSopenharmony_ci hibyte = s->decode_buffer[hibytes]; 536cabdff1aSopenharmony_ci vector_index = (hibyte << 8) | lobyte; 537cabdff1aSopenharmony_ci vector_index <<= index_shift; 538cabdff1aSopenharmony_ci lines = s->vector_height; 539cabdff1aSopenharmony_ci break; 540cabdff1aSopenharmony_ci 541cabdff1aSopenharmony_ci case 3: 542cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "VQA3 shouldn't have a color palette"); 543cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 544cabdff1aSopenharmony_ci } 545cabdff1aSopenharmony_ci 546cabdff1aSopenharmony_ci while (lines--) { 547cabdff1aSopenharmony_ci frame->data[0][pixel_ptr + 0] = s->codebook[vector_index++]; 548cabdff1aSopenharmony_ci frame->data[0][pixel_ptr + 1] = s->codebook[vector_index++]; 549cabdff1aSopenharmony_ci frame->data[0][pixel_ptr + 2] = s->codebook[vector_index++]; 550cabdff1aSopenharmony_ci frame->data[0][pixel_ptr + 3] = s->codebook[vector_index++]; 551cabdff1aSopenharmony_ci pixel_ptr += frame->linesize[0]; 552cabdff1aSopenharmony_ci } 553cabdff1aSopenharmony_ci } 554cabdff1aSopenharmony_ci } 555cabdff1aSopenharmony_ci 556cabdff1aSopenharmony_ci /* handle partial codebook */ 557cabdff1aSopenharmony_ci if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) { 558cabdff1aSopenharmony_ci /* a chunk should not have both chunk types */ 559cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBP0 and CBPZ chunks\n"); 560cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 561cabdff1aSopenharmony_ci } 562cabdff1aSopenharmony_ci 563cabdff1aSopenharmony_ci if (cbp0_chunk != -1) { 564cabdff1aSopenharmony_ci 565cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET); 566cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 567cabdff1aSopenharmony_ci 568cabdff1aSopenharmony_ci if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { 569cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "cbp0 chunk too large (%u bytes)\n", 570cabdff1aSopenharmony_ci chunk_size); 571cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 572cabdff1aSopenharmony_ci } 573cabdff1aSopenharmony_ci 574cabdff1aSopenharmony_ci /* accumulate partial codebook */ 575cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], 576cabdff1aSopenharmony_ci chunk_size); 577cabdff1aSopenharmony_ci s->next_codebook_buffer_index += chunk_size; 578cabdff1aSopenharmony_ci 579cabdff1aSopenharmony_ci s->partial_countdown--; 580cabdff1aSopenharmony_ci if (s->partial_countdown <= 0) { 581cabdff1aSopenharmony_ci 582cabdff1aSopenharmony_ci /* time to replace codebook */ 583cabdff1aSopenharmony_ci memcpy(s->codebook, s->next_codebook_buffer, 584cabdff1aSopenharmony_ci s->next_codebook_buffer_index); 585cabdff1aSopenharmony_ci 586cabdff1aSopenharmony_ci /* reset accounting */ 587cabdff1aSopenharmony_ci s->next_codebook_buffer_index = 0; 588cabdff1aSopenharmony_ci s->partial_countdown = s->partial_count; 589cabdff1aSopenharmony_ci } 590cabdff1aSopenharmony_ci } 591cabdff1aSopenharmony_ci 592cabdff1aSopenharmony_ci if (cbpz_chunk != -1) { 593cabdff1aSopenharmony_ci 594cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET); 595cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 596cabdff1aSopenharmony_ci 597cabdff1aSopenharmony_ci if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) { 598cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "cbpz chunk too large (%u bytes)\n", 599cabdff1aSopenharmony_ci chunk_size); 600cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 601cabdff1aSopenharmony_ci } 602cabdff1aSopenharmony_ci 603cabdff1aSopenharmony_ci /* accumulate partial codebook */ 604cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index], 605cabdff1aSopenharmony_ci chunk_size); 606cabdff1aSopenharmony_ci s->next_codebook_buffer_index += chunk_size; 607cabdff1aSopenharmony_ci 608cabdff1aSopenharmony_ci s->partial_countdown--; 609cabdff1aSopenharmony_ci if (s->partial_countdown <= 0) { 610cabdff1aSopenharmony_ci bytestream2_init(&s->gb, s->next_codebook_buffer, s->next_codebook_buffer_index); 611cabdff1aSopenharmony_ci /* decompress codebook */ 612cabdff1aSopenharmony_ci res = decode_format80(s, s->next_codebook_buffer_index, 613cabdff1aSopenharmony_ci s->codebook, s->codebook_size, 0); 614cabdff1aSopenharmony_ci 615cabdff1aSopenharmony_ci /* reset accounting */ 616cabdff1aSopenharmony_ci s->next_codebook_buffer_index = 0; 617cabdff1aSopenharmony_ci s->partial_countdown = s->partial_count; 618cabdff1aSopenharmony_ci if (res < 0) 619cabdff1aSopenharmony_ci return res; 620cabdff1aSopenharmony_ci } 621cabdff1aSopenharmony_ci } 622cabdff1aSopenharmony_ci 623cabdff1aSopenharmony_ci return 0; 624cabdff1aSopenharmony_ci} 625cabdff1aSopenharmony_ci 626cabdff1aSopenharmony_cistatic int vqa_decode_frame_hicolor(VqaContext *s, AVFrame *frame) 627cabdff1aSopenharmony_ci{ 628cabdff1aSopenharmony_ci unsigned int chunk_type; 629cabdff1aSopenharmony_ci unsigned int chunk_size; 630cabdff1aSopenharmony_ci unsigned int index = 0; 631cabdff1aSopenharmony_ci int res; 632cabdff1aSopenharmony_ci 633cabdff1aSopenharmony_ci int cbf0_chunk = -1; 634cabdff1aSopenharmony_ci int cbfz_chunk = -1; 635cabdff1aSopenharmony_ci int vptr_chunk = -1; 636cabdff1aSopenharmony_ci int vprz_chunk = -1; 637cabdff1aSopenharmony_ci 638cabdff1aSopenharmony_ci GetByteContext gb_stream; 639cabdff1aSopenharmony_ci 640cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(&s->gb) >= 8) { 641cabdff1aSopenharmony_ci chunk_type = bytestream2_get_be32u(&s->gb); 642cabdff1aSopenharmony_ci index = bytestream2_tell(&s->gb); 643cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32u(&s->gb); 644cabdff1aSopenharmony_ci 645cabdff1aSopenharmony_ci switch (chunk_type) { 646cabdff1aSopenharmony_ci case CBF0_TAG: 647cabdff1aSopenharmony_ci cbf0_chunk = index; 648cabdff1aSopenharmony_ci break; 649cabdff1aSopenharmony_ci case CBFZ_TAG: 650cabdff1aSopenharmony_ci cbfz_chunk = index; 651cabdff1aSopenharmony_ci break; 652cabdff1aSopenharmony_ci case VPTR_TAG: 653cabdff1aSopenharmony_ci vptr_chunk = index; 654cabdff1aSopenharmony_ci break; 655cabdff1aSopenharmony_ci case VPRZ_TAG: 656cabdff1aSopenharmony_ci vprz_chunk = index; 657cabdff1aSopenharmony_ci break; 658cabdff1aSopenharmony_ci default: 659cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n", 660cabdff1aSopenharmony_ci av_fourcc2str(av_bswap32(chunk_type)), chunk_type); 661cabdff1aSopenharmony_ci break; 662cabdff1aSopenharmony_ci } 663cabdff1aSopenharmony_ci 664cabdff1aSopenharmony_ci bytestream2_skip(&s->gb, chunk_size + (chunk_size & 0x01)); 665cabdff1aSopenharmony_ci } 666cabdff1aSopenharmony_ci 667cabdff1aSopenharmony_ci /* next, look for a full codebook */ 668cabdff1aSopenharmony_ci if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { 669cabdff1aSopenharmony_ci /* a chunk should not have both chunk types */ 670cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n"); 671cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 672cabdff1aSopenharmony_ci } 673cabdff1aSopenharmony_ci 674cabdff1aSopenharmony_ci /* decompress the full codebook chunk */ 675cabdff1aSopenharmony_ci if (cbfz_chunk != -1) { 676cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET); 677cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 678cabdff1aSopenharmony_ci if ((res = decode_format80(s, chunk_size, s->codebook, 679cabdff1aSopenharmony_ci s->codebook_size, 0)) < 0) 680cabdff1aSopenharmony_ci return res; 681cabdff1aSopenharmony_ci } 682cabdff1aSopenharmony_ci 683cabdff1aSopenharmony_ci /* copy a full codebook */ 684cabdff1aSopenharmony_ci if (cbf0_chunk != -1) { 685cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET); 686cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 687cabdff1aSopenharmony_ci /* sanity check the full codebook size */ 688cabdff1aSopenharmony_ci if (chunk_size > MAX_CODEBOOK_SIZE) { 689cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n", 690cabdff1aSopenharmony_ci chunk_size); 691cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 692cabdff1aSopenharmony_ci } 693cabdff1aSopenharmony_ci 694cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->gb, s->codebook, chunk_size); 695cabdff1aSopenharmony_ci } 696cabdff1aSopenharmony_ci 697cabdff1aSopenharmony_ci /* decode the frame */ 698cabdff1aSopenharmony_ci 699cabdff1aSopenharmony_ci if (vptr_chunk != -1) { 700cabdff1aSopenharmony_ci /* copy uncompressed tile data */ 701cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, vptr_chunk, SEEK_SET); 702cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 703cabdff1aSopenharmony_ci if (chunk_size > s->decode_buffer_size) { 704cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "VPTR chunk didn't fit in decode buffer"); 705cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 706cabdff1aSopenharmony_ci } 707cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->gb, s->decode_buffer, chunk_size); 708cabdff1aSopenharmony_ci } else if (vprz_chunk != -1) { 709cabdff1aSopenharmony_ci /* decompress the tile data */ 710cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, vprz_chunk, SEEK_SET); 711cabdff1aSopenharmony_ci 712cabdff1aSopenharmony_ci chunk_size = bytestream2_get_be32(&s->gb); 713cabdff1aSopenharmony_ci if ((res = decode_format80(s, chunk_size, s->decode_buffer, s->decode_buffer_size, 0)) < 0) 714cabdff1aSopenharmony_ci return res; 715cabdff1aSopenharmony_ci } else { 716cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "frame has no block data\n"); 717cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 718cabdff1aSopenharmony_ci } 719cabdff1aSopenharmony_ci 720cabdff1aSopenharmony_ci /* now uncompress the per-row RLE of the decode buffer and draw the blocks in framebuffer */ 721cabdff1aSopenharmony_ci 722cabdff1aSopenharmony_ci bytestream2_init(&gb_stream, s->decode_buffer, s->decode_buffer_size); 723cabdff1aSopenharmony_ci 724cabdff1aSopenharmony_ci for (int y_pos = 0; y_pos < s->height; y_pos += s->vector_height) { 725cabdff1aSopenharmony_ci int x_pos = 0; 726cabdff1aSopenharmony_ci 727cabdff1aSopenharmony_ci while (x_pos < s->width) { 728cabdff1aSopenharmony_ci int vector_index = 0; 729cabdff1aSopenharmony_ci int count = 0; 730cabdff1aSopenharmony_ci uint16_t code; 731cabdff1aSopenharmony_ci int type; 732cabdff1aSopenharmony_ci 733cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&gb_stream) < 2) 734cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 735cabdff1aSopenharmony_ci 736cabdff1aSopenharmony_ci code = bytestream2_get_le16(&gb_stream); 737cabdff1aSopenharmony_ci 738cabdff1aSopenharmony_ci type = code >> 13; 739cabdff1aSopenharmony_ci code &= 0x1fff; 740cabdff1aSopenharmony_ci 741cabdff1aSopenharmony_ci if (type == 0) { 742cabdff1aSopenharmony_ci x_pos += 4 * code; 743cabdff1aSopenharmony_ci continue; 744cabdff1aSopenharmony_ci } else if (type < 3) { 745cabdff1aSopenharmony_ci vector_index = code & 0xff; 746cabdff1aSopenharmony_ci count = ((code & 0x1f00) >> 7) + 1 + type; 747cabdff1aSopenharmony_ci } else if (type < 5) { 748cabdff1aSopenharmony_ci vector_index = code; 749cabdff1aSopenharmony_ci count = 1; 750cabdff1aSopenharmony_ci } else if (type < 7) { 751cabdff1aSopenharmony_ci vector_index = code; 752cabdff1aSopenharmony_ci count = bytestream2_get_byte(&gb_stream); 753cabdff1aSopenharmony_ci } else { 754cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, " unknown type in VPTR chunk (%d)\n",type); 755cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 756cabdff1aSopenharmony_ci } 757cabdff1aSopenharmony_ci 758cabdff1aSopenharmony_ci if (count < 0 || count > (s->width - x_pos) / s->vector_width) { 759cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "invalid count: %d\n", count); 760cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 761cabdff1aSopenharmony_ci } 762cabdff1aSopenharmony_ci 763cabdff1aSopenharmony_ci while (count-- && x_pos < s->width) { 764cabdff1aSopenharmony_ci const int bytes_per_vector = 4 * s->vector_height * sizeof(uint16_t); 765cabdff1aSopenharmony_ci unsigned char *src = s->codebook + vector_index * bytes_per_vector; 766cabdff1aSopenharmony_ci unsigned char *dst = s->frame->data[0] + y_pos * s->frame->linesize[0] 767cabdff1aSopenharmony_ci + sizeof(uint16_t) * x_pos; 768cabdff1aSopenharmony_ci 769cabdff1aSopenharmony_ci if (vector_index >= MAX_VECTORS) 770cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 771cabdff1aSopenharmony_ci 772cabdff1aSopenharmony_ci for (int y = 0; y < s->vector_height; y++) { 773cabdff1aSopenharmony_ci int size = 4 * sizeof(uint16_t); 774cabdff1aSopenharmony_ci memcpy(dst, src, size); 775cabdff1aSopenharmony_ci dst += s->frame->linesize[0]; 776cabdff1aSopenharmony_ci src += size; 777cabdff1aSopenharmony_ci } 778cabdff1aSopenharmony_ci 779cabdff1aSopenharmony_ci /* we might want to read the next block index from stream */ 780cabdff1aSopenharmony_ci if ((type == 2) && count > 0) { 781cabdff1aSopenharmony_ci vector_index = bytestream2_get_byte(&gb_stream); 782cabdff1aSopenharmony_ci } 783cabdff1aSopenharmony_ci 784cabdff1aSopenharmony_ci x_pos += 4; 785cabdff1aSopenharmony_ci } 786cabdff1aSopenharmony_ci 787cabdff1aSopenharmony_ci if (count > 0) { 788cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "had %d leftover vectors\n", count); 789cabdff1aSopenharmony_ci return AVERROR_BUG; 790cabdff1aSopenharmony_ci } 791cabdff1aSopenharmony_ci } 792cabdff1aSopenharmony_ci } 793cabdff1aSopenharmony_ci 794cabdff1aSopenharmony_ci return 0; 795cabdff1aSopenharmony_ci} 796cabdff1aSopenharmony_ci 797cabdff1aSopenharmony_cistatic int vqa_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 798cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 799cabdff1aSopenharmony_ci{ 800cabdff1aSopenharmony_ci VqaContext *s = avctx->priv_data; 801cabdff1aSopenharmony_ci int res; 802cabdff1aSopenharmony_ci 803cabdff1aSopenharmony_ci if ((res = ff_reget_buffer(avctx, s->frame, 0)) < 0) 804cabdff1aSopenharmony_ci return res; 805cabdff1aSopenharmony_ci 806cabdff1aSopenharmony_ci bytestream2_init(&s->gb, avpkt->data, avpkt->size); 807cabdff1aSopenharmony_ci 808cabdff1aSopenharmony_ci if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { 809cabdff1aSopenharmony_ci if ((res = vqa_decode_frame_pal8(s, s->frame)) < 0) 810cabdff1aSopenharmony_ci return res; 811cabdff1aSopenharmony_ci 812cabdff1aSopenharmony_ci /* make the palette available on the way out */ 813cabdff1aSopenharmony_ci memcpy(s->frame->data[1], s->palette, PALETTE_COUNT * 4); 814cabdff1aSopenharmony_ci s->frame->palette_has_changed = 1; 815cabdff1aSopenharmony_ci } else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) { 816cabdff1aSopenharmony_ci if ((res = vqa_decode_frame_hicolor(s, s->frame)) < 0) 817cabdff1aSopenharmony_ci return res; 818cabdff1aSopenharmony_ci } else { 819cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "unsupported pixel format\n"); 820cabdff1aSopenharmony_ci return AVERROR_BUG; 821cabdff1aSopenharmony_ci } 822cabdff1aSopenharmony_ci 823cabdff1aSopenharmony_ci if ((res = av_frame_ref(rframe, s->frame)) < 0) 824cabdff1aSopenharmony_ci return res; 825cabdff1aSopenharmony_ci 826cabdff1aSopenharmony_ci *got_frame = 1; 827cabdff1aSopenharmony_ci 828cabdff1aSopenharmony_ci /* report that the buffer was completely consumed */ 829cabdff1aSopenharmony_ci return avpkt->size; 830cabdff1aSopenharmony_ci} 831cabdff1aSopenharmony_ci 832cabdff1aSopenharmony_cistatic av_cold int vqa_decode_end(AVCodecContext *avctx) 833cabdff1aSopenharmony_ci{ 834cabdff1aSopenharmony_ci VqaContext *s = avctx->priv_data; 835cabdff1aSopenharmony_ci 836cabdff1aSopenharmony_ci av_frame_free(&s->frame); 837cabdff1aSopenharmony_ci av_freep(&s->codebook); 838cabdff1aSopenharmony_ci av_freep(&s->next_codebook_buffer); 839cabdff1aSopenharmony_ci av_freep(&s->decode_buffer); 840cabdff1aSopenharmony_ci 841cabdff1aSopenharmony_ci return 0; 842cabdff1aSopenharmony_ci} 843cabdff1aSopenharmony_ci 844cabdff1aSopenharmony_cistatic const FFCodecDefault vqa_defaults[] = { 845cabdff1aSopenharmony_ci { "max_pixels", "640*480" }, 846cabdff1aSopenharmony_ci { NULL }, 847cabdff1aSopenharmony_ci}; 848cabdff1aSopenharmony_ci 849cabdff1aSopenharmony_ciconst FFCodec ff_vqa_decoder = { 850cabdff1aSopenharmony_ci .p.name = "vqavideo", 851cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"), 852cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 853cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_WS_VQA, 854cabdff1aSopenharmony_ci .priv_data_size = sizeof(VqaContext), 855cabdff1aSopenharmony_ci .init = vqa_decode_init, 856cabdff1aSopenharmony_ci .close = vqa_decode_end, 857cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(vqa_decode_frame), 858cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 859cabdff1aSopenharmony_ci .defaults = vqa_defaults, 860cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 861cabdff1aSopenharmony_ci}; 862