[FFmpeg-devel] [PATCH] Electronic Arts TGV decoder
Michael Niedermayer
michaelni
Thu Jul 10 01:00:32 CEST 2008
On Wed, Jul 09, 2008 at 09:18:13PM +1000, pross at xvid.org wrote:
> Hi!
>
> Second video codec in the EA series.
>
> Samples: http://samples.mplayerhq.hu/game-formats/ea-tgv/
> Write-up: http://wiki.multimedia.cx/index.php?title=Electronic_Arts_TGV
[...]
> +
> +/**
> + * Unpack buffer
> + * @return 0 on success, -1 on critical buffer underflow
> + */
> +static int unpack(const uint8_t *src, const uint8_t *src_end, unsigned char *dst, int width, int stride) {
> + int size1,size2,offset;
> + int size;
> + int i;
> + int o = 0;
> +
> + if (src+2>src_end)
> + return -1;
> + if ((AV_RB16(&src[0]) & 0x0100))
> + src += 5;
> + else
> + src += 2;
> +
> + if (src+4>src_end)
> + return -1;
> + size = AV_RB24(&src[0]);
> + src += 3;
the first end check seems unneeded, and reading a byte would be enough for
the if()
> +
> + while(size>0 && src<src_end) {
> +
> + /* determine size1 and size2 */
> + if ( src[0] & 0x80 ) { // 1
> + if (src[0] & 0x40 ) { // 11
> + if ( src[0] & 0x20 ) { // 111
> + if ( src[0] >= 0xFC ) { // 111111
> + size1 = (src[0] & 3);
> + src++;
> + size2 = 0;
> + } else {
> + size1 = (((src[0] & 31) + 1) << 2);
> + src++;
> + size2 = 0;
> + }
2 of these statements can be factored out
> + } else { // 110
> + if (src+4>src_end)
> + break;
> + size1 = (src[0] & 3);
> + offset = -(((src[0] & 0x10) << 12) + (src[1] << 8) + src[2]) - 1;
> + size2 = ((src[0] & 0xC) << 6) + src[3] + 5;
> + src += 4;
> + }
> + } else { // 10
> + if (src+3>src_end)
> + break;
> + size1 = ( ( src[1] & 0xC0) >> 6 );
> + offset = -(((src[1] & 0x3F) << 8) + src[2]) - 1;
> + size2 = (src[0] & 0x3F) + 4;
> + src += 3;
> + }
> + } else { // 0
> + if (src+2>src_end)
> + break;
> + size1 = (src[0] & 3);
this occurs multiple times and can be factored out as well
and it does not appear that the src+X>src_end checks are needed except
the one below
> + offset = -( ((src[0] & 0x60) << 3) + src[1] ) - 1;
> + size2 = ((src[0] & 0x1C) >> 2) + 3;
> + src += 2;
> + }
> +
> + /* fetch strip from src */
> + if (src+size1>src_end)
> + break;
> + for (i=0; i<size1; i++)
> + dst[ CALC_LOCATION(o+i,width,stride) ] = src[i];
> + size -= size1;
> + src += size1;
> + o += size1;
> +
> + /* fetch strip within */
> + if (size2) {
> + /* offset is guarded by size2 */
> + for (i=0; i<size2; i++)
> + dst[ CALC_LOCATION(o+i,width,stride) ] = dst[ CALC_LOCATION(o+offset+i,width,stride) ];
> + size -= size2;
> + o += size2;
> + }
your code is exploitable it does not contain any checks for dst size
at all
also the divide and modulo in the innermost loop are very ugly and
slow
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * Decode inter-frame
> + * @return 0 on success, -1 on critical buffer underflow
> + */
> +static int tgv_decode_inter(TgvContext * s, const uint8_t *buf, const uint8_t *buf_end){
> + int num_mvs;
> + int num_blocks_raw;
> + int num_blocks_packed;
> + int num_blocks;
> + int vector_bits;
> + int i,j,x,y;
> + GetBitContext gb;
> + int mvbits;
> +
> + if(buf+12>buf_end)
> + return -1;
> +
> + num_mvs = AV_RL16(&buf[0]);
> + num_blocks_raw = AV_RL16(&buf[2]);
> + num_blocks_packed = AV_RL16(&buf[4]);
> + num_blocks = num_blocks_raw + num_blocks_packed;
> + vector_bits = AV_RL16(&buf[6]);
vertical align
> + buf += 12;
> +
> + /* allocate codebook buffers as neccessary */
> + if (s->mv_codebook==NULL) {
> + s->mv_codebook = av_malloc(num_mvs *2*sizeof(int));
> + s->max_num_mvs = num_mvs;
> + }else if (num_mvs > s->max_num_mvs) {
> + s->mv_codebook = av_realloc(s->mv_codebook, num_mvs*2*sizeof(int));
> + s->max_num_mvs = num_mvs;
> + }
> +
> + if (s->block_codebook==NULL) {
> + s->block_codebook = av_malloc(num_blocks*16*sizeof(unsigned char));
> + s->max_num_blocks = num_blocks;
> + }else if (num_blocks > s->max_num_blocks) {
> + s->block_codebook = av_realloc(s->block_codebook, num_blocks*16*sizeof(unsigned char));
> + s->max_num_blocks = num_blocks;
> + }
av_realloc() already does handle NULL
[...]
> + /* read uncompressed blocks */
> + for (i=0; i<num_blocks_raw; i++) {
> + for(j=0; j<16; j++)
> + s->block_codebook[i][j] = buf[j];
> + buf += 16;
> + }
memcpy() or even better access that stuff from buf if possible
[...]
> + if(chunk_type==kVGT_TAG) {
> + s->frame.key_frame = 1;
> + s->frame.pict_type = FF_I_TYPE;
> + if (unpack(buf, buf_end, s->frame.data[0], s->avctx->width, s->frame.linesize[0])<0) {
> + av_log(avctx, AV_LOG_WARNING, "truncated inter frame\n");
> + return -1;
> + }
> + }else{
> + s->frame.key_frame = 1;
> + s->frame.pict_type = FF_I_TYPE;
This doesnt look correct
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
I hate to see young programmers poisoned by the kind of thinking
Ulrich Drepper puts forward since it is simply too narrow -- Roman Shaposhnik
-------------- 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/20080710/dd514c23/attachment.pgp>
More information about the ffmpeg-devel
mailing list