From patchwork Mon Sep 20 19:13:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?UGVra2EgVsOkw6Ruw6RuZW4=?= X-Patchwork-Id: 30386 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:6506:0:0:0:0:0 with SMTP id z6csp1734335iob; Mon, 20 Sep 2021 12:13:37 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxaF9iGMDMwLkhxqeUUT02SM+fSpMXU+8kp2kzTT9CCgnFHQ0w8HW98rGK5VgwAyBUf/shU X-Received: by 2002:a17:906:4fd6:: with SMTP id i22mr29875462ejw.92.1632165217279; Mon, 20 Sep 2021 12:13:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632165217; cv=none; d=google.com; s=arc-20160816; b=FJ/DZdvgEbIAZ+kh/z8gY/OuRQpmvhZJZzrHmIJxFg5PoE5ErcgX7M6QKbPYWkkodl HEdqHfJ3lPyDKUhB2xHO9aowrStP8VJlMoa4A2iWjgoNM6UdInGPx1nuwk+lijqJ9UOg W89WO8A/g6emLTYVLKKQXvpLADU6dMo2uW3OJHzbTPRfcQihA0ud1kCuWeg4c20F37aS DzPz6pqWmZqkOENB3y00AeZGyghyOvWDYrwC9zYwPLc/Ay4Re659Dg35T7r1Lf8iWNVq xRQgtjsDRldKfMPNR/9CaIVYT7S4PTUBhPxKtj6/Jl+1qG/mrDAMeVJ1dsO8Ie3rOOsT QU3w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:delivered-to; bh=kO8FXNLqf6VoDjbpDeawCed0obQvNq+Jh+MoMpfPGfg=; b=S/PAUcyc5rOVgdNfI7dhcstsMq+bLlQUy0YX0Zv+8yDd5641YlgtZz4+Yp81ldu3YO ghyRpRBeBxLELhOPGEt1hCzadeW36QRssawadSOlSUArhi1Rowu1YdNu6wV1EexjKMjX RvtUWDjAkmzMHSCBFt0y0480vIWcOY8+jrLP7JA0AmGR8r6UEIaB0A+0P4EZUu+ZYnow gdaZhh+zK/UdgaAOiUNxnUYLD7F9L+WNxwoFyHfEcyNj+mR8JAlZqBGPGvOBy3ZnaZ81 DDInTc6AxYWigjkyXT3VBpSEediRozkXAK0g2xofANCI9pOcZ+zpvShjLs5fdauDGsNS F9iQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id jz21si17851746ejb.539.2021.09.20.12.13.35; Mon, 20 Sep 2021 12:13:37 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4F07868AF82; Mon, 20 Sep 2021 22:13:23 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f43.google.com (mail-lf1-f43.google.com [209.85.167.43]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 857F768AEDE for ; Mon, 20 Sep 2021 22:13:16 +0300 (EEST) Received: by mail-lf1-f43.google.com with SMTP id b15so53525478lfe.7 for ; Mon, 20 Sep 2021 12:13:16 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=TvztniRbkZl+ZII4qXAHYUSg9YceqPJFQchuVRbRjcA=; b=D6zfu4RJy66PRsv6PAS63NofbFr1CMmpy2DV/btpRxildketKBIUlLjHv6i/UOZWSu BVpYspfbCZVbyBSvkQ9YPCkfEFeigvwWERjAfJvsomkuxXx2C4X9defWU7AlMejTqwFQ 3ZgdNrZJvHMbi5wE4vPCxhmYK84Dd2HTe8r9iM/Sa+GJFao/y7rDZOgSUfI7MYwv3BOE DIy7EI8ydDqvT9d4AZuPs23QdwGnTXR+6HvFQXVQYivb52pf+H1CY81H2WX6KLHg59xP bqoo8ajA0EyYClCoN/AaKhUh+UXMc1fQXmFLG5jqCK4TazObAeIZmCydRYt8u08a9Rb8 F3Ow== X-Gm-Message-State: AOAM533y1zFtiNxuaPd35RQjb+isfNINRi9bBZHKBFbloatlr0R+BR5u GJIvzyZv8ztjJ7xj0Lc0tkni6bb/GN8zqA== X-Received: by 2002:a2e:9942:: with SMTP id r2mr24930980ljj.92.1632165195741; Mon, 20 Sep 2021 12:13:15 -0700 (PDT) Received: from romu.localdomain (87-92-247-137.rev.dnainternet.fi. [87.92.247.137]) by smtp.gmail.com with ESMTPSA id 206sm105151ljf.18.2021.09.20.12.13.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 Sep 2021 12:13:15 -0700 (PDT) From: =?utf-8?b?UGVra2EgVsOkw6Ruw6RuZW4=?= To: ffmpeg-devel@ffmpeg.org Date: Mon, 20 Sep 2021 22:13:05 +0300 Message-Id: <20210920191305.11676-2-pekka.vaananen@iki.fi> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210920191305.11676-1-pekka.vaananen@iki.fi> References: <20210920191305.11676-1-pekka.vaananen@iki.fi> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avcodec/vqavideo: Decode 15-bit VQA3 files X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: =?utf-8?b?UGVra2EgVsOkw6Ruw6RuZW4=?= Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 2/TeSNfC7pt8 Adds support for 15-bit VQA3 videos used in Westwood Studios' games. Signed-off-by: Pekka Väänänen --- libavcodec/vqavideo.c | 279 +++++++++++++++++++++++++++++++++---- libavformat/westwood_vqa.c | 12 +- 2 files changed, 262 insertions(+), 29 deletions(-) diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c index 12698dc2e8..e9db6b80a5 100644 --- a/libavcodec/vqavideo.c +++ b/libavcodec/vqavideo.c @@ -1,6 +1,7 @@ /* * Westwood Studios VQA Video Decoder - * Copyright (C) 2003 The FFmpeg project + * Copyright (c) 2003 Mike Melanson + * Copyright (c) 2021 Pekka Väänänen * * This file is part of FFmpeg. * @@ -61,6 +62,11 @@ * 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. + * + * 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 @@ -81,7 +87,7 @@ #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 MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4 * sizeof(uint16_t)) #define CBF0_TAG MKBETAG('C', 'B', 'F', '0') #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z') @@ -90,6 +96,8 @@ #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 VPTR_TAG MKBETAG('V', 'P', 'T', 'R') +#define VPRZ_TAG MKBETAG('V', 'P', 'R', 'Z') typedef struct VqaContext { @@ -104,9 +112,12 @@ typedef struct VqaContext { int vector_height; /* height of individual vector */ int vqa_version; /* this should be either 1, 2 or 3 */ - unsigned char *codebook; /* the current codebook */ + uint16_t *framebuffer; /* current frame's pixels for 15-bit videos */ + int framebuffer_size; + + unsigned char *codebook; /* the current codebook */ int codebook_size; - unsigned char *next_codebook_buffer; /* accumulator for next codebook */ + unsigned char *next_codebook_buffer; /* accumulator for next codebook */ int next_codebook_buffer_index; unsigned char *decode_buffer; @@ -115,16 +126,15 @@ typedef struct VqaContext { /* number of frames to go before replacing codebook */ int partial_countdown; int partial_count; - } VqaContext; static av_cold int vqa_decode_init(AVCodecContext *avctx) { VqaContext *s = avctx->priv_data; int i, j, codebook_index, ret; + int colors; s->avctx = avctx; - avctx->pix_fmt = AV_PIX_FMT_PAL8; /* make sure the extradata made it */ if (s->avctx->extradata_size != VQA_HEADER_SIZE) { @@ -134,17 +144,12 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx) /* load up the VQA parameters from the header */ s->vqa_version = s->avctx->extradata[0]; - switch (s->vqa_version) { - case 1: - case 2: - break; - case 3: - avpriv_report_missing_feature(avctx, "VQA Version %d", s->vqa_version); - return AVERROR_PATCHWELCOME; - default: + + if (s->vqa_version < 1 || s->vqa_version > 3) { 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->height = AV_RL16(&s->avctx->extradata[8]); if ((ret = ff_set_dimensions(avctx, s->width, s->height)) < 0) { @@ -155,6 +160,14 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx) s->vector_height = s->avctx->extradata[11]; 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 */ if ((s->vector_width != 4) || ((s->vector_height != 2) && (s->vector_height != 4))) { @@ -167,6 +180,12 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } + /* allocate the framebuffer */ + s->framebuffer_size = s->width * s->height * sizeof(s->framebuffer[0]); + s->framebuffer = av_mallocz(s->framebuffer_size); + if (!s->framebuffer) + return AVERROR(ENOMEM); + /* allocate codebooks */ s->codebook_size = MAX_CODEBOOK_SIZE; s->codebook = av_malloc(s->codebook_size); @@ -225,6 +244,7 @@ static int decode_format80(VqaContext *s, int src_size, int src_pos; unsigned char color; int i; + int relative = 0; 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", @@ -232,6 +252,13 @@ static int decode_format80(VqaContext *s, int src_size, 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); while (bytestream2_tell(&s->gb) - start < src_size) { opcode = bytestream2_get_byte(&s->gb); @@ -251,7 +278,9 @@ static int decode_format80(VqaContext *s, int src_size, count = 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_COPY(src_pos); for (i = 0; i < count; i++) @@ -271,7 +300,9 @@ static int decode_format80(VqaContext *s, int src_size, count = (opcode & 0x3F) + 3; 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_COPY(src_pos); for (i = 0; i < count; i++) @@ -313,7 +344,7 @@ static int decode_format80(VqaContext *s, int src_size, 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_size; @@ -512,9 +543,8 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame) break; case 3: -/* not implemented yet */ - lines = 0; - break; + av_log(s->avctx, AV_LOG_ERROR, "VQA3 shouldn't have a color palette"); + return AVERROR_INVALIDDATA; } while (lines--) { @@ -596,6 +626,180 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame) 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; + + 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 = *(uint16_t*)stream; + int type; + + stream += 2; + 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); + uint16_t* vectordata = (uint16_t*)&s->codebook[vector_index * bytes_per_vector]; + + if (vector_index >= MAX_VECTORS) + return AVERROR_INVALIDDATA; + + for (int y = 0; y < s->vector_height; y++) { + for (int x = 0; x < 4; x++) { + s->framebuffer[(y_pos + y) * s->width + x_pos + x] = *vectordata++; + } + } + + /* we might want to read the next block index from stream */ + if ((type == 2) && count > 0) { + vector_index = *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, void *data, int *got_frame, AVPacket *avpkt) @@ -603,19 +807,37 @@ static int vqa_decode_frame(AVCodecContext *avctx, VqaContext *s = avctx->priv_data; AVFrame *frame = data; int res; + unsigned char* pixels; if ((res = ff_get_buffer(avctx, frame, 0)) < 0) return res; bytestream2_init(&s->gb, avpkt->data, avpkt->size); - if ((res = vqa_decode_chunk(s, frame)) < 0) - return res; - /* make the palette available on the way out */ - memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4); - frame->palette_has_changed = 1; + if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { + if ((res = vqa_decode_frame_pal8(s, frame)) < 0) + return res; + + /* make the palette available on the way out */ + memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4); + frame->palette_has_changed = 1; + } else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) { + if ((res = vqa_decode_frame_hicolor(s, frame)) < 0) + return res; + + pixels = frame->data[0]; + + /* copy our internal framebuffer to the frame */ + for (int y = 0; y < s->height; y++) { + memcpy(pixels, &s->framebuffer[y * s->width], s->width * sizeof(s->framebuffer[0])); + pixels += frame->linesize[0]; + } + } else { + av_log(s->avctx, AV_LOG_ERROR, "unsupported pixel format\n"); + return AVERROR_BUG; + } - *got_frame = 1; + *got_frame = 1; /* report that the buffer was completely consumed */ return avpkt->size; @@ -625,6 +847,7 @@ static av_cold int vqa_decode_end(AVCodecContext *avctx) { VqaContext *s = avctx->priv_data; + av_freep(&s->framebuffer); av_freep(&s->codebook); av_freep(&s->next_codebook_buffer); av_freep(&s->decode_buffer); @@ -633,7 +856,7 @@ static av_cold int vqa_decode_end(AVCodecContext *avctx) } static const AVCodecDefault vqa_defaults[] = { - { "max_pixels", "320*240" }, + { "max_pixels", "640*480" }, { NULL }, }; diff --git a/libavformat/westwood_vqa.c b/libavformat/westwood_vqa.c index 587626ea67..1a516bdba2 100644 --- a/libavformat/westwood_vqa.c +++ b/libavformat/westwood_vqa.c @@ -47,10 +47,14 @@ #define CINF_TAG MKBETAG('C', 'I', 'N', 'F') #define CINH_TAG MKBETAG('C', 'I', 'N', 'H') #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 PINH_TAG MKBETAG('P', 'I', 'N', 'H') #define PIND_TAG MKBETAG('P', 'I', 'N', 'D') #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_PREAMBLE_SIZE 8 @@ -142,11 +146,14 @@ static int wsvqa_read_header(AVFormatContext *s) case CINF_TAG: case CINH_TAG: case CIND_TAG: + case LINF_TAG: case PINF_TAG: case PINH_TAG: case PIND_TAG: case FINF_TAG: case CMDS_TAG: + case VIEW_TAG: + case ZBUF_TAG: break; default: @@ -287,8 +294,11 @@ static int wsvqa_read_packet(AVFormatContext *s, return ret; } else { - switch(chunk_type){ + switch(chunk_type) { case CMDS_TAG: + case SN2J_TAG: + case VIEW_TAG: + case ZBUF_TAG: break; default: av_log(s, AV_LOG_INFO, "Skipping unknown chunk %s\n",