Mercurial > libavcodec.hg
annotate eatgv.c @ 12518:67e7e49058c2 libavcodec
Split and then simplify address generation macro.
Allows nasm to work for this code.
author | reimar |
---|---|
date | Sun, 26 Sep 2010 09:08:11 +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 }; |