1/* 2 * amr file format 3 * Copyright (c) 2001 ffmpeg project 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/* 23Write and read amr data according to RFC3267, http://www.ietf.org/rfc/rfc3267.txt?number=3267 24 25Only mono files are supported. 26 27*/ 28#include "avformat.h" 29 30static const char AMR_header [] = "#!AMR\n"; 31static const char AMRWB_header [] = "#!AMR-WB\n"; 32 33#if CONFIG_AMR_MUXER 34static int amr_write_header(AVFormatContext *s) 35{ 36 ByteIOContext *pb = s->pb; 37 AVCodecContext *enc = s->streams[0]->codec; 38 39 s->priv_data = NULL; 40 41 if (enc->codec_id == CODEC_ID_AMR_NB) 42 { 43 put_tag(pb, AMR_header); /* magic number */ 44 } 45 else if(enc->codec_id == CODEC_ID_AMR_WB) 46 { 47 put_tag(pb, AMRWB_header); /* magic number */ 48 } 49 else 50 { 51 return -1; 52 } 53 put_flush_packet(pb); 54 return 0; 55} 56 57static int amr_write_packet(AVFormatContext *s, AVPacket *pkt) 58{ 59 put_buffer(s->pb, pkt->data, pkt->size); 60 put_flush_packet(s->pb); 61 return 0; 62} 63#endif /* CONFIG_AMR_MUXER */ 64 65static int amr_probe(AVProbeData *p) 66{ 67 //Only check for "#!AMR" which could be amr-wb, amr-nb. 68 //This will also trigger multichannel files: "#!AMR_MC1.0\n" and 69 //"#!AMR-WB_MC1.0\n" (not supported) 70 71 if(memcmp(p->buf,AMR_header,5)==0) 72 return AVPROBE_SCORE_MAX; 73 else 74 return 0; 75} 76 77/* amr input */ 78static int amr_read_header(AVFormatContext *s, 79 AVFormatParameters *ap) 80{ 81 ByteIOContext *pb = s->pb; 82 AVStream *st; 83 uint8_t header[9]; 84 85 get_buffer(pb, header, 6); 86 87 st = av_new_stream(s, 0); 88 if (!st) 89 { 90 return AVERROR(ENOMEM); 91 } 92 if(memcmp(header,AMR_header,6)!=0) 93 { 94 get_buffer(pb, header+6, 3); 95 if(memcmp(header,AMRWB_header,9)!=0) 96 { 97 return -1; 98 } 99 100 st->codec->codec_tag = MKTAG('s', 'a', 'w', 'b'); 101 st->codec->codec_id = CODEC_ID_AMR_WB; 102 st->codec->sample_rate = 16000; 103 } 104 else 105 { 106 st->codec->codec_tag = MKTAG('s', 'a', 'm', 'r'); 107 st->codec->codec_id = CODEC_ID_AMR_NB; 108 st->codec->sample_rate = 8000; 109 } 110 st->codec->channels = 1; 111 st->codec->codec_type = CODEC_TYPE_AUDIO; 112 av_set_pts_info(st, 64, 1, st->codec->sample_rate); 113 114 return 0; 115} 116 117static int amr_read_packet(AVFormatContext *s, 118 AVPacket *pkt) 119{ 120 AVCodecContext *enc = s->streams[0]->codec; 121 int read, size = 0, toc, mode; 122 123 if (url_feof(s->pb)) 124 { 125 return AVERROR(EIO); 126 } 127 128//FIXME this is wrong, this should rather be in a AVParset 129 toc=get_byte(s->pb); 130 mode = (toc >> 3) & 0x0F; 131 132 if (enc->codec_id == CODEC_ID_AMR_NB) 133 { 134 static const uint8_t packed_size[16] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0}; 135 136 size=packed_size[mode]+1; 137 } 138 else if(enc->codec_id == CODEC_ID_AMR_WB) 139 { 140 static uint8_t packed_size[16] = {18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1}; 141 142 size=packed_size[mode]; 143 } 144 else 145 { 146 assert(0); 147 } 148 149 if ( (size==0) || av_new_packet(pkt, size)) 150 { 151 return AVERROR(EIO); 152 } 153 154 pkt->stream_index = 0; 155 pkt->pos= url_ftell(s->pb); 156 pkt->data[0]=toc; 157 pkt->duration= enc->codec_id == CODEC_ID_AMR_NB ? 160 : 320; 158 read = get_buffer(s->pb, pkt->data+1, size-1); 159 160 if (read != size-1) 161 { 162 av_free_packet(pkt); 163 return AVERROR(EIO); 164 } 165 166 return 0; 167} 168 169#if CONFIG_AMR_DEMUXER 170AVInputFormat amr_demuxer = { 171 "amr", 172 NULL_IF_CONFIG_SMALL("3GPP AMR file format"), 173 0, /*priv_data_size*/ 174 amr_probe, 175 amr_read_header, 176 amr_read_packet, 177 NULL, 178}; 179#endif 180 181#if CONFIG_AMR_MUXER 182AVOutputFormat amr_muxer = { 183 "amr", 184 NULL_IF_CONFIG_SMALL("3GPP AMR file format"), 185 "audio/amr", 186 "amr", 187 0, 188 CODEC_ID_AMR_NB, 189 CODEC_ID_NONE, 190 amr_write_header, 191 amr_write_packet, 192}; 193#endif 194