Mercurial > libavformat.hg
comparison mmf.c @ 818:b1d7ee1c792d libavformat
Yamaha SMAF file format support patch by (Vidar Madsen: vidarino, gmail com)
author | michael |
---|---|
date | Fri, 15 Jul 2005 12:50:00 +0000 |
parents | |
children | feca73904e67 |
comparison
equal
deleted
inserted
replaced
817:8e9c4e5d157b | 818:b1d7ee1c792d |
---|---|
1 /* | |
2 * Yamaha SMAF format | |
3 * Copyright (c) 2005 Vidar Madsen | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library 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 GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 #include "avformat.h" | |
20 #include "avi.h" | |
21 | |
22 #ifdef CONFIG_ENCODERS | |
23 typedef struct { | |
24 offset_t atrpos, atsqpos, awapos; | |
25 offset_t data_size; | |
26 } MMFContext; | |
27 | |
28 static int mmf_rates[] = { 4000, 8000, 11025, 22050, 44100 }; | |
29 | |
30 static int mmf_rate_code(int rate) | |
31 { | |
32 int i; | |
33 for(i = 0; i < 5; i++) | |
34 if(mmf_rates[i] == rate) | |
35 return i; | |
36 return -1; | |
37 } | |
38 | |
39 static int mmf_rate(int code) | |
40 { | |
41 if((code < 0) || (code > 4)) | |
42 return -1; | |
43 return mmf_rates[code]; | |
44 } | |
45 | |
46 /* Copy of end_tag() from avienc.c, but for big-endian chunk size */ | |
47 static void end_tag_be(ByteIOContext *pb, offset_t start) | |
48 { | |
49 offset_t pos; | |
50 | |
51 pos = url_ftell(pb); | |
52 url_fseek(pb, start - 4, SEEK_SET); | |
53 put_be32(pb, (uint32_t)(pos - start)); | |
54 url_fseek(pb, pos, SEEK_SET); | |
55 } | |
56 | |
57 static int mmf_write_header(AVFormatContext *s) | |
58 { | |
59 MMFContext *mmf = s->priv_data; | |
60 ByteIOContext *pb = &s->pb; | |
61 offset_t pos; | |
62 int rate; | |
63 | |
64 rate = mmf_rate_code(s->streams[0]->codec.sample_rate); | |
65 if(rate < 0) { | |
66 av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d\n", s->streams[0]->codec.sample_rate); | |
67 return -1; | |
68 } | |
69 | |
70 put_tag(pb, "MMMD"); | |
71 put_be32(pb, 0); | |
72 pos = start_tag(pb, "CNTI"); | |
73 put_byte(pb, 0); /* class */ | |
74 put_byte(pb, 0); /* type */ | |
75 put_byte(pb, 0); /* code type */ | |
76 put_byte(pb, 0); /* status */ | |
77 put_byte(pb, 0); /* counts */ | |
78 put_tag(pb, "VN:libavcodec,"); /* metadata ("ST:songtitle,VN:version,...") */ | |
79 end_tag_be(pb, pos); | |
80 | |
81 put_buffer(pb, "ATR\x00", 4); | |
82 put_be32(pb, 0); | |
83 mmf->atrpos = url_ftell(pb); | |
84 put_byte(pb, 0); /* format type */ | |
85 put_byte(pb, 0); /* sequence type */ | |
86 put_byte(pb, (0 << 7) | (1 << 4) | rate); /* (channel << 7) | (format << 4) | rate */ | |
87 put_byte(pb, 0); /* wave base bit */ | |
88 put_byte(pb, 2); /* time base d */ | |
89 put_byte(pb, 2); /* time base g */ | |
90 | |
91 put_tag(pb, "Atsq"); | |
92 put_be32(pb, 16); | |
93 mmf->atsqpos = url_ftell(pb); | |
94 /* Will be filled on close */ | |
95 put_buffer(pb, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); | |
96 | |
97 mmf->awapos = start_tag(pb, "Awa\x01"); | |
98 | |
99 av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec.sample_rate); | |
100 | |
101 put_flush_packet(pb); | |
102 | |
103 return 0; | |
104 } | |
105 | |
106 static int mmf_write_packet(AVFormatContext *s, AVPacket *pkt) | |
107 { | |
108 ByteIOContext *pb = &s->pb; | |
109 put_buffer(pb, pkt->data, pkt->size); | |
110 return 0; | |
111 } | |
112 | |
113 /* Write a variable-length symbol */ | |
114 static void put_varlength(ByteIOContext *pb, int val) | |
115 { | |
116 if(val < 128) | |
117 put_byte(pb, val); | |
118 else { | |
119 val -= 128; | |
120 put_byte(pb, 0x80 | val >> 7); | |
121 put_byte(pb, 0x7f & val); | |
122 } | |
123 } | |
124 | |
125 static int mmf_write_trailer(AVFormatContext *s) | |
126 { | |
127 ByteIOContext *pb = &s->pb; | |
128 MMFContext *mmf = s->priv_data; | |
129 offset_t pos, size; | |
130 int gatetime; | |
131 | |
132 if (!url_is_streamed(&s->pb)) { | |
133 /* Fill in length fields */ | |
134 end_tag_be(pb, mmf->awapos); | |
135 end_tag_be(pb, mmf->atrpos); | |
136 end_tag_be(pb, 8); | |
137 | |
138 pos = url_ftell(pb); | |
139 size = pos - mmf->awapos; | |
140 | |
141 /* Fill Atsq chunk */ | |
142 url_fseek(pb, mmf->atsqpos, SEEK_SET); | |
143 | |
144 /* "play wav" */ | |
145 put_byte(pb, 0); /* start time */ | |
146 put_byte(pb, 1); /* (channel << 6) | wavenum */ | |
147 gatetime = size * 500 / s->streams[0]->codec.sample_rate; | |
148 put_varlength(pb, gatetime); /* duration */ | |
149 | |
150 /* "nop" */ | |
151 put_varlength(pb, gatetime); /* start time */ | |
152 put_buffer(pb, "\xff\x00", 2); /* nop */ | |
153 | |
154 /* "end of sequence" */ | |
155 put_buffer(pb, "\x00\x00\x00\x00", 4); | |
156 | |
157 url_fseek(pb, pos, SEEK_SET); | |
158 | |
159 put_flush_packet(pb); | |
160 } | |
161 return 0; | |
162 } | |
163 #endif //CONFIG_ENCODERS | |
164 | |
165 static int mmf_probe(AVProbeData *p) | |
166 { | |
167 /* check file header */ | |
168 if (p->buf_size <= 32) | |
169 return 0; | |
170 if (p->buf[0] == 'M' && p->buf[1] == 'M' && | |
171 p->buf[2] == 'M' && p->buf[3] == 'D' && | |
172 p->buf[8] == 'C' && p->buf[9] == 'N' && | |
173 p->buf[10] == 'T' && p->buf[11] == 'I') | |
174 return AVPROBE_SCORE_MAX; | |
175 else | |
176 return 0; | |
177 } | |
178 | |
179 /* mmf input */ | |
180 static int mmf_read_header(AVFormatContext *s, | |
181 AVFormatParameters *ap) | |
182 { | |
183 MMFContext *mmf = s->priv_data; | |
184 unsigned int tag; | |
185 ByteIOContext *pb = &s->pb; | |
186 AVStream *st; | |
187 offset_t file_size, size; | |
188 int rate, params; | |
189 | |
190 tag = get_le32(pb); | |
191 if (tag != MKTAG('M', 'M', 'M', 'D')) | |
192 return -1; | |
193 file_size = get_be32(pb); | |
194 | |
195 /* Skip some unused chunks that may or may not be present */ | |
196 for(;; url_fseek(pb, size, SEEK_CUR)) { | |
197 tag = get_le32(pb); | |
198 size = get_be32(pb); | |
199 if(tag == MKTAG('C','N','T','I')) continue; | |
200 if(tag == MKTAG('O','P','D','A')) continue; | |
201 break; | |
202 } | |
203 | |
204 /* Tag = "ATRx", where "x" = track number */ | |
205 if ((tag & 0xffffff) != MKTAG('A', 'T', 'R', 0)) { | |
206 av_log(s, AV_LOG_ERROR, "Unsupported SMAF chunk %08x\n", tag); | |
207 return -1; | |
208 } | |
209 | |
210 get_byte(pb); /* format type */ | |
211 get_byte(pb); /* sequence type */ | |
212 params = get_byte(pb); /* (channel << 7) | (format << 4) | rate */ | |
213 rate = mmf_rate(params & 0x0f); | |
214 if(rate < 0) { | |
215 av_log(s, AV_LOG_ERROR, "Invalid sample rate\n"); | |
216 return -1; | |
217 } | |
218 get_byte(pb); /* wave base bit */ | |
219 get_byte(pb); /* time base d */ | |
220 get_byte(pb); /* time base g */ | |
221 | |
222 /* Skip some unused chunks that may or may not be present */ | |
223 for(;; url_fseek(pb, size, SEEK_CUR)) { | |
224 tag = get_le32(pb); | |
225 size = get_be32(pb); | |
226 if(tag == MKTAG('A','t','s','q')) continue; | |
227 if(tag == MKTAG('A','s','p','I')) continue; | |
228 break; | |
229 } | |
230 | |
231 /* Make sure it's followed by an Awa chunk, aka wave data */ | |
232 if ((tag & 0xffffff) != MKTAG('A', 'w', 'a', 0)) { | |
233 av_log(s, AV_LOG_ERROR, "Unexpected SMAF chunk %08x\n", tag); | |
234 return -1; | |
235 } | |
236 mmf->data_size = size; | |
237 | |
238 st = av_new_stream(s, 0); | |
239 if (!st) | |
240 return AVERROR_NOMEM; | |
241 | |
242 st->codec.codec_type = CODEC_TYPE_AUDIO; | |
243 st->codec.codec_id = CODEC_ID_ADPCM_YAMAHA; | |
244 st->codec.sample_rate = rate; | |
245 st->codec.channels = 1; | |
246 st->codec.bits_per_sample = 4; | |
247 st->codec.bit_rate = st->codec.sample_rate * st->codec.bits_per_sample; | |
248 | |
249 av_set_pts_info(st, 64, 1, st->codec.sample_rate); | |
250 | |
251 return 0; | |
252 } | |
253 | |
254 #define MAX_SIZE 4096 | |
255 | |
256 static int mmf_read_packet(AVFormatContext *s, | |
257 AVPacket *pkt) | |
258 { | |
259 MMFContext *mmf = s->priv_data; | |
260 AVStream *st; | |
261 int ret, size; | |
262 | |
263 if (url_feof(&s->pb)) | |
264 return AVERROR_IO; | |
265 st = s->streams[0]; | |
266 | |
267 size = MAX_SIZE; | |
268 if(size > mmf->data_size) | |
269 size = mmf->data_size; | |
270 | |
271 if(!size) | |
272 return AVERROR_IO; | |
273 | |
274 if (av_new_packet(pkt, size)) | |
275 return AVERROR_IO; | |
276 pkt->stream_index = 0; | |
277 | |
278 ret = get_buffer(&s->pb, pkt->data, pkt->size); | |
279 if (ret < 0) | |
280 av_free_packet(pkt); | |
281 | |
282 mmf->data_size -= ret; | |
283 | |
284 pkt->size = ret; | |
285 return ret; | |
286 } | |
287 | |
288 static int mmf_read_close(AVFormatContext *s) | |
289 { | |
290 return 0; | |
291 } | |
292 | |
293 static int mmf_read_seek(AVFormatContext *s, | |
294 int stream_index, int64_t timestamp, int flags) | |
295 { | |
296 return pcm_read_seek(s, stream_index, timestamp, flags); | |
297 } | |
298 | |
299 | |
300 static AVInputFormat mmf_iformat = { | |
301 "mmf", | |
302 "mmf format", | |
303 sizeof(MMFContext), | |
304 mmf_probe, | |
305 mmf_read_header, | |
306 mmf_read_packet, | |
307 mmf_read_close, | |
308 mmf_read_seek, | |
309 }; | |
310 | |
311 #ifdef CONFIG_ENCODERS | |
312 static AVOutputFormat mmf_oformat = { | |
313 "mmf", | |
314 "mmf format", | |
315 "application/vnd.smaf", | |
316 "mmf", | |
317 sizeof(MMFContext), | |
318 CODEC_ID_ADPCM_YAMAHA, | |
319 CODEC_ID_NONE, | |
320 mmf_write_header, | |
321 mmf_write_packet, | |
322 mmf_write_trailer, | |
323 }; | |
324 #endif //CONFIG_ENCODERS | |
325 | |
326 int ff_mmf_init(void) | |
327 { | |
328 av_register_input_format(&mmf_iformat); | |
329 #ifdef CONFIG_ENCODERS | |
330 av_register_output_format(&mmf_oformat); | |
331 #endif //CONFIG_ENCODERS | |
332 return 0; | |
333 } | |
334 |