3 * Copyright (c) 2009 Colin McQuillian
4 * Copyright (c) 2010 Josh Allmann
6 * This file is part of FFmpeg.
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.
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.
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
25 * @brief Xiph / RTP Code
26 * @author Colin McQuillan <m.niloc@gmail.com>
27 * @author Josh Allmann <joshua.allmann@gmail.com>
30 #include "libavutil/avstring.h"
31 #include "libavutil/base64.h"
32 #include "libavcodec/bytestream.h"
37 #include "rtpdec_xiph.h"
40 * RTP/Xiph specific private data.
42 struct PayloadContext
{
43 unsigned ident
; ///< 24-bit stream configuration identifier
45 ByteIOContext
* fragment
; ///< buffer for split payloads
48 static PayloadContext
*xiph_new_context(void)
50 return av_mallocz(sizeof(PayloadContext
));
53 static inline void free_fragment_if_needed(PayloadContext
* data
)
57 url_close_dyn_buf(data
->fragment
, &p
);
59 data
->fragment
= NULL
;
63 static void xiph_free_context(PayloadContext
* data
)
65 free_fragment_if_needed(data
);
69 static int xiph_handle_packet(AVFormatContext
* ctx
,
70 PayloadContext
* data
,
74 const uint8_t * buf
, int len
, int flags
)
77 int ident
, fragmented
, tdt
, num_pkts
, pkt_len
;
80 av_log(ctx
, AV_LOG_ERROR
, "Invalid %d byte packet\n", len
);
81 return AVERROR_INVALIDDATA
;
84 // read xiph rtp headers
86 fragmented
= buf
[3] >> 6;
87 tdt
= (buf
[3] >> 4) & 3;
88 num_pkts
= buf
[3] & 7;
89 pkt_len
= AV_RB16(buf
+ 4);
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
,
95 return AVERROR_INVALIDDATA
;
98 if (ident
!= data
->ident
) {
99 av_log(ctx
, AV_LOG_ERROR
,
100 "Unimplemented Xiph SDP configuration change detected\n");
101 return AVERROR_PATCHWELCOME
;
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
;
111 buf
+= 6; // move past header bits
114 if (fragmented
== 0) {
116 int i
, data_len
, write_len
;
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
);
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",
132 return AVERROR_INVALIDDATA
;
135 if (av_new_packet(pkt
, data_len
)) {
136 av_log(ctx
, AV_LOG_ERROR
, "Out of memory.\n");
137 return AVERROR(ENOMEM
);
139 pkt
->stream_index
= st
->index
;
141 // concatenate frames
142 for (i
= 0, write_len
= 0; write_len
< data_len
; i
++) {
143 pkt_len
= AV_RB16(buf
);
145 memcpy(pkt
->data
+ write_len
, buf
, pkt_len
);
146 write_len
+= pkt_len
;
149 assert(write_len
== data_len
);
153 } else if (fragmented
== 1) {
154 // start of xiph data fragment
157 // end packet has been lost somewhere, so drop buffered data
158 free_fragment_if_needed(data
);
160 if((res
= url_open_dyn_buf(&data
->fragment
)) < 0)
163 put_buffer(data
->fragment
, buf
, pkt_len
);
164 data
->timestamp
= *timestamp
;
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
;
176 // copy data to fragment buffer
177 put_buffer(data
->fragment
, buf
, pkt_len
);
179 if (fragmented
== 3) {
180 // end of xiph data packet
182 int frame_size
= url_close_dyn_buf(data
->fragment
, &xiph_data
);
184 if (frame_size
< 0) {
185 av_log(ctx
, AV_LOG_ERROR
,
186 "Error occurred when getting fragment buffer.");
190 if (av_new_packet(pkt
, frame_size
)) {
191 av_log(ctx
, AV_LOG_ERROR
, "Out of memory.\n");
192 return AVERROR(ENOMEM
);
195 memcpy(pkt
->data
, xiph_data
, frame_size
);
196 pkt
->stream_index
= st
->index
;
199 data
->fragment
= NULL
;
205 return AVERROR(EAGAIN
);
209 * Length encoding described in RFC5215 section 3.1.1.
211 static int get_base128(const uint8_t ** buf
, const uint8_t * buf_end
)
214 for (; *buf
< buf_end
; ++*buf
) {
217 if (!(**buf
& 0x80)) {
226 * Based off parse_packed_headers in Vorbis RTP
229 parse_packed_headers(const uint8_t * packed_headers
,
230 const uint8_t * packed_headers_end
,
231 AVCodecContext
* codec
, PayloadContext
* xiph_data
)
234 unsigned num_packed
, num_headers
, length
, length1
, length2
, extradata_alloc
;
237 if (packed_headers_end
- packed_headers
< 9) {
238 av_log(codec
, AV_LOG_ERROR
,
239 "Invalid %td byte packed header.",
240 packed_headers_end
- packed_headers
);
241 return AVERROR_INVALIDDATA
;
244 num_packed
= bytestream_get_be32(&packed_headers
);
245 xiph_data
->ident
= bytestream_get_be24(&packed_headers
);
246 length
= bytestream_get_be16(&packed_headers
);
247 num_headers
= get_base128(&packed_headers
, packed_headers_end
);
248 length1
= get_base128(&packed_headers
, packed_headers_end
);
249 length2
= get_base128(&packed_headers
, packed_headers_end
);
251 if (num_packed
!= 1 || num_headers
> 3) {
252 av_log(codec
, AV_LOG_ERROR
,
253 "Unimplemented number of headers: %d packed headers, %d headers\n",
254 num_packed
, num_headers
);
255 return AVERROR_PATCHWELCOME
;
258 if (packed_headers_end
- packed_headers
!= length
||
259 length1
> length
|| length2
> length
- length1
) {
260 av_log(codec
, AV_LOG_ERROR
,
261 "Bad packed header lengths (%d,%d,%td,%d)\n", length1
,
262 length2
, packed_headers_end
- packed_headers
, length
);
263 return AVERROR_INVALIDDATA
;
266 /* allocate extra space:
267 * -- length/255 +2 for xiphlacing
268 * -- one for the '2' marker
269 * -- FF_INPUT_BUFFER_PADDING_SIZE required */
270 extradata_alloc
= length
+ length
/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE
;
272 ptr
= codec
->extradata
= av_malloc(extradata_alloc
);
274 av_log(codec
, AV_LOG_ERROR
, "Out of memory\n");
275 return AVERROR(ENOMEM
);
278 ptr
+= av_xiphlacing(ptr
, length1
);
279 ptr
+= av_xiphlacing(ptr
, length2
);
280 memcpy(ptr
, packed_headers
, length
);
282 codec
->extradata_size
= ptr
- codec
->extradata
;
283 // clear out remaining parts of the buffer
284 memset(ptr
, 0, extradata_alloc
- codec
->extradata_size
);
289 static int xiph_parse_fmtp_pair(AVCodecContext
* codec
,
290 PayloadContext
*xiph_data
,
291 char *attr
, char *value
)
295 if (!strcmp(attr
, "sampling")) {
296 return AVERROR_PATCHWELCOME
;
297 } else if (!strcmp(attr
, "width")) {
298 /* This is an integer between 1 and 1048561
299 * and MUST be in multiples of 16. */
300 codec
->width
= atoi(value
);
302 } else if (!strcmp(attr
, "height")) {
303 /* This is an integer between 1 and 1048561
304 * and MUST be in multiples of 16. */
305 codec
->height
= atoi(value
);
307 } else if (!strcmp(attr
, "delivery-method")) {
308 /* Possible values are: inline, in_band, out_band/specific_name. */
309 return AVERROR_PATCHWELCOME
;
310 } else if (!strcmp(attr
, "configuration-uri")) {
311 /* NOTE: configuration-uri is supported only under 2 conditions:
312 *--after the delivery-method tag
313 * --with a delivery-method value of out_band */
314 return AVERROR_PATCHWELCOME
;
315 } else if (!strcmp(attr
, "configuration")) {
316 /* NOTE: configuration is supported only AFTER the delivery-method tag
317 * The configuration value is a base64 encoded packed header */
318 uint8_t *decoded_packet
= NULL
;
320 size_t decoded_alloc
= strlen(value
) / 4 * 3 + 4;
322 if (decoded_alloc
<= INT_MAX
) {
323 decoded_packet
= av_malloc(decoded_alloc
);
324 if (decoded_packet
) {
326 av_base64_decode(decoded_packet
, value
, decoded_alloc
);
328 result
= parse_packed_headers
329 (decoded_packet
, decoded_packet
+ packet_size
, codec
,
332 av_log(codec
, AV_LOG_ERROR
,
333 "Out of memory while decoding SDP configuration.\n");
334 result
= AVERROR(ENOMEM
);
337 av_log(codec
, AV_LOG_ERROR
, "Packet too large\n");
338 result
= AVERROR_INVALIDDATA
;
340 av_free(decoded_packet
);
345 static int xiph_parse_sdp_line(AVFormatContext
*s
, int st_index
,
346 PayloadContext
*data
, const char *line
)
351 int value_size
= strlen(line
), attr_size
= sizeof(attr
), res
= 0;
352 AVCodecContext
* codec
= s
->streams
[st_index
]->codec
;
356 if (!(value
= av_malloc(value_size
))) {
357 av_log(codec
, AV_LOG_ERROR
, "Out of memory\n");
358 return AVERROR(ENOMEM
);
361 if (av_strstart(line
, "fmtp:", &p
)) {
362 // remove protocol identifier
363 while (*p
&& *p
== ' ') p
++; // strip spaces
364 while (*p
&& *p
!= ' ') p
++; // eat protocol identifier
365 while (*p
&& *p
== ' ') p
++; // strip trailing spaces
367 while (ff_rtsp_next_attr_and_value(&p
,
369 value
, value_size
)) {
370 res
= xiph_parse_fmtp_pair(codec
, data
, attr
, value
);
371 if (res
< 0 && res
!= AVERROR_PATCHWELCOME
)
380 RTPDynamicProtocolHandler ff_theora_dynamic_handler
= {
381 .enc_name
= "theora",
382 .codec_type
= AVMEDIA_TYPE_VIDEO
,
383 .codec_id
= CODEC_ID_THEORA
,
384 .parse_sdp_a_line
= xiph_parse_sdp_line
,
385 .open
= xiph_new_context
,
386 .close
= xiph_free_context
,
387 .parse_packet
= xiph_handle_packet
390 RTPDynamicProtocolHandler ff_vorbis_dynamic_handler
= {
391 .enc_name
= "vorbis",
392 .codec_type
= AVMEDIA_TYPE_AUDIO
,
393 .codec_id
= CODEC_ID_VORBIS
,
394 .parse_sdp_a_line
= xiph_parse_sdp_line
,
395 .open
= xiph_new_context
,
396 .close
= xiph_free_context
,
397 .parse_packet
= xiph_handle_packet