Initial revision
[ffmpeg.git] / libav / avidec.c
1 /*
2  * AVI decoder.
3  * Copyright (c) 2001 Gerard Lantau.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <netinet/in.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include "avformat.h"
26 #include "avi.h"
27
28 //#define DEBUG
29
30 typedef struct AVIIndex {
31     unsigned char tag[4];
32     unsigned int flags, pos, len;
33     struct AVIIndex *next;
34 } AVIIndex;
35
36 typedef struct {
37     INT64 movi_end;
38     offset_t movi_list;
39     AVIIndex *first, *last;
40 } AVIContext;
41
42 #ifdef DEBUG
43 void print_tag(const char *str, unsigned int tag, int size)
44 {
45     printf("%s: tag=%c%c%c%c size=0x%x\n",
46            str, tag & 0xff,
47            (tag >> 8) & 0xff,
48            (tag >> 16) & 0xff,
49            (tag >> 24) & 0xff,
50            size);
51 }
52 #endif
53
54 int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
55 {
56     AVIContext *avi;
57     ByteIOContext *pb = &s->pb;
58     UINT32 tag, tag1;
59     int codec_type, stream_index, size, frame_period, bit_rate;
60     int i;
61     AVStream *st;
62
63     avi = malloc(sizeof(AVIContext));
64     if (!avi)
65         return -1;
66     memset(avi, 0, sizeof(AVIContext));
67     s->priv_data = avi;
68
69     /* check RIFF header */
70     tag = get_le32(pb);
71
72     if (tag != MKTAG('R', 'I', 'F', 'F'))
73         return -1;
74     get_le32(pb); /* file size */
75     tag = get_le32(pb);
76     if (tag != MKTAG('A', 'V', 'I', ' '))
77         return -1;
78     
79     /* first list tag */
80     stream_index = -1;
81     codec_type = -1;
82     frame_period = 0;
83     for(;;) {
84         if (url_feof(pb))
85             goto fail;
86         tag = get_le32(pb);
87         size = get_le32(pb);
88 #ifdef DEBUG
89         print_tag("tag", tag, size);
90 #endif
91
92         switch(tag) {
93         case MKTAG('L', 'I', 'S', 'T'):
94             /* ignored, except when start of video packets */
95             tag1 = get_le32(pb);
96 #ifdef DEBUG
97             print_tag("list", tag1, 0);
98 #endif
99             if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
100                 avi->movi_end = url_ftell(pb) + size - 4;
101 #ifdef DEBUG
102                 printf("movi end=%Lx\n", avi->movi_end);
103 #endif
104                 goto end_of_header;
105             }
106             break;
107         case MKTAG('a', 'v', 'i', 'h'):
108             /* avi header */
109             frame_period = get_le32(pb);
110             bit_rate = get_le32(pb) * 8;
111             url_fskip(pb, 4 * 4);
112             s->nb_streams = get_le32(pb);
113             for(i=0;i<s->nb_streams;i++) {
114                 AVStream *st;
115                 st = malloc(sizeof(AVStream));
116                 if (!st)
117                     goto fail;
118                 memset(st, 0, sizeof(AVStream));
119                 s->streams[i] = st;
120             }
121             url_fskip(pb, size - 7 * 4);
122             break;
123         case MKTAG('s', 't', 'r', 'h'):
124             /* stream header */
125             stream_index++;
126             tag1 = get_le32(pb);
127             switch(tag1) {
128             case MKTAG('v', 'i', 'd', 's'):
129                 codec_type = CODEC_TYPE_VIDEO;
130                 get_le32(pb); /* codec tag */
131                 get_le32(pb); /* flags */
132                 get_le16(pb); /* priority */
133                 get_le16(pb); /* language */
134                 get_le32(pb); /* XXX: initial frame ? */
135                 get_le32(pb); /* scale */
136                 get_le32(pb); /* rate */
137                 url_fskip(pb, size - 7 * 4);
138                 break;
139             case MKTAG('a', 'u', 'd', 's'):
140                 codec_type = CODEC_TYPE_AUDIO;
141                 /* nothing really useful */
142                 url_fskip(pb, size - 4);
143                 break;
144             default:
145                 goto fail;
146             }
147             break;
148         case MKTAG('s', 't', 'r', 'f'):
149             /* stream header */
150             if (stream_index >= s->nb_streams) {
151                 url_fskip(pb, size);
152             } else {
153                 st = s->streams[stream_index];
154                 switch(codec_type) {
155                 case CODEC_TYPE_VIDEO:
156                     get_le32(pb); /* size */
157                     st->codec.width = get_le32(pb);
158                     st->codec.height = get_le32(pb);
159                     if (frame_period)
160                         st->codec.frame_rate = (1000000LL * FRAME_RATE_BASE) / frame_period;
161                     else
162                         st->codec.frame_rate = 25 * FRAME_RATE_BASE;
163                     get_le16(pb); /* panes */
164                     get_le16(pb); /* depth */
165                     tag1 = get_le32(pb);
166 #ifdef DEBUG
167                     print_tag("video", tag1, 0);
168 #endif
169                     st->codec.codec_type = CODEC_TYPE_VIDEO;
170                     st->codec.codec_tag = tag1;
171                     st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
172                     url_fskip(pb, size - 5 * 4);
173                     break;
174                 case CODEC_TYPE_AUDIO:
175                     tag1 = get_le16(pb);
176                     st->codec.codec_type = CODEC_TYPE_AUDIO;
177                     st->codec.codec_tag = tag1;
178                     st->codec.codec_id = codec_get_id(codec_wav_tags, tag1);
179 #ifdef DEBUG
180                     printf("audio: 0x%x\n", tag1);
181 #endif
182                     st->codec.channels = get_le16(pb);
183                     st->codec.sample_rate = get_le32(pb);
184                     st->codec.bit_rate = get_le32(pb) * 8;
185                     url_fskip(pb, size - 3 * 4);
186                     break;
187                 default:
188                     url_fskip(pb, size);
189                     break;
190                 }
191             }
192             break;
193         default:
194             /* skip tag */
195             size += (size & 1);
196             url_fskip(pb, size);
197             break;
198         }
199     }
200  end_of_header:
201     /* check stream number */
202     if (stream_index != s->nb_streams - 1) {
203     fail:
204         for(i=0;i<s->nb_streams;i++) {
205             if (s->streams[i])
206                 free(s->streams[i]);
207         }
208         return -1;
209     }
210         
211     return 0;
212 }
213
214 int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
215 {
216     AVIContext *avi = s->priv_data;
217     ByteIOContext *pb = &s->pb;
218     int n, d1, d2, size;
219     
220  find_next:
221     if (url_feof(pb) || url_ftell(pb) >= avi->movi_end)
222         return -1;
223     d1 = get_byte(pb);
224     if (d1 < '0' || d1 > '9')
225         goto find_next;
226     d2 = get_byte(pb);
227     if (d2 < '0' || d2 > '9')
228         goto find_next;
229     n = (d1 - '0') * 10 + (d2 - '0');
230     
231     if (n < 0 || n >= s->nb_streams)
232         goto find_next;
233     
234     d1 = get_byte(pb);
235     d2 = get_byte(pb);
236     if ((d1 != 'd' && d2 != 'c') &&
237         (d1 != 'w' && d2 != 'b'))
238         goto find_next;
239     
240     size = get_le32(pb);
241     av_new_packet(pkt, size);
242     pkt->stream_index = n;
243
244     get_buffer(pb, pkt->data, pkt->size);
245     
246     if (size & 1)
247         get_byte(pb);
248     
249     return 0;
250 }
251
252 int avi_read_close(AVFormatContext *s)
253 {
254     AVIContext *avi = s->priv_data;
255     free(avi);
256     return 0;
257 }