00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "libavutil/avassert.h"
00030 #include "libavutil/channel_layout.h"
00031 #include "avformat.h"
00032 #include "internal.h"
00033
00034 static const char AMR_header[] = "#!AMR\n";
00035 static const char AMRWB_header[] = "#!AMR-WB\n";
00036
00037 #if CONFIG_AMR_MUXER
00038 static int amr_write_header(AVFormatContext *s)
00039 {
00040 AVIOContext *pb = s->pb;
00041 AVCodecContext *enc = s->streams[0]->codec;
00042
00043 s->priv_data = NULL;
00044
00045 if (enc->codec_id == AV_CODEC_ID_AMR_NB) {
00046 avio_write(pb, AMR_header, sizeof(AMR_header) - 1);
00047 } else if (enc->codec_id == AV_CODEC_ID_AMR_WB) {
00048 avio_write(pb, AMRWB_header, sizeof(AMRWB_header) - 1);
00049 } else {
00050 return -1;
00051 }
00052 avio_flush(pb);
00053 return 0;
00054 }
00055
00056 static int amr_write_packet(AVFormatContext *s, AVPacket *pkt)
00057 {
00058 avio_write(s->pb, pkt->data, pkt->size);
00059 avio_flush(s->pb);
00060 return 0;
00061 }
00062 #endif
00063
00064 static int amr_probe(AVProbeData *p)
00065 {
00066
00067
00068
00069
00070 if (!memcmp(p->buf, AMR_header, 5))
00071 return AVPROBE_SCORE_MAX;
00072 else
00073 return 0;
00074 }
00075
00076
00077 static int amr_read_header(AVFormatContext *s)
00078 {
00079 AVIOContext *pb = s->pb;
00080 AVStream *st;
00081 uint8_t header[9];
00082
00083 avio_read(pb, header, 6);
00084
00085 st = avformat_new_stream(s, NULL);
00086 if (!st)
00087 return AVERROR(ENOMEM);
00088 if (memcmp(header, AMR_header, 6)) {
00089 avio_read(pb, header + 6, 3);
00090 if (memcmp(header, AMRWB_header, 9)) {
00091 return -1;
00092 }
00093
00094 st->codec->codec_tag = MKTAG('s', 'a', 'w', 'b');
00095 st->codec->codec_id = AV_CODEC_ID_AMR_WB;
00096 st->codec->sample_rate = 16000;
00097 } else {
00098 st->codec->codec_tag = MKTAG('s', 'a', 'm', 'r');
00099 st->codec->codec_id = AV_CODEC_ID_AMR_NB;
00100 st->codec->sample_rate = 8000;
00101 }
00102 st->codec->channels = 1;
00103 st->codec->channel_layout = AV_CH_LAYOUT_MONO;
00104 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00105 avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
00106
00107 return 0;
00108 }
00109
00110 static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
00111 {
00112 AVCodecContext *enc = s->streams[0]->codec;
00113 int read, size = 0, toc, mode;
00114 int64_t pos = avio_tell(s->pb);
00115
00116 if (url_feof(s->pb)) {
00117 return AVERROR(EIO);
00118 }
00119
00120
00121 toc = avio_r8(s->pb);
00122 mode = (toc >> 3) & 0x0F;
00123
00124 if (enc->codec_id == AV_CODEC_ID_AMR_NB) {
00125 static const uint8_t packed_size[16] = {
00126 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0
00127 };
00128
00129 size = packed_size[mode] + 1;
00130 } else if (enc->codec_id == AV_CODEC_ID_AMR_WB) {
00131 static const uint8_t packed_size[16] = {
00132 18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1
00133 };
00134
00135 size = packed_size[mode];
00136 } else {
00137 av_assert0(0);
00138 }
00139
00140 if (!size || av_new_packet(pkt, size))
00141 return AVERROR(EIO);
00142
00143
00144 s->streams[0]->codec->bit_rate = size*8*50;
00145
00146 pkt->stream_index = 0;
00147 pkt->pos = pos;
00148 pkt->data[0] = toc;
00149 pkt->duration = enc->codec_id == AV_CODEC_ID_AMR_NB ? 160 : 320;
00150 read = avio_read(s->pb, pkt->data + 1, size - 1);
00151
00152 if (read != size - 1) {
00153 av_free_packet(pkt);
00154 return AVERROR(EIO);
00155 }
00156
00157 return 0;
00158 }
00159
00160 #if CONFIG_AMR_DEMUXER
00161 AVInputFormat ff_amr_demuxer = {
00162 .name = "amr",
00163 .long_name = NULL_IF_CONFIG_SMALL("3GPP AMR"),
00164 .read_probe = amr_probe,
00165 .read_header = amr_read_header,
00166 .read_packet = amr_read_packet,
00167 .flags = AVFMT_GENERIC_INDEX,
00168 };
00169 #endif
00170
00171 #if CONFIG_AMR_MUXER
00172 AVOutputFormat ff_amr_muxer = {
00173 .name = "amr",
00174 .long_name = NULL_IF_CONFIG_SMALL("3GPP AMR"),
00175 .mime_type = "audio/amr",
00176 .extensions = "amr",
00177 .audio_codec = AV_CODEC_ID_AMR_NB,
00178 .video_codec = AV_CODEC_ID_NONE,
00179 .write_header = amr_write_header,
00180 .write_packet = amr_write_packet,
00181 };
00182 #endif