ffmpeg / libavformat / amr.c @ 5509bffa
History | View | Annotate | Download (5.52 KB)
1 | 115329f1 | Diego Biurrun | /*
|
---|---|---|---|
2 | 067cbf31 | Zdenek Kabelac | * amr file format
|
3 | * Copyright (c) 2001 ffmpeg project
|
||
4 | *
|
||
5 | * This library is free software; you can redistribute it and/or
|
||
6 | * modify it under the terms of the GNU Lesser General Public
|
||
7 | * License as published by the Free Software Foundation; either
|
||
8 | * version 2 of the License, or (at your option) any later version.
|
||
9 | *
|
||
10 | * This library is distributed in the hope that it will be useful,
|
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
13 | * Lesser General Public License for more details.
|
||
14 | *
|
||
15 | * You should have received a copy of the GNU Lesser General Public
|
||
16 | * License along with this library; if not, write to the Free Software
|
||
17 | 5509bffa | Diego Biurrun | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18 | 067cbf31 | Zdenek Kabelac | */
|
19 | |||
20 | /*
|
||
21 | Write and read amr data according to RFC3267, http://www.ietf.org/rfc/rfc3267.txt?number=3267
|
||
22 | |||
23 | d663a1fd | Michael Niedermayer | Only mono files are supported.
|
24 | 067cbf31 | Zdenek Kabelac | |
25 | */
|
||
26 | #include "avformat.h" |
||
27 | |||
28 | static const unsigned char AMR_header [] = "#!AMR\n"; |
||
29 | d663a1fd | Michael Niedermayer | static const unsigned char AMRWB_header [] = "#!AMR-WB\n"; |
30 | 067cbf31 | Zdenek Kabelac | |
31 | static int amr_write_header(AVFormatContext *s) |
||
32 | { |
||
33 | ByteIOContext *pb = &s->pb; |
||
34 | 01f4895c | Michael Niedermayer | AVCodecContext *enc = s->streams[0]->codec;
|
35 | 067cbf31 | Zdenek Kabelac | |
36 | s->priv_data = NULL;
|
||
37 | |||
38 | d663a1fd | Michael Niedermayer | if (enc->codec_id == CODEC_ID_AMR_NB)
|
39 | { |
||
40 | put_tag(pb, AMR_header); /* magic number */
|
||
41 | } |
||
42 | else if(enc->codec_id == CODEC_ID_AMR_WB) |
||
43 | { |
||
44 | put_tag(pb, AMRWB_header); /* magic number */
|
||
45 | } |
||
46 | else
|
||
47 | { |
||
48 | //This is an error!
|
||
49 | 067cbf31 | Zdenek Kabelac | } |
50 | put_flush_packet(pb); |
||
51 | return 0; |
||
52 | } |
||
53 | |||
54 | e928649b | Michael Niedermayer | static int amr_write_packet(AVFormatContext *s, AVPacket *pkt) |
55 | 067cbf31 | Zdenek Kabelac | { |
56 | e928649b | Michael Niedermayer | put_buffer(&s->pb, pkt->data, pkt->size); |
57 | 067cbf31 | Zdenek Kabelac | put_flush_packet(&s->pb); |
58 | return 0; |
||
59 | } |
||
60 | |||
61 | static int amr_write_trailer(AVFormatContext *s) |
||
62 | { |
||
63 | return 0; |
||
64 | } |
||
65 | |||
66 | static int amr_probe(AVProbeData *p) |
||
67 | { |
||
68 | 115329f1 | Diego Biurrun | //Only check for "#!AMR" which could be amr-wb, amr-nb.
|
69 | //This will also trigger multichannel files: "#!AMR_MC1.0\n" and
|
||
70 | d663a1fd | Michael Niedermayer | //"#!AMR-WB_MC1.0\n" (not supported)
|
71 | |||
72 | if (p->buf_size < 5) |
||
73 | 067cbf31 | Zdenek Kabelac | return 0; |
74 | d663a1fd | Michael Niedermayer | if(memcmp(p->buf,AMR_header,5)==0) |
75 | 067cbf31 | Zdenek Kabelac | return AVPROBE_SCORE_MAX;
|
76 | else
|
||
77 | return 0; |
||
78 | } |
||
79 | |||
80 | /* amr input */
|
||
81 | static int amr_read_header(AVFormatContext *s, |
||
82 | AVFormatParameters *ap) |
||
83 | { |
||
84 | ByteIOContext *pb = &s->pb; |
||
85 | AVStream *st; |
||
86 | d663a1fd | Michael Niedermayer | uint8_t header[9];
|
87 | 067cbf31 | Zdenek Kabelac | |
88 | get_buffer(pb, header, 6);
|
||
89 | |||
90 | if(memcmp(header,AMR_header,6)!=0) |
||
91 | { |
||
92 | d663a1fd | Michael Niedermayer | get_buffer(pb, header+6, 3); |
93 | if(memcmp(header,AMRWB_header,9)!=0) |
||
94 | { |
||
95 | return -1; |
||
96 | } |
||
97 | st = av_new_stream(s, 0);
|
||
98 | if (!st)
|
||
99 | { |
||
100 | return AVERROR_NOMEM;
|
||
101 | } |
||
102 | 115329f1 | Diego Biurrun | |
103 | 01f4895c | Michael Niedermayer | st->codec->codec_type = CODEC_TYPE_AUDIO; |
104 | st->codec->codec_tag = MKTAG('s', 'a', 'w', 'b'); |
||
105 | st->codec->codec_id = CODEC_ID_AMR_WB; |
||
106 | st->codec->channels = 1;
|
||
107 | st->codec->sample_rate = 16000;
|
||
108 | d663a1fd | Michael Niedermayer | } |
109 | else
|
||
110 | { |
||
111 | st = av_new_stream(s, 0);
|
||
112 | if (!st)
|
||
113 | { |
||
114 | return AVERROR_NOMEM;
|
||
115 | } |
||
116 | 115329f1 | Diego Biurrun | |
117 | 01f4895c | Michael Niedermayer | st->codec->codec_type = CODEC_TYPE_AUDIO; |
118 | st->codec->codec_tag = MKTAG('s', 'a', 'm', 'r'); |
||
119 | st->codec->codec_id = CODEC_ID_AMR_NB; |
||
120 | st->codec->channels = 1;
|
||
121 | st->codec->sample_rate = 8000;
|
||
122 | 067cbf31 | Zdenek Kabelac | } |
123 | |||
124 | return 0; |
||
125 | } |
||
126 | |||
127 | #define MAX_SIZE 32 |
||
128 | |||
129 | static int amr_read_packet(AVFormatContext *s, |
||
130 | AVPacket *pkt) |
||
131 | { |
||
132 | 01f4895c | Michael Niedermayer | AVCodecContext *enc = s->streams[0]->codec;
|
133 | 067cbf31 | Zdenek Kabelac | |
134 | d663a1fd | Michael Niedermayer | if (enc->codec_id == CODEC_ID_AMR_NB)
|
135 | { |
||
136 | const static uint8_t packed_size[16] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0}; |
||
137 | uint8_t toc, q, ft; |
||
138 | int read;
|
||
139 | int size;
|
||
140 | 115329f1 | Diego Biurrun | |
141 | d663a1fd | Michael Niedermayer | if (url_feof(&s->pb))
|
142 | { |
||
143 | 0bd586c5 | Mike Melanson | return AVERROR_IO;
|
144 | d663a1fd | Michael Niedermayer | } |
145 | 115329f1 | Diego Biurrun | |
146 | d663a1fd | Michael Niedermayer | toc=get_byte(&s->pb); |
147 | q = (toc >> 2) & 0x01; |
||
148 | ft = (toc >> 3) & 0x0F; |
||
149 | 115329f1 | Diego Biurrun | |
150 | d663a1fd | Michael Niedermayer | size=packed_size[ft]; |
151 | 115329f1 | Diego Biurrun | |
152 | d663a1fd | Michael Niedermayer | if (av_new_packet(pkt, size+1)) |
153 | { |
||
154 | 0bd586c5 | Mike Melanson | return AVERROR_IO;
|
155 | d663a1fd | Michael Niedermayer | } |
156 | pkt->stream_index = 0;
|
||
157 | 2692067a | Michael Niedermayer | pkt->pos= url_ftell(&s->pb); |
158 | d663a1fd | Michael Niedermayer | pkt->data[0]=toc;
|
159 | 115329f1 | Diego Biurrun | |
160 | d663a1fd | Michael Niedermayer | read = get_buffer(&s->pb, pkt->data+1, size);
|
161 | 115329f1 | Diego Biurrun | |
162 | d663a1fd | Michael Niedermayer | if (read != size)
|
163 | { |
||
164 | av_free_packet(pkt); |
||
165 | 0bd586c5 | Mike Melanson | return AVERROR_IO;
|
166 | d663a1fd | Michael Niedermayer | } |
167 | 115329f1 | Diego Biurrun | |
168 | d663a1fd | Michael Niedermayer | return 0; |
169 | } |
||
170 | else if(enc->codec_id == CODEC_ID_AMR_WB) |
||
171 | { |
||
172 | static uint8_t packed_size[16] = {18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1}; |
||
173 | uint8_t toc, mode; |
||
174 | int read;
|
||
175 | int size;
|
||
176 | 115329f1 | Diego Biurrun | |
177 | d663a1fd | Michael Niedermayer | if (url_feof(&s->pb))
|
178 | { |
||
179 | 0bd586c5 | Mike Melanson | return AVERROR_IO;
|
180 | d663a1fd | Michael Niedermayer | } |
181 | 115329f1 | Diego Biurrun | |
182 | d663a1fd | Michael Niedermayer | toc=get_byte(&s->pb); |
183 | mode = (uint8_t)((toc >> 3) & 0x0F); |
||
184 | size = packed_size[mode]; |
||
185 | 115329f1 | Diego Biurrun | |
186 | d663a1fd | Michael Niedermayer | if ( (size==0) || av_new_packet(pkt, size)) |
187 | { |
||
188 | 0bd586c5 | Mike Melanson | return AVERROR_IO;
|
189 | d663a1fd | Michael Niedermayer | } |
190 | 115329f1 | Diego Biurrun | |
191 | d663a1fd | Michael Niedermayer | pkt->stream_index = 0;
|
192 | 2692067a | Michael Niedermayer | pkt->pos= url_ftell(&s->pb); |
193 | d663a1fd | Michael Niedermayer | pkt->data[0]=toc;
|
194 | 115329f1 | Diego Biurrun | |
195 | d663a1fd | Michael Niedermayer | read = get_buffer(&s->pb, pkt->data+1, size-1); |
196 | 115329f1 | Diego Biurrun | |
197 | d663a1fd | Michael Niedermayer | if (read != (size-1)) |
198 | { |
||
199 | av_free_packet(pkt); |
||
200 | 0bd586c5 | Mike Melanson | return AVERROR_IO;
|
201 | d663a1fd | Michael Niedermayer | } |
202 | 115329f1 | Diego Biurrun | |
203 | d663a1fd | Michael Niedermayer | return 0; |
204 | } |
||
205 | else
|
||
206 | 067cbf31 | Zdenek Kabelac | { |
207 | 0bd586c5 | Mike Melanson | return AVERROR_IO;
|
208 | 067cbf31 | Zdenek Kabelac | } |
209 | } |
||
210 | |||
211 | static int amr_read_close(AVFormatContext *s) |
||
212 | { |
||
213 | return 0; |
||
214 | } |
||
215 | |||
216 | static AVInputFormat amr_iformat = {
|
||
217 | "amr",
|
||
218 | "3gpp amr file format",
|
||
219 | d663a1fd | Michael Niedermayer | 0, /*priv_data_size*/ |
220 | 067cbf31 | Zdenek Kabelac | amr_probe, |
221 | amr_read_header, |
||
222 | amr_read_packet, |
||
223 | amr_read_close, |
||
224 | }; |
||
225 | |||
226 | static AVOutputFormat amr_oformat = {
|
||
227 | "amr",
|
||
228 | "3gpp amr file format",
|
||
229 | "audio/amr",
|
||
230 | "amr",
|
||
231 | 0,
|
||
232 | CODEC_ID_AMR_NB, |
||
233 | CODEC_ID_NONE, |
||
234 | amr_write_header, |
||
235 | amr_write_packet, |
||
236 | amr_write_trailer, |
||
237 | }; |
||
238 | |||
239 | int amr_init(void) |
||
240 | { |
||
241 | av_register_input_format(&amr_iformat); |
||
242 | av_register_output_format(&amr_oformat); |
||
243 | return 0; |
||
244 | } |