changed av_open_input_file() prototype
[libav.git] / libav / wav.c
CommitLineData
de6d9b64
FB
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 */
de6d9b64
FB
19#include "avformat.h"
20#include "avi.h"
21
22typedef struct {
23 offset_t data;
24} WAVContext;
25
26static int wav_write_header(AVFormatContext *s)
27{
28 WAVContext *wav;
29 ByteIOContext *pb = &s->pb;
30 offset_t fmt;
31
32 wav = malloc(sizeof(WAVContext));
33 if (!wav)
34 return -1;
35 memset(wav, 0, sizeof(WAVContext));
36 s->priv_data = wav;
37
38 put_tag(pb, "RIFF");
39 put_le32(pb, 0); /* file length */
40 put_tag(pb, "WAVE");
41
42 /* format header */
43 fmt = start_tag(pb, "fmt ");
44 put_wav_header(pb, &s->streams[0]->codec);
45 end_tag(pb, fmt);
46
47 /* data header */
48 wav->data = start_tag(pb, "data");
49
50 put_flush_packet(pb);
51
52 return 0;
53}
54
55static int wav_write_packet(AVFormatContext *s, int stream_index_ptr,
56 UINT8 *buf, int size)
57{
58 ByteIOContext *pb = &s->pb;
59 put_buffer(pb, buf, size);
60 return 0;
61}
62
63static int wav_write_trailer(AVFormatContext *s)
64{
65 ByteIOContext *pb = &s->pb;
66 WAVContext *wav = s->priv_data;
67 offset_t file_size;
68
69 if (!url_is_streamed(&s->pb)) {
70 end_tag(pb, wav->data);
71
72 /* update file size */
73 file_size = url_ftell(pb);
74 url_fseek(pb, 4, SEEK_SET);
67e9bb0d 75 put_le32(pb, (UINT32)(file_size - 8));
de6d9b64
FB
76 url_fseek(pb, file_size, SEEK_SET);
77
78 put_flush_packet(pb);
79 }
80
81 free(wav);
82 return 0;
83}
84
85/* return the size of the found tag */
86/* XXX: > 2GB ? */
8be1c656 87static int find_tag(ByteIOContext *pb, UINT32 tag1)
de6d9b64
FB
88{
89 unsigned int tag;
90 int size;
91
92 for(;;) {
93 if (url_feof(pb))
94 return -1;
95 tag = get_le32(pb);
96 size = get_le32(pb);
97 if (tag == tag1)
98 break;
99 url_fseek(pb, size, SEEK_CUR);
100 }
101 if (size < 0)
102 size = 0x7fffffff;
103 return size;
104}
105
106/* wav input */
107static int wav_read_header(AVFormatContext *s,
108 AVFormatParameters *ap)
109{
110 int size;
111 unsigned int tag;
112 ByteIOContext *pb = &s->pb;
5ed8fafc 113 unsigned int id, channels, rate, bit_rate, extra_size, bps;
de6d9b64
FB
114 AVStream *st;
115
116 /* check RIFF header */
117 tag = get_le32(pb);
118
119 if (tag != MKTAG('R', 'I', 'F', 'F'))
120 return -1;
121 get_le32(pb); /* file size */
122 tag = get_le32(pb);
123 if (tag != MKTAG('W', 'A', 'V', 'E'))
124 return -1;
125
126 /* parse fmt header */
127 size = find_tag(pb, MKTAG('f', 'm', 't', ' '));
128 if (size < 0)
129 return -1;
130 id = get_le16(pb);
131 channels = get_le16(pb);
132 rate = get_le32(pb);
133 bit_rate = get_le32(pb) * 8;
134 get_le16(pb); /* block align */
5ed8fafc 135 bps = get_le16(pb); /* bits per sample */
de6d9b64
FB
136 if (size >= 18) {
137 /* wav_extra_size */
138 extra_size = get_le16(pb);
139 /* skip unused data */
140 url_fseek(pb, size - 18, SEEK_CUR);
141 }
142
143 size = find_tag(pb, MKTAG('d', 'a', 't', 'a'));
144 if (size < 0)
145 return -1;
146
147 /* now we are ready: build format streams */
148 st = malloc(sizeof(AVStream));
149 if (!st)
150 return -1;
151 s->nb_streams = 1;
152 s->streams[0] = st;
153
154 st->id = 0;
155
156 st->codec.codec_type = CODEC_TYPE_AUDIO;
157 st->codec.codec_tag = id;
158 st->codec.codec_id = codec_get_id(codec_wav_tags, id);
159 st->codec.channels = channels;
160 st->codec.sample_rate = rate;
5ed8fafc
FB
161 if (st->codec.codec_id == CODEC_ID_PCM_S16LE && bps == 8) {
162 st->codec.codec_id = CODEC_ID_PCM_U8;
163 }
de6d9b64
FB
164 return 0;
165}
166
167#define MAX_SIZE 4096
168
169static int wav_read_packet(AVFormatContext *s,
170 AVPacket *pkt)
171{
172 int packet_size, n, ret;
173
174 if (url_feof(&s->pb))
175 return -EIO;
176 packet_size = url_get_packet_size(&s->pb);
177 n = MAX_SIZE / packet_size;
178 if (n <= 0)
179 return n = 1;
180 if (av_new_packet(pkt, n * packet_size))
181 return -EIO;
182 pkt->stream_index = 0;
183
184 ret = get_buffer(&s->pb, pkt->data, pkt->size);
185 if (ret < 0)
186 av_free_packet(pkt);
5ed8fafc
FB
187 /* note: we need to modify the packet size here to handle the last
188 packet */
189 pkt->size = ret;
de6d9b64
FB
190 return ret;
191}
192
193static int wav_read_close(AVFormatContext *s)
194{
195 return 0;
196}
197
198AVFormat wav_format = {
199 "wav",
200 "wav format",
201 "audio/x-wav",
202 "wav",
5ed8fafc 203 CODEC_ID_PCM_S16LE,
de6d9b64
FB
204 CODEC_ID_NONE,
205 wav_write_header,
206 wav_write_packet,
207 wav_write_trailer,
208
209 wav_read_header,
210 wav_read_packet,
211 wav_read_close,
212};