libavcodec/vqavideo.c
Go to the documentation of this file.
00001 /*
00002  * Westwood Studios VQA Video Decoder
00003  * Copyright (C) 2003 the ffmpeg project
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * Libav is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with Libav; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00066 #include <stdio.h>
00067 #include <stdlib.h>
00068 #include <string.h>
00069 
00070 #include "libavutil/intreadwrite.h"
00071 #include "libavutil/imgutils.h"
00072 #include "avcodec.h"
00073 #include "bytestream.h"
00074 
00075 #define PALETTE_COUNT 256
00076 #define VQA_HEADER_SIZE 0x2A
00077 
00078 /* allocate the maximum vector space, regardless of the file version:
00079  * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */
00080 #define MAX_CODEBOOK_VECTORS 0xFF00
00081 #define SOLID_PIXEL_VECTORS 0x100
00082 #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS)
00083 #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4)
00084 
00085 #define CBF0_TAG MKBETAG('C', 'B', 'F', '0')
00086 #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z')
00087 #define CBP0_TAG MKBETAG('C', 'B', 'P', '0')
00088 #define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z')
00089 #define CPL0_TAG MKBETAG('C', 'P', 'L', '0')
00090 #define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z')
00091 #define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z')
00092 
00093 typedef struct VqaContext {
00094 
00095     AVCodecContext *avctx;
00096     AVFrame frame;
00097     GetByteContext gb;
00098 
00099     uint32_t palette[PALETTE_COUNT];
00100 
00101     int width;   /* width of a frame */
00102     int height;   /* height of a frame */
00103     int vector_width;  /* width of individual vector */
00104     int vector_height;  /* height of individual vector */
00105     int vqa_version;  /* this should be either 1, 2 or 3 */
00106 
00107     unsigned char *codebook;         /* the current codebook */
00108     int codebook_size;
00109     unsigned char *next_codebook_buffer;  /* accumulator for next codebook */
00110     int next_codebook_buffer_index;
00111 
00112     unsigned char *decode_buffer;
00113     int decode_buffer_size;
00114 
00115     /* number of frames to go before replacing codebook */
00116     int partial_countdown;
00117     int partial_count;
00118 
00119 } VqaContext;
00120 
00121 static av_cold int vqa_decode_init(AVCodecContext *avctx)
00122 {
00123     VqaContext *s = avctx->priv_data;
00124     int i, j, codebook_index;
00125 
00126     s->avctx = avctx;
00127     avctx->pix_fmt = PIX_FMT_PAL8;
00128 
00129     /* make sure the extradata made it */
00130     if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
00131         av_log(s->avctx, AV_LOG_ERROR, "  VQA video: expected extradata size of %d\n", VQA_HEADER_SIZE);
00132         return -1;
00133     }
00134 
00135     /* load up the VQA parameters from the header */
00136     s->vqa_version = s->avctx->extradata[0];
00137     switch (s->vqa_version) {
00138     case 1:
00139     case 2:
00140         break;
00141     case 3:
00142         av_log_missing_feature(avctx, "VQA Version 3", 0);
00143         return AVERROR_PATCHWELCOME;
00144     default:
00145         av_log_missing_feature(avctx, "VQA Version", 1);
00146         return AVERROR_PATCHWELCOME;
00147     }
00148     s->width = AV_RL16(&s->avctx->extradata[6]);
00149     s->height = AV_RL16(&s->avctx->extradata[8]);
00150     if(av_image_check_size(s->width, s->height, 0, avctx)){
00151         s->width= s->height= 0;
00152         return -1;
00153     }
00154     s->vector_width = s->avctx->extradata[10];
00155     s->vector_height = s->avctx->extradata[11];
00156     s->partial_count = s->partial_countdown = s->avctx->extradata[13];
00157 
00158     /* the vector dimensions have to meet very stringent requirements */
00159     if ((s->vector_width != 4) ||
00160         ((s->vector_height != 2) && (s->vector_height != 4))) {
00161         /* return without further initialization */
00162         return -1;
00163     }
00164 
00165     if (s->width  & (s->vector_width  - 1) ||
00166         s->height & (s->vector_height - 1)) {
00167         av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n");
00168         return AVERROR_INVALIDDATA;
00169     }
00170 
00171     /* allocate codebooks */
00172     s->codebook_size = MAX_CODEBOOK_SIZE;
00173     s->codebook = av_malloc(s->codebook_size);
00174     s->next_codebook_buffer = av_malloc(s->codebook_size);
00175 
00176     /* initialize the solid-color vectors */
00177     if (s->vector_height == 4) {
00178         codebook_index = 0xFF00 * 16;
00179         for (i = 0; i < 256; i++)
00180             for (j = 0; j < 16; j++)
00181                 s->codebook[codebook_index++] = i;
00182     } else {
00183         codebook_index = 0xF00 * 8;
00184         for (i = 0; i < 256; i++)
00185             for (j = 0; j < 8; j++)
00186                 s->codebook[codebook_index++] = i;
00187     }
00188     s->next_codebook_buffer_index = 0;
00189 
00190     /* allocate decode buffer */
00191     s->decode_buffer_size = (s->width / s->vector_width) *
00192         (s->height / s->vector_height) * 2;
00193     s->decode_buffer = av_malloc(s->decode_buffer_size);
00194 
00195     s->frame.data[0] = NULL;
00196 
00197     return 0;
00198 }
00199 
00200 #define CHECK_COUNT() \
00201     if (dest_index + count > dest_size) { \
00202         av_log(NULL, AV_LOG_ERROR, "  VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
00203         av_log(NULL, AV_LOG_ERROR, "  VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \
00204             dest_index, count, dest_size); \
00205         return AVERROR_INVALIDDATA; \
00206     }
00207 
00208 #define CHECK_COPY(idx) \
00209     if (idx < 0 || idx + count > dest_size) { \
00210         av_log(NULL, AV_LOG_ERROR, "  VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
00211         av_log(NULL, AV_LOG_ERROR, "  VQA video: current src_pos = %d, count = %d, dest_size = %d\n", \
00212             src_pos, count, dest_size); \
00213         return AVERROR_INVALIDDATA; \
00214     }
00215 
00216 
00217 static int decode_format80(GetByteContext *gb, int src_size,
00218     unsigned char *dest, int dest_size, int check_size) {
00219 
00220     int dest_index = 0;
00221     int count, opcode, start;
00222     int src_pos;
00223     unsigned char color;
00224     int i;
00225 
00226     start = bytestream2_tell(gb);
00227     while (bytestream2_tell(gb) - start < src_size) {
00228         opcode = bytestream2_get_byte(gb);
00229         av_dlog(NULL, "      opcode %02X: ", opcode);
00230 
00231         /* 0x80 means that frame is finished */
00232         if (opcode == 0x80)
00233             return 0;
00234 
00235         if (dest_index >= dest_size) {
00236             av_log(NULL, AV_LOG_ERROR, "  VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",
00237                 dest_index, dest_size);
00238             return AVERROR_INVALIDDATA;
00239         }
00240 
00241         if (opcode == 0xFF) {
00242 
00243             count   = bytestream2_get_le16(gb);
00244             src_pos = bytestream2_get_le16(gb);
00245             av_dlog(NULL, "(1) copy %X bytes from absolute pos %X\n", count, src_pos);
00246             CHECK_COUNT();
00247             CHECK_COPY(src_pos);
00248             for (i = 0; i < count; i++)
00249                 dest[dest_index + i] = dest[src_pos + i];
00250             dest_index += count;
00251 
00252         } else if (opcode == 0xFE) {
00253 
00254             count = bytestream2_get_le16(gb);
00255             color = bytestream2_get_byte(gb);
00256             av_dlog(NULL, "(2) set %X bytes to %02X\n", count, color);
00257             CHECK_COUNT();
00258             memset(&dest[dest_index], color, count);
00259             dest_index += count;
00260 
00261         } else if ((opcode & 0xC0) == 0xC0) {
00262 
00263             count = (opcode & 0x3F) + 3;
00264             src_pos = bytestream2_get_le16(gb);
00265             av_dlog(NULL, "(3) copy %X bytes from absolute pos %X\n", count, src_pos);
00266             CHECK_COUNT();
00267             CHECK_COPY(src_pos);
00268             for (i = 0; i < count; i++)
00269                 dest[dest_index + i] = dest[src_pos + i];
00270             dest_index += count;
00271 
00272         } else if (opcode > 0x80) {
00273 
00274             count = opcode & 0x3F;
00275             av_dlog(NULL, "(4) copy %X bytes from source to dest\n", count);
00276             CHECK_COUNT();
00277             bytestream2_get_buffer(gb, &dest[dest_index], count);
00278             dest_index += count;
00279 
00280         } else {
00281 
00282             count = ((opcode & 0x70) >> 4) + 3;
00283             src_pos = bytestream2_get_byte(gb) | ((opcode & 0x0F) << 8);
00284             av_dlog(NULL, "(5) copy %X bytes from relpos %X\n", count, src_pos);
00285             CHECK_COUNT();
00286             CHECK_COPY(dest_index - src_pos);
00287             for (i = 0; i < count; i++)
00288                 dest[dest_index + i] = dest[dest_index - src_pos + i];
00289             dest_index += count;
00290         }
00291     }
00292 
00293     /* validate that the entire destination buffer was filled; this is
00294      * important for decoding frame maps since each vector needs to have a
00295      * codebook entry; it is not important for compressed codebooks because
00296      * not every entry needs to be filled */
00297     if (check_size)
00298         if (dest_index < dest_size)
00299             av_log(NULL, AV_LOG_ERROR, "  VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
00300                 dest_index, dest_size);
00301 
00302     return 0; // let's display what we decoded anyway
00303 }
00304 
00305 static int vqa_decode_chunk(VqaContext *s)
00306 {
00307     unsigned int chunk_type;
00308     unsigned int chunk_size;
00309     int byte_skip;
00310     unsigned int index = 0;
00311     int i;
00312     unsigned char r, g, b;
00313     int index_shift;
00314     int res;
00315 
00316     int cbf0_chunk = -1;
00317     int cbfz_chunk = -1;
00318     int cbp0_chunk = -1;
00319     int cbpz_chunk = -1;
00320     int cpl0_chunk = -1;
00321     int cplz_chunk = -1;
00322     int vptz_chunk = -1;
00323 
00324     int x, y;
00325     int lines = 0;
00326     int pixel_ptr;
00327     int vector_index = 0;
00328     int lobyte = 0;
00329     int hibyte = 0;
00330     int lobytes = 0;
00331     int hibytes = s->decode_buffer_size / 2;
00332 
00333     /* first, traverse through the frame and find the subchunks */
00334     while (bytestream2_get_bytes_left(&s->gb) >= 8) {
00335 
00336         chunk_type = bytestream2_get_be32u(&s->gb);
00337         index      = bytestream2_tell(&s->gb);
00338         chunk_size = bytestream2_get_be32u(&s->gb);
00339 
00340         switch (chunk_type) {
00341 
00342         case CBF0_TAG:
00343             cbf0_chunk = index;
00344             break;
00345 
00346         case CBFZ_TAG:
00347             cbfz_chunk = index;
00348             break;
00349 
00350         case CBP0_TAG:
00351             cbp0_chunk = index;
00352             break;
00353 
00354         case CBPZ_TAG:
00355             cbpz_chunk = index;
00356             break;
00357 
00358         case CPL0_TAG:
00359             cpl0_chunk = index;
00360             break;
00361 
00362         case CPLZ_TAG:
00363             cplz_chunk = index;
00364             break;
00365 
00366         case VPTZ_TAG:
00367             vptz_chunk = index;
00368             break;
00369 
00370         default:
00371             av_log(s->avctx, AV_LOG_ERROR, "  VQA video: Found unknown chunk type: %c%c%c%c (%08X)\n",
00372             (chunk_type >> 24) & 0xFF,
00373             (chunk_type >> 16) & 0xFF,
00374             (chunk_type >>  8) & 0xFF,
00375             (chunk_type >>  0) & 0xFF,
00376             chunk_type);
00377             break;
00378         }
00379 
00380         byte_skip = chunk_size & 0x01;
00381         bytestream2_skip(&s->gb, chunk_size + byte_skip);
00382     }
00383 
00384     /* next, deal with the palette */
00385     if ((cpl0_chunk != -1) && (cplz_chunk != -1)) {
00386 
00387         /* a chunk should not have both chunk types */
00388         av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: found both CPL0 and CPLZ chunks\n");
00389         return AVERROR_INVALIDDATA;
00390     }
00391 
00392     /* decompress the palette chunk */
00393     if (cplz_chunk != -1) {
00394 
00395 /* yet to be handled */
00396 
00397     }
00398 
00399     /* convert the RGB palette into the machine's endian format */
00400     if (cpl0_chunk != -1) {
00401 
00402         bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET);
00403         chunk_size = bytestream2_get_be32(&s->gb);
00404         /* sanity check the palette size */
00405         if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) {
00406             av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: found a palette chunk with %d colors\n",
00407                 chunk_size / 3);
00408             return AVERROR_INVALIDDATA;
00409         }
00410         for (i = 0; i < chunk_size / 3; i++) {
00411             /* scale by 4 to transform 6-bit palette -> 8-bit */
00412             r = bytestream2_get_byteu(&s->gb) * 4;
00413             g = bytestream2_get_byteu(&s->gb) * 4;
00414             b = bytestream2_get_byteu(&s->gb) * 4;
00415             s->palette[i] = (r << 16) | (g << 8) | (b);
00416         }
00417     }
00418 
00419     /* next, look for a full codebook */
00420     if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
00421 
00422         /* a chunk should not have both chunk types */
00423         av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: found both CBF0 and CBFZ chunks\n");
00424         return AVERROR_INVALIDDATA;
00425     }
00426 
00427     /* decompress the full codebook chunk */
00428     if (cbfz_chunk != -1) {
00429 
00430         bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET);
00431         chunk_size = bytestream2_get_be32(&s->gb);
00432         if ((res = decode_format80(&s->gb, chunk_size, s->codebook,
00433                                    s->codebook_size, 0)) < 0)
00434             return res;
00435     }
00436 
00437     /* copy a full codebook */
00438     if (cbf0_chunk != -1) {
00439 
00440         bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET);
00441         chunk_size = bytestream2_get_be32(&s->gb);
00442         /* sanity check the full codebook size */
00443         if (chunk_size > MAX_CODEBOOK_SIZE) {
00444             av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: CBF0 chunk too large (0x%X bytes)\n",
00445                 chunk_size);
00446             return AVERROR_INVALIDDATA;
00447         }
00448 
00449         bytestream2_get_buffer(&s->gb, s->codebook, chunk_size);
00450     }
00451 
00452     /* decode the frame */
00453     if (vptz_chunk == -1) {
00454 
00455         /* something is wrong if there is no VPTZ chunk */
00456         av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: no VPTZ chunk found\n");
00457         return AVERROR_INVALIDDATA;
00458     }
00459 
00460     bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET);
00461     chunk_size = bytestream2_get_be32(&s->gb);
00462     if ((res = decode_format80(&s->gb, chunk_size,
00463                                s->decode_buffer, s->decode_buffer_size, 1)) < 0)
00464         return res;
00465 
00466     /* render the final PAL8 frame */
00467     if (s->vector_height == 4)
00468         index_shift = 4;
00469     else
00470         index_shift = 3;
00471     for (y = 0; y < s->frame.linesize[0] * s->height;
00472         y += s->frame.linesize[0] * s->vector_height) {
00473 
00474         for (x = y; x < y + s->width; x += 4, lobytes++, hibytes++) {
00475             pixel_ptr = x;
00476 
00477             /* get the vector index, the method for which varies according to
00478              * VQA file version */
00479             switch (s->vqa_version) {
00480 
00481             case 1:
00482                 lobyte = s->decode_buffer[lobytes * 2];
00483                 hibyte = s->decode_buffer[(lobytes * 2) + 1];
00484                 vector_index = ((hibyte << 8) | lobyte) >> 3;
00485                 vector_index <<= index_shift;
00486                 lines = s->vector_height;
00487                 /* uniform color fill - a quick hack */
00488                 if (hibyte == 0xFF) {
00489                     while (lines--) {
00490                         s->frame.data[0][pixel_ptr + 0] = 255 - lobyte;
00491                         s->frame.data[0][pixel_ptr + 1] = 255 - lobyte;
00492                         s->frame.data[0][pixel_ptr + 2] = 255 - lobyte;
00493                         s->frame.data[0][pixel_ptr + 3] = 255 - lobyte;
00494                         pixel_ptr += s->frame.linesize[0];
00495                     }
00496                     lines=0;
00497                 }
00498                 break;
00499 
00500             case 2:
00501                 lobyte = s->decode_buffer[lobytes];
00502                 hibyte = s->decode_buffer[hibytes];
00503                 vector_index = (hibyte << 8) | lobyte;
00504                 vector_index <<= index_shift;
00505                 lines = s->vector_height;
00506                 break;
00507 
00508             case 3:
00509 /* not implemented yet */
00510                 lines = 0;
00511                 break;
00512             }
00513 
00514             while (lines--) {
00515                 s->frame.data[0][pixel_ptr + 0] = s->codebook[vector_index++];
00516                 s->frame.data[0][pixel_ptr + 1] = s->codebook[vector_index++];
00517                 s->frame.data[0][pixel_ptr + 2] = s->codebook[vector_index++];
00518                 s->frame.data[0][pixel_ptr + 3] = s->codebook[vector_index++];
00519                 pixel_ptr += s->frame.linesize[0];
00520             }
00521         }
00522     }
00523 
00524     /* handle partial codebook */
00525     if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
00526         /* a chunk should not have both chunk types */
00527         av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: found both CBP0 and CBPZ chunks\n");
00528         return AVERROR_INVALIDDATA;
00529     }
00530 
00531     if (cbp0_chunk != -1) {
00532 
00533         bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET);
00534         chunk_size = bytestream2_get_be32(&s->gb);
00535 
00536         /* accumulate partial codebook */
00537         bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
00538                                chunk_size);
00539         s->next_codebook_buffer_index += chunk_size;
00540 
00541         s->partial_countdown--;
00542         if (s->partial_countdown == 0) {
00543 
00544             /* time to replace codebook */
00545             memcpy(s->codebook, s->next_codebook_buffer,
00546                 s->next_codebook_buffer_index);
00547 
00548             /* reset accounting */
00549             s->next_codebook_buffer_index = 0;
00550             s->partial_countdown = s->partial_count;
00551         }
00552     }
00553 
00554     if (cbpz_chunk != -1) {
00555 
00556         bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET);
00557         chunk_size = bytestream2_get_be32(&s->gb);
00558 
00559         /* accumulate partial codebook */
00560         bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
00561                                chunk_size);
00562         s->next_codebook_buffer_index += chunk_size;
00563 
00564         s->partial_countdown--;
00565         if (s->partial_countdown == 0) {
00566             GetByteContext gb;
00567 
00568             bytestream2_init(&gb, s->next_codebook_buffer, s->next_codebook_buffer_index);
00569             /* decompress codebook */
00570             if ((res = decode_format80(&gb, s->next_codebook_buffer_index,
00571                                        s->codebook, s->codebook_size, 0)) < 0)
00572                 return res;
00573 
00574             /* reset accounting */
00575             s->next_codebook_buffer_index = 0;
00576             s->partial_countdown = s->partial_count;
00577         }
00578     }
00579 
00580     return 0;
00581 }
00582 
00583 static int vqa_decode_frame(AVCodecContext *avctx,
00584                             void *data, int *data_size,
00585                             AVPacket *avpkt)
00586 {
00587     VqaContext *s = avctx->priv_data;
00588     int res;
00589 
00590     if (s->frame.data[0])
00591         avctx->release_buffer(avctx, &s->frame);
00592 
00593     if (avctx->get_buffer(avctx, &s->frame)) {
00594         av_log(s->avctx, AV_LOG_ERROR, "  VQA Video: get_buffer() failed\n");
00595         return -1;
00596     }
00597 
00598     bytestream2_init(&s->gb, avpkt->data, avpkt->size);
00599     if ((res = vqa_decode_chunk(s)) < 0)
00600         return res;
00601 
00602     /* make the palette available on the way out */
00603     memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
00604     s->frame.palette_has_changed = 1;
00605 
00606     *data_size = sizeof(AVFrame);
00607     *(AVFrame*)data = s->frame;
00608 
00609     /* report that the buffer was completely consumed */
00610     return avpkt->size;
00611 }
00612 
00613 static av_cold int vqa_decode_end(AVCodecContext *avctx)
00614 {
00615     VqaContext *s = avctx->priv_data;
00616 
00617     av_free(s->codebook);
00618     av_free(s->next_codebook_buffer);
00619     av_free(s->decode_buffer);
00620 
00621     if (s->frame.data[0])
00622         avctx->release_buffer(avctx, &s->frame);
00623 
00624     return 0;
00625 }
00626 
00627 AVCodec ff_vqa_decoder = {
00628     .name           = "vqavideo",
00629     .type           = AVMEDIA_TYPE_VIDEO,
00630     .id             = CODEC_ID_WS_VQA,
00631     .priv_data_size = sizeof(VqaContext),
00632     .init           = vqa_decode_init,
00633     .close          = vqa_decode_end,
00634     .decode         = vqa_decode_frame,
00635     .capabilities   = CODEC_CAP_DR1,
00636     .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"),
00637 };