mmf.c 8.23 KB
Newer Older
1
/*
2 3 4
 * Yamaha SMAF format
 * Copyright (c) 2005 Vidar Madsen
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * 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 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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 "raw.h"
23
#include "riff.h"
24 25

typedef struct {
26 27
    int64_t atrpos, atsqpos, awapos;
    int64_t data_size;
28 29
} MMFContext;

30
static const int mmf_rates[] = { 4000, 8000, 11025, 22050, 44100 };
31

32 33 34 35 36 37 38
static int mmf_rate(int code)
{
    if((code < 0) || (code > 4))
        return -1;
    return mmf_rates[code];
}

39
#if CONFIG_MMF_MUXER
40 41 42 43 44 45 46 47 48 49
static int mmf_rate_code(int rate)
{
    int i;
    for(i = 0; i < 5; i++)
        if(mmf_rates[i] == rate)
            return i;
    return -1;
}

/* Copy of end_tag() from avienc.c, but for big-endian chunk size */
50
static void end_tag_be(ByteIOContext *pb, int64_t start)
51
{
52
    int64_t pos;
53 54 55 56 57 58 59 60 61 62

    pos = url_ftell(pb);
    url_fseek(pb, start - 4, SEEK_SET);
    put_be32(pb, (uint32_t)(pos - start));
    url_fseek(pb, pos, SEEK_SET);
}

static int mmf_write_header(AVFormatContext *s)
{
    MMFContext *mmf = s->priv_data;
63
    ByteIOContext *pb = s->pb;
64
    int64_t pos;
65 66
    int rate;

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 71
        return -1;
    }
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
    put_tag(pb, "MMMD");
    put_be32(pb, 0);
    pos = start_tag(pb, "CNTI");
    put_byte(pb, 0); /* class */
    put_byte(pb, 0); /* type */
    put_byte(pb, 0); /* code type */
    put_byte(pb, 0); /* status */
    put_byte(pb, 0); /* counts */
    put_tag(pb, "VN:libavcodec,"); /* metadata ("ST:songtitle,VN:version,...") */
    end_tag_be(pb, pos);

    put_buffer(pb, "ATR\x00", 4);
    put_be32(pb, 0);
    mmf->atrpos = url_ftell(pb);
    put_byte(pb, 0); /* format type */
    put_byte(pb, 0); /* sequence type */
    put_byte(pb, (0 << 7) | (1 << 4) | rate); /* (channel << 7) | (format << 4) | rate */
    put_byte(pb, 0); /* wave base bit */
    put_byte(pb, 2); /* time base d */
    put_byte(pb, 2); /* time base g */

    put_tag(pb, "Atsq");
    put_be32(pb, 16);
    mmf->atsqpos = url_ftell(pb);
    /* Will be filled on close */
    put_buffer(pb, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);

    mmf->awapos = start_tag(pb, "Awa\x01");

102
    av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
103 104 105 106 107 108 109 110

    put_flush_packet(pb);

    return 0;
}

static int mmf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
111
    ByteIOContext *pb = s->pb;
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    put_buffer(pb, pkt->data, pkt->size);
    return 0;
}

/* Write a variable-length symbol */
static void put_varlength(ByteIOContext *pb, int val)
{
    if(val < 128)
        put_byte(pb, val);
    else {
        val -= 128;
        put_byte(pb, 0x80 | val >> 7);
        put_byte(pb, 0x7f & val);
    }
}

static int mmf_write_trailer(AVFormatContext *s)
{
130
    ByteIOContext *pb = s->pb;
131
    MMFContext *mmf = s->priv_data;
132
    int64_t pos, size;
133 134
    int gatetime;

135
    if (!url_is_streamed(s->pb)) {
136 137 138 139 140 141 142 143 144 145 146 147 148 149
        /* Fill in length fields */
        end_tag_be(pb, mmf->awapos);
        end_tag_be(pb, mmf->atrpos);
        end_tag_be(pb, 8);

        pos = url_ftell(pb);
        size = pos - mmf->awapos;

        /* Fill Atsq chunk */
        url_fseek(pb, mmf->atsqpos, SEEK_SET);

        /* "play wav" */
        put_byte(pb, 0); /* start time */
        put_byte(pb, 1); /* (channel << 6) | wavenum */
150
        gatetime = size * 500 / s->streams[0]->codec->sample_rate;
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
        put_varlength(pb, gatetime); /* duration */

        /* "nop" */
        put_varlength(pb, gatetime); /* start time */
        put_buffer(pb, "\xff\x00", 2); /* nop */

        /* "end of sequence" */
        put_buffer(pb, "\x00\x00\x00\x00", 4);

        url_fseek(pb, pos, SEEK_SET);

        put_flush_packet(pb);
    }
    return 0;
}
166
#endif /* CONFIG_MMF_MUXER */
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

