[FFmpeg-devel] [PATCH] Unfinished GSoC qual task (16bit VQA Video Decoder)
Michael Niedermayer
michaelni
Sat Apr 25 19:20:45 CEST 2009
On Sat, Apr 25, 2009 at 12:46:24AM +0200, Adam Iglewski wrote:
> Hi,
>
> I was tracking (I really wanted to see videos from BladeRunner again :))
> the progress of this task and it looks like The Deep Explorer finally gave
> up. I had some spare time so I thought I will give a try. So here it is.
>
> I'm sending 3 patches:
>
> add_vqa_hc - adds decoding of HC video chunks. I'm not sure about parts
> that I added in vqa_decode_frame function. I don't know well
> ffmpeg internals so I based my changes on msvideo1 decoder.
>
> mod_westwood_dmux - modifies demuxer to recognize new chunks in hc files
>
> fix_adpcm_ws - fixes decoding of stereo audio.
>
> Non patched ffmpeg plays distorted sound on files with 2 channels.
> Description of SND2 chunk
>
> http://wiki.multimedia.cx/index.php?title=VQA#SND2_chunk
>
> says that in stereo files first half of chunk is for left channel and
> second half for right channel but the code doesn't match the
> description. But code for decoding nibbles for codec with id
> CODEC_ID_ADPCM_4XM does. So I just replaced relevant parts and now it
> plays fine but there is slight desync between video and audio when
> playing files in ffplay. Any hints how to fix this?
>
> Adam
>
> --- ffmpeg/libavcodec/vqavideo.c 2009-04-20 20:37:46.000000000 +0200
> +++ ffmpeg_work/libavcodec/vqavideo.c 2009-04-24 22:54:09.000000000 +0200
> @@ -89,6 +89,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 +137,6 @@ static av_cold int vqa_decode_init(AVCod
> 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 +157,11 @@ static av_cold int vqa_decode_init(AVCod
> 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;
> +
inconsistent indention
> /* the vector dimensions have to meet very stringent requirements */
> if ((s->vector_width != 4) ||
> ((s->vector_height != 2) && (s->vector_height != 4))) {
> @@ -205,11 +211,17 @@ static void decode_format80(const unsign
>
> 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)) {
superflous ()
> + new_format = 1;
> + src_index++;
> + }
> +
> while (src_index < src_size) {
>
> vqa_debug(" opcode %02X: ", src[src_index]);
> @@ -230,6 +242,8 @@ static void decode_format80(const unsign
> 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 +266,8 @@ static void decode_format80(const unsign
>
> 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();
looks like code duplication (this should be fixed in a seperate patch)
> @@ -291,6 +307,124 @@ static void decode_format80(const unsign
> dest_index, dest_size);
> }
>
> +static inline void vqa_copy_hc_block(unsigned short *pixels,int pixel_ptr,int stride,unsigned short *codebook,
> + int vector_index,int block_h)
> +{
> + int pixel_y;
> + for (pixel_y = 0; pixel_y < block_h; pixel_y++) {
> + pixels[pixel_ptr] = codebook[vector_index++];
> + pixels[pixel_ptr+1] = codebook[vector_index++];
> + pixels[pixel_ptr+2] = codebook[vector_index++];
> + pixels[pixel_ptr+3] = codebook[vector_index++];
> + pixel_ptr += stride;
> + }
> +}
vector_index is redundant, so is pixel_ptr
> +
> +static void vqa_decode_hc_video_chunk(VqaContext *s,const unsigned char *src,unsigned int src_ptr,unsigned int src_size)
> +{
> + int pixel_ptr;
> + int total_blocks;
> + int block_x, block_y; /* block width and height iterators */
> + int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
> + int block_inc;
> + int index_shift;
> + int i;
> +
> + /* decoding parameters */
> + int blocks_done;
> + unsigned short *pixels = (unsigned short *)s->frame.data[0];
> + unsigned short *codebook = (unsigned short *)s->codebook;
> + int stride = s->frame.linesize[0] / 2;
> +
> + int vptr_action_code;
> + int vector_index = 0;
> +
> + blocks_done = 0;
> + blocks_wide = s->width / 4;
> + blocks_high = s->height / s->vector_height;
> + total_blocks = blocks_wide * blocks_high;
> + block_inc = 4;
> +
> + if (s->vector_height == 4)
> + index_shift = 4;
> + else
> + index_shift = 3;
> +
> + block_x = block_y = 0;
> + while(total_blocks > 0) {
> +
> + pixel_ptr = ((block_y * s->vector_height) * stride)+block_x*block_inc;
superflous ()
> + vptr_action_code = AV_RL16(&src[src_ptr]);
> + src_ptr+=2;
bytestream_get_le16()
> +
> + switch(vptr_action_code & 0xe000) {
> +
> + /* Skip Count blocks. Count is (Val & 0x1fff). */
> + case 0x0000:
> + blocks_done = vptr_action_code & 0x1fff;
> + break;
> +
> + /* Write block number (Val & 0xff) Count times.
> + * Count is (((Val/256) & 0x1f)+1)*2. */
> + case 0x2000:
> + vector_index = (vptr_action_code & 0xff) << index_shift;
> + blocks_done = (((vptr_action_code>>8) & 0x1f)+1) << 1;
> +
> + for(i=0;i<blocks_done;i++) {
> + vqa_copy_hc_block(pixels,pixel_ptr,stride,codebook,
> + vector_index,s->vector_height);
> + pixel_ptr += block_inc;
> + }
> + break;
> +
> + /* Write block number (Val & 0xff) and then write Count blocks
> + * getting their indexes by reading next Count bytes from
> + * the VPTR chunk. Count is (((Val/256) & 0x1f)+1)*2. */
> + case 0x4000:
> + vector_index = (vptr_action_code & 0xff) << index_shift;
please indent the comments differerntly so the code is easier to
see / is more seperated from the comments
> + blocks_done = (((vptr_action_code>>8) & 0x1f)+1) << 1;
> +
> + vqa_copy_hc_block(pixels,pixel_ptr,stride,codebook,
> + vector_index,s->vector_height);
> + pixel_ptr += block_inc;
> +
> + for(i=0;i<blocks_done;i++) {
> + vector_index = src[src_ptr++];
> + vector_index <<= index_shift;
> + vqa_copy_hc_block(pixels,pixel_ptr,stride,codebook,
> + vector_index,s->vector_height);
> + pixel_ptr += block_inc;
> + }
> + blocks_done++;
> + break;
> +
> + /* Write block (Val & 0x1fff).*/
> + case 0x6000:
> + vector_index = (vptr_action_code & 0x1fff) << index_shift;
> + vqa_copy_hc_block(pixels,pixel_ptr,stride,codebook,
> + vector_index,s->vector_height);
> + blocks_done=1;
> + break;
> +
> + /* Write block (Val & 0x1fff) Count times.
> + * Count is the next byte from the VPTR chunk.*/
> + case 0xa000:
> + vector_index = (vptr_action_code & 0x1fff) << index_shift;
> + blocks_done = src[src_ptr++];
> +
> + for(i=0;i<blocks_done;i++) {
> + vqa_copy_hc_block(pixels,pixel_ptr,stride,codebook,
> + vector_index,s->vector_height);
> + pixel_ptr += block_inc;
> + }
looks exploitable
> + break;
> + }
> + block_y += (block_x + blocks_done) / blocks_wide;
> + block_x = (block_x + blocks_done) % blocks_wide;
> + total_blocks -= blocks_done;
> + }
> +}
> +
> static void vqa_decode_chunk(VqaContext *s)
> {
> unsigned int chunk_type;
> @@ -308,6 +442,8 @@ static void vqa_decode_chunk(VqaContext
> 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;
> @@ -353,6 +489,14 @@ static void vqa_decode_chunk(VqaContext
> case VPTZ_TAG:
> vptz_chunk = index;
> break;
> +
trailing whitespace
> + case VPTR_TAG:
> + vptr_chunk = index;
> + break;
> +
> + case VPRZ_TAG:
> + vprz_chunk = index;
> + break;
>
why are the chunks not decoded immedeatly?
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Those who are too smart to engage in politics are punished by being
governed by those who are dumber. -- Plato
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090425/c54a5732/attachment.pgp>
More information about the ffmpeg-devel
mailing list