Mercurial > libavcodec.hg
annotate eatgv.c @ 11032:01bd040f8607 libavcodec
Unroll main loop so the edge==0 case is seperate.
This allows many things to be simplified away.
h264 decoder is overall 1% faster with a mbaff sample and
0.1% slower with the cathedral sample, probably because the slow loop
filter code must be loaded into the code cache for each first MB of each
row but isnt used for the following MBs.
author | michael |
---|---|
date | Thu, 28 Jan 2010 01:24:25 +0000 |
parents | dff431441c9c |
children | b0cb1f7efcbc |
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 /** | |
8718
e9d9d946f213
Use full internal pathname in doxygen @file directives.
diego
parents:
8597
diff
changeset
|
23 * @file libavcodec/eatgv.c |
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 | |
195 /* read vectors and build frame */ | |
196 for(y=0; y<s->avctx->height/4; y++) | |
197 for(x=0; x<s->avctx->width/4; x++) { | |
198 unsigned int vector = get_bits(&gb, vector_bits); | |
199 const unsigned char *src; | |
200 int src_stride; | |
201 | |
202 if (vector < num_mvs) { | |
203 src = s->last_frame.data[0] + | |
204 (y*4 + s->mv_codebook[vector][1])*s->last_frame.linesize[0] + | |
205 x*4 + s->mv_codebook[vector][0]; | |
206 src_stride = s->last_frame.linesize[0]; | |
207 if (src+3*src_stride+3>=frame0_end) | |
208 continue; | |
209 }else{ | |
210 int offset = vector - num_mvs; | |
211 if (offset<num_blocks_raw) | |
212 src = blocks_raw + 16*offset; | |
213 else if (offset-num_blocks_raw<num_blocks_packed) | |
214 src = s->block_codebook[offset-num_blocks_raw]; | |
215 else | |
216 continue; | |
217 src_stride = 4; | |
218 } | |
219 | |
220 for(j=0; j<4; j++) | |
221 for(i=0; i<4; i++) | |
222 s->frame.data[0][ (y*4+j)*s->frame.linesize[0] + (x*4+i) ] = | |
223 src[j*src_stride + i]; | |
224 } | |
225 | |
226 return 0; | |
227 } | |
228 | |
229 /** release AVFrame buffers if allocated */ | |
230 static void cond_release_buffer(AVFrame *pic) | |
231 { | |
232 if (pic->data[0]) { | |
233 av_freep(&pic->data[0]); | |
234 av_free(pic->data[1]); | |
235 } | |
236 } | |
237 | |
238 static int tgv_decode_frame(AVCodecContext *avctx, | |
239 void *data, int *data_size, | |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
240 AVPacket *avpkt) |
7510 | 241 { |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
242 const uint8_t *buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
243 int buf_size = avpkt->size; |
7510 | 244 TgvContext *s = avctx->priv_data; |
245 const uint8_t *buf_end = buf + buf_size; | |
246 int chunk_type; | |
247 | |
248 chunk_type = AV_RL32(&buf[0]); | |
249 buf += EA_PREAMBLE_SIZE; | |
250 | |
251 if (chunk_type==kVGT_TAG) { | |
252 int pal_count, i; | |
253 if(buf+12>buf_end) { | |
254 av_log(avctx, AV_LOG_WARNING, "truncated header\n"); | |
255 return -1; | |
256 } | |
257 | |
258 s->width = AV_RL16(&buf[0]); | |
259 s->height = AV_RL16(&buf[2]); | |
260 if (s->avctx->width!=s->width || s->avctx->height!=s->height) { | |
261 avcodec_set_dimensions(s->avctx, s->width, s->height); | |
262 cond_release_buffer(&s->frame); | |
263 cond_release_buffer(&s->last_frame); | |
264 } | |
265 | |
266 pal_count = AV_RL16(&buf[6]); | |
267 buf += 12; | |
268 for(i=0; i<pal_count && i<AVPALETTE_COUNT && buf+2<buf_end; i++) { | |
269 s->palette[i] = AV_RB24(buf); | |
270 buf += 3; | |
271 } | |
272 } | |
273 | |
274 if (avcodec_check_dimensions(avctx, s->width, s->height)) | |
275 return -1; | |
276 | |
277 /* shuffle */ | |
278 FFSWAP(AVFrame, s->frame, s->last_frame); | |
279 if (!s->frame.data[0]) { | |
280 s->frame.reference = 1; | |
281 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; | |
282 s->frame.linesize[0] = s->width; | |
283 | |
284 /* allocate additional 12 bytes to accomodate av_memcpy_backptr() OUTBUF_PADDED optimisation */ | |
285 s->frame.data[0] = av_malloc(s->width*s->height + 12); | |
286 if (!s->frame.data[0]) | |
287 return AVERROR_NOMEM; | |
288 s->frame.data[1] = av_malloc(AVPALETTE_SIZE); | |
289 if (!s->frame.data[1]) { | |
290 av_freep(&s->frame.data[0]); | |
291 return AVERROR_NOMEM; | |
292 } | |
293 } | |
294 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); | |
295 | |
296 if(chunk_type==kVGT_TAG) { | |
297 s->frame.key_frame = 1; | |
298 s->frame.pict_type = FF_I_TYPE; | |
299 if (unpack(buf, buf_end, s->frame.data[0], s->avctx->width, s->avctx->height)<0) { | |
300 av_log(avctx, AV_LOG_WARNING, "truncated intra frame\n"); | |
301 return -1; | |
302 } | |
303 }else{ | |
304 if (!s->last_frame.data[0]) { | |
305 av_log(avctx, AV_LOG_WARNING, "inter frame without corresponding intra frame\n"); | |
306 return buf_size; | |
307 } | |
308 s->frame.key_frame = 0; | |
309 s->frame.pict_type = FF_P_TYPE; | |
310 if (tgv_decode_inter(s, buf, buf_end)<0) { | |
311 av_log(avctx, AV_LOG_WARNING, "truncated inter frame\n"); | |
312 return -1; | |
313 } | |
314 } | |
315 | |
316 *data_size = sizeof(AVFrame); | |
317 *(AVFrame*)data = s->frame; | |
318 | |
319 return buf_size; | |
320 } | |
321 | |
322 static av_cold int tgv_decode_end(AVCodecContext *avctx) | |
323 { | |
324 TgvContext *s = avctx->priv_data; | |
325 cond_release_buffer(&s->frame); | |
326 cond_release_buffer(&s->last_frame); | |
327 av_free(s->mv_codebook); | |
328 av_free(s->block_codebook); | |
329 return 0; | |
330 } | |
331 | |
332 AVCodec eatgv_decoder = { | |
333 "eatgv", | |
334 CODEC_TYPE_VIDEO, | |
335 CODEC_ID_TGV, | |
336 sizeof(TgvContext), | |
337 tgv_decode_init, | |
338 NULL, | |
339 tgv_decode_end, | |
340 tgv_decode_frame, | |
9083
bf274494b66e
Change a bunch of codec long_names to be more consistent and descriptive.
diego
parents:
8801
diff
changeset
|
341 .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TGV video"), |
7510 | 342 }; |