[PATCH] Simplify vqa_decode_chunk

Adam Iglewski adam.iglewski
Thu May 7 00:38:11 CEST 2009


---
 libavcodec/vqavideo.c |  383 ++++++++++++++++++-------------------------------
 1 files changed, 139 insertions(+), 244 deletions(-)

diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c
index 3de8d88..48f0e10 100644
--- a/libavcodec/vqavideo.c
+++ b/libavcodec/vqavideo.c
@@ -121,6 +121,7 @@ typedef struct VqaContext {
     int codebook_size;
     unsigned char *next_codebook_buffer;  /* accumulator for next codebook */
     int next_codebook_buffer_index;
+    int is_codebook;
 
     unsigned char *decode_buffer;
     int decode_buffer_size;
@@ -188,6 +189,7 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
                 s->codebook[codebook_index++] = i;
     }
     s->next_codebook_buffer_index = 0;
+    s->is_codebook = 0;
 
     /* allocate decode buffer */
     s->decode_buffer_size = (s->width / s->vector_width) *
@@ -276,7 +278,7 @@ static inline void vqa_copy_hc_block(uint16_t *pixels,int stride,const uint16_t
     }
 }
 
-static void vqa_decode_hc_video_chunk(VqaContext *s,const unsigned char *src,unsigned int src_size)
+static void vqa_decode_hc_video_frame(VqaContext *s,const unsigned char *src,unsigned int src_size)
 {
     int block_x, block_y;          /* block width and height iterators */
     int blocks_wide, blocks_high;  /* width and height in 4x4|2 blocks */
@@ -346,185 +348,30 @@ static void vqa_decode_hc_video_chunk(VqaContext *s,const unsigned char *src,uns
     }
 }
 
-static void vqa_decode_chunk(VqaContext *s)
+static void vqa_decode_pal8_video_frame(VqaContext *s,const unsigned char *src,unsigned int src_size)
 {
-    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;
-
-    int cbf0_chunk = -1;
-    int cbfz_chunk = -1;
-    int cbp0_chunk = -1;
-    int cbpz_chunk = -1;
-    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;
-    int pixel_ptr;
-    int vector_index = 0;
-    int lobyte = 0;
-    int hibyte = 0;
-    int lobytes = 0;
-    int hibytes = s->decode_buffer_size / 2;
-
-    /* first, traverse through the frame and find the subchunks */
-    while (index < s->size) {
-
-        chunk_type = AV_RB32(&s->buf[index]);
-        chunk_size = AV_RB32(&s->buf[index + 4]);
-
-        switch (chunk_type) {
-
-        case CBF0_TAG:
-            cbf0_chunk = index;
-            break;
-
-        case CBFZ_TAG:
-            cbfz_chunk = index;
-            break;
-
-        case CBP0_TAG:
-            cbp0_chunk = index;
-            break;
-
-        case CBPZ_TAG:
-            cbpz_chunk = index;
-            break;
-
-        case CPL0_TAG:
-            cpl0_chunk = index;
-            break;
-
-        case CPLZ_TAG:
-            cplz_chunk = index;
-            break;
-
-        case VPTZ_TAG:
-            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, "  VQA video: Found unknown chunk type: %c%c%c%c (%08X)\n",
-            (chunk_type >> 24) & 0xFF,
-            (chunk_type >> 16) & 0xFF,
-            (chunk_type >>  8) & 0xFF,
-            (chunk_type >>  0) & 0xFF,
-            chunk_type);
-            break;
-        }
-
-        byte_skip = chunk_size & 0x01;
-        index += (CHUNK_PREAMBLE_SIZE + chunk_size + byte_skip);
-    }
-
-    /* next, deal with the palette */
-    if ((cpl0_chunk != -1) && (cplz_chunk != -1)) {
-
-        /* a chunk should not have both chunk types */
-        av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: found both CPL0 and CPLZ chunks\n");
-        return;
-    }
-
-    /* decompress the palette chunk */
-    if (cplz_chunk != -1) {
-
-/* yet to be handled */
-
-    }
-
-    /* convert the RGB palette into the machine's endian format */
-    if (cpl0_chunk != -1) {
-
-        chunk_size = AV_RB32(&s->buf[cpl0_chunk + 4]);
-        /* sanity check the palette size */
-        if (chunk_size / 3 > 256) {
-            av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: found a palette chunk with %d colors\n",
-                chunk_size / 3);
-            return;
-        }
-        cpl0_chunk += CHUNK_PREAMBLE_SIZE;
-        for (i = 0; i < chunk_size / 3; i++) {
-            /* scale by 4 to transform 6-bit palette -> 8-bit */
-            r = s->buf[cpl0_chunk++] * 4;
-            g = s->buf[cpl0_chunk++] * 4;
-            b = s->buf[cpl0_chunk++] * 4;
-            s->palette[i] = (r << 16) | (g << 8) | (b);
-        }
-    }
-
-    /* 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, "  VQA video: problem: found both CBF0 and CBFZ chunks\n");
-        return;
-    }
-
-    /* decompress the full codebook chunk */
-    if (cbfz_chunk != -1) {
-
-        chunk_size = AV_RB32(&s->buf[cbfz_chunk + 4]);
-        cbfz_chunk += CHUNK_PREAMBLE_SIZE;
-        decode_format80(&s->buf[cbfz_chunk], chunk_size,
-            s->codebook, s->codebook_size, 0);
-    }
-
-    /* copy a full codebook */
-    if (cbf0_chunk != -1) {
-
-        chunk_size = AV_RB32(&s->buf[cbf0_chunk + 4]);
-        /* sanity check the full codebook size */
-        if (chunk_size > MAX_CODEBOOK_SIZE) {
-            av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: CBF0 chunk too large (0x%X bytes)\n",
-                chunk_size);
-            return;
-        }
-        cbf0_chunk += CHUNK_PREAMBLE_SIZE;
-
-        memcpy(s->codebook, &s->buf[cbf0_chunk], chunk_size);
-    }
-
-    /* decode the frame */
-    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, "  VQA video: problem: no VPTZ or VPTR or VPRZ chunk found\n");
-        return;
-    }
+    int lines;
+    int vector_index;
+    int index_shift;
 
