Mercurial > libavcodec.hg
annotate eatgv.c @ 12530:63edd10ad4bc libavcodec tip
Try to fix crashes introduced by r25218
r25218 made assumptions about the existence of past reference frames that
weren't necessarily true.
| author | darkshikari |
|---|---|
| date | Tue, 28 Sep 2010 09:06:22 +0000 |
| parents | ffb3668ff7af |
| children |
| rev | line source |
|---|---|
| 7510 | 1 /* |
| 2 * Electronic Arts TGV Video Decoder | |
| 3 * Copyright (c) 2007-2008 Peter Ross | |
| 4 * | |
| 5 * This file is part of FFmpeg. | |
| 6 * | |
| 7 * FFmpeg is free software; you can redistribute it and/or | |
| 8 * modify it under the terms of the GNU Lesser General Public | |
| 9 * License as published by the Free Software Foundation; either | |
| 10 * version 2.1 of the License, or (at your option) any later version. | |
| 11 * | |
| 12 * FFmpeg is distributed in the hope that it will be useful, | |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 * Lesser General Public License for more details. | |
| 16 * | |
| 17 * You should have received a copy of the GNU Lesser General Public | |
| 18 * License along with FFmpeg; if not, write to the Free Software | |
| 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
| 20 */ | |
| 21 | |
| 22 /** | |
|
11644
7dd2a45249a9
Remove explicit filename from Doxygen @file commands.
diego
parents:
11581
diff
changeset
|
23 * @file |
| 7510 | 24 * Electronic Arts TGV Video Decoder |
| 10825 | 25 * by Peter Ross (pross@xvid.org) |
| 7510 | 26 * |
| 27 * Technical details here: | |
| 28 * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_TGV | |
| 29 */ | |
| 30 | |
| 31 #include "avcodec.h" | |
| 32 #define ALT_BITSTREAM_READER_LE | |
| 9428 | 33 #include "get_bits.h" |
| 8597 | 34 #include "libavutil/lzo.h" |
|
12372
914f484bb476
Remove use of the deprecated function avcodec_check_dimensions(), use
stefano
parents:
11644
diff
changeset
|
35 #include "libavcore/imgutils.h" |
| 7510 | 36 |
| 37 #define EA_PREAMBLE_SIZE 8 | |
| 38 #define kVGT_TAG MKTAG('k', 'V', 'G', 'T') | |
| 39 | |
| 40 typedef struct TgvContext { | |
| 41 AVCodecContext *avctx; | |
| 42 AVFrame frame; | |
| 43 AVFrame last_frame; | |
| 44 int width,height; | |
| 45 unsigned int palette[AVPALETTE_COUNT]; | |
| 46 | |
| 47 int (*mv_codebook)[2]; | |
| 48 unsigned char (*block_codebook)[16]; | |
| 49 int num_mvs; ///< current length of mv_codebook | |
| 50 int num_blocks_packed; ///< current length of block_codebook | |
| 51 } TgvContext; | |
| 52 | |
| 53 static av_cold int tgv_decode_init(AVCodecContext *avctx){ | |
| 54 TgvContext *s = avctx->priv_data; | |
| 55 s->avctx = avctx; | |
| 56 avctx->time_base = (AVRational){1, 15}; | |
| 57 avctx->pix_fmt = PIX_FMT_PAL8; | |
| 58 return 0; | |
| 59 } | |
| 60 | |
| 61 /** | |
| 62 * Unpack buffer | |
| 63 * @return 0 on success, -1 on critical buffer underflow | |
| 64 */ | |
| 65 static int unpack(const uint8_t *src, const uint8_t *src_end, unsigned char *dst, int width, int height) { | |
| 66 unsigned char *dst_end = dst + width*height; | |
|
8801
154d81241ac0
Add av_uninit macro to variable to avoid false positive warning:
diego
parents:
8718
diff
changeset
|
67 int size, size1, size2, av_uninit(offset), run; |
| 7510 | 68 unsigned char *dst_start = dst; |
| 69 | |
| 70 if (src[0] & 0x01) | |
| 71 src += 5; | |
| 72 else | |
| 73 src += 2; | |
| 74 | |
| 75 if (src+3>src_end) | |
| 76 return -1; | |
| 77 size = AV_RB24(src); | |
| 78 src += 3; | |
| 79 | |
| 80 while(size>0 && src<src_end) { | |
| 81 | |
| 82 /* determine size1 and size2 */ | |
| 83 size1 = (src[0] & 3); | |
| 84 if ( src[0] & 0x80 ) { // 1 | |
| 85 if (src[0] & 0x40 ) { // 11 | |
| 86 if ( src[0] & 0x20 ) { // 111 | |
| 87 if ( src[0] < 0xFC ) // !(111111) | |
| 88 size1 = (((src[0] & 31) + 1) << 2); | |
| 89 src++; | |
| 90 size2 = 0; | |
| 91 } else { // 110 | |
| 92 offset = ((src[0] & 0x10) << 12) + AV_RB16(&src[1]) + 1; | |
| 93 size2 = ((src[0] & 0xC) << 6) + src[3] + 5; | |
| 94 src += 4; | |
| 95 } | |
| 96 } else { // 10 | |
| 97 size1 = ( ( src[1] & 0xC0) >> 6 ); | |
| 98 offset = (AV_RB16(&src[1]) & 0x3FFF) + 1; | |
| 99 size2 = (src[0] & 0x3F) + 4; | |
| 100 src += 3; | |
| 101 } | |
| 102 } else { // 0 | |
| 103 offset = ((src[0] & 0x60) << 3) + src[1] + 1; | |
| 104 size2 = ((src[0] & 0x1C) >> 2) + 3; | |
| 105 src += 2; | |
| 106 } | |
| 107 | |
| 108 | |
| 109 /* fetch strip from src */ | |
| 110 if (size1>src_end-src) | |
| 111 break; | |
| 112 | |
| 113 if (size1>0) { | |
| 114 size -= size1; | |
| 115 run = FFMIN(size1, dst_end-dst); | |
| 116 memcpy(dst, src, run); | |
| 117 dst += run; | |
| 118 src += run; | |
| 119 } | |
| 120 | |
| 121 if (size2>0) { | |
| 122 if (dst-dst_start<offset) | |
| 123 return 0; | |
| 124 size -= size2; | |
| 125 run = FFMIN(size2, dst_end-dst); | |
| 126 av_memcpy_backptr(dst, offset, run); | |
| 127 dst += run; | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 return 0; | |
| 132 } | |
| 133 | |
| 134 /** | |
| 135 * Decode inter-frame | |
| 136 * @return 0 on success, -1 on critical buffer underflow | |
| 137 */ | |
| 138 static int tgv_decode_inter(TgvContext * s, const uint8_t *buf, const uint8_t *buf_end){ | |
| 139 unsigned char *frame0_end = s->last_frame.data[0] + s->avctx->width*s->last_frame.linesize[0]; | |
| 140 int num_mvs; | |
| 141 int num_blocks_raw; | |
| 142 int num_blocks_packed; | |
| 143 int vector_bits; | |
| 144 int i,j,x,y; | |
| 145 GetBitContext gb; | |
| 146 int mvbits; | |
| 147 const unsigned char *blocks_raw; | |
| 148 | |
| 149 if(buf+12>buf_end) | |
| 150 return -1; | |
| 151 | |
| 152 num_mvs = AV_RL16(&buf[0]); | |
| 153 num_blocks_raw = AV_RL16(&buf[2]); | |
| 154 num_blocks_packed = AV_RL16(&buf[4]); | |
| 155 vector_bits = AV_RL16(&buf[6]); | |
| 156 buf += 12; | |
| 157 | |
| 158 /* allocate codebook buffers as neccessary */ | |
| 159 if (num_mvs > s->num_mvs) { | |
| 160 s->mv_codebook = av_realloc(s->mv_codebook, num_mvs*2*sizeof(int)); | |
| 161 s->num_mvs = num_mvs; | |
| 162 } | |
| 163 | |
| 164 if (num_blocks_packed > s->num_blocks_packed) { | |
| 165 s->block_codebook = av_realloc(s->block_codebook, num_blocks_packed*16*sizeof(unsigned char)); | |
| 166 s->num_blocks_packed = num_blocks_packed; | |
| 167 } | |
| 168 | |
| 169 /* read motion vectors */ | |
| 170 mvbits = (num_mvs*2*10+31) & ~31; | |
| 171 | |
| 172 if (buf+(mvbits>>3)+16*num_blocks_raw+8*num_blocks_packed>buf_end) | |
| 173 return -1; | |
| 174 | |
| 175 init_get_bits(&gb, buf, mvbits); | |
| 176 for (i=0; i<num_mvs; i++) { | |
| 177 s->mv_codebook[i][0] = get_sbits(&gb, 10); | |
| 178 s->mv_codebook[i][1] = get_sbits(&gb, 10); | |
| 179 } | |
| 180 buf += mvbits>>3; | |
| 181 | |
| 182 /* note ptr to uncompressed blocks */ | |
| 183 blocks_raw = buf; | |
| 184 buf += num_blocks_raw*16; | |
| 185 | |
| 186 /* read compressed blocks */ | |
| 187 init_get_bits(&gb, buf, (buf_end-buf)<<3); | |
| 188 for (i=0; i<num_blocks_packed; i++) { | |
| 189 int tmp[4]; | |
| 190 for(j=0; j<4; j++) | |
| 191 tmp[j] = get_bits(&gb, 8); | |
| 192 for(j=0; j<16; j++) | |
| 193 s->block_codebook[i][15-j] = tmp[get_bits(&gb, 2)]; | |
| 194 } | |
| 195 | |
|
11303
b0cb1f7efcbc
Do not read beyond end of input in EA-TGV. This should avoid FATE test #362
vitor
parents:
10825
diff
changeset
|
196 if (get_bits_left(&gb) < vector_bits * |
|
b0cb1f7efcbc
Do not read beyond end of input in EA-TGV. This should avoid FATE test #362
vitor
parents:
10825
diff
changeset
|
197 (s->avctx->height/4) * (s->avctx->width/4)) |
|
b0cb1f7efcbc
Do not read beyond end of input in EA-TGV. This should avoid FATE test #362
vitor
parents:
10825
diff
changeset
|
198 return -1; |
|
b0cb1f7efcbc
Do not read beyond end of input in EA-TGV. This should avoid FATE test #362
vitor
parents:
10825
diff
changeset
|
199 |
| 7510 | 200 /* read vectors and build frame */ |
| 201 for(y=0; y<s->avctx->height/4; y++) | |
| 202 for(x=0; x<s->avctx->width/4; x++) { | |
| 203 unsigned int vector = get_bits(&gb, vector_bits); | |
| 204 const unsigned char *src; | |
| 205 int src_stride; | |
| 206 | |
| 207 if (vector < num_mvs) { | |
| 208 src = s->last_frame.data[0] + | |
| 209 (y*4 + s->mv_codebook[vector][1])*s->last_frame.linesize[0] + | |
| 210 x*4 + s->mv_codebook[vector][0]; | |
| 211 src_stride = s->last_frame.linesize[0]; | |
| 212 if (src+3*src_stride+3>=frame0_end) | |
| 213 continue; | |
| 214 }else{ | |
| 215 int offset = vector - num_mvs; | |
| 216 if (offset<num_blocks_raw) | |
| 217 src = blocks_raw + 16*offset; | |
| 218 else if (offset-num_blocks_raw<num_blocks_packed) | |
| 219 src = s->block_codebook[offset-num_blocks_raw]; | |
| 220 else | |
| 221 continue; | |
| 222 src_stride = 4; | |
| 223 } | |
| 224 | |
| 225 for(j=0; j<4; j++) | |
| 226 for(i=0; i<4; i++) | |
| 227 s->frame.data[0][ (y*4+j)*s->frame.linesize[0] + (x*4+i) ] = | |
| 228 src[j*src_stride + i]; | |
| 229 } | |
| 230 | |
| 231 return 0; | |
| 232 } | |
| 233 | |
| 234 /** release AVFrame buffers if allocated */ | |
| 235 static void cond_release_buffer(AVFrame *pic) | |
| 236 { | |
| 237 if (pic->data[0]) { | |
| 238 av_freep(&pic->data[0]); | |
| 239 av_free(pic->data[1]); | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 static int tgv_decode_frame(AVCodecContext *avctx, | |
| 244 void *data, int *data_size, | |
|
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
245 AVPacket *avpkt) |
| 7510 | 246 { |
|
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
247 const uint8_t *buf = avpkt->data; |
|
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
248 int buf_size = avpkt->size; |
| 7510 | 249 TgvContext *s = avctx->priv_data; |
| 250 const uint8_t *buf_end = buf + buf_size; | |
| 251 int chunk_type; | |
| 252 | |
| 253 chunk_type = AV_RL32(&buf[0]); | |
| 254 buf += EA_PREAMBLE_SIZE; | |
| 255 | |
| 256 if (chunk_type==kVGT_TAG) { | |
| 257 int pal_count, i; | |
| 258 if(buf+12>buf_end) { | |
| 259 av_log(avctx, AV_LOG_WARNING, "truncated header\n"); | |
| 260 return -1; | |
| 261 } | |
| 262 | |
| 263 s->width = AV_RL16(&buf[0]); | |
| 264 s->height = AV_RL16(&buf[2]); | |
| 265 if (s->avctx->width!=s->width || s->avctx->height!=s->height) { | |
| 266 avcodec_set_dimensions(s->avctx, s->width, s->height); | |
| 267 cond_release_buffer(&s->frame); | |
| 268 cond_release_buffer(&s->last_frame); | |
| 269 } | |
| 270 | |
| 271 pal_count = AV_RL16(&buf[6]); | |
| 272 buf += 12; | |
| 273 for(i=0; i<pal_count && i<AVPALETTE_COUNT && buf+2<buf_end; i++) { | |
| 274 s->palette[i] = AV_RB24(buf); | |
| 275 buf += 3; | |
| 276 } | |
| 277 } | |
| 278 | |
|
12462
ffb3668ff7af
Use new imgutils.h API names, fix deprecation warnings.
stefano
parents:
12372
diff
changeset
|
279 if (av_image_check_size(s->width, s->height, 0, avctx)) |
| 7510 | 280 return -1; |
| 281 | |
| 282 /* shuffle */ | |
| 283 FFSWAP(AVFrame, s->frame, s->last_frame); | |
| 284 if (!s->frame.data[0]) { | |
| 285 s->frame.reference = 1; | |
| 286 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; | |
| 287 s->frame.linesize[0] = s->width; | |
| 288 | |
| 289 /* allocate additional 12 bytes to accomodate av_memcpy_backptr() OUTBUF_PADDED optimisation */ | |
| 290 s->frame.data[0] = av_malloc(s->width*s->height + 12); | |
| 291 if (!s->frame.data[0]) | |
|
11581
998691d7f8f5
Replace all remaining occurrences of AVERROR_NOMEM with
stefano
parents:
11560
diff
changeset
|
292 return AVERROR(ENOMEM); |
| 7510 | 293 s->frame.data[1] = av_malloc(AVPALETTE_SIZE); |
| 294 if (!s->frame.data[1]) { | |
| 295 av_freep(&s->frame.data[0]); | |
|
11581
998691d7f8f5
Replace all remaining occurrences of AVERROR_NOMEM with
stefano
parents:
11560
diff
changeset
|
296 return AVERROR(ENOMEM); |
| 7510 | 297 } |
| 298 } | |
| 299 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); | |
| 300 | |
| 301 if(chunk_type==kVGT_TAG) { | |
| 302 s->frame.key_frame = 1; | |
| 303 s->frame.pict_type = FF_I_TYPE; | |
| 304 if (unpack(buf, buf_end, s->frame.data[0], s->avctx->width, s->avctx->height)<0) { | |
| 305 av_log(avctx, AV_LOG_WARNING, "truncated intra frame\n"); | |
| 306 return -1; | |
| 307 } | |
| 308 }else{ | |
| 309 if (!s->last_frame.data[0]) { | |
| 310 av_log(avctx, AV_LOG_WARNING, "inter frame without corresponding intra frame\n"); | |
| 311 return buf_size; | |
| 312 } | |
| 313 s->frame.key_frame = 0; | |
| 314 s->frame.pict_type = FF_P_TYPE; | |
| 315 if (tgv_decode_inter(s, buf, buf_end)<0) { | |
| 316 av_log(avctx, AV_LOG_WARNING, "truncated inter frame\n"); | |
| 317 return -1; | |
| 318 } | |
| 319 } | |
| 320 | |
| 321 *data_size = sizeof(AVFrame); | |
| 322 *(AVFrame*)data = s->frame; | |
| 323 | |
| 324 return buf_size; | |
| 325 } | |
| 326 | |
| 327 static av_cold int tgv_decode_end(AVCodecContext *avctx) | |
| 328 { | |
| 329 TgvContext *s = avctx->priv_data; | |
| 330 cond_release_buffer(&s->frame); | |
| 331 cond_release_buffer(&s->last_frame); | |
| 332 av_free(s->mv_codebook); | |
| 333 av_free(s->block_codebook); | |
| 334 return 0; | |
| 335 } | |
| 336 | |
| 337 AVCodec eatgv_decoder = { | |
| 338 "eatgv", | |
|
11560
8a4984c5cacc
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
11303
diff
changeset
|
339 AVMEDIA_TYPE_VIDEO, |
| 7510 | 340 CODEC_ID_TGV, |
| 341 sizeof(TgvContext), | |
| 342 tgv_decode_init, | |
| 343 NULL, | |
| 344 tgv_decode_end, | |
| 345 tgv_decode_frame, | |
|
9083
bf274494b66e
Change a bunch of codec long_names to be more consistent and descriptive.
diego
parents:
8801
diff
changeset
|
346 .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TGV video"), |
| 7510 | 347 }; |
