Mercurial > libavcodec.hg
annotate eatgv.c @ 12266:48d6738904a9 libavcodec
Fix SPLATB_REG mess. Used to be a if/elseif/elseif/elseif spaghetti, so this
splits it into small optimization-specific macros which are selected for each
DSP function. The advantage of this approach is that the sse4 functions now
use the ssse3 codepath also without needing an explicit sse4 codepath.
author | rbultje |
---|---|
date | Sat, 24 Jul 2010 19:33:05 +0000 |
parents | 7dd2a45249a9 |
children | 914f484bb476 |
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" |
7510 | 35 |
36 #define EA_PREAMBLE_SIZE 8 | |
37 #define kVGT_TAG MKTAG('k', 'V', 'G', 'T') | |
38 | |
39 typedef struct TgvContext { | |
40 AVCodecContext *avctx; | |
41 AVFrame frame; | |
42 AVFrame last_frame; | |
43 int width,height; | |
44 unsigned int palette[AVPALETTE_COUNT]; | |
45 | |
46 int (*mv_codebook)[2]; | |
47 unsigned char (*block_codebook)[16]; | |
48 int num_mvs; ///< current length of mv_codebook | |
49 int num_blocks_packed; ///< current length of block_codebook | |
50 } TgvContext; | |
51 | |
52 static av_cold int tgv_decode_init(AVCodecContext *avctx){ | |
53 TgvContext *s = avctx->priv_data; | |
54 s->avctx = avctx; | |
55 avctx->time_base = (AVRational){1, 15}; | |
56 avctx->pix_fmt = PIX_FMT_PAL8; | |
57 return 0; | |
58 } | |
59 | |
60 /** | |
61 * Unpack buffer | |
62 * @return 0 on success, -1 on critical buffer underflow | |
63 */ | |
64 static int unpack(const uint8_t *src, const uint8_t *src_end, unsigned char *dst, int width, int height) { | |
65 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
|
66 int size, size1, size2, av_uninit(offset), run; |
7510 | 67 unsigned char *dst_start = dst; |
68 | |
69 if (src[0] & 0x01) | |
70 src += 5; | |
71 else | |
72 src += 2; | |
73 | |
74 if (src+3>src_end) | |
75 return -1; | |
76 size = AV_RB24(src); | |
77 src += 3; | |
78 | |
79 while(size>0 && src<src_end) { | |
80 | |
81 /* determine size1 and size2 */ | |
82 size1 = (src[0] & 3); | |
83 if ( src[0] & 0x80 ) { // 1 | |
84 if (src[0] & 0x40 ) { // 11 | |
85 if ( src[0] & 0x20 ) { // 111 | |
86 if ( src[0] < 0xFC ) // !(111111) | |
87 size1 = (((src[0] & 31) + 1) << 2); | |
88 src++; | |
89 size2 = 0; | |
90 } else { // 110 | |
91 offset = ((src[0] & 0x10) << 12) + AV_RB16(&src[1]) + 1; | |
92 size2 = ((src[0] & 0xC) << 6) + src[3] + 5; | |
93 src += 4; | |
94 } | |
95 } else { // 10 | |
96 size1 = ( ( src[1] & 0xC0) >> 6 ); | |
97 offset = (AV_RB16(&src[1]) & 0x3FFF) + 1; | |
98 size2 = (src[0] & 0x3F) + 4; | |
99 src += 3; | |
100 } | |
101 } else { // 0 | |
102 offset = ((src[0] & 0x60) << 3) + src[1] + 1; | |
103 size2 = ((src[0] & 0x1C) >> 2) + 3; | |
104 src += 2; | |
105 } | |
106 | |
107 | |
108 /* fetch strip from src */ | |
109 if (size1>src_end-src) | |
110 break; | |
111 | |
112 if (size1>0) { | |
113 size -= size1; | |
114 run = FFMIN(size1, dst_end-dst); | |
115 memcpy(dst, src, run); | |
116 dst += run; | |
117 src += run; | |
118 } | |
119 | |
120 if (size2>0) { | |
121 if (dst-dst_start<offset) | |
122 return 0; | |
123 size -= size2; | |
124 run = FFMIN(size2, dst_end-dst); | |
125 av_memcpy_backptr(dst, offset, run); | |
126 dst += run; | |
127 } | |
128 } | |
129 | |
130 return 0; | |
131 } | |
132 | |
133 /** | |
134 * Decode inter-frame | |
135 * @return 0 on success, -1 on critical buffer underflow | |
136 */ | |
137 static int tgv_decode_inter(TgvContext * s, const uint8_t *buf, const uint8_t *buf_end){ | |
138 unsigned char *frame0_end = s->last_frame.data[0] + s->avctx->width*s->last_frame.linesize[0]; | |
139 int num_mvs; | |
140 int num_blocks_raw; | |
141 int num_blocks_packed; | |
142 int vector_bits; | |
143 int i,j,x,y; | |
144 GetBitContext gb; | |
145 int mvbits; | |
146 const unsigned char *blocks_raw; | |
147 | |
148 if(buf+12>buf_end) | |
149 return -1; | |
150 | |
151 num_mvs = AV_RL16(&buf[0]); | |
152 num_blocks_raw = AV_RL16(&buf[2]); | |
153 num_blocks_packed = AV_RL16(&buf[4]); | |
154 vector_bits = AV_RL16(&buf[6]); | |
155 buf += 12; | |
156 | |
157 /* allocate codebook buffers as neccessary */ | |
158 if (num_mvs > s->num_mvs) { | |
159 s->mv_codebook = av_realloc(s->mv_codebook, num_mvs*2*sizeof(int)); | |
160 s->num_mvs = num_mvs; | |
161 } | |
162 | |
163 if (num_blocks_packed > s->num_blocks_packed) { | |
164 s->block_codebook = av_realloc(s->block_codebook, num_blocks_packed*16*sizeof(unsigned char)); | |
165 s->num_blocks_packed = num_blocks_packed; | |
166 } | |
167 | |
168 /* read motion vectors */ | |
169 mvbits = (num_mvs*2*10+31) & ~31; | |
170 | |
171 if (buf+(mvbits>>3)+16*num_blocks_raw+8*num_blocks_packed>buf_end) | |
172 return -1; | |
173 | |
174 init_get_bits(&gb, buf, mvbits); | |
175 for (i=0; i<num_mvs; i++) { | |
176 s->mv_codebook[i][0] = get_sbits(&gb, 10); | |
177 s->mv_codebook[i][1] = get_sbits(&gb, 10); | |
178 } | |
179 buf += mvbits>>3; | |
180 | |
181 /* note ptr to uncompressed blocks */ | |
182 blocks_raw = buf; | |
183 buf += num_blocks_raw*16; | |
184 | |
185 /* read compressed blocks */ | |
186 init_get_bits(&gb, buf, (buf_end-buf)<<3); | |
187 for (i=0; i<num_blocks_packed; i++) { | |
188 int tmp[4]; | |
189 for(j=0; j<4; j++) | |
190 tmp[j] = get_bits(&gb, 8); | |
191 for(j=0; j<16; j++) | |
192 s->block_codebook[i][15-j] = tmp[get_bits(&gb, 2)]; | |
193 } | |
194 | |
11303
b0cb1f7efcbc
Do not read beyond end of input in EA-TGV. This should avoid FATE test #362
vitor
parents:
10825
diff
changeset
|
195 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
|
196 (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
|
197 return -1; |
b0cb1f7efcbc
Do not read beyond end of input in EA-TGV. This should avoid FATE test #362
vitor
parents:
10825
diff
changeset
|
198 |
7510 | 199 /* read vectors and build frame */ |
200 for(y=0; y<s->avctx->height/4; y++) | |
201 for(x=0; x<s->avctx->width/4; x++) { | |
202 unsigned int vector = get_bits(&gb, vector_bits); | |
203 const unsigned char *src; | |
204 int src_stride; | |
205 | |
206 if (vector < num_mvs) { | |
207 src = s->last_frame.data[0] + | |
208 (y*4 + s->mv_codebook[vector][1])*s->last_frame.linesize[0] + | |
209 x*4 + s->mv_codebook[vector][0]; | |
210 src_stride = s->last_frame.linesize[0]; | |
211 if (src+3*src_stride+3>=frame0_end) | |
212 continue; | |
213 }else{ | |
214 int offset = vector - num_mvs; | |
215 if (offset<num_blocks_raw) | |
216 src = blocks_raw + 16*offset; | |
217 else if (offset-num_blocks_raw<num_blocks_packed) | |
218 src = s->block_codebook[offset-num_blocks_raw]; | |
219 else | |
220 continue; | |
221 src_stride = 4; | |
222 } | |
223 | |
224 for(j=0; j<4; j++) | |
225 for(i=0; i<4; i++) | |
226 s->frame.data[0][ (y*4+j)*s->frame.linesize[0] + (x*4+i) ] = | |
227 src[j*src_stride + i]; | |
228 } | |
229 | |
230 return 0; | |
231 } | |
232 | |
233 /** release AVFrame buffers if allocated */ | |
234 static void cond_release_buffer(AVFrame *pic) | |
235 { | |
236 if (pic->data[0]) { | |
237 av_freep(&pic->data[0]); | |
238 av_free(pic->data[1]); | |
239 } | |
240 } | |
241 | |
242 static int tgv_decode_frame(AVCodecContext *avctx, | |
243 void *data, int *data_size, | |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
244 AVPacket *avpkt) |
7510 | 245 { |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
246 const uint8_t *buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
247 int buf_size = avpkt->size; |
7510 | 248 TgvContext *s = avctx->priv_data; |
249 const uint8_t *buf_end = buf + buf_size; | |
250 int chunk_type; | |
251 | |
252 chunk_type = AV_RL32(&buf[0]); | |
253 buf += EA_PREAMBLE_SIZE; | |
254 | |
255 if (chunk_type==kVGT_TAG) { | |
256 int pal_count, i; | |
257 if(buf+12>buf_end) { | |
258 av_log(avctx, AV_LOG_WARNING, "truncated header\n"); | |
259 return -1; | |
260 } | |
261 | |
262 s->width = AV_RL16(&buf[0]); | |
263 s->height = AV_RL16(&buf[2]); | |
264 if (s->avctx->width!=s->width || s->avctx->height!=s->height) { | |
265 avcodec_set_dimensions(s->avctx, s->width, s->height); | |
266 cond_release_buffer(&s->frame); | |
267 cond_release_buffer(&s->last_frame); | |
268 } | |
269 | |
270 pal_count = AV_RL16(&buf[6]); | |
271 buf += 12; | |
272 for(i=0; i<pal_count && i<AVPALETTE_COUNT && buf+2<buf_end; i++) { | |
273 s->palette[i] = AV_RB24(buf); | |
274 buf += 3; | |
275 } | |
276 } | |
277 | |
278 if (avcodec_check_dimensions(avctx, s->width, s->height)) | |
279 return -1; | |
280 | |
281 /* shuffle */ | |
282 FFSWAP(AVFrame, s->frame, s->last_frame); | |
283 if (!s->frame.data[0]) { | |
284 s->frame.reference = 1; | |
285 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; | |
286 s->frame.linesize[0] = s->width; | |
287 | |
288 /* allocate additional 12 bytes to accomodate av_memcpy_backptr() OUTBUF_PADDED optimisation */ | |
289 s->frame.data[0] = av_malloc(s->width*s->height + 12); | |
290 if (!s->frame.data[0]) | |
11581
998691d7f8f5
Replace all remaining occurrences of AVERROR_NOMEM with
stefano
parents:
11560
diff
changeset
|
291 return AVERROR(ENOMEM); |
7510 | 292 s->frame.data[1] = av_malloc(AVPALETTE_SIZE); |
293 if (!s->frame.data[1]) { | |
294 av_freep(&s->frame.data[0]); | |
11581
998691d7f8f5
Replace all remaining occurrences of AVERROR_NOMEM with
stefano
parents:
11560
diff
changeset
|
295 return AVERROR(ENOMEM); |
7510 | 296 } |
297 } | |
298 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); | |
299 | |
300 if(chunk_type==kVGT_TAG) { | |
301 s->frame.key_frame = 1; | |
302 s->frame.pict_type = FF_I_TYPE; | |
303 if (unpack(buf, buf_end, s->frame.data[0], s->avctx->width, s->avctx->height)<0) { | |
304 av_log(avctx, AV_LOG_WARNING, "truncated intra frame\n"); | |
305 return -1; | |
306 } | |
307 }else{ | |
308 if (!s->last_frame.data[0]) { | |
309 av_log(avctx, AV_LOG_WARNING, "inter frame without corresponding intra frame\n"); | |
310 return buf_size; | |
311 } | |
312 s->frame.key_frame = 0; | |
313 s->frame.pict_type = FF_P_TYPE; | |
314 if (tgv_decode_inter(s, buf, buf_end)<0) { | |
315 av_log(avctx, AV_LOG_WARNING, "truncated inter frame\n"); | |
316 return -1; | |
317 } | |
318 } | |
319 | |
320 *data_size = sizeof(AVFrame); | |
321 *(AVFrame*)data = s->frame; | |
322 | |
323 return buf_size; | |
324 } | |
325 | |
326 static av_cold int tgv_decode_end(AVCodecContext *avctx) | |
327 { | |
328 TgvContext *s = avctx->priv_data; | |
329 cond_release_buffer(&s->frame); | |
330 cond_release_buffer(&s->last_frame); | |
331 av_free(s->mv_codebook); | |
332 av_free(s->block_codebook); | |
333 return 0; | |
334 } | |
335 | |
336 AVCodec eatgv_decoder = { | |
337 "eatgv", | |
11560
8a4984c5cacc
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
11303
diff
changeset
|
338 AVMEDIA_TYPE_VIDEO, |
7510 | 339 CODEC_ID_TGV, |
340 sizeof(TgvContext), | |
341 tgv_decode_init, | |
342 NULL, | |
343 tgv_decode_end, | |
344 tgv_decode_frame, | |
9083
bf274494b66e
Change a bunch of codec long_names to be more consistent and descriptive.
diego
parents:
8801
diff
changeset
|
345 .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TGV video"), |
7510 | 346 }; |