[FFmpeg-devel] [PATCH] VQA-highcolor (15 bit rgb555) decoder by Adam Iglewski
u-owvm at aetey.se
u-owvm at aetey.se
Mon Jan 13 11:28:30 CET 2014
Hello,
Adjusted to the current master:
VQA-highcolor (15 bit rgb555) decoder based on patches from June 2009
by Adam Iglewski <szwagros at szwagros-desktop.(none)>.
Hope it may make it through this time.
Regards,
Rl
-------------- next part --------------
>From 8d59d425d2a138fe08cc8295c32dbfd36a6e8423 Mon Sep 17 00:00:00 2001
From: Rl <addr-see-the-website at aetey.se>
Date: Sun, 12 Jan 2014 18:32:48 +0100
Subject: [PATCH] VQA-highcolor (15 bit rgb555) decoder based on patches from June 2009
by Adam Iglewski <szwagros at szwagros-desktop.(none)>,
adjusted for git master
2013-02-16 by Rl @ Aetey Global Technologies AB, http://www.aetey.se
2014-01-12 by Rl @ Aetey Global Technologies AB, http://www.aetey.se
---
libavcodec/vqavideo.c | 150 +++++++++++++++++++++++++++++++++++++++++---
libavformat/westwood_vqa.c | 44 ++++++++++++-
2 files changed, 184 insertions(+), 10 deletions(-)
diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c
index c34849d..9e8281f 100644
--- a/libavcodec/vqavideo.c
+++ b/libavcodec/vqavideo.c
@@ -90,6 +90,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 {
@@ -124,7 +126,6 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
int i, j, codebook_index, ret;
s->avctx = avctx;
- avctx->pix_fmt = AV_PIX_FMT_PAL8;
/* make sure the extradata made it */
if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
@@ -137,10 +138,8 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
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;
+ break;
default:
avpriv_request_sample(avctx, "VQA Version %i", s->vqa_version);
return AVERROR_PATCHWELCOME;
@@ -155,6 +154,11 @@ 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];
+ if(!AV_RL16(&s->avctx->extradata[14]))
+ avctx->pix_fmt = PIX_FMT_RGB555;
+ else
+ avctx->pix_fmt = PIX_FMT_PAL8;
+
/* the vector dimensions have to meet very stringent requirements */
if ((s->vector_width != 4) ||
((s->vector_height != 2) && (s->vector_height != 4))) {
@@ -221,16 +225,21 @@ fail:
return AVERROR_INVALIDDATA; \
}
-
static int decode_format80(VqaContext *s, int src_size,
unsigned char *dest, int dest_size, int check_size) {
int dest_index = 0;
+ int new_format = 0;
int count, opcode, start;
int src_pos;
unsigned char color;
int i;
+ if (s->vqa_version == 3 && !bytestream2_peek_byte(&s->gb)) {
+ new_format = 1;
+ bytestream2_get_byte(&s->gb); // skip the first zero byte
+ }
+
start = bytestream2_tell(&s->gb);
while (bytestream2_tell(&s->gb) - start < src_size) {
opcode = bytestream2_get_byte(&s->gb);
@@ -250,6 +259,8 @@ static int decode_format80(VqaContext *s, int src_size,
count = bytestream2_get_le16(&s->gb);
src_pos = bytestream2_get_le16(&s->gb);
+ if(new_format)
+ src_pos = dest_index-src_pos;
av_dlog(s->avctx, "(1) copy %X bytes from absolute pos %X\n", count, src_pos);
CHECK_COUNT();
CHECK_COPY(src_pos);
@@ -270,6 +281,8 @@ static int decode_format80(VqaContext *s, int src_size,
count = (opcode & 0x3F) + 3;
src_pos = bytestream2_get_le16(&s->gb);
+ if(new_format)
+ src_pos = dest_index-src_pos;
av_dlog(s->avctx, "(3) copy %X bytes from absolute pos %X\n", count, src_pos);
CHECK_COUNT();
CHECK_COPY(src_pos);
@@ -312,6 +325,88 @@ static int decode_format80(VqaContext *s, int src_size,
return 0; // let's display what we decoded anyway
}
+static inline void vqa_copy_hc_block(uint16_t *pixels, int stride,
+ const uint16_t *codebook,
+ int block_h)
+{
+ while(block_h--) {
+ memcpy(pixels,codebook,8);
+ pixels += stride;
+ codebook += 4;
+ }
+}
+
+static void vqa_decode_hc_video_chunk(VqaContext *s, const unsigned char *src,
+ unsigned int src_size, AVFrame *frame)
+{
+ int block_x, block_y; /* block width and height iterators */
+ int blocks_wide, blocks_high; /* width and height in 4x4|2 blocks */
+ int block_inc;
+ int index_shift;
+ int i;
+
+ /* decoding parameters */
+ uint16_t *pixels,*frame_end;
+ uint16_t *codebook = (uint16_t *)s->codebook;
+ int stride = frame->linesize[0] >> 1;
+
+ int type,code;
+ int vector_index = 0;
+
+ blocks_wide = s->width >> 2;
+ blocks_high = s->height / s->vector_height;
+ block_inc = 4;
+ frame_end = (uint16_t *)frame->data[0] + s->height * stride + s->width;
+
+ if (s->vector_height == 4)
+ index_shift = 4;
+ else
+ index_shift = 3;
+
+ for(block_y=0; block_y < blocks_high; block_y ++) {
+ pixels = (uint16_t *)frame->data[0] + (block_y * s->vector_height * stride);
+
+ for(block_x=0; block_x < blocks_wide; ) {
+ int blocks_done;
+ code = bytestream_get_le16(&src);
+ type = code >> 13;
+ code &= 0x1fff;
+
+ if(!type) {
+ blocks_done = code;
+ block_x += blocks_done;
+ pixels += blocks_done * block_inc;
+ continue;
+ } else if (type < 3) {
+ vector_index = (code & 0xff) << index_shift;
+ blocks_done = ((code & 0x1f00) >> 7) + 1 + type;
+ } else if (type == 3 || type == 5) {
+ vector_index = code << index_shift;
+ if (type == 3)
+ blocks_done = 1;
+ else
+ blocks_done = *src++;
+ } else {
+ av_log(s->avctx, AV_LOG_ERROR, " unknown type in VPTR chunk (%d)\n",type);
+ return;
+ }
+
+ if(pixels + s->vector_height * stride + blocks_done * block_inc > frame_end) {
+ av_log(s->avctx, AV_LOG_ERROR, " too many blocks in frame.\n");
+ return;
+ }
+
+ for(i=0; i < blocks_done; i++) {
+ if(i && (type == 2))
+ vector_index = *src++ << index_shift;
+ vqa_copy_hc_block(pixels,stride,&codebook[vector_index],s->vector_height);
+ pixels += block_inc;
+ }
+ block_x += blocks_done;
+ }
+ }
+}
+
static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
{
unsigned int chunk_type;
@@ -330,6 +425,8 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
int cpl0_chunk = -1;
int cplz_chunk = -1;
int vptz_chunk = -1;
+ int vptr_chunk = -1;
+ int vprz_chunk = -1;
int x, y;
int lines = 0;
@@ -377,6 +474,14 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
vptz_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: %c%c%c%c (%08X)\n",
(chunk_type >> 24) & 0xFF,
@@ -461,13 +566,16 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
}
/* decode the frame */
- if (vptz_chunk == -1) {
+ if ((vptz_chunk == -1) && (vptr_chunk == -1) &&
+ (vprz_chunk == -1) && (cbfz_chunk==-1)) {
- /* something is wrong if there is no VPTZ chunk */
- av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n");
+ /* something is wrong if there is no VPTZ or VPTR chunk */
+ av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ or VPTR chunk found\n");
return AVERROR_INVALIDDATA;
}
+ if (vptz_chunk != -1) {
+
bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET);
chunk_size = bytestream2_get_be32(&s->gb);
if ((res = decode_format80(s, chunk_size,
@@ -529,6 +637,7 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
}
}
}
+ }
/* handle partial codebook */
if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
@@ -596,6 +705,29 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
}
}
+ if(vptr_chunk != -1) {
+ bytestream2_seek(&s->gb, vptr_chunk, SEEK_SET);
+ chunk_size = bytestream2_get_be32(&s->gb);
+// can we use decode_buffer here?
+// can chunk_size happen to be bigger than decode_buffer_size? I don't think so
+ if (chunk_size > s->decode_buffer_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "problem: too big VPTR chunk?\n");
+ return AVERROR_INVALIDDATA;
+ }
+ bytestream2_get_buffer(&s->gb, s->decode_buffer, chunk_size);
+ vqa_decode_hc_video_chunk(s,s->decode_buffer,chunk_size, frame);
+ }
+
+ if(vprz_chunk != -1) {
+ 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, 1)) < 0)
+ return res;
+ vqa_decode_hc_video_chunk(s,s->decode_buffer,s->decode_buffer_size, frame);
+ }
+
return 0;
}
@@ -614,9 +746,11 @@ static int vqa_decode_frame(AVCodecContext *avctx,
if ((res = vqa_decode_chunk(s, frame)) < 0)
return res;
+ if (s->avctx->pix_fmt == PIX_FMT_PAL8) {
/* make the palette available on the way out */
memcpy(frame->data[1], s->palette, PALETTE_COUNT * 4);
frame->palette_has_changed = 1;
+ }
*got_frame = 1;
diff --git a/libavformat/westwood_vqa.c b/libavformat/westwood_vqa.c
index 2a988ad..383a918 100644
--- a/libavformat/westwood_vqa.c
+++ b/libavformat/westwood_vqa.c
@@ -40,6 +40,7 @@
#define SND1_TAG MKBETAG('S', 'N', 'D', '1')
#define SND2_TAG MKBETAG('S', 'N', 'D', '2')
#define VQFR_TAG MKBETAG('V', 'Q', 'F', 'R')
+#define VQFL_TAG MKBETAG('V', 'Q', 'F', 'L')
/* don't know what these tags are for, but acknowledge their existence */
#define CINF_TAG MKBETAG('C', 'I', 'N', 'F')
@@ -49,6 +50,9 @@
#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
@@ -60,6 +64,8 @@ typedef struct WsVqaDemuxContext {
int sample_rate;
int audio_stream_index;
int video_stream_index;
+ unsigned int vqfl_chunk_size;
+ unsigned char* vqfl_chunk_data;
} WsVqaDemuxContext;
static int wsvqa_probe(AVProbeData *p)
@@ -141,6 +147,8 @@ static int wsvqa_read_header(AVFormatContext *s)
case PIND_TAG:
case FINF_TAG:
case CMDS_TAG:
+ case VIEW_TAG:
+ case ZBUF_TAG:
break;
default:
@@ -153,6 +161,8 @@ static int wsvqa_read_header(AVFormatContext *s)
avio_skip(pb, chunk_size);
} while (chunk_tag != FINF_TAG);
+ wsvqa->vqfl_chunk_size=0;
+ wsvqa->vqfl_chunk_data=NULL;
return 0;
}
@@ -173,12 +183,39 @@ static int wsvqa_read_packet(AVFormatContext *s,
skip_byte = chunk_size & 0x01;
- if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
- (chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
+ if (chunk_type == VQFL_TAG) {
+
+ wsvqa->vqfl_chunk_size = chunk_size;
+ wsvqa->vqfl_chunk_data = av_mallocz(chunk_size);
+ if (!wsvqa->vqfl_chunk_data)
+ return AVERROR(ENOMEM);
+ ret = avio_read(pb, wsvqa->vqfl_chunk_data, chunk_size);
+ if (ret != chunk_size)
+ return AVERROR(EIO);
+ if (skip_byte)
+ avio_seek(pb, 1, SEEK_CUR);
+ continue;
+
+ } else if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
+ (chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
+
+ if ((chunk_type == VQFR_TAG) && wsvqa->vqfl_chunk_size) {
+ if (av_new_packet(pkt, chunk_size + wsvqa->vqfl_chunk_size))
+ return AVERROR(EIO);
+ ret = avio_read(pb, pkt->data, chunk_size);
+ if (ret != chunk_size) {
+ av_free_packet(pkt);
+ return AVERROR(EIO);
+ }
+ memcpy(pkt->data + chunk_size,wsvqa->vqfl_chunk_data,wsvqa->vqfl_chunk_size);
+ wsvqa->vqfl_chunk_size=0;
+ av_free(wsvqa->vqfl_chunk_data);
+ } else {
ret= av_get_packet(pb, pkt, chunk_size);
if (ret<0)
return AVERROR(EIO);
+ }
switch (chunk_type) {
case SND0_TAG:
@@ -249,6 +286,9 @@ static int wsvqa_read_packet(AVFormatContext *s,
} else {
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 0x%08X\n", chunk_type);
--
1.6.1
More information about the ffmpeg-devel
mailing list