LCOV - code coverage report
Current view: top level - libavcodec - vqavideo.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 189 284 66.5 %
Date: 2017-12-15 11:05:35 Functions: 5 5 100.0 %

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

Generated by: LCOV version 1.13