⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vqavideo.c

📁 ffmpeg源码分析
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Westwood Studios VQA Video Decoder * Copyright (C) 2003 the ffmpeg project * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * *//** * @file vqavideo.c * VQA Video Decoder by Mike Melanson (melanson@pcisys.net) * For more information about the RPZA format, visit: *   http://www.pcisys.net/~melanson/codecs/ * * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending * on the type of data in the file. * * This decoder needs the 42-byte VQHD header from the beginning * of the VQA file passed through the extradata field. The VQHD header * is laid out as: * *   bytes 0-3   chunk fourcc: 'VQHD' *   bytes 4-7   chunk size in big-endian format, should be 0x0000002A *   bytes 8-49  VQHD chunk data * * Bytes 8-49 are what this decoder expects to see. * * Briefly, VQA is a vector quantized animation format that operates in a * VGA palettized colorspace. It operates on pixel vectors (blocks) * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector * codebooks, palette information, and code maps for rendering vectors onto * frames. Any of these components can also be compressed with a run-length * encoding (RLE) algorithm commonly referred to as "format80". * * VQA takes a novel approach to rate control. Each group of n frames * (usually, n = 8) relies on a different vector codebook. Rather than * transporting an entire codebook every 8th frame, the new codebook is * broken up into 8 pieces and sent along with the compressed video chunks * for each of the 8 frames preceding the 8 frames which require the * codebook. A full codebook is also sent on the very first frame of a * file. This is an interesting technique, although it makes random file * seeking difficult despite the fact that the frames are all intracoded. * * V1,2 VQA uses 12-bit codebook indices. If the 12-bit indices were * packed into bytes and then RLE compressed, bytewise, the results would * be poor. That is why the coding method divides each index into 2 parts, * the top 4 bits and the bottom 8 bits, then RL encodes the 4-bit pieces * together and the 8-bit pieces together. If most of the vectors are * clustered into one group of 256 vectors, most of the 4-bit index pieces * should be the same. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "common.h"#include "avcodec.h"#include "dsputil.h"#define PALETTE_COUNT 256#define VQA_HEADER_SIZE 0x2A#define CHUNK_PREAMBLE_SIZE 8/* allocate the maximum vector space, regardless of the file version: * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */#define MAX_CODEBOOK_VECTORS 0xFF00#define SOLID_PIXEL_VECTORS 0x100#define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS)#define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4)#define CBF0_TAG MKBETAG('C', 'B', 'F', '0')#define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z')#define CBP0_TAG MKBETAG('C', 'B', 'P', '0')#define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z')#define CPL0_TAG MKBETAG('C', 'P', 'L', '0')#define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z')#define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z')#define VQA_DEBUG 0#if VQA_DEBUG#define vqa_debug printf#elsestatic inline void vqa_debug(const char *format, ...) { }#endiftypedef struct VqaContext {    AVCodecContext *avctx;    DSPContext dsp;    AVFrame frame;    unsigned char *buf;    int size;    unsigned int palette[PALETTE_COUNT];    int width;   /* width of a frame */    int height;   /* height of a frame */    int vector_width;  /* width of individual vector */    int vector_height;  /* height of individual vector */    int vqa_version;  /* this should be either 1, 2 or 3 */    unsigned char *codebook;         /* the current codebook */    int codebook_size;    unsigned char *next_codebook_buffer;  /* accumulator for next codebook */    int next_codebook_buffer_index;    unsigned char *decode_buffer;    int decode_buffer_size;    /* number of frames to go before replacing codebook */    int partial_countdown;    int partial_count;} VqaContext;static int vqa_decode_init(AVCodecContext *avctx){    VqaContext *s = (VqaContext *)avctx->priv_data;    unsigned char *vqa_header;    int i, j, codebook_index;;    s->avctx = avctx;    avctx->pix_fmt = PIX_FMT_PAL8;    avctx->has_b_frames = 0;    dsputil_init(&s->dsp, avctx);    /* make sure the extradata made it */    if (s->avctx->extradata_size != VQA_HEADER_SIZE) {        av_log(s->avctx, AV_LOG_ERROR, "  VQA video: expected extradata size of %d\n", VQA_HEADER_SIZE);        return -1;    }    /* load up the VQA parameters from the header */    vqa_header = (unsigned char *)s->avctx->extradata;    s->vqa_version = vqa_header[0];    s->width = LE_16(&vqa_header[6]);    s->height = LE_16(&vqa_header[8]);    if(avcodec_check_dimensions(avctx, s->width, s->height)){        s->width= s->height= 0;        return -1;    }    s->vector_width = vqa_header[10];    s->vector_height = vqa_header[11];    s->partial_count = s->partial_countdown = vqa_header[13];    /* the vector dimensions have to meet very stringent requirements */    if ((s->vector_width != 4) ||        ((s->vector_height != 2) && (s->vector_height != 4))) {        /* return without further initialization */        return -1;    }    /* allocate codebooks */    s->codebook_size = MAX_CODEBOOK_SIZE;    s->codebook = av_malloc(s->codebook_size);    s->next_codebook_buffer = av_malloc(s->codebook_size);    /* initialize the solid-color vectors */    if (s->vector_height == 4) {        codebook_index = 0xFF00 * 16;        for (i = 0; i < 256; i++)            for (j = 0; j < 16; j++)                s->codebook[codebook_index++] = i;    } else {        codebook_index = 0xF00 * 8;        for (i = 0; i < 256; i++)            for (j = 0; j < 8; j++)                s->codebook[codebook_index++] = i;    }    s->next_codebook_buffer_index = 0;    /* allocate decode buffer */    s->decode_buffer_size = (s->width / s->vector_width) *        (s->height / s->vector_height) * 2;    s->decode_buffer = av_malloc(s->decode_buffer_size);    s->frame.data[0] = NULL;    return 0;}#define CHECK_COUNT() \    if (dest_index + count > dest_size) { \        av_log(NULL, AV_LOG_ERROR, "  VQA video: decode_format80 problem: next op would overflow dest_index\n"); \        av_log(NULL, AV_LOG_ERROR, "  VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \            dest_index, count, dest_size); \        return; \    }static void decode_format80(unsigned char *src, int src_size,    unsigned char *dest, int dest_size, int check_size) {    int src_index = 0;    int dest_index = 0;    int count;    int src_pos;    unsigned char color;    int i;    while (src_index < src_size) {        vqa_debug("      opcode %02X: ", src[src_index]);        /* 0x80 means that frame is finished */        if (src[src_index] == 0x80)            return;        if (dest_index >= dest_size) {            av_log(NULL, AV_LOG_ERROR, "  VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",                dest_index, dest_size);            return;        }        if (src[src_index] == 0xFF) {            src_index++;            count = LE_16(&src[src_index]);            src_index += 2;            src_pos = LE_16(&src[src_index]);            src_index += 2;            vqa_debug("(1) copy %X bytes from absolute pos %X\n", count, src_pos);            CHECK_COUNT();            for (i = 0; i < count; i++)                dest[dest_index + i] = dest[src_pos + i];            dest_index += count;        } else if (src[src_index] == 0xFE) {            src_index++;            count = LE_16(&src[src_index]);            src_index += 2;            color = src[src_index++];            vqa_debug("(2) set %X bytes to %02X\n", count, color);            CHECK_COUNT();            memset(&dest[dest_index], color, count);            dest_index += count;        } else if ((src[src_index] & 0xC0) == 0xC0) {            count = (src[src_index++] & 0x3F) + 3;            src_pos = LE_16(&src[src_index]);            src_index += 2;            vqa_debug("(3) copy %X bytes from absolute pos %X\n", count, src_pos);            CHECK_COUNT();            for (i = 0; i < count; i++)                dest[dest_index + i] = dest[src_pos + i];            dest_index += count;        } else if (src[src_index] > 0x80) {            count = src[src_index++] & 0x3F;            vqa_debug("(4) copy %X bytes from source to dest\n", count);            CHECK_COUNT();            memcpy(&dest[dest_index], &src[src_index], count);            src_index += count;            dest_index += count;        } else {            count = ((src[src_index] & 0x70) >> 4) + 3;            src_pos = BE_16(&src[src_index]) & 0x0FFF;            src_index += 2;            vqa_debug("(5) copy %X bytes from relpos %X\n", count, src_pos);            CHECK_COUNT();            for (i = 0; i < count; i++)                dest[dest_index + i] = dest[dest_index - src_pos + i];            dest_index += count;        }    }    /* validate that the entire destination buffer was filled; this is     * important for decoding frame maps since each vector needs to have a     * codebook entry; it is not important for compressed codebooks because     * not every entry needs to be filled */    if (check_size)        if (dest_index < dest_size)            av_log(NULL, AV_LOG_ERROR, "  VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",                dest_index, dest_size);}static void vqa_decode_chunk(VqaContext *s){    unsigned int chunk_type;    unsigned int chunk_size;    int byte_skip;    unsigned int index = 0;    int i;    unsigned char r, g, b;    int index_shift;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -