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