-    if (vptz_chunk != -1) {
+    unsigned char *pixels, *frame_end;
+    const unsigned char *mid_src = src + (src_size>>1);
+    unsigned int *codebook = (unsigned int *)s->codebook;
 
-    chunk_size = AV_RB32(&s->buf[vptz_chunk + 4]);
-    vptz_chunk += CHUNK_PREAMBLE_SIZE;
-    decode_format80(&s->buf[vptz_chunk], chunk_size,
-        s->decode_buffer, s->decode_buffer_size, 1);
+    frame_end = s->frame.data[0] + s->height * s->frame.linesize[0] + s->width;
 
-    /* render the final PAL8 frame */
     if (s->vector_height == 4)
         index_shift = 4;
     else
         index_shift = 3;
+
     for (y = 0; y < s->frame.linesize[0] * s->height;
         y += s->frame.linesize[0] * s->vector_height) {
 
-        for (x = y; x < y + s->width; x += 4, lobytes++, hibytes++) {
-            pixel_ptr = x;
+        for (x = y; x < y + s->width; x += 4) {
+            pixels = s->frame.data[0] + x;
+            lines = s->vector_height;
 
             /* get the vector index, the method for which varies according to
              * VQA file version */
@@ -533,116 +380,164 @@ static void vqa_decode_chunk(VqaContext *s)
             case 1:
 /* still need sample media for this case (only one game, "Legend of
  * Kyrandia III : Malcolm's Revenge", is known to use this version) */
-                lobyte = s->decode_buffer[lobytes * 2];
-                hibyte = s->decode_buffer[(lobytes * 2) + 1];
-                vector_index = ((hibyte << 8) | lobyte) >> 3;
-                vector_index <<= index_shift;
-                lines = s->vector_height;
+
+                vector_index = bytestream_get_le16(&src);
+
                 /* uniform color fill - a quick hack */
-                if (hibyte == 0xFF) {
-                    while (lines--) {
-                        s->frame.data[0][pixel_ptr + 0] = 255 - lobyte;
-                        s->frame.data[0][pixel_ptr + 1] = 255 - lobyte;
-                        s->frame.data[0][pixel_ptr + 2] = 255 - lobyte;
-                        s->frame.data[0][pixel_ptr + 3] = 255 - lobyte;
-                        pixel_ptr += s->frame.linesize[0];
+                if((vector_index & 0xff00) == 0xff00) {
+                    while(lines--) {
+                        memset(pixels,255-(vector_index & 0x00ff),4);
+                        pixels += s->frame.linesize[0];
                     }
-                    lines=0;
+                    continue;
                 }
+                vector_index >>= 3;
                 break;
 
             case 2:
-                lobyte = s->decode_buffer[lobytes];
-                hibyte = s->decode_buffer[hibytes];
-                vector_index = (hibyte << 8) | lobyte;
-                vector_index <<= index_shift;
-                lines = s->vector_height;
-                break;
-
-            case 3:
-/* not implemented yet */
-                lines = 0;
+                vector_index = (*mid_src++ << 8) | *src++;
                 break;
             }
 
+            codebook = (unsigned int *) (s->codebook + (vector_index << index_shift));
             while (lines--) {
-                s->frame.data[0][pixel_ptr + 0] = s->codebook[vector_index++];
-                s->frame.data[0][pixel_ptr + 1] = s->codebook[vector_index++];
-                s->frame.data[0][pixel_ptr + 2] = s->codebook[vector_index++];
-                s->frame.data[0][pixel_ptr + 3] = s->codebook[vector_index++];
-                pixel_ptr += s->frame.linesize[0];
+                *(unsigned int *) pixels = *codebook++;
+                pixels += s->frame.linesize[0];
             }
         }
     }
-    }
+}
 
-    /* handle partial codebook */
-    if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
-        /* a chunk should not have both chunk types */
-        av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: found both CBP0 and CBPZ chunks\n");
-        return;
+static const unsigned char* vqa_get_chunk(unsigned int chunk_type, const unsigned char *buff,
+                                     unsigned int buff_size,unsigned int *chunk_size)
+{
+    const unsigned char *buff_end = buff + buff_size;
+    unsigned int curr_chunk_type;
+    unsigned int curr_chunk_size;
+
+    while(buff + CHUNK_PREAMBLE_SIZE < buff_end) {
+        curr_chunk_type = bytestream_get_be32(&buff);
+        curr_chunk_size = bytestream_get_be32(&buff);
+        if(chunk_type == curr_chunk_type) {
+            if(curr_chunk_size + buff > buff_end) {
+                av_log(NULL, AV_LOG_ERROR, "  VQA video: problem: chunk exceeded packet size\n");
+                return 0;
+            }
+            *chunk_size = curr_chunk_size;
+            return buff;
+        }
+        buff += curr_chunk_size + (curr_chunk_size & 0x01);
     }
 
-    if (cbp0_chunk != -1) {
-
-        chunk_size = AV_RB32(&s->buf[cbp0_chunk + 4]);
-        cbp0_chunk += CHUNK_PREAMBLE_SIZE;
+    return 0;
+}
 
-        /* accumulate partial codebook */
-        memcpy(&s->next_codebook_buffer[s->next_codebook_buffer_index],
-            &s->buf[cbp0_chunk], chunk_size);
-        s->next_codebook_buffer_index += chunk_size;
+static void vqa_join_partial_codebook(VqaContext *s,unsigned int chunk_type,const unsigned char *chunk,
+                                       unsigned int chunk_size)
+{
+    /* accumulate partial codebook */
+    memcpy(&s->next_codebook_buffer[s->next_codebook_buffer_index],
+        chunk, chunk_size);
+    s->next_codebook_buffer_index += chunk_size;
 
-        s->partial_countdown--;
-        if (s->partial_countdown == 0) {
+    s->partial_countdown--;
+    if (!s->partial_countdown) {
 
-            /* time to replace codebook */
+        /* time to replace codebook */
+        if(chunk_type == CBP0_TAG)
             memcpy(s->codebook, s->next_codebook_buffer,
-                s->next_codebook_buffer_index);
+                    s->next_codebook_buffer_index);
+        else
+            decode_format80(s->next_codebook_buffer,
+                s->next_codebook_buffer_index,
+                s->codebook, s->codebook_size, 0);
 
-            /* reset accounting */
-            s->next_codebook_buffer_index = 0;
-            s->partial_countdown = s->partial_count;
-        }
+        /* reset accounting */
+        s->next_codebook_buffer_index = 0;
+        s->partial_countdown = s->partial_count;
+        s->is_codebook = 1;
     }
+}
 
-    if (cbpz_chunk != -1) {
-
-        chunk_size = AV_RB32(&s->buf[cbpz_chunk + 4]);
-        cbpz_chunk += CHUNK_PREAMBLE_SIZE;
+static void vqa_decode_chunk(VqaContext *s)
+{
+    int i;
+    const unsigned char *current_chunk;
+    unsigned int current_chunk_size;
 
-        /* accumulate partial codebook */
-        memcpy(&s->next_codebook_buffer[s->next_codebook_buffer_index],
-            &s->buf[cbpz_chunk], chunk_size);
-        s->next_codebook_buffer_index += chunk_size;
+    /* convert the RGB palette into the machine's endian format */
+    current_chunk = vqa_get_chunk(CPL0_TAG,s->buf,s->size,&current_chunk_size);
+    if (current_chunk) {
 
-        s->partial_countdown--;
-        if (s->partial_countdown == 0) {
+        /* sanity check the palette size */
+        if (current_chunk_size / 3 > 256) {
+            av_log(s->avctx, AV_LOG_ERROR, "  VQA video: problem: found a palette chunk with %d colors\n",
+                current_chunk_size / 3);
+            return;
+        }
+        for (i = 0; i < current_chunk_size / 3; i++) {
+            /* scale by 4 to transform 6-bit palette -> 8-bit */
+            s->palette[i]  = *current_chunk++ << 18;
+            s->palette[i] |= *current_chunk++ << 10;
+            s->palette[i] |= *current_chunk++ <<  2;
+        }
+    }
 
-            /* decompress codebook */
-            decode_format80(s->next_codebook_buffer,
-                s->next_codebook_buffer_index,
-                s->codebook, s->codebook_size, 0);
+    /* copy a full codebook */
+    current_chunk = vqa_get_chunk(CBF0_TAG,s->buf,s->size,&current_chunk_size);
+    if (current_chunk) {
 
-            /* reset accounting */
-            s->next_codebook_buffer_index = 0;
-            s->partial_countdown = s->partial_count;
+        /* sanity check the full codebook size */
+        if (current_chunk_size > MAX_CODEBOOK_SIZE) {
+            av_log(s->avctx, AV_LOG_ERROR, "  problem: CBF0 chunk too large (0x%X bytes)\n",
+                current_chunk_size);
+            return;
         }
+        memcpy(s->codebook, current_chunk, current_chunk_size);
+        s->is_codebook = 1;
+    }
+
+    /* decompress the full codebook chunk */
+    current_chunk = vqa_get_chunk(CBFZ_TAG,s->buf,s->size,&current_chunk_size);
+    if (current_chunk) {
+        decode_format80(current_chunk, current_chunk_size,
+            s->codebook, s->codebook_size, 0);
+        s->is_codebook = 1;
+    }
+
+    if(!s->is_codebook) {
+        av_log(s->avctx, AV_LOG_ERROR, "  problem: no codebook available for decoding frame data\n");
+        return;
     }
 
-    if(vptr_chunk != -1) {
-        chunk_size = AV_RB32(&s->buf[vptr_chunk + 4]);
-        vptr_chunk += CHUNK_PREAMBLE_SIZE;
-        vqa_decode_hc_video_chunk(s,&s->buf[vptr_chunk],chunk_size);
+    /* decode the PAL frame */
+    current_chunk = vqa_get_chunk(VPTZ_TAG,s->buf,s->size,&current_chunk_size);
+    if (current_chunk) {
+        decode_format80(current_chunk, current_chunk_size,
+            s->decode_buffer, s->decode_buffer_size, 1);
+        vqa_decode_pal8_video_frame(s,s->decode_buffer,s->decode_buffer_size);
     }
 
-    if(vprz_chunk != -1) {
-        chunk_size = AV_RB32(&s->buf[vprz_chunk + 4]);
-        vprz_chunk += CHUNK_PREAMBLE_SIZE;
-        decode_format80(&s->buf[vprz_chunk], chunk_size,
+    /* decode the 16bit frame */
+    current_chunk = vqa_get_chunk(VPTR_TAG,s->buf,s->size,&current_chunk_size);
+    if(current_chunk)
+        vqa_decode_hc_video_frame(s,current_chunk,current_chunk_size);
+
+    current_chunk = vqa_get_chunk(VPRZ_TAG,s->buf,s->size,&current_chunk_size);
+    if(current_chunk) {
+        decode_format80(current_chunk, current_chunk_size,
             s->decode_buffer, s->decode_buffer_size, 0);
-        vqa_decode_hc_video_chunk(s,s->decode_buffer,s->decode_buffer_size);
+        vqa_decode_hc_video_frame(s,s->decode_buffer,s->decode_buffer_size);
     }
+
+    /* handle partial codebook */
+    current_chunk = vqa_get_chunk(CBP0_TAG,s->buf,s->size,&current_chunk_size);
+    if (current_chunk)
+        vqa_join_partial_codebook(s,CBP0_TAG,current_chunk,current_chunk_size);
+
+    current_chunk = vqa_get_chunk(CBPZ_TAG,s->buf,s->size,&current_chunk_size);
+    if (current_chunk)
+        vqa_join_partial_codebook(s,CBPZ_TAG,current_chunk,current_chunk_size);
 }
 
 static int vqa_decode_frame(AVCodecContext *avctx,
-- 
1.6.0.4


--------------010706080102070000040602--



More information about the ffmpeg-devel mailing list