mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-22 15:23:11 +00:00
avcodec/vqavideo: Decode 15-bit VQA3 files
Adds support for 15-bit VQA3 videos used in Westwood Studios' games. Signed-off-by: Pekka Väänänen <pekka.vaananen@iki.fi>
This commit is contained in:
parent
27c0dd5560
commit
947d0ce0ea
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Westwood Studios VQA Video Decoder
|
* Westwood Studios VQA Video Decoder
|
||||||
* Copyright (C) 2003 The FFmpeg project
|
* Copyright (c) 2003 Mike Melanson <melanson@pcisys.net>
|
||||||
|
* Copyright (c) 2021 Pekka Väänänen <pekka.vaananen@iki.fi>
|
||||||
*
|
*
|
||||||
* This file is part of FFmpeg.
|
* This file is part of FFmpeg.
|
||||||
*
|
*
|
||||||
@ -61,6 +62,11 @@
|
|||||||
* together and the 8-bit pieces together. If most of the vectors are
|
* 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
|
* clustered into one group of 256 vectors, most of the 4-bit index pieces
|
||||||
* should be the same.
|
* should be the same.
|
||||||
|
*
|
||||||
|
* VQA3 introduces a 15-bit high color codebook, delta coding, replaces
|
||||||
|
* the above "split byte" scheme with RLE compression, and extends the
|
||||||
|
* "format80" compression with relative references. In VQA3 the whole
|
||||||
|
* codebook is always updated as a whole without splitting it into pieces.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -81,7 +87,7 @@
|
|||||||
#define MAX_CODEBOOK_VECTORS 0xFF00
|
#define MAX_CODEBOOK_VECTORS 0xFF00
|
||||||
#define SOLID_PIXEL_VECTORS 0x100
|
#define SOLID_PIXEL_VECTORS 0x100
|
||||||
#define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS)
|
#define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS)
|
||||||
#define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4)
|
#define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4 * sizeof(uint16_t))
|
||||||
|
|
||||||
#define CBF0_TAG MKBETAG('C', 'B', 'F', '0')
|
#define CBF0_TAG MKBETAG('C', 'B', 'F', '0')
|
||||||
#define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z')
|
#define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z')
|
||||||
@ -90,9 +96,11 @@
|
|||||||
#define CPL0_TAG MKBETAG('C', 'P', 'L', '0')
|
#define CPL0_TAG MKBETAG('C', 'P', 'L', '0')
|
||||||
#define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z')
|
#define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z')
|
||||||
#define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z')
|
#define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z')
|
||||||
|
#define VPTR_TAG MKBETAG('V', 'P', 'T', 'R')
|
||||||
|
#define VPRZ_TAG MKBETAG('V', 'P', 'R', 'Z')
|
||||||
|
|
||||||
typedef struct VqaContext {
|
typedef struct VqaContext {
|
||||||
|
AVFrame *frame;
|
||||||
AVCodecContext *avctx;
|
AVCodecContext *avctx;
|
||||||
GetByteContext gb;
|
GetByteContext gb;
|
||||||
|
|
||||||
@ -115,16 +123,15 @@ typedef struct VqaContext {
|
|||||||
/* number of frames to go before replacing codebook */
|
/* number of frames to go before replacing codebook */
|
||||||
int partial_countdown;
|
int partial_countdown;
|
||||||
int partial_count;
|
int partial_count;
|
||||||
|
|
||||||
} VqaContext;
|
} VqaContext;
|
||||||
|
|
||||||
static av_cold int vqa_decode_init(AVCodecContext *avctx)
|
static av_cold int vqa_decode_init(AVCodecContext *avctx)
|
||||||
{
|
{
|
||||||
VqaContext *s = avctx->priv_data;
|
VqaContext *s = avctx->priv_data;
|
||||||
int i, j, codebook_index, ret;
|
int i, j, codebook_index, ret;
|
||||||
|
int colors;
|
||||||
|
|
||||||
s->avctx = avctx;
|
s->avctx = avctx;
|
||||||
avctx->pix_fmt = AV_PIX_FMT_PAL8;
|
|
||||||
|
|
||||||
/* make sure the extradata made it */
|
/* make sure the extradata made it */
|
||||||
if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
|
if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
|
||||||
@ -134,17 +141,12 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
|
|||||||
|
|
||||||
/* load up the VQA parameters from the header */
|
/* load up the VQA parameters from the header */
|
||||||
s->vqa_version = s->avctx->extradata[0];
|
s->vqa_version = s->avctx->extradata[0];
|
||||||
switch (s->vqa_version) {
|
|
||||||
case 1:
|
if (s->vqa_version < 1 || s->vqa_version > 3) {
|
||||||
case 2:
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
avpriv_report_missing_feature(avctx, "VQA Version %d", s->vqa_version);
|
|
||||||
return AVERROR_PATCHWELCOME;
|
|
||||||
default:
|
|
||||||
avpriv_request_sample(avctx, "VQA Version %i", s->vqa_version);
|
avpriv_request_sample(avctx, "VQA Version %i", s->vqa_version);
|
||||||
return AVERROR_PATCHWELCOME;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->width = AV_RL16(&s->avctx->extradata[6]);
|
s->width = AV_RL16(&s->avctx->extradata[6]);
|
||||||
s->height = AV_RL16(&s->avctx->extradata[8]);
|
s->height = AV_RL16(&s->avctx->extradata[8]);
|
||||||
if ((ret = ff_set_dimensions(avctx, s->width, s->height)) < 0) {
|
if ((ret = ff_set_dimensions(avctx, s->width, s->height)) < 0) {
|
||||||
@ -155,6 +157,14 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
|
|||||||
s->vector_height = s->avctx->extradata[11];
|
s->vector_height = s->avctx->extradata[11];
|
||||||
s->partial_count = s->partial_countdown = s->avctx->extradata[13];
|
s->partial_count = s->partial_countdown = s->avctx->extradata[13];
|
||||||
|
|
||||||
|
colors = (s->avctx->extradata[14] << 8) | s->avctx->extradata[15];
|
||||||
|
|
||||||
|
if (colors > 0) {
|
||||||
|
avctx->pix_fmt = AV_PIX_FMT_PAL8;
|
||||||
|
} else {
|
||||||
|
avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
|
||||||
|
}
|
||||||
|
|
||||||
/* the vector dimensions have to meet very stringent requirements */
|
/* the vector dimensions have to meet very stringent requirements */
|
||||||
if ((s->vector_width != 4) ||
|
if ((s->vector_width != 4) ||
|
||||||
((s->vector_height != 2) && (s->vector_height != 4))) {
|
((s->vector_height != 2) && (s->vector_height != 4))) {
|
||||||
@ -167,6 +177,10 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
|
|||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->frame = av_frame_alloc();
|
||||||
|
if (!s->frame)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
/* allocate codebooks */
|
/* allocate codebooks */
|
||||||
s->codebook_size = MAX_CODEBOOK_SIZE;
|
s->codebook_size = MAX_CODEBOOK_SIZE;
|
||||||
s->codebook = av_malloc(s->codebook_size);
|
s->codebook = av_malloc(s->codebook_size);
|
||||||
@ -225,6 +239,7 @@ static int decode_format80(VqaContext *s, int src_size,
|
|||||||
int src_pos;
|
int src_pos;
|
||||||
unsigned char color;
|
unsigned char color;
|
||||||
int i;
|
int i;
|
||||||
|
int relative = 0;
|
||||||
|
|
||||||
if (src_size < 0 || src_size > bytestream2_get_bytes_left(&s->gb)) {
|
if (src_size < 0 || src_size > bytestream2_get_bytes_left(&s->gb)) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Chunk size %d is out of range\n",
|
av_log(s->avctx, AV_LOG_ERROR, "Chunk size %d is out of range\n",
|
||||||
@ -232,6 +247,13 @@ static int decode_format80(VqaContext *s, int src_size,
|
|||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* the "new" scheme makes references relative to destination pointer */
|
||||||
|
if (bytestream2_peek_byte(&s->gb) == 0x00) {
|
||||||
|
relative = 1;
|
||||||
|
bytestream2_get_byte(&s->gb);
|
||||||
|
ff_tlog(s->avctx, "found new format stream ");
|
||||||
|
}
|
||||||
|
|
||||||
start = bytestream2_tell(&s->gb);
|
start = bytestream2_tell(&s->gb);
|
||||||
while (bytestream2_tell(&s->gb) - start < src_size) {
|
while (bytestream2_tell(&s->gb) - start < src_size) {
|
||||||
opcode = bytestream2_get_byte(&s->gb);
|
opcode = bytestream2_get_byte(&s->gb);
|
||||||
@ -251,7 +273,9 @@ static int decode_format80(VqaContext *s, int src_size,
|
|||||||
|
|
||||||
count = bytestream2_get_le16(&s->gb);
|
count = bytestream2_get_le16(&s->gb);
|
||||||
src_pos = bytestream2_get_le16(&s->gb);
|
src_pos = bytestream2_get_le16(&s->gb);
|
||||||
ff_tlog(s->avctx, "(1) copy %X bytes from absolute pos %X\n", count, src_pos);
|
if (relative)
|
||||||
|
src_pos = dest_index - src_pos;
|
||||||
|
ff_tlog(s->avctx, "(1) copy %X bytes from pos %X\n", count, src_pos);
|
||||||
CHECK_COUNT();
|
CHECK_COUNT();
|
||||||
CHECK_COPY(src_pos);
|
CHECK_COPY(src_pos);
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
@ -271,7 +295,9 @@ static int decode_format80(VqaContext *s, int src_size,
|
|||||||
|
|
||||||
count = (opcode & 0x3F) + 3;
|
count = (opcode & 0x3F) + 3;
|
||||||
src_pos = bytestream2_get_le16(&s->gb);
|
src_pos = bytestream2_get_le16(&s->gb);
|
||||||
ff_tlog(s->avctx, "(3) copy %X bytes from absolute pos %X\n", count, src_pos);
|
if (relative)
|
||||||
|
src_pos = dest_index - src_pos;
|
||||||
|
ff_tlog(s->avctx, "(3) copy %X bytes from pos %X\n", count, src_pos);
|
||||||
CHECK_COUNT();
|
CHECK_COUNT();
|
||||||
CHECK_COPY(src_pos);
|
CHECK_COPY(src_pos);
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
@ -313,7 +339,7 @@ static int decode_format80(VqaContext *s, int src_size,
|
|||||||
return 0; // let's display what we decoded anyway
|
return 0; // let's display what we decoded anyway
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
|
static int vqa_decode_frame_pal8(VqaContext *s, AVFrame *frame)
|
||||||
{
|
{
|
||||||
unsigned int chunk_type;
|
unsigned int chunk_type;
|
||||||
unsigned int chunk_size;
|
unsigned int chunk_size;
|
||||||
@ -512,9 +538,8 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
/* not implemented yet */
|
av_log(s->avctx, AV_LOG_ERROR, "VQA3 shouldn't have a color palette");
|
||||||
lines = 0;
|
return AVERROR_INVALIDDATA;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (lines--) {
|
while (lines--) {
|
||||||
@ -596,24 +621,206 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vqa_decode_frame_hicolor(VqaContext *s, AVFrame *frame)
|
||||||
|
{
|
||||||
|
unsigned int chunk_type;
|
||||||
|
unsigned int chunk_size;
|
||||||
|
unsigned int index = 0;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
int cbf0_chunk = -1;
|
||||||
|
int cbfz_chunk = -1;
|
||||||
|
int vptr_chunk = -1;
|
||||||
|
int vprz_chunk = -1;
|
||||||
|
|
||||||
|
const unsigned char *stream;
|
||||||
|
|
||||||
|
while (bytestream2_get_bytes_left(&s->gb) >= 8) {
|
||||||
|
chunk_type = bytestream2_get_be32u(&s->gb);
|
||||||
|
index = bytestream2_tell(&s->gb);
|
||||||
|
chunk_size = bytestream2_get_be32u(&s->gb);
|
||||||
|
|
||||||
|
switch (chunk_type) {
|
||||||
|
case CBF0_TAG:
|
||||||
|
cbf0_chunk = index;
|
||||||
|
break;
|
||||||
|
case CBFZ_TAG:
|
||||||
|
cbfz_chunk = index;
|
||||||
|
break;
|
||||||
|
case VPTR_TAG:
|
||||||
|
vptr_chunk = index;
|
||||||
|
break;
|
||||||
|
case VPRZ_TAG:
|
||||||
|
vprz_chunk = index;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n",
|
||||||
|
av_fourcc2str(av_bswap32(chunk_type)), chunk_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytestream2_skip(&s->gb, chunk_size + (chunk_size & 0x01));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* next, look for a full codebook */
|
||||||
|
if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
|
||||||
|
/* a chunk should not have both chunk types */
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decompress the full codebook chunk */
|
||||||
|
if (cbfz_chunk != -1) {
|
||||||
|
bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET);
|
||||||
|
chunk_size = bytestream2_get_be32(&s->gb);
|
||||||
|
if ((res = decode_format80(s, chunk_size, s->codebook,
|
||||||
|
s->codebook_size, 0)) < 0)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy a full codebook */
|
||||||
|
if (cbf0_chunk != -1) {
|
||||||
|
bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET);
|
||||||
|
chunk_size = bytestream2_get_be32(&s->gb);
|
||||||
|
/* sanity check the full codebook size */
|
||||||
|
if (chunk_size > MAX_CODEBOOK_SIZE) {
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n",
|
||||||
|
chunk_size);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytestream2_get_buffer(&s->gb, s->codebook, chunk_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vprz_chunk == -1 && vptr_chunk == -1) {
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "frame has no block data\n");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode the frame */
|
||||||
|
|
||||||
|
if (vptr_chunk != -1) {
|
||||||
|
/* copy uncompressed tile data */
|
||||||
|
bytestream2_seek(&s->gb, vptr_chunk, SEEK_SET);
|
||||||
|
chunk_size = bytestream2_get_be32(&s->gb);
|
||||||
|
if (chunk_size > s->decode_buffer_size) {
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "VPTR chunk didn't fit in decode buffer");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
bytestream2_get_buffer(&s->gb, s->decode_buffer, chunk_size);
|
||||||
|
} else if (vprz_chunk != -1) {
|
||||||
|
/* decompress the tile data */
|
||||||
|
bytestream2_seek(&s->gb, vprz_chunk, SEEK_SET);
|
||||||
|
|
||||||
|
chunk_size = bytestream2_get_be32(&s->gb);
|
||||||
|
if ((res = decode_format80(s, chunk_size, s->decode_buffer, s->decode_buffer_size, 0)) < 0)
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "expected either VPTR or VPRZ chunk\n");
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now uncompress the per-row RLE of the decode buffer and draw the blocks in framebuffer */
|
||||||
|
|
||||||
|
stream = (unsigned char*)s->decode_buffer;
|
||||||
|
|
||||||
|
for (int y_pos = 0; y_pos < s->height; y_pos += s->vector_height) {
|
||||||
|
int x_pos = 0;
|
||||||
|
|
||||||
|
while (x_pos < s->width) {
|
||||||
|
int vector_index = 0;
|
||||||
|
int count = 0;
|
||||||
|
uint16_t code = bytestream_get_le16(&stream);
|
||||||
|
int type;
|
||||||
|
|
||||||
|
type = code >> 13;
|
||||||
|
code &= 0x1fff;
|
||||||
|
|
||||||
|
if (type == 0) {
|
||||||
|
x_pos += 4 * code;
|
||||||
|
continue;
|
||||||
|
} else if (type < 3) {
|
||||||
|
vector_index = code & 0xff;
|
||||||
|
count = ((code & 0x1f00) >> 7) + 1 + type;
|
||||||
|
} else if (type < 5) {
|
||||||
|
vector_index = code;
|
||||||
|
count = 1;
|
||||||
|
} else if (type < 7) {
|
||||||
|
vector_index = code;
|
||||||
|
count = *stream++;
|
||||||
|
} else {
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, " unknown type in VPTR chunk (%d)\n",type);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0 || count > (s->width - x_pos) / s->vector_width) {
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "invalid count: %d\n", count);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count-- && x_pos < s->width) {
|
||||||
|
const int bytes_per_vector = 4 * s->vector_height * sizeof(uint16_t);
|
||||||
|
unsigned char *src = s->codebook + vector_index * bytes_per_vector;
|
||||||
|
unsigned char *dst = s->frame->data[0] + y_pos * s->frame->linesize[0]
|
||||||
|
+ sizeof(uint16_t) * x_pos;
|
||||||
|
|
||||||
|
if (vector_index >= MAX_VECTORS)
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
|
||||||
|
for (int y = 0; y < s->vector_height; y++) {
|
||||||
|
int size = 4 * sizeof(uint16_t);
|
||||||
|
memcpy(dst, src, size);
|
||||||
|
dst += s->frame->linesize[0];
|
||||||
|
src += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we might want to read the next block index from stream */
|
||||||
|
if ((type == 2) && count > 0) {
|
||||||
|
vector_index = bytestream_get_byte(&stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
x_pos += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "had %d leftover vectors\n", count);
|
||||||
|
return AVERROR_BUG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int vqa_decode_frame(AVCodecContext *avctx,
|
static int vqa_decode_frame(AVCodecContext *avctx,
|
||||||
void *data, int *got_frame,
|
void *data, int *got_frame,
|
||||||
AVPacket *avpkt)
|
AVPacket *avpkt)
|
||||||
{
|
{
|
||||||
VqaContext *s = avctx->priv_data;
|
VqaContext *s = avctx->priv_data;
|
||||||
AVFrame *frame = data;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if ((res = ff_get_buffer(avctx, frame, 0)) < 0)
|
if ((res = ff_reget_buffer(avctx, s->frame, 0)) < 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
bytestream2_init(&s->gb, avpkt->data, avpkt->size);
|
bytestream2_init(&s->gb, avpkt->data, avpkt->size);
|
||||||
if ((res = vqa_decode_chunk(s, frame)) < 0)
|
|
||||||
|
if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
|
||||||
|
if ((res = vqa_decode_frame_pal8(s, s->frame)) < 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* make the palette available on the way out */
|
/* make the palette available on the way out */
|
||||||
memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4);
|
memcpy(s->frame->data[1], s->palette, PALETTE_COUNT * 4);
|
||||||
frame->palette_has_changed = 1;
|
s->frame->palette_has_changed = 1;
|
||||||
|
} else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) {
|
||||||
|
if ((res = vqa_decode_frame_hicolor(s, s->frame)) < 0)
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "unsupported pixel format\n");
|
||||||
|
return AVERROR_BUG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = av_frame_ref(data, s->frame)) < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
*got_frame = 1;
|
*got_frame = 1;
|
||||||
|
|
||||||
@ -625,6 +832,7 @@ static av_cold int vqa_decode_end(AVCodecContext *avctx)
|
|||||||
{
|
{
|
||||||
VqaContext *s = avctx->priv_data;
|
VqaContext *s = avctx->priv_data;
|
||||||
|
|
||||||
|
av_frame_free(&s->frame);
|
||||||
av_freep(&s->codebook);
|
av_freep(&s->codebook);
|
||||||
av_freep(&s->next_codebook_buffer);
|
av_freep(&s->next_codebook_buffer);
|
||||||
av_freep(&s->decode_buffer);
|
av_freep(&s->decode_buffer);
|
||||||
@ -633,7 +841,7 @@ static av_cold int vqa_decode_end(AVCodecContext *avctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const AVCodecDefault vqa_defaults[] = {
|
static const AVCodecDefault vqa_defaults[] = {
|
||||||
{ "max_pixels", "320*240" },
|
{ "max_pixels", "640*480" },
|
||||||
{ NULL },
|
{ NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,10 +48,14 @@
|
|||||||
#define CINF_TAG MKBETAG('C', 'I', 'N', 'F')
|
#define CINF_TAG MKBETAG('C', 'I', 'N', 'F')
|
||||||
#define CINH_TAG MKBETAG('C', 'I', 'N', 'H')
|
#define CINH_TAG MKBETAG('C', 'I', 'N', 'H')
|
||||||
#define CIND_TAG MKBETAG('C', 'I', 'N', 'D')
|
#define CIND_TAG MKBETAG('C', 'I', 'N', 'D')
|
||||||
|
#define LINF_TAG MKBETAG('L', 'I', 'N', 'F')
|
||||||
#define PINF_TAG MKBETAG('P', 'I', 'N', 'F')
|
#define PINF_TAG MKBETAG('P', 'I', 'N', 'F')
|
||||||
#define PINH_TAG MKBETAG('P', 'I', 'N', 'H')
|
#define PINH_TAG MKBETAG('P', 'I', 'N', 'H')
|
||||||
#define PIND_TAG MKBETAG('P', 'I', 'N', 'D')
|
#define PIND_TAG MKBETAG('P', 'I', 'N', 'D')
|
||||||
#define CMDS_TAG MKBETAG('C', 'M', 'D', 'S')
|
#define CMDS_TAG MKBETAG('C', 'M', 'D', 'S')
|
||||||
|
#define SN2J_TAG MKBETAG('S', 'N', '2', 'J')
|
||||||
|
#define VIEW_TAG MKBETAG('V', 'I', 'E', 'W')
|
||||||
|
#define ZBUF_TAG MKBETAG('Z', 'B', 'U', 'F')
|
||||||
|
|
||||||
#define VQA_HEADER_SIZE 0x2A
|
#define VQA_HEADER_SIZE 0x2A
|
||||||
#define VQA_PREAMBLE_SIZE 8
|
#define VQA_PREAMBLE_SIZE 8
|
||||||
@ -143,11 +147,14 @@ static int wsvqa_read_header(AVFormatContext *s)
|
|||||||
case CINF_TAG:
|
case CINF_TAG:
|
||||||
case CINH_TAG:
|
case CINH_TAG:
|
||||||
case CIND_TAG:
|
case CIND_TAG:
|
||||||
|
case LINF_TAG:
|
||||||
case PINF_TAG:
|
case PINF_TAG:
|
||||||
case PINH_TAG:
|
case PINH_TAG:
|
||||||
case PIND_TAG:
|
case PIND_TAG:
|
||||||
case FINF_TAG:
|
case FINF_TAG:
|
||||||
case CMDS_TAG:
|
case CMDS_TAG:
|
||||||
|
case VIEW_TAG:
|
||||||
|
case ZBUF_TAG:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -292,6 +299,9 @@ static int wsvqa_read_packet(AVFormatContext *s,
|
|||||||
} else {
|
} else {
|
||||||
switch(chunk_type){
|
switch(chunk_type){
|
||||||
case CMDS_TAG:
|
case CMDS_TAG:
|
||||||
|
case SN2J_TAG:
|
||||||
|
case VIEW_TAG:
|
||||||
|
case ZBUF_TAG:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
av_log(s, AV_LOG_INFO, "Skipping unknown chunk %s\n",
|
av_log(s, AV_LOG_INFO, "Skipping unknown chunk %s\n",
|
||||||
|
Loading…
Reference in New Issue
Block a user