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