ffmpeg / libavformat / mmf.c @ 6cc7f139
History | View | Annotate | Download (8.24 KB)
1 | 115329f1 | Diego Biurrun | /*
|
---|---|---|---|
2 | 93a23627 | Vidar Madsen | * Yamaha SMAF format
|
3 | * Copyright (c) 2005 Vidar Madsen
|
||
4 | *
|
||
5 | 2912e87a | Mans Rullgard | * This file is part of Libav.
|
6 | b78e7197 | Diego Biurrun | *
|
7 | 2912e87a | Mans Rullgard | * Libav is free software; you can redistribute it and/or
|
8 | 93a23627 | Vidar Madsen | * modify it under the terms of the GNU Lesser General Public
|
9 | * License as published by the Free Software Foundation; either
|
||
10 | b78e7197 | Diego Biurrun | * version 2.1 of the License, or (at your option) any later version.
|
11 | 93a23627 | Vidar Madsen | *
|
12 | 2912e87a | Mans Rullgard | * Libav is distributed in the hope that it will be useful,
|
13 | 93a23627 | Vidar Madsen | * 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 | 2912e87a | Mans Rullgard | * License along with Libav; if not, write to the Free Software
|
19 | 5509bffa | Diego Biurrun | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
20 | 93a23627 | Vidar Madsen | */
|
21 | #include "avformat.h" |
||
22 | 0abdb293 | Anton Khirnov | #include "avio_internal.h" |
23 | e94204df | Aurelien Jacobs | #include "pcm.h" |
24 | 9d9f4119 | Måns Rullgård | #include "riff.h" |
25 | 93a23627 | Vidar Madsen | |
26 | typedef struct { |
||
27 | bc5c918e | Diego Biurrun | int64_t atrpos, atsqpos, awapos; |
28 | int64_t data_size; |
||
29 | 93a23627 | Vidar Madsen | } MMFContext; |
30 | |||
31 | aecf157e | Reimar Döffinger | static const int mmf_rates[] = { 4000, 8000, 11025, 22050, 44100 }; |
32 | 93a23627 | Vidar Madsen | |
33 | 37673b1b | Diego Biurrun | static int mmf_rate(int code) |
34 | { |
||
35 | if((code < 0) || (code > 4)) |
||
36 | return -1; |
||
37 | return mmf_rates[code];
|
||
38 | } |
||
39 | |||
40 | b250f9c6 | Aurelien Jacobs | #if CONFIG_MMF_MUXER
|
41 | 93a23627 | Vidar Madsen | static int mmf_rate_code(int rate) |
42 | { |
||
43 | int i;
|
||
44 | for(i = 0; i < 5; i++) |
||
45 | if(mmf_rates[i] == rate)
|
||
46 | return i;
|
||
47 | return -1; |
||
48 | } |
||
49 | |||
50 | /* Copy of end_tag() from avienc.c, but for big-endian chunk size */
|
||
51 | ae628ec1 | Anton Khirnov | static void end_tag_be(AVIOContext *pb, int64_t start) |
52 | 93a23627 | Vidar Madsen | { |
53 | bc5c918e | Diego Biurrun | int64_t pos; |
54 | 93a23627 | Vidar Madsen | |
55 | a2704c97 | Anton Khirnov | pos = avio_tell(pb); |
56 | 6b4aa5da | Anton Khirnov | avio_seek(pb, start - 4, SEEK_SET);
|
57 | 77eb5504 | Anton Khirnov | avio_wb32(pb, (uint32_t)(pos - start)); |
58 | 6b4aa5da | Anton Khirnov | avio_seek(pb, pos, SEEK_SET); |
59 | 93a23627 | Vidar Madsen | } |
60 | |||
61 | static int mmf_write_header(AVFormatContext *s) |
||
62 | { |
||
63 | MMFContext *mmf = s->priv_data; |
||
64 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
65 | bc5c918e | Diego Biurrun | int64_t pos; |
66 | 93a23627 | Vidar Madsen | int rate;
|
67 | |||
68 | 01f4895c | Michael Niedermayer | rate = mmf_rate_code(s->streams[0]->codec->sample_rate);
|
69 | 93a23627 | Vidar Madsen | if(rate < 0) { |
70 | 01f4895c | Michael Niedermayer | av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d\n", s->streams[0]->codec->sample_rate); |
71 | 93a23627 | Vidar Madsen | return -1; |
72 | } |
||
73 | 115329f1 | Diego Biurrun | |
74 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "MMMD");
|
75 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
76 | 1a40491e | Daniel Verkamp | pos = ff_start_tag(pb, "CNTI");
|
77 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0); /* class */ |
78 | avio_w8(pb, 0); /* type */ |
||
79 | avio_w8(pb, 0); /* code type */ |
||
80 | avio_w8(pb, 0); /* status */ |
||
81 | avio_w8(pb, 0); /* counts */ |
||
82 | bbc413f9 | Anton Khirnov | avio_write(pb, "VN:libavcodec,", sizeof("VN:libavcodec,") -1); /* metadata ("ST:songtitle,VN:version,...") */ |
83 | 93a23627 | Vidar Madsen | end_tag_be(pb, pos); |
84 | |||
85 | 77eb5504 | Anton Khirnov | avio_write(pb, "ATR\x00", 4); |
86 | avio_wb32(pb, 0);
|
||
87 | a2704c97 | Anton Khirnov | mmf->atrpos = avio_tell(pb); |
88 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0); /* format type */ |
89 | avio_w8(pb, 0); /* sequence type */ |
||
90 | avio_w8(pb, (0 << 7) | (1 << 4) | rate); /* (channel << 7) | (format << 4) | rate */ |
||
91 | avio_w8(pb, 0); /* wave base bit */ |
||
92 | avio_w8(pb, 2); /* time base d */ |
||
93 | avio_w8(pb, 2); /* time base g */ |
||
94 | 93a23627 | Vidar Madsen | |
95 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "Atsq");
|
96 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 16);
|
97 | a2704c97 | Anton Khirnov | mmf->atsqpos = avio_tell(pb); |
98 | 93a23627 | Vidar Madsen | /* Will be filled on close */
|
99 | 77eb5504 | Anton Khirnov | avio_write(pb, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); |
100 | 93a23627 | Vidar Madsen | |
101 | 1a40491e | Daniel Verkamp | mmf->awapos = ff_start_tag(pb, "Awa\x01");
|
102 | 93a23627 | Vidar Madsen | |
103 | 01f4895c | Michael Niedermayer | av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); |
104 | 93a23627 | Vidar Madsen | |
105 | b7f2fdde | Anton Khirnov | avio_flush(pb); |
106 | 93a23627 | Vidar Madsen | |
107 | return 0; |
||
108 | } |
||
109 | |||
110 | static int mmf_write_packet(AVFormatContext *s, AVPacket *pkt) |
||
111 | { |
||
112 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
113 | 77eb5504 | Anton Khirnov | avio_write(pb, pkt->data, pkt->size); |
114 | 93a23627 | Vidar Madsen | return 0; |
115 | } |
||
116 | |||
117 | /* Write a variable-length symbol */
|
||
118 | ae628ec1 | Anton Khirnov | static void put_varlength(AVIOContext *pb, int val) |
119 | 93a23627 | Vidar Madsen | { |
120 | if(val < 128) |
||
121 | 77eb5504 | Anton Khirnov | avio_w8(pb, val); |
122 | 93a23627 | Vidar Madsen | else {
|
123 | val -= 128;
|
||
124 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0x80 | val >> 7); |
125 | avio_w8(pb, 0x7f & val);
|
||
126 | 93a23627 | Vidar Madsen | } |
127 | } |
||
128 | |||
129 | static int mmf_write_trailer(AVFormatContext *s) |
||
130 | { |
||
131 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
132 | 93a23627 | Vidar Madsen | MMFContext *mmf = s->priv_data; |
133 | bc5c918e | Diego Biurrun | int64_t pos, size; |
134 | 93a23627 | Vidar Madsen | int gatetime;
|
135 | |||
136 | 8978feda | Anton Khirnov | if (s->pb->seekable) {
|
137 | 93a23627 | Vidar Madsen | /* Fill in length fields */
|
138 | end_tag_be(pb, mmf->awapos); |
||
139 | end_tag_be(pb, mmf->atrpos); |
||
140 | end_tag_be(pb, 8);
|
||
141 | |||
142 | a2704c97 | Anton Khirnov | pos = avio_tell(pb); |
143 | 93a23627 | Vidar Madsen | size = pos - mmf->awapos; |
144 | |||
145 | /* Fill Atsq chunk */
|
||
146 | 6b4aa5da | Anton Khirnov | avio_seek(pb, mmf->atsqpos, SEEK_SET); |
147 | 93a23627 | Vidar Madsen | |
148 | /* "play wav" */
|
||
149 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0); /* start time */ |
150 | avio_w8(pb, 1); /* (channel << 6) | wavenum */ |
||
151 | 01f4895c | Michael Niedermayer | gatetime = size * 500 / s->streams[0]->codec->sample_rate; |
152 | 93a23627 | Vidar Madsen | put_varlength(pb, gatetime); /* duration */
|
153 | |||
154 | /* "nop" */
|
||
155 | put_varlength(pb, gatetime); /* start time */
|
||
156 | 77eb5504 | Anton Khirnov | avio_write(pb, "\xff\x00", 2); /* nop */ |
157 | 93a23627 | Vidar Madsen | |
158 | /* "end of sequence" */
|
||
159 | 77eb5504 | Anton Khirnov | avio_write(pb, "\x00\x00\x00\x00", 4); |
160 | 93a23627 | Vidar Madsen | |
161 | 6b4aa5da | Anton Khirnov | avio_seek(pb, pos, SEEK_SET); |
162 | 93a23627 | Vidar Madsen | |
163 | b7f2fdde | Anton Khirnov | avio_flush(pb); |
164 | 93a23627 | Vidar Madsen | } |
165 | return 0; |
||
166 | } |
||
167 | 8212568a | Diego Biurrun | #endif /* CONFIG_MMF_MUXER */ |
168 | 93a23627 | Vidar Madsen | |
169 | static int mmf_probe(AVProbeData *p) |
||
170 | { |
||
171 | /* check file header */
|
||
172 | if (p->buf[0] == 'M' && p->buf[1] == 'M' && |
||
173 | p->buf[2] == 'M' && p->buf[3] == 'D' && |
||
174 | p->buf[8] == 'C' && p->buf[9] == 'N' && |
||
175 | p->buf[10] == 'T' && p->buf[11] == 'I') |
||
176 | return AVPROBE_SCORE_MAX;
|
||
177 | else
|
||
178 | return 0; |
||
179 | } |
||
180 | |||
181 | /* mmf input */
|
||
182 | static int mmf_read_header(AVFormatContext *s, |
||
183 | AVFormatParameters *ap) |
||
184 | { |
||
185 | MMFContext *mmf = s->priv_data; |
||
186 | unsigned int tag; |
||
187 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
188 | 93a23627 | Vidar Madsen | AVStream *st; |
189 | bc5c918e | Diego Biurrun | int64_t file_size, size; |
190 | 93a23627 | Vidar Madsen | int rate, params;
|
191 | |||
192 | b7effd4e | Anton Khirnov | tag = avio_rl32(pb); |
193 | 93a23627 | Vidar Madsen | if (tag != MKTAG('M', 'M', 'M', 'D')) |
194 | return -1; |
||
195 | b7effd4e | Anton Khirnov | file_size = avio_rb32(pb); |
196 | 93a23627 | Vidar Madsen | |
197 | /* Skip some unused chunks that may or may not be present */
|
||
198 | 45a8a02a | Anton Khirnov | for(;; avio_skip(pb, size)) {
|
199 | b7effd4e | Anton Khirnov | tag = avio_rl32(pb); |
200 | size = avio_rb32(pb); |
||
201 | 93a23627 | Vidar Madsen | if(tag == MKTAG('C','N','T','I')) continue; |
202 | if(tag == MKTAG('O','P','D','A')) continue; |
||
203 | break;
|
||
204 | } |
||
205 | |||
206 | /* Tag = "ATRx", where "x" = track number */
|
||
207 | c2ea5f06 | Alex Beregszaszi | if ((tag & 0xffffff) == MKTAG('M', 'T', 'R', 0)) { |
208 | av_log(s, AV_LOG_ERROR, "MIDI like format found, unsupported\n");
|
||
209 | return -1; |
||
210 | } |
||
211 | 93a23627 | Vidar Madsen | if ((tag & 0xffffff) != MKTAG('A', 'T', 'R', 0)) { |
212 | av_log(s, AV_LOG_ERROR, "Unsupported SMAF chunk %08x\n", tag);
|
||
213 | return -1; |
||
214 | } |
||
215 | |||
216 | b7effd4e | Anton Khirnov | avio_r8(pb); /* format type */
|
217 | avio_r8(pb); /* sequence type */
|
||
218 | params = avio_r8(pb); /* (channel << 7) | (format << 4) | rate */
|
||
219 | 93a23627 | Vidar Madsen | rate = mmf_rate(params & 0x0f);
|
220 | if(rate < 0) { |
||
221 | av_log(s, AV_LOG_ERROR, "Invalid sample rate\n");
|
||
222 | return -1; |
||
223 | } |
||
224 | b7effd4e | Anton Khirnov | avio_r8(pb); /* wave base bit */
|
225 | avio_r8(pb); /* time base d */
|
||
226 | avio_r8(pb); /* time base g */
|
||
227 | 93a23627 | Vidar Madsen | |
228 | /* Skip some unused chunks that may or may not be present */
|
||
229 | 45a8a02a | Anton Khirnov | for(;; avio_skip(pb, size)) {
|
230 | b7effd4e | Anton Khirnov | tag = avio_rl32(pb); |
231 | size = avio_rb32(pb); |
||
232 | 93a23627 | Vidar Madsen | if(tag == MKTAG('A','t','s','q')) continue; |
233 | if(tag == MKTAG('A','s','p','I')) continue; |
||
234 | break;
|
||
235 | } |
||
236 | |||
237 | /* Make sure it's followed by an Awa chunk, aka wave data */
|
||
238 | if ((tag & 0xffffff) != MKTAG('A', 'w', 'a', 0)) { |
||
239 | av_log(s, AV_LOG_ERROR, "Unexpected SMAF chunk %08x\n", tag);
|
||
240 | return -1; |
||
241 | } |
||
242 | mmf->data_size = size; |
||
243 | |||
244 | st = av_new_stream(s, 0);
|
||
245 | if (!st)
|
||
246 | 769e10f0 | Panagiotis Issaris | return AVERROR(ENOMEM);
|
247 | 93a23627 | Vidar Madsen | |
248 | 72415b2a | Stefano Sabatini | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
249 | 01f4895c | Michael Niedermayer | st->codec->codec_id = CODEC_ID_ADPCM_YAMAHA; |
250 | st->codec->sample_rate = rate; |
||
251 | st->codec->channels = 1;
|
||
252 | dd1c8f3e | Luca Abeni | st->codec->bits_per_coded_sample = 4;
|
253 | st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_coded_sample; |
||
254 | 93a23627 | Vidar Madsen | |
255 | 01f4895c | Michael Niedermayer | av_set_pts_info(st, 64, 1, st->codec->sample_rate); |
256 | 93a23627 | Vidar Madsen | |
257 | return 0; |
||
258 | } |
||
259 | |||
260 | #define MAX_SIZE 4096 |
||
261 | |||
262 | static int mmf_read_packet(AVFormatContext *s, |
||
263 | AVPacket *pkt) |
||
264 | { |
||
265 | MMFContext *mmf = s->priv_data; |
||
266 | AVStream *st; |
||
267 | int ret, size;
|
||
268 | |||
269 | 66e5b1df | Anton Khirnov | if (s->pb->eof_reached)
|
270 | 6f3e0b21 | Panagiotis Issaris | return AVERROR(EIO);
|
271 | 93a23627 | Vidar Madsen | st = s->streams[0];
|
272 | |||
273 | size = MAX_SIZE; |
||
274 | if(size > mmf->data_size)
|
||
275 | size = mmf->data_size; |
||
276 | |||
277 | if(!size)
|
||
278 | 6f3e0b21 | Panagiotis Issaris | return AVERROR(EIO);
|
279 | 115329f1 | Diego Biurrun | |
280 | 93a23627 | Vidar Madsen | if (av_new_packet(pkt, size))
|
281 | 6f3e0b21 | Panagiotis Issaris | return AVERROR(EIO);
|
282 | 93a23627 | Vidar Madsen | pkt->stream_index = 0;
|
283 | |||
284 | b7effd4e | Anton Khirnov | ret = avio_read(s->pb, pkt->data, pkt->size); |
285 | 93a23627 | Vidar Madsen | if (ret < 0) |
286 | av_free_packet(pkt); |
||
287 | |||
288 | mmf->data_size -= ret; |
||
289 | |||
290 | pkt->size = ret; |
||
291 | return ret;
|
||
292 | } |
||
293 | |||
294 | b250f9c6 | Aurelien Jacobs | #if CONFIG_MMF_DEMUXER
|
295 | c6610a21 | Diego Elio Pettenò | AVInputFormat ff_mmf_demuxer = { |
296 | 93a23627 | Vidar Madsen | "mmf",
|
297 | 517ac243 | Diego Biurrun | NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
|
298 | 93a23627 | Vidar Madsen | sizeof(MMFContext),
|
299 | mmf_probe, |
||
300 | mmf_read_header, |
||
301 | mmf_read_packet, |
||
302 | e7fd7b9a | Reimar Döffinger | NULL,
|
303 | 15d856e8 | Ramiro Polla | pcm_read_seek, |
304 | 93a23627 | Vidar Madsen | }; |
305 | ff70e601 | Måns Rullgård | #endif
|
306 | b250f9c6 | Aurelien Jacobs | #if CONFIG_MMF_MUXER
|
307 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_mmf_muxer = { |
308 | 93a23627 | Vidar Madsen | "mmf",
|
309 | 517ac243 | Diego Biurrun | NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
|
310 | 93a23627 | Vidar Madsen | "application/vnd.smaf",
|
311 | "mmf",
|
||
312 | sizeof(MMFContext),
|
||
313 | CODEC_ID_ADPCM_YAMAHA, |
||
314 | CODEC_ID_NONE, |
||
315 | mmf_write_header, |
||
316 | mmf_write_packet, |
||
317 | mmf_write_trailer, |
||
318 | }; |
||
319 | ff70e601 | Måns Rullgård | #endif |