[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,¤t_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,¤t_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,¤t_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,¤t_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,¤t_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,¤t_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,¤t_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,¤t_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