- Added MP3 encoding through libmp3lame contributed by Lennert Buytenhek.
[ffmpeg.git] / libav / wav.c
1 /* 
2  * WAV encoder and 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 "avformat.h"
20 #include "avi.h"
21
22 CodecTag codec_wav_tags[] = {
23     { CODEC_ID_MP2, 0x55 },
24     { CODEC_ID_MP3LAME, 0x55 },
25     { CODEC_ID_MP2, 0x50 },
26     { CODEC_ID_AC3, 0x2000 },
27     { CODEC_ID_PCM_S16LE, 0x01 },
28     { CODEC_ID_PCM_U8, 0x01 }, /* must come after s16le in this list */
29     { CODEC_ID_PCM_ALAW, 0x06 },
30     { CODEC_ID_PCM_MULAW, 0x07 },
31     { 0, 0 },
32 };
33
34 /* WAVEFORMATEX header */
35 int put_wav_header(ByteIOContext *pb, AVCodecContext *enc)
36 {
37     int tag, bps, blkalign, bytespersec;
38
39     tag = codec_get_tag(codec_wav_tags, enc->codec_id);
40     if (tag == 0)
41         return -1;
42     put_le16(pb, tag); 
43     put_le16(pb, enc->channels);
44     put_le32(pb, enc->sample_rate);
45     if (enc->codec_id == CODEC_ID_PCM_U8 ||
46         enc->codec_id == CODEC_ID_PCM_ALAW ||
47         enc->codec_id == CODEC_ID_PCM_MULAW) {
48         bps = 8;
49     } else if (enc->codec_id == CODEC_ID_MP2 || enc->codec_id == CODEC_ID_MP3LAME) {
50         bps = 0;
51     } else {
52         bps = 16;
53     }
54     
55     if (enc->codec_id == CODEC_ID_MP2 || enc->codec_id == CODEC_ID_MP3LAME)
56         blkalign = 1;
57     else
58         blkalign = enc->channels*bps >> 3;
59     if (enc->codec_id == CODEC_ID_PCM_U8 ||
60         enc->codec_id == CODEC_ID_PCM_S16LE) {
61         bytespersec = enc->sample_rate * blkalign;
62     } else {
63         bytespersec = enc->bit_rate / 8;
64     }
65     put_le32(pb, bytespersec); /* bytes per second */
66     put_le16(pb, blkalign); /* block align */
67     put_le16(pb, bps); /* bits per sample */
68     if (enc->codec_id == CODEC_ID_MP2 || enc->codec_id == CODEC_ID_MP3LAME) {
69         put_le16(pb, 12); /* wav_extra_size */
70         put_le16(pb, 1); /* wID */
71         put_le32(pb, 2); /* fdwFlags */
72         put_le16(pb, 1152); /* nBlockSize */
73         put_le16(pb, 1); /* nFramesPerBlock */
74         put_le16(pb, 1393); /* nCodecDelay */
75     } else
76         put_le16(pb, 0); /* wav_extra_size */
77
78     return 0;
79 }
80
81 int wav_codec_get_id(unsigned int tag, int bps)
82 {
83     int id;
84     id = codec_get_id(codec_wav_tags, tag);
85     if (id <= 0)
86         return id;
87     /* handle specific u8 codec */
88     if (id == CODEC_ID_PCM_S16LE && bps == 8)
89         id = CODEC_ID_PCM_U8;
90     return id;
91 }
92
93 typedef struct {
94     offset_t data;
95 } WAVContext;
96
97 static int wav_write_header(AVFormatContext *s)
98 {
99     WAVContext *wav;
100     ByteIOContext *pb = &s->pb;
101     offset_t fmt;
102
103     wav = malloc(sizeof(WAVContext));
104     if (!wav)
105         return -1;
106     memset(wav, 0, sizeof(WAVContext));
107     s->priv_data = wav;
108
109     put_tag(pb, "RIFF");
110     put_le32(pb, 0); /* file length */
111     put_tag(pb, "WAVE");
112
113     /* format header */
114     fmt = start_tag(pb, "fmt ");
115     if (put_wav_header(pb, &s->streams[0]->codec) < 0) {
116         free(wav);
117         return -1;
118     }
119     end_tag(pb, fmt);
120
121     /* data header */
122     wav->data = start_tag(pb, "data");
123     
124     put_flush_packet(pb);
125
126     return 0;
127 }
128
129 static int wav_write_packet(AVFormatContext *s, int stream_index_ptr,
130                            UINT8 *buf, int size)
131 {
132     ByteIOContext *pb = &s->pb;
133     put_buffer(pb, buf, size);
134     return 0;
135 }
136
137 static int wav_write_trailer(AVFormatContext *s)
138 {
139     ByteIOContext *pb = &s->pb;
140     WAVContext *wav = s->priv_data;
141     offset_t file_size;
142
143     if (!url_is_streamed(&s->pb)) {
144         end_tag(pb, wav->data);
145
146         /* update file size */
147         file_size = url_ftell(pb);
148         url_fseek(pb, 4, SEEK_SET);
149         put_le32(pb, (UINT32)(file_size - 8));
150         url_fseek(pb, file_size, SEEK_SET);
151
152         put_flush_packet(pb);
153     }
154
155     free(wav);
156     return 0;
157 }
158
159 /* return the size of the found tag */
160 /* XXX: > 2GB ? */
161 static int find_tag(ByteIOContext *pb, UINT32 tag1)
162 {
163     unsigned int tag;
164     int size;
165
166     for(;;) {
167         if (url_feof(pb))
168             return -1;
169         tag = get_le32(pb);
170         size = get_le32(pb);
171         if (tag == tag1)
172             break;
173         url_fseek(pb, size, SEEK_CUR);
174     }
175     if (size < 0)
176         size = 0x7fffffff;
177     return size;
178 }
179
180 /* wav input */
181 static int wav_read_header(AVFormatContext *s,
182                            AVFormatParameters *ap)
183 {
184     int size;
185     unsigned int tag;
186     ByteIOContext *pb = &s->pb;
187     unsigned int id, channels, rate, bit_rate, extra_size, bps;
188     AVStream *st;
189
190     /* check RIFF header */
191     tag = get_le32(pb);
192
193     if (tag != MKTAG('R', 'I', 'F', 'F'))
194         return -1;
195     get_le32(pb); /* file size */
196     tag = get_le32(pb);
197     if (tag != MKTAG('W', 'A', 'V', 'E'))
198         return -1;
199     
200     /* parse fmt header */
201     size = find_tag(pb, MKTAG('f', 'm', 't', ' '));
202     if (size < 0)
203         return -1;
204     id = get_le16(pb); 
205     channels = get_le16(pb);
206     rate = get_le32(pb);
207     bit_rate = get_le32(pb) * 8;
208     get_le16(pb); /* block align */
209     bps = get_le16(pb); /* bits per sample */
210     if (size >= 18) {
211         /* wav_extra_size */
212         extra_size = get_le16(pb); 
213         /* skip unused data */
214         url_fseek(pb, size - 18, SEEK_CUR);
215     }
216
217     size = find_tag(pb, MKTAG('d', 'a', 't', 'a'));
218     if (size < 0)
219         return -1;
220     
221     /* now we are ready: build format streams */
222     st = malloc(sizeof(AVStream));
223     if (!st)
224         return -1;
225     s->nb_streams = 1;
226     s->streams[0] = st;
227
228     st->id = 0;
229     
230     st->codec.codec_type = CODEC_TYPE_AUDIO;
231     st->codec.codec_tag = id;
232     st->codec.codec_id = wav_codec_get_id(id, bps);
233     st->codec.channels = channels;
234     st->codec.sample_rate = rate;
235     return 0;
236 }
237
238 #define MAX_SIZE 4096
239
240 static int wav_read_packet(AVFormatContext *s,
241                            AVPacket *pkt)
242 {
243     int packet_size, n, ret;
244
245     if (url_feof(&s->pb))
246         return -EIO;
247     packet_size = url_get_packet_size(&s->pb);
248     n = MAX_SIZE / packet_size;
249     if (n <= 0)
250         return n = 1;
251     if (av_new_packet(pkt, n * packet_size))
252         return -EIO;
253     pkt->stream_index = 0;
254
255     ret = get_buffer(&s->pb, pkt->data, pkt->size);
256     if (ret < 0)
257         av_free_packet(pkt);
258     /* note: we need to modify the packet size here to handle the last
259        packet */
260     pkt->size = ret;
261     return ret;
262 }
263
264 static int wav_read_close(AVFormatContext *s)
265 {
266     return 0;
267 }
268
269 AVFormat wav_format = {
270     "wav",
271     "wav format",
272     "audio/x-wav",
273     "wav",
274     CODEC_ID_PCM_S16LE,
275     CODEC_ID_NONE,
276     wav_write_header,
277     wav_write_packet,
278     wav_write_trailer,
279
280     wav_read_header,
281     wav_read_packet,
282     wav_read_close,
283 };