avio: rename ByteIOContext to AVIOContext.
[ffmpeg.git] / libavformat / mmf.c
1 /*
2  * Yamaha SMAF format
3  * Copyright (c) 2005 Vidar Madsen
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 #include "avformat.h"
22 #include "pcm.h"
23 #include "riff.h"
24
25 typedef struct {
26     int64_t atrpos, atsqpos, awapos;
27     int64_t data_size;
28 } MMFContext;
29
30 static const int mmf_rates[] = { 4000, 8000, 11025, 22050, 44100 };
31
32 static int mmf_rate(int code)
33 {
34     if((code < 0) || (code > 4))
35         return -1;
36     return mmf_rates[code];
37 }
38
39 #if CONFIG_MMF_MUXER
40 static int mmf_rate_code(int rate)
41 {
42     int i;
43     for(i = 0; i < 5; i++)
44         if(mmf_rates[i] == rate)
45             return i;
46     return -1;
47 }
48
49 /* Copy of end_tag() from avienc.c, but for big-endian chunk size */
50 static void end_tag_be(AVIOContext *pb, int64_t start)
51 {
52     int64_t pos;
53
54     pos = url_ftell(pb);
55     url_fseek(pb, start - 4, SEEK_SET);
56     put_be32(pb, (uint32_t)(pos - start));
57     url_fseek(pb, pos, SEEK_SET);
58 }
59
60 static int mmf_write_header(AVFormatContext *s)
61 {
62     MMFContext *mmf = s->priv_data;
63     AVIOContext *pb = s->pb;
64     int64_t pos;
65     int rate;
66
67     rate = mmf_rate_code(s->streams[0]->codec->sample_rate);
68     if(rate < 0) {
69         av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d\n", s->streams[0]->codec->sample_rate);
70         return -1;
71     }
72
73     put_tag(pb, "MMMD");
74     put_be32(pb, 0);
75     pos = ff_start_tag(pb, "CNTI");
76     put_byte(pb, 0); /* class */
77     put_byte(pb, 0); /* type */
78     put_byte(pb, 0); /* code type */
79     put_byte(pb, 0); /* status */
80     put_byte(pb, 0); /* counts */
81     put_tag(pb, "VN:libavcodec,"); /* metadata ("ST:songtitle,VN:version,...") */
82     end_tag_be(pb, pos);
83
84     put_buffer(pb, "ATR\x00", 4);
85     put_be32(pb, 0);
86     mmf->atrpos = url_ftell(pb);
87     put_byte(pb, 0); /* format type */
88     put_byte(pb, 0); /* sequence type */
89     put_byte(pb, (0 << 7) | (1 << 4) | rate); /* (channel << 7) | (format << 4) | rate */
90     put_byte(pb, 0); /* wave base bit */
91     put_byte(pb, 2); /* time base d */
92     put_byte(pb, 2); /* time base g */
93
94     put_tag(pb, "Atsq");
95     put_be32(pb, 16);
96     mmf->atsqpos = url_ftell(pb);
97     /* Will be filled on close */
98     put_buffer(pb, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
99
100     mmf->awapos = ff_start_tag(pb, "Awa\x01");
101
102     av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
103
104     put_flush_packet(pb);
105
106     return 0;
107 }
108
109 static int mmf_write_packet(AVFormatContext *s, AVPacket *pkt)
110 {
111     AVIOContext *pb = s->pb;
112     put_buffer(pb, pkt->data, pkt->size);
113     return 0;
114 }
115
116 /* Write a variable-length symbol */
117 static void put_varlength(AVIOContext *pb, int val)
118 {
119     if(val < 128)
120         put_byte(pb, val);
121     else {
122         val -= 128;
123         put_byte(pb, 0x80 | val >> 7);
124         put_byte(pb, 0x7f & val);
125     }
126 }
127
128 static int mmf_write_trailer(AVFormatContext *s)
129 {
130     AVIOContext *pb = s->pb;
131     MMFContext *mmf = s->priv_data;
132     int64_t pos, size;
133     int gatetime;
134
135     if (!url_is_streamed(s->pb)) {
136         /* Fill in length fields */
137         end_tag_be(pb, mmf->awapos);
138         end_tag_be(pb, mmf->atrpos);
139         end_tag_be(pb, 8);
140
141         pos = url_ftell(pb);
142         size = pos - mmf->awapos;
143
144         /* Fill Atsq chunk */
145         url_fseek(pb, mmf->atsqpos, SEEK_SET);
146
147         /* "play wav" */
148         put_byte(pb, 0); /* start time */
149         put_byte(pb, 1); /* (channel << 6) | wavenum */
150         gatetime = size * 500 / s->streams[0]->codec->sample_rate;
151         put_varlength(pb, gatetime); /* duration */
152
153         /* "nop" */
154         put_varlength(pb, gatetime); /* start time */
155         put_buffer(pb, "\xff\x00", 2); /* nop */
156
157         /* "end of sequence" */
158         put_buffer(pb, "\x00\x00\x00\x00", 4);
159
160         url_fseek(pb, pos, SEEK_SET);
161
162         put_flush_packet(pb);
163     }
164     return 0;
165 }
166 #endif /* CONFIG_MMF_MUXER */
167
168 static int mmf_probe(AVProbeData *p)
169 {
170     /* check file header */
171     if (p->buf[0] == 'M' && p->buf[1] == 'M' &&
172         p->buf[2] == 'M' && p->buf[3] == 'D' &&
173         p->buf[8] == 'C' && p->buf[9] == 'N' &&
174         p->buf[10] == 'T' && p->buf[11] == 'I')
175         return AVPROBE_SCORE_MAX;
176     else
177         return 0;
178 }
179
180 /* mmf input */
181 static int mmf_read_header(AVFormatContext *s,
182                            AVFormatParameters *ap)
183 {
184     MMFContext *mmf = s->priv_data;
185     unsigned int tag;
186     AVIOContext *pb = s->pb;
187     AVStream *st;
188     int64_t file_size, size;
189     int rate, params;
190
191     tag = get_le32(pb);
192     if (tag != MKTAG('M', 'M', 'M', 'D'))
193         return -1;
194     file_size = get_be32(pb);
195
196     /* Skip some unused chunks that may or may not be present */
197     for(;; url_fseek(pb, size, SEEK_CUR)) {
198         tag = get_le32(pb);
199         size = get_be32(pb);
200         if(tag == MKTAG('C','N','T','I')) continue;
201         if(tag == MKTAG('O','P','D','A')) continue;
202         break;
203     }
204
205     /* Tag = "ATRx", where "x" = track number */
206     if ((tag & 0xffffff) == MKTAG('M', 'T', 'R', 0)) {
207         av_log(s, AV_LOG_ERROR, "MIDI like format found, unsupported\n");
208         return -1;
209     }
210     if ((tag & 0xffffff) != MKTAG('A', 'T', 'R', 0)) {
211         av_log(s, AV_LOG_ERROR, "Unsupported SMAF chunk %08x\n", tag);
212         return -1;
213     }
214
215     get_byte(pb); /* format type */
216     get_byte(pb); /* sequence type */
217     params = get_byte(pb); /* (channel << 7) | (format << 4) | rate */
218     rate = mmf_rate(params & 0x0f);
219     if(rate  < 0) {
220         av_log(s, AV_LOG_ERROR, "Invalid sample rate\n");
221         return -1;
222     }
223     get_byte(pb); /* wave base bit */
224     get_byte(pb); /* time base d */
225     get_byte(pb); /* time base g */
226
227     /* Skip some unused chunks that may or may not be present */
228     for(;; url_fseek(pb, size, SEEK_CUR)) {
229         tag = get_le32(pb);
230         size = get_be32(pb);
231         if(tag == MKTAG('A','t','s','q')) continue;
232         if(tag == MKTAG('A','s','p','I')) continue;
233         break;
234     }
235
236     /* Make sure it's followed by an Awa chunk, aka wave data */
237     if ((tag & 0xffffff) != MKTAG('A', 'w', 'a', 0)) {
238         av_log(s, AV_LOG_ERROR, "Unexpected SMAF chunk %08x\n", tag);
239         return -1;
240     }
241     mmf->data_size = size;
242
243     st = av_new_stream(s, 0);
244     if (!st)
245         return AVERROR(ENOMEM);
246
247     st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
248     st->codec->codec_id = CODEC_ID_ADPCM_YAMAHA;
249     st->codec->sample_rate = rate;
250     st->codec->channels = 1;
251     st->codec->bits_per_coded_sample = 4;
252     st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_coded_sample;
253
254     av_set_pts_info(st, 64, 1, st->codec->sample_rate);
255
256     return 0;
257 }
258
259 #define MAX_SIZE 4096
260
261 static int mmf_read_packet(AVFormatContext *s,
262                            AVPacket *pkt)
263 {
264     MMFContext *mmf = s->priv_data;
265     AVStream *st;
266     int ret, size;
267
268     if (url_feof(s->pb))
269         return AVERROR(EIO);
270     st = s->streams[0];
271
272     size = MAX_SIZE;
273     if(size > mmf->data_size)
274         size = mmf->data_size;
275
276     if(!size)
277         return AVERROR(EIO);
278
279     if (av_new_packet(pkt, size))
280         return AVERROR(EIO);
281     pkt->stream_index = 0;
282
283     ret = get_buffer(s->pb, pkt->data, pkt->size);
284     if (ret < 0)
285         av_free_packet(pkt);
286
287     mmf->data_size -= ret;
288
289     pkt->size = ret;
290     return ret;
291 }
292
293 #if CONFIG_MMF_DEMUXER
294 AVInputFormat ff_mmf_demuxer = {
295     "mmf",
296     NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
297     sizeof(MMFContext),
298     mmf_probe,
299     mmf_read_header,
300     mmf_read_packet,
301     NULL,
302     pcm_read_seek,
303 };
304 #endif
305 #if CONFIG_MMF_MUXER
306 AVOutputFormat ff_mmf_muxer = {
307     "mmf",
308     NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
309     "application/vnd.smaf",
310     "mmf",
311     sizeof(MMFContext),
312     CODEC_ID_ADPCM_YAMAHA,
313     CODEC_ID_NONE,
314     mmf_write_header,
315     mmf_write_packet,
316     mmf_write_trailer,
317 };
318 #endif