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