annotate ffmpeg/libavformat/mmf.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * Yamaha SMAF format
yading@11 3 * Copyright (c) 2005 Vidar Madsen
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 #include "libavutil/channel_layout.h"
yading@11 23 #include "avformat.h"
yading@11 24 #include "internal.h"
yading@11 25 #include "avio_internal.h"
yading@11 26 #include "pcm.h"
yading@11 27 #include "rawenc.h"
yading@11 28 #include "riff.h"
yading@11 29
yading@11 30 typedef struct {
yading@11 31 int64_t atrpos, atsqpos, awapos;
yading@11 32 int64_t data_end;
yading@11 33 int stereo;
yading@11 34 } MMFContext;
yading@11 35
yading@11 36 static const int mmf_rates[] = { 4000, 8000, 11025, 22050, 44100 };
yading@11 37
yading@11 38 static int mmf_rate(int code)
yading@11 39 {
yading@11 40 if((code < 0) || (code > 4))
yading@11 41 return -1;
yading@11 42 return mmf_rates[code];
yading@11 43 }
yading@11 44
yading@11 45 #if CONFIG_MMF_MUXER
yading@11 46 static int mmf_rate_code(int rate)
yading@11 47 {
yading@11 48 int i;
yading@11 49 for(i = 0; i < 5; i++)
yading@11 50 if(mmf_rates[i] == rate)
yading@11 51 return i;
yading@11 52 return -1;
yading@11 53 }
yading@11 54
yading@11 55 /* Copy of end_tag() from avienc.c, but for big-endian chunk size */
yading@11 56 static void end_tag_be(AVIOContext *pb, int64_t start)
yading@11 57 {
yading@11 58 int64_t pos;
yading@11 59
yading@11 60 pos = avio_tell(pb);
yading@11 61 avio_seek(pb, start - 4, SEEK_SET);
yading@11 62 avio_wb32(pb, (uint32_t)(pos - start));
yading@11 63 avio_seek(pb, pos, SEEK_SET);
yading@11 64 }
yading@11 65
yading@11 66 static int mmf_write_header(AVFormatContext *s)
yading@11 67 {
yading@11 68 MMFContext *mmf = s->priv_data;
yading@11 69 AVIOContext *pb = s->pb;
yading@11 70 int64_t pos;
yading@11 71 int rate;
yading@11 72 const char *version = s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT ?
yading@11 73 "VN:Lavf," :
yading@11 74 "VN:"LIBAVFORMAT_IDENT",";
yading@11 75
yading@11 76 rate = mmf_rate_code(s->streams[0]->codec->sample_rate);
yading@11 77 if(rate < 0) {
yading@11 78 av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d, supported are 4000, 8000, 11025, 22050 and 44100\n", s->streams[0]->codec->sample_rate);
yading@11 79 return AVERROR(EINVAL);
yading@11 80 }
yading@11 81
yading@11 82 mmf->stereo = s->streams[0]->codec->channels > 1;
yading@11 83 if (mmf->stereo &&
yading@11 84 s->streams[0]->codec->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
yading@11 85 av_log(s, AV_LOG_ERROR, "Yamaha SMAF stereo is experimental, "
yading@11 86 "add '-strict %d' if you want to use it.\n",
yading@11 87 FF_COMPLIANCE_EXPERIMENTAL);
yading@11 88 return AVERROR(EINVAL);
yading@11 89 }
yading@11 90
yading@11 91 ffio_wfourcc(pb, "MMMD");
yading@11 92 avio_wb32(pb, 0);
yading@11 93 pos = ff_start_tag(pb, "CNTI");
yading@11 94 avio_w8(pb, 0); /* class */
yading@11 95 avio_w8(pb, 1); /* type */
yading@11 96 avio_w8(pb, 1); /* code type */
yading@11 97 avio_w8(pb, 0); /* status */
yading@11 98 avio_w8(pb, 0); /* counts */
yading@11 99 end_tag_be(pb, pos);
yading@11 100 pos = ff_start_tag(pb, "OPDA");
yading@11 101 avio_write(pb, version, strlen(version)); /* metadata ("ST:songtitle,VN:version,...") */
yading@11 102 end_tag_be(pb, pos);
yading@11 103
yading@11 104 avio_write(pb, "ATR\x00", 4);
yading@11 105 avio_wb32(pb, 0);
yading@11 106 mmf->atrpos = avio_tell(pb);
yading@11 107 avio_w8(pb, 0); /* format type */
yading@11 108 avio_w8(pb, 0); /* sequence type */
yading@11 109 avio_w8(pb, (mmf->stereo << 7) | (1 << 4) | rate); /* (channel << 7) | (format << 4) | rate */
yading@11 110 avio_w8(pb, 0); /* wave base bit */
yading@11 111 avio_w8(pb, 2); /* time base d */
yading@11 112 avio_w8(pb, 2); /* time base g */
yading@11 113
yading@11 114 ffio_wfourcc(pb, "Atsq");
yading@11 115 avio_wb32(pb, 16);
yading@11 116 mmf->atsqpos = avio_tell(pb);
yading@11 117 /* Will be filled on close */
yading@11 118 avio_write(pb, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
yading@11 119
yading@11 120 mmf->awapos = ff_start_tag(pb, "Awa\x01");
yading@11 121
yading@11 122 avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
yading@11 123
yading@11 124 avio_flush(pb);
yading@11 125
yading@11 126 return 0;
yading@11 127 }
yading@11 128
yading@11 129 /* Write a variable-length symbol */
yading@11 130 static void put_varlength(AVIOContext *pb, int val)
yading@11 131 {
yading@11 132 if(val < 128)
yading@11 133 avio_w8(pb, val);
yading@11 134 else {
yading@11 135 val -= 128;
yading@11 136 avio_w8(pb, 0x80 | val >> 7);
yading@11 137 avio_w8(pb, 0x7f & val);
yading@11 138 }
yading@11 139 }
yading@11 140
yading@11 141 static int mmf_write_trailer(AVFormatContext *s)
yading@11 142 {
yading@11 143 AVIOContext *pb = s->pb;
yading@11 144 MMFContext *mmf = s->priv_data;
yading@11 145 int64_t pos, size;
yading@11 146 int gatetime;
yading@11 147
yading@11 148 if (s->pb->seekable) {
yading@11 149 /* Fill in length fields */
yading@11 150 end_tag_be(pb, mmf->awapos);
yading@11 151 end_tag_be(pb, mmf->atrpos);
yading@11 152 end_tag_be(pb, 8);
yading@11 153
yading@11 154 pos = avio_tell(pb);
yading@11 155 size = pos - mmf->awapos;
yading@11 156
yading@11 157 /* Fill Atsq chunk */
yading@11 158 avio_seek(pb, mmf->atsqpos, SEEK_SET);
yading@11 159
yading@11 160 /* "play wav" */
yading@11 161 avio_w8(pb, 0); /* start time */
yading@11 162 avio_w8(pb, (mmf->stereo << 6) | 1); /* (channel << 6) | wavenum */
yading@11 163 gatetime = size * 500 / s->streams[0]->codec->sample_rate;
yading@11 164 put_varlength(pb, gatetime); /* duration */
yading@11 165
yading@11 166 /* "nop" */
yading@11 167 put_varlength(pb, gatetime); /* start time */
yading@11 168 avio_write(pb, "\xff\x00", 2); /* nop */
yading@11 169
yading@11 170 /* "end of sequence" */
yading@11 171 avio_write(pb, "\x00\x00\x00\x00", 4);
yading@11 172
yading@11 173 avio_seek(pb, pos, SEEK_SET);
yading@11 174
yading@11 175 avio_flush(pb);
yading@11 176 }
yading@11 177 return 0;
yading@11 178 }
yading@11 179 #endif /* CONFIG_MMF_MUXER */
yading@11 180
yading@11 181 static int mmf_probe(AVProbeData *p)
yading@11 182 {
yading@11 183 /* check file header */
yading@11 184 if (p->buf[0] == 'M' && p->buf[1] == 'M' &&
yading@11 185 p->buf[2] == 'M' && p->buf[3] == 'D' &&
yading@11 186 p->buf[8] == 'C' && p->buf[9] == 'N' &&
yading@11 187 p->buf[10] == 'T' && p->buf[11] == 'I')
yading@11 188 return AVPROBE_SCORE_MAX;
yading@11 189 else
yading@11 190 return 0;
yading@11 191 }
yading@11 192
yading@11 193 /* mmf input */
yading@11 194 static int mmf_read_header(AVFormatContext *s)
yading@11 195 {
yading@11 196 MMFContext *mmf = s->priv_data;
yading@11 197 unsigned int tag;
yading@11 198 AVIOContext *pb = s->pb;
yading@11 199 AVStream *st;
yading@11 200 int64_t size;
yading@11 201 int rate, params;
yading@11 202
yading@11 203 tag = avio_rl32(pb);
yading@11 204 if (tag != MKTAG('M', 'M', 'M', 'D'))
yading@11 205 return AVERROR_INVALIDDATA;
yading@11 206 avio_skip(pb, 4); /* file_size */
yading@11 207
yading@11 208 /* Skip some unused chunks that may or may not be present */
yading@11 209 for(;; avio_skip(pb, size)) {
yading@11 210 tag = avio_rl32(pb);
yading@11 211 size = avio_rb32(pb);
yading@11 212 if(tag == MKTAG('C','N','T','I')) continue;
yading@11 213 if(tag == MKTAG('O','P','D','A')) continue;
yading@11 214 break;
yading@11 215 }
yading@11 216
yading@11 217 /* Tag = "ATRx", where "x" = track number */
yading@11 218 if ((tag & 0xffffff) == MKTAG('M', 'T', 'R', 0)) {
yading@11 219 av_log(s, AV_LOG_ERROR, "MIDI like format found, unsupported\n");
yading@11 220 return AVERROR_PATCHWELCOME;
yading@11 221 }
yading@11 222 if ((tag & 0xffffff) != MKTAG('A', 'T', 'R', 0)) {
yading@11 223 av_log(s, AV_LOG_ERROR, "Unsupported SMAF chunk %08x\n", tag);
yading@11 224 return AVERROR_PATCHWELCOME;
yading@11 225 }
yading@11 226
yading@11 227 avio_r8(pb); /* format type */
yading@11 228 avio_r8(pb); /* sequence type */
yading@11 229 params = avio_r8(pb); /* (channel << 7) | (format << 4) | rate */
yading@11 230 rate = mmf_rate(params & 0x0f);
yading@11 231 if(rate < 0) {
yading@11 232 av_log(s, AV_LOG_ERROR, "Invalid sample rate\n");
yading@11 233 return AVERROR_INVALIDDATA;
yading@11 234 }
yading@11 235 avio_r8(pb); /* wave base bit */
yading@11 236 avio_r8(pb); /* time base d */
yading@11 237 avio_r8(pb); /* time base g */
yading@11 238
yading@11 239 /* Skip some unused chunks that may or may not be present */
yading@11 240 for(;; avio_skip(pb, size)) {
yading@11 241 tag = avio_rl32(pb);
yading@11 242 size = avio_rb32(pb);
yading@11 243 if(tag == MKTAG('A','t','s','q')) continue;
yading@11 244 if(tag == MKTAG('A','s','p','I')) continue;
yading@11 245 break;
yading@11 246 }
yading@11 247
yading@11 248 /* Make sure it's followed by an Awa chunk, aka wave data */
yading@11 249 if ((tag & 0xffffff) != MKTAG('A', 'w', 'a', 0)) {
yading@11 250 av_log(s, AV_LOG_ERROR, "Unexpected SMAF chunk %08x\n", tag);
yading@11 251 return AVERROR_INVALIDDATA;
yading@11 252 }
yading@11 253 mmf->data_end = avio_tell(pb) + size;
yading@11 254
yading@11 255 st = avformat_new_stream(s, NULL);
yading@11 256 if (!st)
yading@11 257 return AVERROR(ENOMEM);
yading@11 258
yading@11 259 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
yading@11 260 st->codec->codec_id = AV_CODEC_ID_ADPCM_YAMAHA;
yading@11 261 st->codec->sample_rate = rate;
yading@11 262 st->codec->channels = (params >> 7) + 1;
yading@11 263 st->codec->channel_layout = params >> 7 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
yading@11 264 st->codec->bits_per_coded_sample = 4;
yading@11 265 st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_coded_sample;
yading@11 266
yading@11 267 avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
yading@11 268
yading@11 269 return 0;
yading@11 270 }
yading@11 271
yading@11 272 #define MAX_SIZE 4096
yading@11 273
yading@11 274 static int mmf_read_packet(AVFormatContext *s,
yading@11 275 AVPacket *pkt)
yading@11 276 {
yading@11 277 MMFContext *mmf = s->priv_data;
yading@11 278 int64_t left, size;
yading@11 279 int ret;
yading@11 280
yading@11 281 left = mmf->data_end - avio_tell(s->pb);
yading@11 282 size = FFMIN(left, MAX_SIZE);
yading@11 283 if (url_feof(s->pb) || size <= 0)
yading@11 284 return AVERROR_EOF;
yading@11 285
yading@11 286 ret = av_get_packet(s->pb, pkt, size);
yading@11 287 if (ret < 0)
yading@11 288 return ret;
yading@11 289
yading@11 290 pkt->stream_index = 0;
yading@11 291
yading@11 292 return ret;
yading@11 293 }
yading@11 294
yading@11 295 #if CONFIG_MMF_DEMUXER
yading@11 296 AVInputFormat ff_mmf_demuxer = {
yading@11 297 .name = "mmf",
yading@11 298 .long_name = NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
yading@11 299 .priv_data_size = sizeof(MMFContext),
yading@11 300 .read_probe = mmf_probe,
yading@11 301 .read_header = mmf_read_header,
yading@11 302 .read_packet = mmf_read_packet,
yading@11 303 .flags = AVFMT_GENERIC_INDEX,
yading@11 304 };
yading@11 305 #endif
yading@11 306 #if CONFIG_MMF_MUXER
yading@11 307 AVOutputFormat ff_mmf_muxer = {
yading@11 308 .name = "mmf",
yading@11 309 .long_name = NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
yading@11 310 .mime_type = "application/vnd.smaf",
yading@11 311 .extensions = "mmf",
yading@11 312 .priv_data_size = sizeof(MMFContext),
yading@11 313 .audio_codec = AV_CODEC_ID_ADPCM_YAMAHA,
yading@11 314 .video_codec = AV_CODEC_ID_NONE,
yading@11 315 .write_header = mmf_write_header,
yading@11 316 .write_packet = ff_raw_write_packet,
yading@11 317 .write_trailer = mmf_write_trailer,
yading@11 318 };
yading@11 319 #endif