Mercurial > libavformat.hg
comparison aiffdec.c @ 5284:6b37260d470e libavformat
Rename aiff.c to aiffdec.c
author | jbr |
---|---|
date | Thu, 15 Oct 2009 09:46:56 +0000 |
parents | aiff.c@63c52dca959b |
children | af65f63f2063 |
comparison
equal
deleted
inserted
replaced
5283:63c52dca959b | 5284:6b37260d470e |
---|---|
1 /* | |
2 * AIFF/AIFF-C demuxer | |
3 * Copyright (c) 2006 Patrick Guimond | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
7 * FFmpeg is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * FFmpeg is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with FFmpeg; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 #include "libavutil/intfloat_readwrite.h" | |
23 #include "avformat.h" | |
24 #include "raw.h" | |
25 #include "aiff.h" | |
26 | |
27 #define AIFF 0 | |
28 #define AIFF_C_VERSION1 0xA2805140 | |
29 | |
30 typedef struct { | |
31 int64_t data_end; | |
32 } AIFFInputContext; | |
33 | |
34 static enum CodecID aiff_codec_get_id(int bps) | |
35 { | |
36 if (bps <= 8) | |
37 return CODEC_ID_PCM_S8; | |
38 if (bps <= 16) | |
39 return CODEC_ID_PCM_S16BE; | |
40 if (bps <= 24) | |
41 return CODEC_ID_PCM_S24BE; | |
42 if (bps <= 32) | |
43 return CODEC_ID_PCM_S32BE; | |
44 | |
45 /* bigger than 32 isn't allowed */ | |
46 return CODEC_ID_NONE; | |
47 } | |
48 | |
49 /* returns the size of the found tag */ | |
50 static int get_tag(ByteIOContext *pb, uint32_t * tag) | |
51 { | |
52 int size; | |
53 | |
54 if (url_feof(pb)) | |
55 return AVERROR(EIO); | |
56 | |
57 *tag = get_le32(pb); | |
58 size = get_be32(pb); | |
59 | |
60 if (size < 0) | |
61 size = 0x7fffffff; | |
62 | |
63 return size; | |
64 } | |
65 | |
66 /* Metadata string read */ | |
67 static void get_meta(AVFormatContext *s, const char *key, int size) | |
68 { | |
69 uint8_t str[1024]; | |
70 int res = get_buffer(s->pb, str, FFMIN(sizeof(str)-1, size)); | |
71 if (res < 0) | |
72 return; | |
73 | |
74 str[res] = 0; | |
75 if (size & 1) | |
76 size++; | |
77 size -= res; | |
78 if (size) | |
79 url_fskip(s->pb, size); | |
80 | |
81 av_metadata_set(&s->metadata, key, str); | |
82 } | |
83 | |
84 /* Returns the number of sound data frames or negative on error */ | |
85 static unsigned int get_aiff_header(ByteIOContext *pb, AVCodecContext *codec, | |
86 int size, unsigned version) | |
87 { | |
88 AVExtFloat ext; | |
89 double sample_rate; | |
90 unsigned int num_frames; | |
91 | |
92 if (size & 1) | |
93 size++; | |
94 codec->codec_type = CODEC_TYPE_AUDIO; | |
95 codec->channels = get_be16(pb); | |
96 num_frames = get_be32(pb); | |
97 codec->bits_per_coded_sample = get_be16(pb); | |
98 | |
99 get_buffer(pb, (uint8_t*)&ext, sizeof(ext));/* Sample rate is in */ | |
100 sample_rate = av_ext2dbl(ext); /* 80 bits BE IEEE extended float */ | |
101 codec->sample_rate = sample_rate; | |
102 size -= 18; | |
103 | |
104 /* Got an AIFF-C? */ | |
105 if (version == AIFF_C_VERSION1) { | |
106 codec->codec_tag = get_le32(pb); | |
107 codec->codec_id = ff_codec_get_id(ff_codec_aiff_tags, codec->codec_tag); | |
108 | |
109 switch (codec->codec_id) { | |
110 case CODEC_ID_PCM_S16BE: | |
111 codec->codec_id = aiff_codec_get_id(codec->bits_per_coded_sample); | |
112 codec->bits_per_coded_sample = av_get_bits_per_sample(codec->codec_id); | |
113 break; | |
114 case CODEC_ID_ADPCM_IMA_QT: | |
115 codec->block_align = 34*codec->channels; | |
116 codec->frame_size = 64; | |
117 break; | |
118 case CODEC_ID_MACE3: | |
119 codec->block_align = 2*codec->channels; | |
120 codec->frame_size = 6; | |
121 break; | |
122 case CODEC_ID_MACE6: | |
123 codec->block_align = 1*codec->channels; | |
124 codec->frame_size = 6; | |
125 break; | |
126 case CODEC_ID_GSM: | |
127 codec->block_align = 33; | |
128 codec->frame_size = 160; | |
129 break; | |
130 default: | |
131 break; | |
132 } | |
133 size -= 4; | |
134 } else { | |
135 /* Need the codec type */ | |
136 codec->codec_id = aiff_codec_get_id(codec->bits_per_coded_sample); | |
137 codec->bits_per_coded_sample = av_get_bits_per_sample(codec->codec_id); | |
138 } | |
139 | |
140 /* Block align needs to be computed in all cases, as the definition | |
141 * is specific to applications -> here we use the WAVE format definition */ | |
142 if (!codec->block_align) | |
143 codec->block_align = (codec->bits_per_coded_sample * codec->channels) >> 3; | |
144 | |
145 codec->bit_rate = (codec->frame_size ? codec->sample_rate/codec->frame_size : | |
146 codec->sample_rate) * (codec->block_align << 3); | |
147 | |
148 /* Chunk is over */ | |
149 if (size) | |
150 url_fseek(pb, size, SEEK_CUR); | |
151 | |
152 return num_frames; | |
153 } | |
154 | |
155 static int aiff_probe(AVProbeData *p) | |
156 { | |
157 /* check file header */ | |
158 if (p->buf[0] == 'F' && p->buf[1] == 'O' && | |
159 p->buf[2] == 'R' && p->buf[3] == 'M' && | |
160 p->buf[8] == 'A' && p->buf[9] == 'I' && | |
161 p->buf[10] == 'F' && (p->buf[11] == 'F' || p->buf[11] == 'C')) | |
162 return AVPROBE_SCORE_MAX; | |
163 else | |
164 return 0; | |
165 } | |
166 | |
167 /* aiff input */ | |
168 static int aiff_read_header(AVFormatContext *s, | |
169 AVFormatParameters *ap) | |
170 { | |
171 int size, filesize; | |
172 int64_t offset = 0; | |
173 uint32_t tag; | |
174 unsigned version = AIFF_C_VERSION1; | |
175 ByteIOContext *pb = s->pb; | |
176 AVStream * st; | |
177 AIFFInputContext *aiff = s->priv_data; | |
178 | |
179 /* check FORM header */ | |
180 filesize = get_tag(pb, &tag); | |
181 if (filesize < 0 || tag != MKTAG('F', 'O', 'R', 'M')) | |
182 return AVERROR_INVALIDDATA; | |
183 | |
184 /* AIFF data type */ | |
185 tag = get_le32(pb); | |
186 if (tag == MKTAG('A', 'I', 'F', 'F')) /* Got an AIFF file */ | |
187 version = AIFF; | |
188 else if (tag != MKTAG('A', 'I', 'F', 'C')) /* An AIFF-C file then */ | |
189 return AVERROR_INVALIDDATA; | |
190 | |
191 filesize -= 4; | |
192 | |
193 st = av_new_stream(s, 0); | |
194 if (!st) | |
195 return AVERROR(ENOMEM); | |
196 | |
197 while (filesize > 0) { | |
198 /* parse different chunks */ | |
199 size = get_tag(pb, &tag); | |
200 if (size < 0) | |
201 return size; | |
202 | |
203 filesize -= size + 8; | |
204 | |
205 switch (tag) { | |
206 case MKTAG('C', 'O', 'M', 'M'): /* Common chunk */ | |
207 /* Then for the complete header info */ | |
208 st->nb_frames = get_aiff_header(pb, st->codec, size, version); | |
209 if (st->nb_frames < 0) | |
210 return st->nb_frames; | |
211 if (offset > 0) // COMM is after SSND | |
212 goto got_sound; | |
213 break; | |
214 case MKTAG('F', 'V', 'E', 'R'): /* Version chunk */ | |
215 version = get_be32(pb); | |
216 break; | |
217 case MKTAG('N', 'A', 'M', 'E'): /* Sample name chunk */ | |
218 get_meta(s, "title" , size); | |
219 break; | |
220 case MKTAG('A', 'U', 'T', 'H'): /* Author chunk */ | |
221 get_meta(s, "author" , size); | |
222 break; | |
223 case MKTAG('(', 'c', ')', ' '): /* Copyright chunk */ | |
224 get_meta(s, "copyright", size); | |
225 break; | |
226 case MKTAG('A', 'N', 'N', 'O'): /* Annotation chunk */ | |
227 get_meta(s, "comment" , size); | |
228 break; | |
229 case MKTAG('S', 'S', 'N', 'D'): /* Sampled sound chunk */ | |
230 aiff->data_end = url_ftell(pb) + size; | |
231 offset = get_be32(pb); /* Offset of sound data */ | |
232 get_be32(pb); /* BlockSize... don't care */ | |
233 offset += url_ftell(pb); /* Compute absolute data offset */ | |
234 if (st->codec->block_align) /* Assume COMM already parsed */ | |
235 goto got_sound; | |
236 if (url_is_streamed(pb)) { | |
237 av_log(s, AV_LOG_ERROR, "file is not seekable\n"); | |
238 return -1; | |
239 } | |
240 url_fskip(pb, size - 8); | |
241 break; | |
242 case MKTAG('w', 'a', 'v', 'e'): | |
243 if ((uint64_t)size > (1<<30)) | |
244 return -1; | |
245 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); | |
246 if (!st->codec->extradata) | |
247 return AVERROR(ENOMEM); | |
248 st->codec->extradata_size = size; | |
249 get_buffer(pb, st->codec->extradata, size); | |
250 break; | |
251 default: /* Jump */ | |
252 if (size & 1) /* Always even aligned */ | |
253 size++; | |
254 url_fskip (pb, size); | |
255 } | |
256 } | |
257 | |
258 if (!st->codec->block_align) { | |
259 av_log(s, AV_LOG_ERROR, "could not find COMM tag\n"); | |
260 return -1; | |
261 } | |
262 | |
263 got_sound: | |
264 /* Now positioned, get the sound data start and end */ | |
265 if (st->nb_frames) | |
266 s->file_size = st->nb_frames * st->codec->block_align; | |
267 | |
268 av_set_pts_info(st, 64, 1, st->codec->sample_rate); | |
269 st->start_time = 0; | |
270 st->duration = st->codec->frame_size ? | |
271 st->nb_frames * st->codec->frame_size : st->nb_frames; | |
272 | |
273 /* Position the stream at the first block */ | |
274 url_fseek(pb, offset, SEEK_SET); | |
275 | |
276 return 0; | |
277 } | |
278 | |
279 #define MAX_SIZE 4096 | |
280 | |
281 static int aiff_read_packet(AVFormatContext *s, | |
282 AVPacket *pkt) | |
283 { | |
284 AVStream *st = s->streams[0]; | |
285 AIFFInputContext *aiff = s->priv_data; | |
286 int64_t max_size; | |
287 int res; | |
288 | |
289 /* calculate size of remaining data */ | |
290 max_size = aiff->data_end - url_ftell(s->pb); | |
291 if (max_size <= 0) | |
292 return AVERROR_EOF; | |
293 | |
294 /* Now for that packet */ | |
295 max_size = FFMIN(max_size, (MAX_SIZE / st->codec->block_align) * st->codec->block_align); | |
296 res = av_get_packet(s->pb, pkt, max_size); | |
297 if (res < 0) | |
298 return res; | |
299 | |
300 /* Only one stream in an AIFF file */ | |
301 pkt->stream_index = 0; | |
302 return 0; | |
303 } | |
304 | |
305 AVInputFormat aiff_demuxer = { | |
306 "aiff", | |
307 NULL_IF_CONFIG_SMALL("Audio IFF"), | |
308 sizeof(AIFFInputContext), | |
309 aiff_probe, | |
310 aiff_read_header, | |
311 aiff_read_packet, | |
312 NULL, | |
313 pcm_read_seek, | |
314 .codec_tag= (const AVCodecTag* const []){ff_codec_aiff_tags, 0}, | |
315 }; |