1/* 2 * amr file format 3 * Copyright (c) 2001 ffmpeg project 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 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#include "internal.h" 30 31static const char AMR_header [] = "#!AMR\n"; 32static const char AMRWB_header [] = "#!AMR-WB\n"; 33 34#if CONFIG_AMR_MUXER 35static int amr_write_header(AVFormatContext *s) 36{ 37 AVIOContext *pb = s->pb; 38 AVCodecContext *enc = s->streams[0]->codec; 39 40 s->priv_data = NULL; 41 42 if (enc->codec_id == CODEC_ID_AMR_NB) 43 { 44 avio_write(pb, AMR_header, sizeof(AMR_header) - 1); /* magic number */ 45 } 46 else if(enc->codec_id == CODEC_ID_AMR_WB) 47 { 48 avio_write(pb, AMRWB_header, sizeof(AMRWB_header) - 1); /* magic number */ 49 } 50 else 51 { 52 return -1; 53 } 54 avio_flush(pb); 55 return 0; 56} 57 58static int amr_write_packet(AVFormatContext *s, AVPacket *pkt) 59{ 60 avio_write(s->pb, pkt->data, pkt->size); 61 avio_flush(s->pb); 62 return 0; 63} 64#endif /* CONFIG_AMR_MUXER */ 65 66static int amr_probe(AVProbeData *p) 67{ 68 //Only check for "#!AMR" which could be amr-wb, amr-nb. 69 //This will also trigger multichannel files: "#!AMR_MC1.0\n" and 70 //"#!AMR-WB_MC1.0\n" (not supported) 71 72 if(memcmp(p->buf,AMR_header,5)==0) 73 return AVPROBE_SCORE_MAX; 74 else 75 return 0; 76} 77 78/* amr input */ 79static int amr_read_header(AVFormatContext *s, 80 AVFormatParameters *ap) 81{ 82 AVIOContext *pb = s->pb; 83 AVStream *st; 84 uint8_t header[9]; 85 86 avio_read(pb, header, 6); 87 88 st = avformat_new_stream(s, NULL); 89 if (!st) 90 { 91 return AVERROR(ENOMEM); 92 } 93 if(memcmp(header,AMR_header,6)!=0) 94 { 95 avio_read(pb, header+6, 3); 96 if(memcmp(header,AMRWB_header,9)!=0) 97 { 98 return -1; 99 } 100 101 st->codec->codec_tag = MKTAG('s', 'a', 'w', 'b'); 102 st->codec->codec_id = CODEC_ID_AMR_WB; 103 st->codec->sample_rate = 16000; 104 st->codec->frame_size = 320; 105 } 106 else 107 { 108 st->codec->codec_tag = MKTAG('s', 'a', 'm', 'r'); 109 st->codec->codec_id = CODEC_ID_AMR_NB; 110 st->codec->sample_rate = 8000; 111 st->codec->frame_size = 160; 112 } 113 st->codec->channels = 1; 114 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 115 avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); 116 117 return 0; 118} 119 120static int amr_read_packet(AVFormatContext *s, 121 AVPacket *pkt) 122{ 123 AVCodecContext *enc = s->streams[0]->codec; 124 int read, size = 0, toc, mode; 125 int64_t pos = avio_tell(s->pb); 126 127 if (s->pb->eof_reached) 128 { 129 return AVERROR(EIO); 130 } 131 132//FIXME this is wrong, this should rather be in a AVParset 133 toc=avio_r8(s->pb); 134 mode = (toc >> 3) & 0x0F; 135 136 if (enc->codec_id == CODEC_ID_AMR_NB) 137 { 138 static const uint8_t packed_size[16] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0}; 139 140 size=packed_size[mode]+1; 141 } 142 else if(enc->codec_id == CODEC_ID_AMR_WB) 143 { 144 static uint8_t packed_size[16] = {18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1}; 145 146 size=packed_size[mode]; 147 } 148 else 149 { 150 assert(0); 151 } 152 153 if ( (size==0) || av_new_packet(pkt, size)) 154 { 155 return AVERROR(EIO); 156 } 157 158 /* Both AMR formats have 50 frames per second */ 159 s->streams[0]->codec->bit_rate = size*8*50; 160 161 pkt->stream_index = 0; 162 pkt->pos = pos; 163 pkt->data[0]=toc; 164 pkt->duration= enc->codec_id == CODEC_ID_AMR_NB ? 160 : 320; 165 read = avio_read(s->pb, pkt->data+1, size-1); 166 167 if (read != size-1) 168 { 169 av_free_packet(pkt); 170 return AVERROR(EIO); 171 } 172 173 return 0; 174} 175 176#if CONFIG_AMR_DEMUXER 177AVInputFormat ff_amr_demuxer = { 178 .name = "amr", 179 .long_name = NULL_IF_CONFIG_SMALL("3GPP AMR file format"), 180 .read_probe = amr_probe, 181 .read_header = amr_read_header, 182 .read_packet = amr_read_packet, 183 .flags = AVFMT_GENERIC_INDEX, 184}; 185#endif 186 187#if CONFIG_AMR_MUXER 188AVOutputFormat ff_amr_muxer = { 189 .name = "amr", 190 .long_name = NULL_IF_CONFIG_SMALL("3GPP AMR file format"), 191 .mime_type = "audio/amr", 192 .extensions = "amr", 193 .audio_codec = CODEC_ID_AMR_NB, 194 .video_codec = CODEC_ID_NONE, 195 .write_header = amr_write_header, 196 .write_packet = amr_write_packet, 197}; 198#endif 199