[PATCH] Add 16 bit video decoding
Adam Iglewski none
szwagros
Wed May 6 22:14:30 CEST 2009
---
libavcodec/vqavideo.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 138 insertions(+), 3 deletions(-)
diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c
index 5026989..da2ff8f 100644
--- a/libavcodec/vqavideo.c
+++ b/libavcodec/vqavideo.c
@@ -70,6 +70,7 @@
#include "libavutil/intreadwrite.h"
#include "avcodec.h"
+#include "bytestream.h"
#define PALETTE_COUNT 256
#define VQA_HEADER_SIZE 0x2A
@@ -89,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')
#define VQA_DEBUG 0
@@ -135,7 +138,6 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
int i, j, codebook_index;
s->avctx = avctx;
- avctx->pix_fmt = PIX_FMT_PAL8;
/* make sure the extradata made it */
if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
@@ -156,6 +158,11 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
s->vector_height = vqa_header[11];
s->partial_count = s->partial_countdown = vqa_header[13];
+ if(!AV_RL16(&vqa_header[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))) {
@@ -205,11 +212,17 @@ static void decode_format80(const unsigned char *src, int src_size,
int src_index = 0;
int dest_index = 0;
+ int new_format = 0;
int count;
int src_pos;
unsigned char color;
int i;
+ if (!src[src_index] || src_size > 0xffff) {
+ new_format = 1;
+ src_index++;
+ }
+
while (src_index < src_size) {
vqa_debug(" opcode %02X: ", src[src_index]);
@@ -230,6 +243,8 @@ static void decode_format80(const unsigned char *src, int src_size,
count = AV_RL16(&src[src_index]);
src_index += 2;
src_pos = AV_RL16(&src[src_index]);
+ if(new_format)
+ src_pos = dest_index-src_pos;
src_index += 2;
vqa_debug("(1) copy %X bytes from absolute pos %X\n", count, src_pos);
CHECK_COUNT();
@@ -252,6 +267,8 @@ static void decode_format80(const unsigned char *src, int src_size,
count = (src[src_index++] & 0x3F) + 3;
src_pos = AV_RL16(&src[src_index]);
+ if(new_format)
+ src_pos = dest_index-src_pos;
src_index += 2;
vqa_debug("(3) copy %X bytes from absolute pos %X\n", count, src_pos);
CHECK_COUNT();
@@ -291,6 +308,86 @@ static void decode_format80(const unsigned char *src, int src_size,
dest_index, dest_size);
}
+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)
+{
+ 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 = s->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 *)s->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 *)s->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 void vqa_decode_chunk(VqaContext *s)
{
unsigned int chunk_type;
@@ -308,6 +405,8 @@ static void vqa_decode_chunk(VqaContext *s)
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;
@@ -354,6 +453,14 @@ static void vqa_decode_chunk(VqaContext *s)
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,
@@ -436,13 +543,15 @@ static void vqa_decode_chunk(VqaContext *s)
}
/* 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, " VQA video: problem: no VPTZ chunk found\n");
+ av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: no VPTZ or VPTR or VPRZ chunk found\n");
return;
}
+ if (vptz_chunk != -1) {
+
chunk_size = AV_RB32(&s->buf[vptz_chunk + 4]);
vptz_chunk += CHUNK_PREAMBLE_SIZE;
decode_format80(&s->buf[vptz_chunk], chunk_size,
@@ -507,6 +616,7 @@ static void vqa_decode_chunk(VqaContext *s)
}
}
}
+ }
/* handle partial codebook */
if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
@@ -561,6 +671,20 @@ static void vqa_decode_chunk(VqaContext *s)
s->partial_countdown = s->partial_count;
}
}
+
+ 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);
+ }
+
+ 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,
+ s->decode_buffer, s->decode_buffer_size, 0);
+ vqa_decode_hc_video_chunk(s,s->decode_buffer,s->decode_buffer_size);
+ }
}
static int vqa_decode_frame(AVCodecContext *avctx,
@@ -574,6 +698,7 @@ static int vqa_decode_frame(AVCodecContext *avctx,
s->buf = buf;
s->size = buf_size;
+ if (s->avctx->pix_fmt == PIX_FMT_PAL8) {
if (s->frame.data[0])
avctx->release_buffer(avctx, &s->frame);
@@ -581,12 +706,22 @@ static int vqa_decode_frame(AVCodecContext *avctx,
av_log(s->avctx, AV_LOG_ERROR, " VQA Video: get_buffer() failed\n");
return -1;
}
+ } else {
+ s->frame.reference = 1;
+ s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
+ if (avctx->reget_buffer(avctx, &s->frame)) {
+ av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ return -1;
+ }
+ }
vqa_decode_chunk(s);
+ if (s->avctx->pix_fmt == PIX_FMT_PAL8) {
/* make the palette available on the way out */
memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
s->frame.palette_has_changed = 1;
+ }
*data_size = sizeof(AVFrame);
*(AVFrame*)data = s->frame;
--
1.6.0.4
--------------010706080102070000040602
Content-Type: text/x-diff;
name="0002-Add-IMA_WS_V3-codec-id.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="0002-Add-IMA_WS_V3-codec-id.patch"
More information about the ffmpeg-devel
mailing list