static int mmf_probe(AVProbeData *p)
{
    /* check file header */
    if (p->buf[0] == 'M' && p->buf[1] == 'M' &&
        p->buf[2] == 'M' && p->buf[3] == 'D' &&
        p->buf[8] == 'C' && p->buf[9] == 'N' &&
        p->buf[10] == 'T' && p->buf[11] == 'I')
        return AVPROBE_SCORE_MAX;
    else
        return 0;
}

/* mmf input */
static int mmf_read_header(AVFormatContext *s,
                           AVFormatParameters *ap)
{
    MMFContext *mmf = s->priv_data;
    unsigned int tag;
186
    ByteIOContext *pb = s->pb;
187
    AVStream *st;
188
    int64_t file_size, size;
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
    int rate, params;

    tag = get_le32(pb);
    if (tag != MKTAG('M', 'M', 'M', 'D'))
        return -1;
    file_size = get_be32(pb);

    /* Skip some unused chunks that may or may not be present */
    for(;; url_fseek(pb, size, SEEK_CUR)) {
        tag = get_le32(pb);
        size = get_be32(pb);
        if(tag == MKTAG('C','N','T','I')) continue;
        if(tag == MKTAG('O','P','D','A')) continue;
        break;
    }

    /* Tag = "ATRx", where "x" = track number */
206 207 208 209
    if ((tag & 0xffffff) == MKTAG('M', 'T', 'R', 0)) {
        av_log(s, AV_LOG_ERROR, "MIDI like format found, unsupported\n");
        return -1;
    }
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
    if ((tag & 0xffffff) != MKTAG('A', 'T', 'R', 0)) {
        av_log(s, AV_LOG_ERROR, "Unsupported SMAF chunk %08x\n", tag);
        return -1;
    }

    get_byte(pb); /* format type */
    get_byte(pb); /* sequence type */
    params = get_byte(pb); /* (channel << 7) | (format << 4) | rate */
    rate = mmf_rate(params & 0x0f);
    if(rate  < 0) {
        av_log(s, AV_LOG_ERROR, "Invalid sample rate\n");
        return -1;
    }
    get_byte(pb); /* wave base bit */
    get_byte(pb); /* time base d */
    get_byte(pb); /* time base g */

    /* Skip some unused chunks that may or may not be present */
    for(;; url_fseek(pb, size, SEEK_CUR)) {
        tag = get_le32(pb);
        size = get_be32(pb);
        if(tag == MKTAG('A','t','s','q')) continue;
        if(tag == MKTAG('A','s','p','I')) continue;
        break;
    }

    /* Make sure it's followed by an Awa chunk, aka wave data */
    if ((tag & 0xffffff) != MKTAG('A', 'w', 'a', 0)) {
        av_log(s, AV_LOG_ERROR, "Unexpected SMAF chunk %08x\n", tag);
        return -1;
    }
    mmf->data_size = size;

    st = av_new_stream(s, 0);
    if (!st)
245
        return AVERROR(ENOMEM);
246

247 248 249 250
    st->codec->codec_type = CODEC_TYPE_AUDIO;
    st->codec->codec_id = CODEC_ID_ADPCM_YAMAHA;
    st->codec->sample_rate = rate;
    st->codec->channels = 1;
251 252
    st->codec->bits_per_coded_sample = 4;
    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 257 258 259 260 261 262 263 264 265 266 267

    return 0;
}

#define MAX_SIZE 4096

static int mmf_read_packet(AVFormatContext *s,
                           AVPacket *pkt)
{
    MMFContext *mmf = s->priv_data;
    AVStream *st;
    int ret, size;

268
    if (url_feof(s->pb))
269
        return AVERROR(EIO);
270 271 272 273 274 275 276
    st = s->streams[0];

    size = MAX_SIZE;
    if(size > mmf->data_size)
        size = mmf->data_size;

    if(!size)
277
        return AVERROR(EIO);
278

279
    if (av_new_packet(pkt, size))
280
        return AVERROR(EIO);
281 282
    pkt->stream_index = 0;

283
    ret = get_buffer(s->pb, pkt->data, pkt->size);
284 285 286 287 288 289 290 291 292
    if (ret < 0)
        av_free_packet(pkt);

    mmf->data_size -= ret;

    pkt->size = ret;
    return ret;
}

293
#if CONFIG_MMF_DEMUXER
294
AVInputFormat mmf_demuxer = {
295
    "mmf",
296
    NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
297 298 299 300
    sizeof(MMFContext),
    mmf_probe,
    mmf_read_header,
    mmf_read_packet,
301
    NULL,
302
    pcm_read_seek,
303
};
304
#endif
305
#if CONFIG_MMF_MUXER
306
AVOutputFormat mmf_muxer = {
307
    "mmf",
308
    NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
309 310 311 312 313 314 315 316 317
    "application/vnd.smaf",
    "mmf",
    sizeof(MMFContext),
    CODEC_ID_ADPCM_YAMAHA,
    CODEC_ID_NONE,
    mmf_write_header,
    mmf_write_packet,
    mmf_write_trailer,
};
318
#endif