[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