Statistics
| Branch: | Revision:

ffmpeg / libavformat / mmf.c @ 01f4895c

History | View | Annotate | Download (8.47 KB)

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