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

libavformat/amr.c

Go to the documentation of this file.
00001 /*
00002  * amr file format
00003  * Copyright (c) 2001 ffmpeg project
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 /*
00023 Write and read amr data according to RFC3267, http://www.ietf.org/rfc/rfc3267.txt?number=3267
00024 
00025 Only mono files are supported.
00026 
00027 */
00028 #include "avformat.h"
00029 #include "internal.h"
00030 
00031 static const char AMR_header [] = "#!AMR\n";
00032 static const char AMRWB_header [] = "#!AMR-WB\n";
00033 
00034 #if CONFIG_AMR_MUXER
00035 static int amr_write_header(AVFormatContext *s)
00036 {
00037     AVIOContext *pb = s->pb;
00038     AVCodecContext *enc = s->streams[0]->codec;
00039 
00040     s->priv_data = NULL;
00041 
00042     if (enc->codec_id == CODEC_ID_AMR_NB)
00043     {
00044         avio_write(pb, AMR_header,   sizeof(AMR_header)   - 1); /* magic number */
00045     }
00046     else if(enc->codec_id == CODEC_ID_AMR_WB)
00047     {
00048         avio_write(pb, AMRWB_header, sizeof(AMRWB_header) - 1); /* magic number */
00049     }
00050     else
00051     {
00052         return -1;
00053     }
00054     avio_flush(pb);
00055     return 0;
00056 }
00057 
00058 static int amr_write_packet(AVFormatContext *s, AVPacket *pkt)
00059 {
00060     avio_write(s->pb, pkt->data, pkt->size);
00061     avio_flush(s->pb);
00062     return 0;
00063 }
00064 #endif /* CONFIG_AMR_MUXER */
00065 
00066 static int amr_probe(AVProbeData *p)
00067 {
00068     //Only check for "#!AMR" which could be amr-wb, amr-nb.
00069     //This will also trigger multichannel files: "#!AMR_MC1.0\n" and
00070     //"#!AMR-WB_MC1.0\n" (not supported)
00071 
00072     if(memcmp(p->buf,AMR_header,5)==0)
00073         return AVPROBE_SCORE_MAX;
00074     else
00075         return 0;
00076 }
00077 
00078 /* amr input */
00079 static int amr_read_header(AVFormatContext *s,
00080                            AVFormatParameters *ap)
00081 {
00082     AVIOContext *pb = s->pb;
00083     AVStream *st;
00084     uint8_t header[9];
00085 
00086     avio_read(pb, header, 6);
00087 
00088     st = avformat_new_stream(s, NULL);
00089     if (!st)
00090     {
00091         return AVERROR(ENOMEM);
00092     }
00093     if(memcmp(header,AMR_header,6)!=0)
00094     {
00095         avio_read(pb, header+6, 3);
00096         if(memcmp(header,AMRWB_header,9)!=0)
00097         {
00098             return -1;
00099         }
00100 
00101         st->codec->codec_tag = MKTAG('s', 'a', 'w', 'b');
00102         st->codec->codec_id = CODEC_ID_AMR_WB;
00103         st->codec->sample_rate = 16000;
00104         st->codec->frame_size = 320;
00105     }
00106     else
00107     {
00108         st->codec->codec_tag = MKTAG('s', 'a', 'm', 'r');
00109         st->codec->codec_id = CODEC_ID_AMR_NB;
00110         st->codec->sample_rate = 8000;
00111         st->codec->frame_size = 160;
00112     }
00113     st->codec->channels = 1;
00114     st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00115     avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
00116 
00117     return 0;
00118 }
00119 
00120 static int amr_read_packet(AVFormatContext *s,
00121                           AVPacket *pkt)
00122 {
00123     AVCodecContext *enc = s->streams[0]->codec;
00124     int read, size = 0, toc, mode;
00125     int64_t pos = avio_tell(s->pb);
00126 
00127     if (s->pb->eof_reached)
00128     {
00129         return AVERROR(EIO);
00130     }
00131 
00132 //FIXME this is wrong, this should rather be in a AVParset
00133     toc=avio_r8(s->pb);
00134     mode = (toc >> 3) & 0x0F;
00135 
00136     if (enc->codec_id == CODEC_ID_AMR_NB)
00137     {
00138         static const uint8_t packed_size[16] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0};
00139 
00140         size=packed_size[mode]+1;
00141     }
00142     else if(enc->codec_id == CODEC_ID_AMR_WB)
00143     {
00144         static uint8_t packed_size[16] = {18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1};
00145 
00146         size=packed_size[mode];
00147     }
00148     else
00149     {
00150         assert(0);
00151     }
00152 
00153     if ( (size==0) || av_new_packet(pkt, size))
00154     {
00155         return AVERROR(EIO);
00156     }
00157 
00158     /* Both AMR formats have 50 frames per second */
00159     s->streams[0]->codec->bit_rate = size*8*50;
00160 
00161     pkt->stream_index = 0;
00162     pkt->pos = pos;
00163     pkt->data[0]=toc;
00164     pkt->duration= enc->codec_id == CODEC_ID_AMR_NB ? 160 : 320;
00165     read = avio_read(s->pb, pkt->data+1, size-1);
00166 
00167     if (read != size-1)
00168     {
00169         av_free_packet(pkt);
00170         return AVERROR(EIO);
00171     }
00172 
00173     return 0;
00174 }
00175 
00176 #if CONFIG_AMR_DEMUXER
00177 AVInputFormat ff_amr_demuxer = {
00178     .name           = "amr",
00179     .long_name      = NULL_IF_CONFIG_SMALL("3GPP AMR file format"),
00180     .read_probe     = amr_probe,
00181     .read_header    = amr_read_header,
00182     .read_packet    = amr_read_packet,
00183     .flags = AVFMT_GENERIC_INDEX,
00184 };
00185 #endif
00186 
00187 #if CONFIG_AMR_MUXER
00188 AVOutputFormat ff_amr_muxer = {
00189     .name              = "amr",
00190     .long_name         = NULL_IF_CONFIG_SMALL("3GPP AMR file format"),
00191     .mime_type         = "audio/amr",
00192     .extensions        = "amr",
00193     .audio_codec       = CODEC_ID_AMR_NB,
00194     .video_codec       = CODEC_ID_NONE,
00195     .write_header      = amr_write_header,
00196     .write_packet      = amr_write_packet,
00197 };
00198 #endif
Generated on Thu Jan 24 2013 17:08:55 for Libav by doxygen 1.7.1