[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