Commit | Line | Data |
---|---|---|
de6d9b64 FB |
1 | /* |
2 | * AVI decoder. | |
19720f15 | 3 | * Copyright (c) 2001 Fabrice Bellard. |
de6d9b64 | 4 | * |
19720f15 FB |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public | |
7 | * License as published by the Free Software Foundation; either | |
8 | * version 2 of the License, or (at your option) any later version. | |
de6d9b64 | 9 | * |
19720f15 | 10 | * This library is distributed in the hope that it will be useful, |
de6d9b64 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19720f15 FB |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. | |
de6d9b64 | 14 | * |
19720f15 FB |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
de6d9b64 | 18 | */ |
de6d9b64 FB |
19 | #include "avformat.h" |
20 | #include "avi.h" | |
21 | ||
22 | //#define DEBUG | |
23 | ||
deb0a292 RS |
24 | static const struct AVI1Handler { |
25 | enum CodecID vcid; | |
26 | enum CodecID acid; | |
27 | uint32_t tag; | |
28 | } AVI1Handlers[] = { | |
29 | { CODEC_ID_DVVIDEO, CODEC_ID_DVAUDIO, MKTAG('d', 'v', 's', 'd') }, | |
30 | { CODEC_ID_DVVIDEO, CODEC_ID_DVAUDIO, MKTAG('d', 'v', 'h', 'd') }, | |
31 | { CODEC_ID_DVVIDEO, CODEC_ID_DVAUDIO, MKTAG('d', 'v', 's', 'l') }, | |
32 | /* This is supposed to be the last one */ | |
33 | { CODEC_ID_NONE, CODEC_ID_NONE, 0 }, | |
34 | }; | |
35 | ||
de6d9b64 FB |
36 | typedef struct AVIIndex { |
37 | unsigned char tag[4]; | |
38 | unsigned int flags, pos, len; | |
39 | struct AVIIndex *next; | |
40 | } AVIIndex; | |
41 | ||
42 | typedef struct { | |
06219cb1 | 43 | int64_t riff_end; |
0c1a9eda | 44 | int64_t movi_end; |
deb0a292 RS |
45 | int type; |
46 | uint8_t *buf; | |
47 | int buf_size; | |
48 | int stream_index; | |
de6d9b64 FB |
49 | offset_t movi_list; |
50 | AVIIndex *first, *last; | |
51 | } AVIContext; | |
52 | ||
53 | #ifdef DEBUG | |
1101abfe | 54 | static void print_tag(const char *str, unsigned int tag, int size) |
de6d9b64 FB |
55 | { |
56 | printf("%s: tag=%c%c%c%c size=0x%x\n", | |
57 | str, tag & 0xff, | |
58 | (tag >> 8) & 0xff, | |
59 | (tag >> 16) & 0xff, | |
60 | (tag >> 24) & 0xff, | |
61 | size); | |
62 | } | |
63 | #endif | |
64 | ||
06219cb1 RS |
65 | static int get_riff(AVIContext *avi, ByteIOContext *pb) |
66 | { | |
67 | uint32_t tag; | |
68 | /* check RIFF header */ | |
69 | tag = get_le32(pb); | |
70 | ||
71 | if (tag != MKTAG('R', 'I', 'F', 'F')) | |
72 | return -1; | |
73 | avi->riff_end = get_le32(pb); /* RIFF chunk size */ | |
74 | avi->riff_end += url_ftell(pb); /* RIFF chunk end */ | |
75 | tag = get_le32(pb); | |
76 | if (tag != MKTAG('A', 'V', 'I', ' ') && tag != MKTAG('A', 'V', 'I', 'X')) | |
77 | return -1; | |
78 | ||
79 | return 0; | |
80 | } | |
81 | ||
1101abfe | 82 | static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) |
de6d9b64 | 83 | { |
c9a65ca8 | 84 | AVIContext *avi = s->priv_data; |
de6d9b64 | 85 | ByteIOContext *pb = &s->pb; |
deb0a292 | 86 | uint32_t tag, tag1, handler; |
b559b29b | 87 | int codec_type, stream_index, frame_period, bit_rate, scale, rate; |
a26058a5 | 88 | unsigned int size; |
e095026a | 89 | int i; |
de6d9b64 FB |
90 | AVStream *st; |
91 | ||
06219cb1 | 92 | if (get_riff(avi, pb) < 0) |
de6d9b64 | 93 | return -1; |
1101abfe | 94 | |
de6d9b64 FB |
95 | /* first list tag */ |
96 | stream_index = -1; | |
97 | codec_type = -1; | |
98 | frame_period = 0; | |
deb0a292 RS |
99 | avi->type = 2; |
100 | avi->buf = av_malloc(1); | |
101 | if (!avi->buf) | |
102 | return -1; | |
103 | avi->buf_size = 1; | |
de6d9b64 FB |
104 | for(;;) { |
105 | if (url_feof(pb)) | |
106 | goto fail; | |
107 | tag = get_le32(pb); | |
108 | size = get_le32(pb); | |
109 | #ifdef DEBUG | |
110 | print_tag("tag", tag, size); | |
111 | #endif | |
112 | ||
113 | switch(tag) { | |
114 | case MKTAG('L', 'I', 'S', 'T'): | |
115 | /* ignored, except when start of video packets */ | |
116 | tag1 = get_le32(pb); | |
117 | #ifdef DEBUG | |
118 | print_tag("list", tag1, 0); | |
119 | #endif | |
120 | if (tag1 == MKTAG('m', 'o', 'v', 'i')) { | |
121 | avi->movi_end = url_ftell(pb) + size - 4; | |
122 | #ifdef DEBUG | |
123 | printf("movi end=%Lx\n", avi->movi_end); | |
124 | #endif | |
125 | goto end_of_header; | |
126 | } | |
127 | break; | |
128 | case MKTAG('a', 'v', 'i', 'h'): | |
1101abfe ZK |
129 | /* avi header */ |
130 | /* using frame_period is bad idea */ | |
de6d9b64 FB |
131 | frame_period = get_le32(pb); |
132 | bit_rate = get_le32(pb) * 8; | |
1101abfe | 133 | url_fskip(pb, 4 * 4); |
de6d9b64 FB |
134 | s->nb_streams = get_le32(pb); |
135 | for(i=0;i<s->nb_streams;i++) { | |
1101abfe | 136 | AVStream *st = av_mallocz(sizeof(AVStream)); |
de6d9b64 FB |
137 | if (!st) |
138 | goto fail; | |
1e491e29 MN |
139 | avcodec_get_context_defaults(&st->codec); |
140 | ||
de6d9b64 | 141 | s->streams[i] = st; |
1101abfe | 142 | } |
de6d9b64 FB |
143 | url_fskip(pb, size - 7 * 4); |
144 | break; | |
145 | case MKTAG('s', 't', 'r', 'h'): | |
146 | /* stream header */ | |
147 | stream_index++; | |
148 | tag1 = get_le32(pb); | |
149 | switch(tag1) { | |
deb0a292 RS |
150 | case MKTAG('i', 'a', 'v', 's'): |
151 | case MKTAG('i', 'v', 'a', 's'): | |
152 | if (s->nb_streams != 1) | |
153 | goto fail; | |
154 | avi->type = 1; | |
155 | avi->stream_index = 0; | |
156 | case MKTAG('v', 'i', 'd', 's'): | |
de6d9b64 | 157 | codec_type = CODEC_TYPE_VIDEO; |
b559b29b MN |
158 | |
159 | if (stream_index >= s->nb_streams) { | |
160 | url_fskip(pb, size - 4); | |
161 | break; | |
162 | } | |
163 | ||
164 | st = s->streams[stream_index]; | |
165 | ||
deb0a292 | 166 | handler = get_le32(pb); /* codec tag */ |
de6d9b64 FB |
167 | get_le32(pb); /* flags */ |
168 | get_le16(pb); /* priority */ | |
169 | get_le16(pb); /* language */ | |
170 | get_le32(pb); /* XXX: initial frame ? */ | |
deb0a292 RS |
171 | scale = get_le32(pb); /* scale */ |
172 | rate = get_le32(pb); /* rate */ | |
b559b29b | 173 | |
14bea432 MN |
174 | if(scale && rate){ |
175 | st->codec.frame_rate = rate; | |
deb0a292 | 176 | st->codec.frame_rate_base = scale; |
14bea432 MN |
177 | }else if(frame_period){ |
178 | st->codec.frame_rate = 1000000; | |
deb0a292 | 179 | st->codec.frame_rate_base = frame_period; |
14bea432 MN |
180 | }else{ |
181 | st->codec.frame_rate = 25; | |
182 | st->codec.frame_rate_base = 1; | |
183 | } | |
b559b29b | 184 | |
deb0a292 RS |
185 | if (avi->type == 1) { |
186 | AVStream *st = av_mallocz(sizeof(AVStream)); | |
187 | if (!st) | |
188 | goto fail; | |
189 | ||
190 | avcodec_get_context_defaults(&st->codec); | |
191 | s->streams[s->nb_streams++] = st; | |
192 | stream_index++; | |
193 | ||
194 | for (i=0; AVI1Handlers[i].tag != 0; ++i) | |
195 | if (AVI1Handlers[i].tag == handler) | |
196 | break; | |
197 | ||
198 | if (AVI1Handlers[i].tag != 0) { | |
199 | s->streams[0]->codec.codec_type = CODEC_TYPE_VIDEO; | |
200 | s->streams[0]->codec.codec_id = AVI1Handlers[i].vcid; | |
201 | s->streams[1]->codec.codec_type = CODEC_TYPE_AUDIO; | |
202 | s->streams[1]->codec.codec_id = AVI1Handlers[i].acid; | |
203 | } else | |
204 | goto fail; | |
205 | } | |
206 | ||
207 | url_fskip(pb, size - 7 * 4); | |
de6d9b64 FB |
208 | break; |
209 | case MKTAG('a', 'u', 'd', 's'): | |
210 | codec_type = CODEC_TYPE_AUDIO; | |
211 | /* nothing really useful */ | |
9bf9a5fc MN |
212 | url_fskip(pb, size - 4); |
213 | break; | |
214 | default: | |
215 | goto fail; | |
de6d9b64 FB |
216 | } |
217 | break; | |
218 | case MKTAG('s', 't', 'r', 'f'): | |
219 | /* stream header */ | |
deb0a292 | 220 | if (stream_index >= s->nb_streams || avi->type == 1) { |
de6d9b64 FB |
221 | url_fskip(pb, size); |
222 | } else { | |
223 | st = s->streams[stream_index]; | |
224 | switch(codec_type) { | |
225 | case CODEC_TYPE_VIDEO: | |
226 | get_le32(pb); /* size */ | |
227 | st->codec.width = get_le32(pb); | |
228 | st->codec.height = get_le32(pb); | |
de6d9b64 | 229 | get_le16(pb); /* panes */ |
b559b29b | 230 | st->codec.bits_per_sample= get_le16(pb); /* depth */ |
de6d9b64 | 231 | tag1 = get_le32(pb); |
b559b29b MN |
232 | get_le32(pb); /* ImageSize */ |
233 | get_le32(pb); /* XPelsPerMeter */ | |
234 | get_le32(pb); /* YPelsPerMeter */ | |
235 | get_le32(pb); /* ClrUsed */ | |
236 | get_le32(pb); /* ClrImportant */ | |
237 | ||
238 | st->codec.extradata_size= size - 10*4; | |
239 | st->codec.extradata= av_malloc(st->codec.extradata_size); //FIXME where should we free this? | |
240 | get_buffer(pb, st->codec.extradata, st->codec.extradata_size); | |
952c69c4 MN |
241 | |
242 | if(st->codec.extradata_size & 1) //FIXME check if the encoder really did this correctly | |
243 | get_byte(pb); | |
b559b29b | 244 | |
de6d9b64 FB |
245 | #ifdef DEBUG |
246 | print_tag("video", tag1, 0); | |
247 | #endif | |
248 | st->codec.codec_type = CODEC_TYPE_VIDEO; | |
249 | st->codec.codec_tag = tag1; | |
250 | st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1); | |
b559b29b | 251 | // url_fskip(pb, size - 5 * 4); |
de6d9b64 | 252 | break; |
9bf9a5fc | 253 | case CODEC_TYPE_AUDIO: |
2e7973bb | 254 | get_wav_header(pb, &st->codec, size); |
1cef9527 FR |
255 | if (size%2) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */ |
256 | url_fskip(pb, 1); | |
de6d9b64 FB |
257 | break; |
258 | default: | |
259 | url_fskip(pb, size); | |
260 | break; | |
261 | } | |
262 | } | |
263 | break; | |
264 | default: | |
265 | /* skip tag */ | |
266 | size += (size & 1); | |
267 | url_fskip(pb, size); | |
268 | break; | |
269 | } | |
270 | } | |
271 | end_of_header: | |
272 | /* check stream number */ | |
273 | if (stream_index != s->nb_streams - 1) { | |
274 | fail: | |
275 | for(i=0;i<s->nb_streams;i++) { | |
8a7b1b18 | 276 | av_freep(&s->streams[i]->codec.extradata); |
9145f8b3 | 277 | av_freep(&s->streams[i]); |
de6d9b64 FB |
278 | } |
279 | return -1; | |
280 | } | |
1101abfe | 281 | |
de6d9b64 FB |
282 | return 0; |
283 | } | |
284 | ||
deb0a292 RS |
285 | static void __destruct_pkt(struct AVPacket *pkt) |
286 | { | |
287 | pkt->data = NULL; pkt->size = 0; | |
288 | return; | |
289 | } | |
290 | ||
1101abfe | 291 | static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) |
de6d9b64 FB |
292 | { |
293 | AVIContext *avi = s->priv_data; | |
294 | ByteIOContext *pb = &s->pb; | |
df99755b | 295 | int n, d[8], size, i; |
deb0a292 | 296 | |
df99755b | 297 | memset(d, -1, sizeof(int)*8); |
de6d9b64 | 298 | |
deb0a292 RS |
299 | if (avi->type == 1 && avi->stream_index) |
300 | goto pkt_init; | |
301 | ||
06219cb1 | 302 | for(i=url_ftell(pb); !url_feof(pb); i++) { |
df99755b | 303 | int j; |
1101abfe | 304 | |
06219cb1 RS |
305 | if (i >= avi->movi_end) { /* Let's see if it's an OpenDML AVI */ |
306 | uint32_t tag, size, tag2; | |
307 | url_fskip(pb, avi->riff_end - url_ftell(pb)); | |
308 | if (get_riff(avi, pb) < 0) | |
309 | return -1; | |
310 | ||
311 | tag = get_le32(pb); | |
312 | size = get_le32(pb); | |
313 | tag2 = get_le32(pb); | |
314 | if (tag == MKTAG('L','I','S','T') && tag2 == MKTAG('m','o','v','i')) | |
315 | avi->movi_end = url_ftell(pb) + size - 4; | |
316 | else | |
317 | return -1; | |
318 | } | |
319 | ||
df99755b MN |
320 | for(j=0; j<7; j++) |
321 | d[j]= d[j+1]; | |
322 | d[7]= get_byte(pb); | |
323 | ||
324 | size= d[4] + (d[5]<<8) + (d[6]<<16) + (d[7]<<24); | |
325 | ||
326 | //parse ix## | |
327 | n= (d[2] - '0') * 10 + (d[3] - '0'); | |
328 | if( d[2] >= '0' && d[2] <= '9' | |
329 | && d[3] >= '0' && d[3] <= '9' | |
330 | && d[0] == 'i' && d[1] == 'x' | |
331 | && n < s->nb_streams | |
332 | && i + size <= avi->movi_end){ | |
333 | ||
334 | url_fskip(pb, size); | |
335 | } | |
336 | ||
337 | //parse ##dc/##wb | |
338 | n= (d[0] - '0') * 10 + (d[1] - '0'); | |
339 | if( d[0] >= '0' && d[0] <= '9' | |
340 | && d[1] >= '0' && d[1] <= '9' | |
deb0a292 RS |
341 | && ((d[2] == 'd' && d[3] == 'c') || |
342 | (d[2] == 'w' && d[3] == 'b') || | |
343 | (d[2] == 'd' && d[3] == 'b') || | |
344 | (d[2] == '_' && d[3] == '_')) | |
df99755b | 345 | && n < s->nb_streams |
deb0a292 | 346 | && i + size <= avi->movi_end) { |
df99755b | 347 | |
deb0a292 RS |
348 | uint8_t *tbuf = av_realloc(avi->buf, size + FF_INPUT_BUFFER_PADDING_SIZE); |
349 | if (!tbuf) | |
350 | return -1; | |
351 | avi->buf = tbuf; | |
352 | avi->buf_size = size; | |
353 | get_buffer(pb, avi->buf, size); | |
354 | if (size & 1) | |
355 | get_byte(pb); | |
356 | if (avi->type != 1) | |
357 | avi->stream_index = n; | |
358 | goto pkt_init; | |
df99755b MN |
359 | } |
360 | } | |
361 | ||
362 | return -1; | |
deb0a292 RS |
363 | |
364 | pkt_init: | |
365 | av_init_packet(pkt); | |
366 | pkt->data = avi->buf; | |
367 | pkt->size = avi->buf_size; | |
368 | pkt->destruct = __destruct_pkt; | |
369 | pkt->stream_index = avi->stream_index; | |
370 | avi->stream_index = !avi->stream_index; | |
371 | return 0; | |
de6d9b64 FB |
372 | } |
373 | ||
1101abfe | 374 | static int avi_read_close(AVFormatContext *s) |
de6d9b64 | 375 | { |
c9a65ca8 FB |
376 | return 0; |
377 | } | |
378 | ||
379 | static int avi_probe(AVProbeData *p) | |
380 | { | |
381 | /* check file header */ | |
382 | if (p->buf_size <= 32) | |
383 | return 0; | |
384 | if (p->buf[0] == 'R' && p->buf[1] == 'I' && | |
385 | p->buf[2] == 'F' && p->buf[3] == 'F' && | |
386 | p->buf[8] == 'A' && p->buf[9] == 'V' && | |
387 | p->buf[10] == 'I' && p->buf[11] == ' ') | |
388 | return AVPROBE_SCORE_MAX; | |
389 | else | |
390 | return 0; | |
391 | } | |
392 | ||
393 | static AVInputFormat avi_iformat = { | |
394 | "avi", | |
395 | "avi format", | |
396 | sizeof(AVIContext), | |
397 | avi_probe, | |
398 | avi_read_header, | |
399 | avi_read_packet, | |
400 | avi_read_close, | |
401 | }; | |
402 | ||
403 | int avidec_init(void) | |
404 | { | |
405 | av_register_input_format(&avi_iformat); | |
de6d9b64 FB |
406 | return 0; |
407 | } |