rtpdec_xiph: Handle the sampling SDP parameter
[libav.git] / libavformat / rtpdec_xiph.c
1 /*
2 * Xiph RTP Protocols
3 * Copyright (c) 2009 Colin McQuillian
4 * Copyright (c) 2010 Josh Allmann
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /**
24 * @file
25 * @brief Xiph / RTP Code
26 * @author Colin McQuillan <m.niloc@gmail.com>
27 * @author Josh Allmann <joshua.allmann@gmail.com>
28 */
29
30 #include "libavutil/avstring.h"
31 #include "libavutil/base64.h"
32 #include "libavcodec/bytestream.h"
33
34 #include <assert.h>
35
36 #include "rtpdec.h"
37 #include "rtpdec_xiph.h"
38
39 /**
40 * RTP/Xiph specific private data.
41 */
42 struct PayloadContext {
43 unsigned ident; ///< 24-bit stream configuration identifier
44 uint32_t timestamp;
45 ByteIOContext* fragment; ///< buffer for split payloads
46 };
47
48 static PayloadContext *xiph_new_context(void)
49 {
50 return av_mallocz(sizeof(PayloadContext));
51 }
52
53 static inline void free_fragment_if_needed(PayloadContext * data)
54 {
55 if (data->fragment) {
56 uint8_t* p;
57 url_close_dyn_buf(data->fragment, &p);
58 av_free(p);
59 data->fragment = NULL;
60 }
61 }
62
63 static void xiph_free_context(PayloadContext * data)
64 {
65 free_fragment_if_needed(data);
66 av_free(data);
67 }
68
69 static int xiph_handle_packet(AVFormatContext * ctx,
70 PayloadContext * data,
71 AVStream * st,
72 AVPacket * pkt,
73 uint32_t * timestamp,
74 const uint8_t * buf, int len, int flags)
75 {
76
77 int ident, fragmented, tdt, num_pkts, pkt_len;
78
79 if (len < 6) {
80 av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len);
81 return AVERROR_INVALIDDATA;
82 }
83
84 // read xiph rtp headers
85 ident = AV_RB24(buf);
86 fragmented = buf[3] >> 6;
87 tdt = (buf[3] >> 4) & 3;
88 num_pkts = buf[3] & 7;
89 pkt_len = AV_RB16(buf + 4);
90
91 if (pkt_len > len - 6) {
92 av_log(ctx, AV_LOG_ERROR,
93 "Invalid packet length %d in %d byte packet\n", pkt_len,
94 len);
95 return AVERROR_INVALIDDATA;
96 }
97
98 if (ident != data->ident) {
99 av_log(ctx, AV_LOG_ERROR,
100 "Unimplemented Xiph SDP configuration change detected\n");
101 return AVERROR_PATCHWELCOME;
102 }
103
104 if (tdt) {
105 av_log(ctx, AV_LOG_ERROR,
106 "Unimplemented RTP Xiph packet settings (%d,%d,%d)\n",
107 fragmented, tdt, num_pkts);
108 return AVERROR_PATCHWELCOME;
109 }
110
111 buf += 6; // move past header bits
112 len -= 6;
113
114 if (fragmented == 0) {
115 // whole frame(s)
116 int i, data_len, write_len;
117 buf -= 2;
118 len += 2;
119
120 // fast first pass to calculate total length
121 for (i = 0, data_len = 0; (i < num_pkts) && (len >= 2); i++) {
122 int off = data_len + (i << 1);
123 pkt_len = AV_RB16(buf + off);
124 data_len += pkt_len;
125 len -= pkt_len + 2;
126 }
127
128 if (len < 0 || i < num_pkts) {
129 av_log(ctx, AV_LOG_ERROR,
130 "Bad packet: %d bytes left at frame %d of %d\n",
131 len, i, num_pkts);
132 return AVERROR_INVALIDDATA;
133 }
134
135 if (av_new_packet(pkt, data_len)) {
136 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
137 return AVERROR(ENOMEM);
138 }
139 pkt->stream_index = st->index;
140
141 // concatenate frames
142 for (i = 0, write_len = 0; write_len < data_len; i++) {
143 pkt_len = AV_RB16(buf);
144 buf += 2;
145 memcpy(pkt->data + write_len, buf, pkt_len);
146 write_len += pkt_len;
147 buf += pkt_len;
148 }
149 assert(write_len == data_len);
150
151 return 0;
152
153 } else if (fragmented == 1) {
154 // start of xiph data fragment
155 int res;
156
157 // end packet has been lost somewhere, so drop buffered data
158 free_fragment_if_needed(data);
159
160 if((res = url_open_dyn_buf(&data->fragment)) < 0)
161 return res;
162
163 put_buffer(data->fragment, buf, pkt_len);
164 data->timestamp = *timestamp;
165
166 } else {
167 assert(fragmented < 4);
168 if (data->timestamp != *timestamp) {
169 // skip if fragmented timestamp is incorrect;
170 // a start packet has been lost somewhere
171 free_fragment_if_needed(data);
172 av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match!\n");
173 return AVERROR_INVALIDDATA;
174 }
175 if (!data->fragment) {
176 av_log(ctx, AV_LOG_WARNING,
177 "Received packet without a start fragment; dropping.\n");
178 return AVERROR(EAGAIN);
179 }
180
181 // copy data to fragment buffer
182 put_buffer(data->fragment, buf, pkt_len);
183
184 if (fragmented == 3) {
185 // end of xiph data packet
186 av_init_packet(pkt);
187 pkt->size = url_close_dyn_buf(data->fragment, &pkt->data);
188
189 if (pkt->size < 0) {
190 av_log(ctx, AV_LOG_ERROR,
191 "Error occurred when getting fragment buffer.");
192 return pkt->size;
193 }
194
195 pkt->stream_index = st->index;
196 pkt->destruct = av_destruct_packet;
197
198 data->fragment = NULL;
199
200 return 0;
201 }
202 }
203
204 return AVERROR(EAGAIN);
205 }
206
207 /**
208 * Length encoding described in RFC5215 section 3.1.1.
209 */
210 static int get_base128(const uint8_t ** buf, const uint8_t * buf_end)
211 {
212 int n = 0;
213 for (; *buf < buf_end; ++*buf) {
214 n <<= 7;
215 n += **buf & 0x7f;
216 if (!(**buf & 0x80)) {
217 ++*buf;
218 return n;
219 }
220 }
221 return 0;
222 }
223
224 /**
225 * Based off parse_packed_headers in Vorbis RTP
226 */
227 static unsigned int
228 parse_packed_headers(const uint8_t * packed_headers,
229 const uint8_t * packed_headers_end,
230 AVCodecContext * codec, PayloadContext * xiph_data)
231 {
232
233 unsigned num_packed, num_headers, length, length1, length2, extradata_alloc;
234 uint8_t *ptr;
235
236 if (packed_headers_end - packed_headers < 9) {
237 av_log(codec, AV_LOG_ERROR,
238 "Invalid %td byte packed header.",
239 packed_headers_end - packed_headers);
240 return AVERROR_INVALIDDATA;
241 }
242
243 num_packed = bytestream_get_be32(&packed_headers);
244 xiph_data->ident = bytestream_get_be24(&packed_headers);
245 length = bytestream_get_be16(&packed_headers);
246 num_headers = get_base128(&packed_headers, packed_headers_end);
247 length1 = get_base128(&packed_headers, packed_headers_end);
248 length2 = get_base128(&packed_headers, packed_headers_end);
249
250 if (num_packed != 1 || num_headers > 3) {
251 av_log(codec, AV_LOG_ERROR,
252 "Unimplemented number of headers: %d packed headers, %d headers\n",
253 num_packed, num_headers);
254 return AVERROR_PATCHWELCOME;
255 }
256
257 if (packed_headers_end - packed_headers != length ||
258 length1 > length || length2 > length - length1) {
259 av_log(codec, AV_LOG_ERROR,
260 "Bad packed header lengths (%d,%d,%td,%d)\n", length1,
261 length2, packed_headers_end - packed_headers, length);
262 return AVERROR_INVALIDDATA;
263 }
264
265 /* allocate extra space:
266 * -- length/255 +2 for xiphlacing
267 * -- one for the '2' marker
268 * -- FF_INPUT_BUFFER_PADDING_SIZE required */
269 extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE;
270
271 ptr = codec->extradata = av_malloc(extradata_alloc);
272 if (!ptr) {
273 av_log(codec, AV_LOG_ERROR, "Out of memory\n");
274 return AVERROR(ENOMEM);
275 }
276 *ptr++ = 2;
277 ptr += av_xiphlacing(ptr, length1);
278 ptr += av_xiphlacing(ptr, length2);
279 memcpy(ptr, packed_headers, length);
280 ptr += length;
281 codec->extradata_size = ptr - codec->extradata;
282 // clear out remaining parts of the buffer
283 memset(ptr, 0, extradata_alloc - codec->extradata_size);
284
285 return 0;
286 }
287
288 static int xiph_parse_fmtp_pair(AVStream* stream,
289 PayloadContext *xiph_data,
290 char *attr, char *value)
291 {
292 AVCodecContext *codec = stream->codec;
293 int result = 0;
294
295 if (!strcmp(attr, "sampling")) {
296 if (!strcmp(value, "YCbCr-4:2:0")) {
297 codec->pix_fmt = PIX_FMT_YUV420P;
298 } else if (!strcmp(value, "YCbCr-4:4:2")) {
299 codec->pix_fmt = PIX_FMT_YUV422P;
300 } else if (!strcmp(value, "YCbCr-4:4:4")) {
301 codec->pix_fmt = PIX_FMT_YUV444P;
302 } else {
303 av_log(codec, AV_LOG_ERROR,
304 "Unsupported pixel format %s\n", attr);
305 return AVERROR_INVALIDDATA;
306 }
307 } else if (!strcmp(attr, "width")) {
308 /* This is an integer between 1 and 1048561
309 * and MUST be in multiples of 16. */
310 codec->width = atoi(value);
311 return 0;
312 } else if (!strcmp(attr, "height")) {
313 /* This is an integer between 1 and 1048561
314 * and MUST be in multiples of 16. */
315 codec->height = atoi(value);
316 return 0;
317 } else if (!strcmp(attr, "delivery-method")) {
318 /* Possible values are: inline, in_band, out_band/specific_name. */
319 return AVERROR_PATCHWELCOME;
320 } else if (!strcmp(attr, "configuration-uri")) {
321 /* NOTE: configuration-uri is supported only under 2 conditions:
322 *--after the delivery-method tag
323 * --with a delivery-method value of out_band */
324 return AVERROR_PATCHWELCOME;
325 } else if (!strcmp(attr, "configuration")) {
326 /* NOTE: configuration is supported only AFTER the delivery-method tag
327 * The configuration value is a base64 encoded packed header */
328 uint8_t *decoded_packet = NULL;
329 int packet_size;
330 size_t decoded_alloc = strlen(value) / 4 * 3 + 4;
331
332 if (decoded_alloc <= INT_MAX) {
333 decoded_packet = av_malloc(decoded_alloc);
334 if (decoded_packet) {
335 packet_size =
336 av_base64_decode(decoded_packet, value, decoded_alloc);
337
338 result = parse_packed_headers
339 (decoded_packet, decoded_packet + packet_size, codec,
340 xiph_data);
341 } else {
342 av_log(codec, AV_LOG_ERROR,
343 "Out of memory while decoding SDP configuration.\n");
344 result = AVERROR(ENOMEM);
345 }
346 } else {
347 av_log(codec, AV_LOG_ERROR, "Packet too large\n");
348 result = AVERROR_INVALIDDATA;
349 }
350 av_free(decoded_packet);
351 }
352 return result;
353 }
354
355 static int xiph_parse_sdp_line(AVFormatContext *s, int st_index,
356 PayloadContext *data, const char *line)
357 {
358 const char *p;
359
360 if (av_strstart(line, "fmtp:", &p)) {
361 return ff_parse_fmtp(s->streams[st_index], data, p,
362 xiph_parse_fmtp_pair);
363 }
364
365 return 0;
366 }
367
368 RTPDynamicProtocolHandler ff_theora_dynamic_handler = {
369 .enc_name = "theora",
370 .codec_type = AVMEDIA_TYPE_VIDEO,
371 .codec_id = CODEC_ID_THEORA,
372 .parse_sdp_a_line = xiph_parse_sdp_line,
373 .open = xiph_new_context,
374 .close = xiph_free_context,
375 .parse_packet = xiph_handle_packet
376 };
377
378 RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = {
379 .enc_name = "vorbis",
380 .codec_type = AVMEDIA_TYPE_AUDIO,
381 .codec_id = CODEC_ID_VORBIS,
382 .parse_sdp_a_line = xiph_parse_sdp_line,
383 .open = xiph_new_context,
384 .close = xiph_free_context,
385 .parse_packet = xiph_handle_packet
386 };