Originally committed as revision 18375 to svn://svn.ffmpeg.org/ffmpeg/trunk
Martin Storsjö authored on 2009/04/08 16:16:14194 | 195 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,66 @@ |
0 |
+/* |
|
1 |
+ * RTP packetization for AMR audio |
|
2 |
+ * Copyright (c) 2007 Luca Abeni |
|
3 |
+ * Copyright (c) 2009 Martin Storsjo |
|
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 |
+#include "avformat.h" |
|
23 |
+#include "rtpenc.h" |
|
24 |
+ |
|
25 |
+/** |
|
26 |
+ * Packetize AMR frames into RTP packets according to RFC 3267, |
|
27 |
+ * in octet-aligned mode. |
|
28 |
+ */ |
|
29 |
+void ff_rtp_send_amr(AVFormatContext *s1, const uint8_t *buff, int size) |
|
30 |
+{ |
|
31 |
+ RTPMuxContext *s = s1->priv_data; |
|
32 |
+ int max_header_toc_size = 1 + s->max_frames_per_packet; |
|
33 |
+ uint8_t *p; |
|
34 |
+ int len; |
|
35 |
+ |
|
36 |
+ /* Test if the packet must be sent. */ |
|
37 |
+ len = s->buf_ptr - s->buf; |
|
38 |
+ if (s->num_frames == s->max_frames_per_packet || (len && len + size - 1 > s->max_payload_size)) { |
|
39 |
+ int header_size = s->num_frames + 1; |
|
40 |
+ p = s->buf + max_header_toc_size - header_size; |
|
41 |
+ if (p != s->buf) |
|
42 |
+ memmove(p, s->buf, header_size); |
|
43 |
+ |
|
44 |
+ ff_rtp_send_data(s1, p, s->buf_ptr - p, 1); |
|
45 |
+ |
|
46 |
+ s->num_frames = 0; |
|
47 |
+ } |
|
48 |
+ |
|
49 |
+ if (!s->num_frames) { |
|
50 |
+ s->buf[0] = 0xf0; |
|
51 |
+ s->buf_ptr = s->buf + max_header_toc_size; |
|
52 |
+ s->timestamp = s->cur_timestamp; |
|
53 |
+ } else { |
|
54 |
+ /* Mark the previous TOC entry as having more entries following. */ |
|
55 |
+ s->buf[1 + s->num_frames - 1] |= 0x80; |
|
56 |
+ } |
|
57 |
+ |
|
58 |
+ /* Copy the frame type and quality bits. */ |
|
59 |
+ s->buf[1 + s->num_frames++] = buff[0] & 0x7C; |
|
60 |
+ buff++; |
|
61 |
+ size--; |
|
62 |
+ memcpy(s->buf_ptr, buff, size); |
|
63 |
+ s->buf_ptr += size; |
|
64 |
+} |
|
65 |
+ |
... | ... |
@@ -60,6 +60,8 @@ static int is_supported(enum CodecID id) |
60 | 60 |
case CODEC_ID_PCM_U16LE: |
61 | 61 |
case CODEC_ID_PCM_U8: |
62 | 62 |
case CODEC_ID_MPEG2TS: |
63 |
+ case CODEC_ID_AMR_NB: |
|
64 |
+ case CODEC_ID_AMR_WB: |
|
63 | 65 |
return 1; |
64 | 66 |
default: |
65 | 67 |
return 0; |
... | ... |
@@ -134,6 +136,23 @@ static int rtp_write_header(AVFormatContext *s1) |
134 | 134 |
s->max_payload_size = n * TS_PACKET_SIZE; |
135 | 135 |
s->buf_ptr = s->buf; |
136 | 136 |
break; |
137 |
+ case CODEC_ID_AMR_NB: |
|
138 |
+ case CODEC_ID_AMR_WB: |
|
139 |
+ if (!s->max_frames_per_packet) |
|
140 |
+ s->max_frames_per_packet = 12; |
|
141 |
+ if (st->codec->codec_id == CODEC_ID_AMR_NB) |
|
142 |
+ n = 31; |
|
143 |
+ else |
|
144 |
+ n = 61; |
|
145 |
+ /* max_header_toc_size + the largest AMR payload must fit */ |
|
146 |
+ if (1 + s->max_frames_per_packet + n > s->max_payload_size) { |
|
147 |
+ av_log(s1, AV_LOG_ERROR, "RTP max payload size too small for AMR\n"); |
|
148 |
+ return -1; |
|
149 |
+ } |
|
150 |
+ if (st->codec->channels != 1) { |
|
151 |
+ av_log(s1, AV_LOG_ERROR, "Only mono is supported\n"); |
|
152 |
+ return -1; |
|
153 |
+ } |
|
137 | 154 |
case CODEC_ID_AAC: |
138 | 155 |
s->num_frames = 0; |
139 | 156 |
default: |
... | ... |
@@ -366,6 +385,10 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) |
366 | 366 |
case CODEC_ID_AAC: |
367 | 367 |
ff_rtp_send_aac(s1, buf1, size); |
368 | 368 |
break; |
369 |
+ case CODEC_ID_AMR_NB: |
|
370 |
+ case CODEC_ID_AMR_WB: |
|
371 |
+ ff_rtp_send_amr(s1, buf1, size); |
|
372 |
+ break; |
|
369 | 373 |
case CODEC_ID_MPEG2TS: |
370 | 374 |
rtp_send_mpegts_raw(s1, buf1, size); |
371 | 375 |
break; |
... | ... |
@@ -59,6 +59,7 @@ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m); |
59 | 59 |
void ff_rtp_send_h264(AVFormatContext *s1, const uint8_t *buf1, int size); |
60 | 60 |
void ff_rtp_send_h263(AVFormatContext *s1, const uint8_t *buf1, int size); |
61 | 61 |
void ff_rtp_send_aac(AVFormatContext *s1, const uint8_t *buff, int size); |
62 |
+void ff_rtp_send_amr(AVFormatContext *s1, const uint8_t *buff, int size); |
|
62 | 63 |
void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size); |
63 | 64 |
|
64 | 65 |
#endif /* AVFORMAT_RTPENC_H */ |
... | ... |
@@ -228,6 +228,18 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, |
228 | 228 |
payload_type, |
229 | 229 |
c->sample_rate, c->channels); |
230 | 230 |
break; |
231 |
+ case CODEC_ID_AMR_NB: |
|
232 |
+ av_strlcatf(buff, size, "a=rtpmap:%d AMR/%d/%d\r\n" |
|
233 |
+ "a=fmtp:%d octet-align=1\r\n", |
|
234 |
+ payload_type, c->sample_rate, c->channels, |
|
235 |
+ payload_type); |
|
236 |
+ break; |
|
237 |
+ case CODEC_ID_AMR_WB: |
|
238 |
+ av_strlcatf(buff, size, "a=rtpmap:%d AMR-WB/%d/%d\r\n" |
|
239 |
+ "a=fmtp:%d octet-align=1\r\n", |
|
240 |
+ payload_type, c->sample_rate, c->channels, |
|
241 |
+ payload_type); |
|
242 |
+ break; |
|
231 | 243 |
default: |
232 | 244 |
/* Nothing special to do here... */ |
233 | 245 |
break; |