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