• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/mmf.c

Go to the documentation of this file.
00001 /*
00002  * Yamaha SMAF format
00003  * Copyright (c) 2005 Vidar Madsen
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 #include "avformat.h"
00022 #include "raw.h"
00023 #include "riff.h"
00024 
00025 typedef struct {
00026     int64_t atrpos, atsqpos, awapos;
00027     int64_t data_size;
00028 } MMFContext;
00029 
00030 static const int mmf_rates[] = { 4000, 8000, 11025, 22050, 44100 };
00031 
00032 static int mmf_rate(int code)
00033 {
00034     if((code < 0) || (code > 4))
00035         return -1;
00036     return mmf_rates[code];
00037 }
00038 
00039 #if CONFIG_MMF_MUXER
00040 static int mmf_rate_code(int rate)
00041 {
00042     int i;
00043     for(i = 0; i < 5; i++)
00044         if(mmf_rates[i] == rate)
00045             return i;
00046     return -1;
00047 }
00048 
00049 /* Copy of end_tag() from avienc.c, but for big-endian chunk size */
00050 static void end_tag_be(ByteIOContext *pb, int64_t start)
00051 {
00052     int64_t pos;
00053 
00054     pos = url_ftell(pb);
00055     url_fseek(pb, start - 4, SEEK_SET);
00056     put_be32(pb, (uint32_t)(pos - start));
00057     url_fseek(pb, pos, SEEK_SET);
00058 }
00059 
00060 static int mmf_write_header(AVFormatContext *s)
00061 {
00062     MMFContext *mmf = s->priv_data;
00063     ByteIOContext *pb = s->pb;
00064     int64_t pos;
00065     int rate;
00066 
00067     rate = mmf_rate_code(s->streams[0]->codec->sample_rate);
00068     if(rate < 0) {
00069         av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d\n", s->streams[0]->codec->sample_rate);
00070         return -1;
00071     }
00072 
00073     put_tag(pb, "MMMD");
00074     put_be32(pb, 0);
00075     pos = ff_start_tag(pb, "CNTI");
00076     put_byte(pb, 0); /* class */
00077     put_byte(pb, 0); /* type */
00078     put_byte(pb, 0); /* code type */
00079     put_byte(pb, 0); /* status */
00080     put_byte(pb, 0); /* counts */
00081     put_tag(pb, "VN:libavcodec,"); /* metadata ("ST:songtitle,VN:version,...") */
00082     end_tag_be(pb, pos);
00083 
00084     put_buffer(pb, "ATR\x00", 4);
00085     put_be32(pb, 0);
00086     mmf->atrpos = url_ftell(pb);
00087     put_byte(pb, 0); /* format type */
00088     put_byte(pb, 0); /* sequence type */
00089     put_byte(pb, (0 << 7) | (1 << 4) | rate); /* (channel << 7) | (format << 4) | rate */
00090     put_byte(pb, 0); /* wave base bit */
00091     put_byte(pb, 2); /* time base d */
00092     put_byte(pb, 2); /* time base g */
00093 
00094     put_tag(pb, "Atsq");
00095     put_be32(pb, 16);
00096     mmf->atsqpos = url_ftell(pb);
00097     /* Will be filled on close */
00098     put_buffer(pb, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
00099 
00100     mmf->awapos = ff_start_tag(pb, "Awa\x01");
00101 
00102     av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
00103 
00104     put_flush_packet(pb);
00105 
00106     return 0;
00107 }
00108 
00109 static int mmf_write_packet(AVFormatContext *s, AVPacket *pkt)
00110 {
00111     ByteIOContext *pb = s->pb;
00112     put_buffer(pb, pkt->data, pkt->size);
00113     return 0;
00114 }
00115 
00116 /* Write a variable-length symbol */
00117 static void put_varlength(ByteIOContext *pb, int val)
00118 {
00119     if(val < 128)
00120         put_byte(pb, val);
00121     else {
00122         val -= 128;
00123         put_byte(pb, 0x80 | val >> 7);
00124         put_byte(pb, 0x7f & val);
00125     }
00126 }
00127 
00128 static int mmf_write_trailer(AVFormatContext *s)
00129 {
00130     ByteIOContext *pb = s->pb;
00131     MMFContext *mmf = s->priv_data;
00132     int64_t pos, size;
00133     int gatetime;
00134 
00135     if (!url_is_streamed(s->pb)) {
00136         /* Fill in length fields */
00137         end_tag_be(pb, mmf->awapos);
00138         end_tag_be(pb, mmf->atrpos);
00139         end_tag_be(pb, 8);
00140 
00141         pos = url_ftell(pb);
00142         size = pos - mmf->awapos;
00143 
00144         /* Fill Atsq chunk */
00145         url_fseek(pb, mmf->atsqpos, SEEK_SET);
00146 
00147         /* "play wav" */
00148         put_byte(pb, 0); /* start time */
00149         put_byte(pb, 1); /* (channel << 6) | wavenum */
00150         gatetime = size * 500 / s->streams[0]->codec->sample_rate;
00151         put_varlength(pb, gatetime); /* duration */
00152 
00153         /* "nop" */
00154         put_varlength(pb, gatetime); /* start time */
00155         put_buffer(pb, "\xff\x00", 2); /* nop */
00156 
00157         /* "end of sequence" */
00158         put_buffer(pb, "\x00\x00\x00\x00", 4);
00159 
00160         url_fseek(pb, pos, SEEK_SET);
00161 
00162         put_flush_packet(pb);
00163     }
00164     return 0;
00165 }
00166 #endif /* CONFIG_MMF_MUXER */
00167 
00168 static int mmf_probe(AVProbeData *p)
00169 {
00170     /* check file header */
00171     if (p->buf[0] == 'M' && p->buf[1] == 'M' &&
00172         p->buf[2] == 'M' && p->buf[3] == 'D' &&
00173         p->buf[8] == 'C' && p->buf[9] == 'N' &&
00174         p->buf[10] == 'T' && p->buf[11] == 'I')
00175         return AVPROBE_SCORE_MAX;
00176     else
00177         return 0;
00178 }
00179 
00180 /* mmf input */
00181 static int mmf_read_header(AVFormatContext *s,
00182                            AVFormatParameters *ap)
00183 {
00184     MMFContext *mmf = s->priv_data;
00185     unsigned int tag;
00186     ByteIOContext *pb = s->pb;
00187     AVStream *st;
00188     int64_t file_size, size;
00189     int rate, params;
00190 
00191     tag = get_le32(pb);
00192     if (tag != MKTAG('M', 'M', 'M', 'D'))
00193         return -1;
00194     file_size = get_be32(pb);
00195 
00196     /* Skip some unused chunks that may or may not be present */
00197     for(;; url_fseek(pb, size, SEEK_CUR)) {
00198         tag = get_le32(pb);
00199         size = get_be32(pb);
00200         if(tag == MKTAG('C','N','T','I')) continue;
00201         if(tag == MKTAG('O','P','D','A')) continue;
00202         break;
00203     }
00204 
00205     /* Tag = "ATRx", where "x" = track number */
00206     if ((tag & 0xffffff) == MKTAG('M', 'T', 'R', 0)) {
00207         av_log(s, AV_LOG_ERROR, "MIDI like format found, unsupported\n");
00208         return -1;
00209     }
00210     if ((tag & 0xffffff) != MKTAG('A', 'T', 'R', 0)) {
00211         av_log(s, AV_LOG_ERROR, "Unsupported SMAF chunk %08x\n", tag);
00212         return -1;
00213     }
00214 
00215     get_byte(pb); /* format type */
00216     get_byte(pb); /* sequence type */
00217     params = get_byte(pb); /* (channel << 7) | (format << 4) | rate */
00218     rate = mmf_rate(params & 0x0f);
00219     if(rate  < 0) {
00220         av_log(s, AV_LOG_ERROR, "Invalid sample rate\n");
00221         return -1;
00222     }
00223     get_byte(pb); /* wave base bit */
00224     get_byte(pb); /* time base d */
00225     get_byte(pb); /* time base g */
00226 
00227     /* Skip some unused chunks that may or may not be present */
00228     for(;; url_fseek(pb, size, SEEK_CUR)) {
00229         tag = get_le32(pb);
00230         size = get_be32(pb);
00231         if(tag == MKTAG('A','t','s','q')) continue;
00232         if(tag == MKTAG('A','s','p','I')) continue;
00233         break;
00234     }
00235 
00236     /* Make sure it's followed by an Awa chunk, aka wave data */
00237     if ((tag & 0xffffff) != MKTAG('A', 'w', 'a', 0)) {
00238         av_log(s, AV_LOG_ERROR, "Unexpected SMAF chunk %08x\n", tag);
00239         return -1;
00240     }
00241     mmf->data_size = size;
00242 
00243     st = av_new_stream(s, 0);
00244     if (!st)
00245         return AVERROR(ENOMEM);
00246 
00247     st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00248     st->codec->codec_id = CODEC_ID_ADPCM_YAMAHA;
00249     st->codec->sample_rate = rate;
00250     st->codec->channels = 1;
00251     st->codec->bits_per_coded_sample = 4;
00252     st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_coded_sample;
00253 
00254     av_set_pts_info(st, 64, 1, st->codec->sample_rate);
00255 
00256     return 0;
00257 }
00258 
00259 #define MAX_SIZE 4096
00260 
00261 static int mmf_read_packet(AVFormatContext *s,
00262                            AVPacket *pkt)
00263 {
00264     MMFContext *mmf = s->priv_data;
00265     AVStream *st;
00266     int ret, size;
00267 
00268     if (url_feof(s->pb))
00269         return AVERROR(EIO);
00270     st = s->streams[0];
00271 
00272     size = MAX_SIZE;
00273     if(size > mmf->data_size)
00274         size = mmf->data_size;
00275 
00276     if(!size)
00277         return AVERROR(EIO);
00278 
00279     if (av_new_packet(pkt, size))
00280         return AVERROR(EIO);
00281     pkt->stream_index = 0;
00282 
00283     ret = get_buffer(s->pb, pkt->data, pkt->size);
00284     if (ret < 0)
00285         av_free_packet(pkt);
00286 
00287     mmf->data_size -= ret;
00288 
00289     pkt->size = ret;
00290     return ret;
00291 }
00292 
00293 #if CONFIG_MMF_DEMUXER
00294 AVInputFormat mmf_demuxer = {
00295     "mmf",
00296     NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
00297     sizeof(MMFContext),
00298     mmf_probe,
00299     mmf_read_header,
00300     mmf_read_packet,
00301     NULL,
00302     pcm_read_seek,
00303 };
00304 #endif
00305 #if CONFIG_MMF_MUXER
00306 AVOutputFormat mmf_muxer = {
00307     "mmf",
00308     NULL_IF_CONFIG_SMALL("Yamaha SMAF"),
00309     "application/vnd.smaf",
00310     "mmf",
00311     sizeof(MMFContext),
00312     CODEC_ID_ADPCM_YAMAHA,
00313     CODEC_ID_NONE,
00314     mmf_write_header,
00315     mmf_write_packet,
00316     mmf_write_trailer,
00317 };
00318 #endif

Generated on Fri Sep 16 2011 17:17:49 for FFmpeg by  doxygen 1.7.1