Mercurial > libavformat.hg
comparison rtpdec_vorbis.c @ 5726:04b39763b51b libavformat
Rename RTP depacketizer files from rtp_* to rtpdec_*
author | mstorsjo |
---|---|
date | Sun, 28 Feb 2010 11:03:14 +0000 |
parents | rtp_vorbis.c@75e51cba276e |
children | 536e5527c1e0 |
comparison
equal
deleted
inserted
replaced
5725:334f223fc455 | 5726:04b39763b51b |
---|---|
1 /* | |
2 * RTP Vorbis Protocol (RFC5215) | |
3 * Copyright (c) 2009 Colin McQuillan | |
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 /** | |
23 * @file libavformat/rtpdec_vorbis.c | |
24 * @brief Vorbis / RTP Code (RFC 5215) | |
25 * @author Colin McQuillan <m.niloc@gmail.com> | |
26 */ | |
27 | |
28 #include "libavutil/base64.h" | |
29 #include "libavutil/avstring.h" | |
30 #include "libavcodec/bytestream.h" | |
31 | |
32 #include <assert.h> | |
33 | |
34 #include "rtpdec.h" | |
35 #include "rtpdec_vorbis.h" | |
36 | |
37 /** | |
38 * RTP/Vorbis specific private data. | |
39 */ | |
40 struct PayloadContext { | |
41 unsigned ident; ///< 24-bit stream configuration identifier | |
42 }; | |
43 | |
44 /** | |
45 * Length encoding described in RFC5215 section 3.1.1. | |
46 */ | |
47 static int get_base128(const uint8_t ** buf, const uint8_t * buf_end) | |
48 { | |
49 int n = 0; | |
50 for (; *buf < buf_end; ++*buf) { | |
51 n <<= 7; | |
52 n += **buf & 0x7f; | |
53 if (!(**buf & 0x80)) { | |
54 ++*buf; | |
55 return n; | |
56 } | |
57 } | |
58 return 0; | |
59 } | |
60 | |
61 /** | |
62 * Out-of-band headers, described in RFC 5251 section 3.2.1 | |
63 */ | |
64 static unsigned int | |
65 parse_packed_headers(const uint8_t * packed_headers, | |
66 const uint8_t * packed_headers_end, | |
67 AVCodecContext * codec, PayloadContext * vorbis_data) | |
68 { | |
69 unsigned num_packed, num_headers, length, length1, length2; | |
70 uint8_t *ptr; | |
71 | |
72 num_packed = bytestream_get_be32(&packed_headers); | |
73 vorbis_data->ident = bytestream_get_be24(&packed_headers); | |
74 length = bytestream_get_be16(&packed_headers); | |
75 num_headers = get_base128(&packed_headers, packed_headers_end); | |
76 length1 = get_base128(&packed_headers, packed_headers_end); | |
77 length2 = get_base128(&packed_headers, packed_headers_end); | |
78 | |
79 if (num_packed != 1 || num_headers > 3) { | |
80 av_log(codec, AV_LOG_ERROR, | |
81 "Unimplemented number of headers: %d packed headers, %d headers\n", | |
82 num_packed, num_headers); | |
83 return AVERROR_PATCHWELCOME; | |
84 } | |
85 | |
86 if (packed_headers_end - packed_headers != length || | |
87 length1 > length || length2 > length - length1) { | |
88 av_log(codec, AV_LOG_ERROR, | |
89 "Bad packed header lengths (%d,%d,%d,%d)\n", length1, | |
90 length2, packed_headers_end - packed_headers, length); | |
91 return AVERROR_INVALIDDATA; | |
92 } | |
93 | |
94 ptr = codec->extradata = av_mallocz(length + length / 255 + 64); | |
95 if (!ptr) { | |
96 av_log(codec, AV_LOG_ERROR, "Out of memory"); | |
97 return AVERROR_NOMEM; | |
98 } | |
99 *ptr++ = 2; | |
100 ptr += av_xiphlacing(ptr, length1); | |
101 ptr += av_xiphlacing(ptr, length2); | |
102 memcpy(ptr, packed_headers, length); | |
103 ptr += length; | |
104 codec->extradata_size = ptr - codec->extradata; | |
105 | |
106 return 0; | |
107 } | |
108 | |
109 int | |
110 ff_vorbis_parse_fmtp_config(AVCodecContext * codec, | |
111 void *vorbis_data, char *attr, char *value) | |
112 { | |
113 int result = 0; | |
114 assert(codec->codec_id == CODEC_ID_VORBIS); | |
115 assert(vorbis_data); | |
116 | |
117 // The configuration value is a base64 encoded packed header | |
118 if (!strcmp(attr, "configuration")) { | |
119 uint8_t *decoded_packet = NULL; | |
120 int packet_size; | |
121 size_t decoded_alloc = strlen(value) / 4 * 3 + 4; | |
122 | |
123 if (decoded_alloc <= INT_MAX) { | |
124 decoded_packet = av_malloc(decoded_alloc); | |
125 if (decoded_packet) { | |
126 packet_size = | |
127 av_base64_decode(decoded_packet, value, decoded_alloc); | |
128 | |
129 result = parse_packed_headers | |
130 (decoded_packet, decoded_packet + packet_size, codec, | |
131 vorbis_data); | |
132 } else { | |
133 av_log(codec, AV_LOG_ERROR, | |
134 "Out of memory while decoding SDP configuration.\n"); | |
135 result = AVERROR_NOMEM; | |
136 } | |
137 } else { | |
138 av_log(codec, AV_LOG_ERROR, "Packet too large\n"); | |
139 result = AVERROR_INVALIDDATA; | |
140 } | |
141 av_free(decoded_packet); | |
142 } | |
143 return result; | |
144 } | |
145 | |
146 static PayloadContext *vorbis_new_context(void) | |
147 { | |
148 return av_mallocz(sizeof(PayloadContext)); | |
149 } | |
150 | |
151 static void vorbis_free_context(PayloadContext * data) | |
152 { | |
153 av_free(data); | |
154 } | |
155 | |
156 /** | |
157 * Handle payload as described in RFC 5215 section 2.2 | |
158 */ | |
159 static int | |
160 vorbis_handle_packet(AVFormatContext * ctx, | |
161 PayloadContext * data, | |
162 AVStream * st, | |
163 AVPacket * pkt, | |
164 uint32_t * timestamp, | |
165 const uint8_t * buf, int len, int flags) | |
166 { | |
167 int ident, fragmented, vdt, num_pkts, pkt_len; | |
168 | |
169 if (len < 6) { | |
170 av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len); | |
171 return AVERROR_INVALIDDATA; | |
172 } | |
173 | |
174 ident = AV_RB24(buf); | |
175 fragmented = buf[3] >> 6; | |
176 vdt = (buf[3] >> 4) & 3; | |
177 num_pkts = buf[3] & 7; | |
178 pkt_len = AV_RB16(buf + 4); | |
179 | |
180 if (pkt_len > len - 6) { | |
181 av_log(ctx, AV_LOG_ERROR, | |
182 "Invalid packet length %d in %d byte packet\n", pkt_len, | |
183 len); | |
184 return AVERROR_INVALIDDATA; | |
185 } | |
186 | |
187 if (ident != data->ident) { | |
188 av_log(ctx, AV_LOG_ERROR, | |
189 "Unimplemented Vorbis SDP configuration change detected\n"); | |
190 return AVERROR_PATCHWELCOME; | |
191 } | |
192 | |
193 if (fragmented != 0 || vdt != 0 || num_pkts != 1) { | |
194 av_log(ctx, AV_LOG_ERROR, | |
195 "Unimplemented RTP Vorbis packet settings (%d,%d,%d)\n", | |
196 fragmented, vdt, num_pkts); | |
197 return AVERROR_PATCHWELCOME; | |
198 } | |
199 | |
200 if (av_new_packet(pkt, pkt_len)) { | |
201 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); | |
202 return AVERROR_NOMEM; | |
203 } | |
204 | |
205 memcpy(pkt->data, buf + 6, pkt_len); | |
206 pkt->stream_index = st->index; | |
207 return 0; | |
208 } | |
209 | |
210 RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = { | |
211 .enc_name = "vorbis", | |
212 .codec_type = CODEC_TYPE_AUDIO, | |
213 .codec_id = CODEC_ID_VORBIS, | |
214 .parse_sdp_a_line = NULL, | |
215 .open = vorbis_new_context, | |
216 .close = vorbis_free_context, | |
217 .parse_packet = vorbis_handle_packet | |
218 }; |