FFmpeg
rtpdec_xiph.c
Go to the documentation of this file.
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/attributes.h"
31 #include "libavutil/avassert.h"
32 #include "libavutil/avstring.h"
33 #include "libavutil/base64.h"
34 #include "libavutil/mem.h"
35 #include "libavcodec/bytestream.h"
36 
37 #include "avio_internal.h"
38 #include "internal.h"
39 #include "rtpdec.h"
40 #include "rtpdec_formats.h"
41 
42 /**
43  * RTP/Xiph specific private data.
44  */
45 struct PayloadContext {
46  unsigned ident; ///< 24-bit stream configuration identifier
47  uint32_t timestamp;
48  AVIOContext* fragment; ///< buffer for split payloads
49  uint8_t *split_buf;
51  int split_pkts;
52 };
53 
55 {
56  ffio_free_dyn_buf(&data->fragment);
57  av_freep(&data->split_buf);
58 }
59 
60 
62  AVStream *st, AVPacket *pkt, uint32_t *timestamp,
63  const uint8_t *buf, int len, uint16_t seq,
64  int flags)
65 {
66 
67  int ident, fragmented, tdt, num_pkts, pkt_len, ret;
68 
69  if (!buf) {
70  if (!data->split_buf || data->split_pos + 2 > data->split_buf_len ||
71  data->split_pkts <= 0) {
72  av_log(ctx, AV_LOG_ERROR, "No more data to return\n");
73  return AVERROR_INVALIDDATA;
74  }
75  pkt_len = AV_RB16(data->split_buf + data->split_pos);
76  data->split_pos += 2;
77  if (pkt_len > data->split_buf_len - data->split_pos) {
78  av_log(ctx, AV_LOG_ERROR, "Not enough data to return\n");
79  return AVERROR_INVALIDDATA;
80  }
81  if ((ret = av_new_packet(pkt, pkt_len)) < 0) {
82  av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
83  return ret;
84  }
85  pkt->stream_index = st->index;
86  memcpy(pkt->data, data->split_buf + data->split_pos, pkt_len);
87  data->split_pos += pkt_len;
88  data->split_pkts--;
89  return data->split_pkts > 0;
90  }
91 
92  if (len < 6 || len > INT_MAX/2) {
93  av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len);
94  return AVERROR_INVALIDDATA;
95  }
96 
97  // read xiph rtp headers
98  ident = AV_RB24(buf);
99  fragmented = buf[3] >> 6;
100  tdt = (buf[3] >> 4) & 3;
101  num_pkts = buf[3] & 0xf;
102  pkt_len = AV_RB16(buf + 4);
103 
104  if (pkt_len > len - 6) {
106  "Invalid packet length %d in %d byte packet\n", pkt_len,
107  len);
108  return AVERROR_INVALIDDATA;
109  }
110 
111  if (ident != data->ident) {
112  avpriv_report_missing_feature(ctx, "Xiph SDP configuration change");
113  return AVERROR_PATCHWELCOME;
114  }
115 
116  if (tdt) {
118  "RTP Xiph packet settings (%d,%d,%d)",
119  fragmented, tdt, num_pkts);
120  return AVERROR_PATCHWELCOME;
121  }
122 
123  buf += 6; // move past header bits
124  len -= 6;
125 
126  if (fragmented == 0) {
127  if ((ret = av_new_packet(pkt, pkt_len)) < 0) {
128  av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
129  return ret;
130  }
131  pkt->stream_index = st->index;
132  memcpy(pkt->data, buf, pkt_len);
133  buf += pkt_len;
134  len -= pkt_len;
135  num_pkts--;
136 
137  if (num_pkts > 0) {
138  if (len > data->split_buf_size || !data->split_buf) {
139  av_freep(&data->split_buf);
140  data->split_buf_size = 2 * len;
141  data->split_buf = av_malloc(data->split_buf_size);
142  if (!data->split_buf) {
143  av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
145  return AVERROR(ENOMEM);
146  }
147  }
148  memcpy(data->split_buf, buf, len);
149  data->split_buf_len = len;
150  data->split_pos = 0;
151  data->split_pkts = num_pkts;
152  return 1;
153  }
154 
155  return 0;
156 
157  } else if (fragmented == 1) {
158  // start of xiph data fragment
159  int res;
160 
161  // end packet has been lost somewhere, so drop buffered data
162  ffio_free_dyn_buf(&data->fragment);
163 
164  if((res = avio_open_dyn_buf(&data->fragment)) < 0)
165  return res;
166 
167  avio_write(data->fragment, buf, pkt_len);
168  data->timestamp = *timestamp;
169 
170  } else {
171  av_assert1(fragmented < 4);
172  if (data->timestamp != *timestamp) {
173  // skip if fragmented timestamp is incorrect;
174  // a start packet has been lost somewhere
175  ffio_free_dyn_buf(&data->fragment);
176  av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match!\n");
177  return AVERROR_INVALIDDATA;
178  }
179  if (!data->fragment) {
181  "Received packet without a start fragment; dropping.\n");
182  return AVERROR(EAGAIN);
183  }
184 
185  // copy data to fragment buffer
186  avio_write(data->fragment, buf, pkt_len);
187 
188  if (fragmented == 3) {
189  // end of xiph data packet
190  int ret = ff_rtp_finalize_packet(pkt, &data->fragment, st->index);
191  if (ret < 0) {
193  "Error occurred when getting fragment buffer.");
194  return ret;
195  }
196 
197  return 0;
198  }
199  }
200 
201  return AVERROR(EAGAIN);
202 }
203 
204 /**
205  * Length encoding described in RFC5215 section 3.1.1.
206  */
207 static int get_base128(const uint8_t ** buf, const uint8_t * buf_end)
208 {
209  int n = 0;
210  for (; *buf < buf_end; ++*buf) {
211  n <<= 7;
212  n += **buf & 0x7f;
213  if (!(**buf & 0x80)) {
214  ++*buf;
215  return n;
216  }
217  }
218  return 0;
219 }
220 
221 /**
222  * Based off parse_packed_headers in Vorbis RTP
223  */
224 static int
226  const uint8_t * packed_headers,
227  const uint8_t * packed_headers_end,
228  AVCodecParameters *par, PayloadContext * xiph_data)
229 {
230 
231  unsigned num_packed, num_headers, length, length1, length2, extradata_alloc;
232  int ret;
233  uint8_t *ptr;
234 
235  if (packed_headers_end - packed_headers < 9) {
237  "Invalid %"PTRDIFF_SPECIFIER" byte packed header.",
238  packed_headers_end - packed_headers);
239  return AVERROR_INVALIDDATA;
240  }
241 
242  num_packed = bytestream_get_be32(&packed_headers);
243  xiph_data->ident = bytestream_get_be24(&packed_headers);
244  length = bytestream_get_be16(&packed_headers);
245  num_headers = get_base128(&packed_headers, packed_headers_end);
246  length1 = get_base128(&packed_headers, packed_headers_end);
247  length2 = get_base128(&packed_headers, packed_headers_end);
248 
249  if (num_packed != 1 || num_headers > 3) {
250  avpriv_report_missing_feature(s, "%u packed headers, %u headers",
251  num_packed, num_headers);
252  return AVERROR_PATCHWELCOME;
253  }
254 
255  if (packed_headers_end - packed_headers != length ||
256  length1 > length || length2 > length - length1) {
258  "Bad packed header lengths (%d,%d,%"PTRDIFF_SPECIFIER",%u)\n", length1,
259  length2, packed_headers_end - packed_headers, length);
260  return AVERROR_INVALIDDATA;
261  }
262 
263  /* allocate extra space:
264  * -- length/255 +2 for xiphlacing
265  * -- one for the '2' marker
266  * -- AV_INPUT_BUFFER_PADDING_SIZE required */
267  extradata_alloc = length + length/255 + 3 + AV_INPUT_BUFFER_PADDING_SIZE;
268 
269  if ((ret = ff_alloc_extradata(par, extradata_alloc)) < 0) {
270  av_log(s, AV_LOG_ERROR, "Out of memory\n");
271  return ret;
272  }
273  ptr = par->extradata;
274  *ptr++ = 2;
275  ptr += av_xiphlacing(ptr, length1);
276  ptr += av_xiphlacing(ptr, length2);
277  memcpy(ptr, packed_headers, length);
278  ptr += length;
279  par->extradata_size = ptr - par->extradata;
280  // clear out remaining parts of the buffer
281  memset(ptr, 0, extradata_alloc - par->extradata_size);
282 
283  return 0;
284 }
285 
287  AVStream* stream,
288  PayloadContext *xiph_data,
289  const char *attr, const char *value)
290 {
291  AVCodecParameters *par = stream->codecpar;
292  int result = 0;
293 
294  if (!strcmp(attr, "sampling")) {
295  if (!strcmp(value, "YCbCr-4:2:0")) {
296  par->format = AV_PIX_FMT_YUV420P;
297  } else if (!strcmp(value, "YCbCr-4:4:2")) {
298  par->format = AV_PIX_FMT_YUV422P;
299  } else if (!strcmp(value, "YCbCr-4:4:4")) {
300  par->format = AV_PIX_FMT_YUV444P;
301  } else {
303  "Unsupported pixel format %s\n", attr);
304  return AVERROR_INVALIDDATA;
305  }
306  } else if (!strcmp(attr, "width")) {
307  /* This is an integer between 1 and 1048561
308  * and MUST be in multiples of 16. */
309  par->width = atoi(value);
310  return 0;
311  } else if (!strcmp(attr, "height")) {
312  /* This is an integer between 1 and 1048561
313  * and MUST be in multiples of 16. */
314  par->height = atoi(value);
315  return 0;
316  } else if (!strcmp(attr, "delivery-method")) {
317  /* Possible values are: inline, in_band, out_band/specific_name. */
318  return AVERROR_PATCHWELCOME;
319  } else if (!strcmp(attr, "configuration-uri")) {
320  /* NOTE: configuration-uri is supported only under 2 conditions:
321  *--after the delivery-method tag
322  * --with a delivery-method value of out_band */
323  return AVERROR_PATCHWELCOME;
324  } else if (!strcmp(attr, "configuration")) {
325  /* NOTE: configuration is supported only AFTER the delivery-method tag
326  * The configuration value is a base64 encoded packed header */
327  uint8_t *decoded_packet = NULL;
328  int packet_size;
329  size_t decoded_alloc = strlen(value) / 4 * 3 + 4;
330 
331  if (decoded_alloc <= INT_MAX) {
332  decoded_packet = av_malloc(decoded_alloc);
333  if (decoded_packet) {
334  packet_size =
335  av_base64_decode(decoded_packet, value, decoded_alloc);
336 
338  (s, decoded_packet, decoded_packet + packet_size, par,
339  xiph_data);
340  } else {
342  "Out of memory while decoding SDP configuration.\n");
343  result = AVERROR(ENOMEM);
344  }
345  } else {
346  av_log(s, AV_LOG_ERROR, "Packet too large\n");
348  }
349  av_free(decoded_packet);
350  }
351  return result;
352 }
353 
354 static int xiph_parse_sdp_line(AVFormatContext *s, int st_index,
355  PayloadContext *data, const char *line)
356 {
357  const char *p;
358 
359  if (st_index < 0)
360  return 0;
361 
362  if (av_strstart(line, "fmtp:", &p)) {
363  return ff_parse_fmtp(s, s->streams[st_index], data, p,
365  }
366 
367  return 0;
368 }
369 
371  .enc_name = "theora",
372  .codec_type = AVMEDIA_TYPE_VIDEO,
373  .codec_id = AV_CODEC_ID_THEORA,
374  .priv_data_size = sizeof(PayloadContext),
375  .parse_sdp_a_line = xiph_parse_sdp_line,
376  .close = xiph_close_context,
378 };
379 
381  .enc_name = "vorbis",
382  .codec_type = AVMEDIA_TYPE_AUDIO,
383  .codec_id = AV_CODEC_ID_VORBIS,
384  .need_parsing = AVSTREAM_PARSE_HEADERS,
385  .priv_data_size = sizeof(PayloadContext),
386  .parse_sdp_a_line = xiph_parse_sdp_line,
387  .close = xiph_close_context,
389 };
get_base128
static int get_base128(const uint8_t **buf, const uint8_t *buf_end)
Length encoding described in RFC5215 section 3.1.1.
Definition: rtpdec_xiph.c:207
ff_theora_dynamic_handler
const RTPDynamicProtocolHandler ff_theora_dynamic_handler
Definition: rtpdec_xiph.c:370
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:429
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:69
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
PayloadContext::split_buf_size
int split_buf_size
Definition: rtpdec_mpa_robust.c:34
xiph_parse_sdp_line
static int xiph_parse_sdp_line(AVFormatContext *s, int st_index, PayloadContext *data, const char *line)
Definition: rtpdec_xiph.c:354
AVCodecParameters
This struct describes the properties of an encoded stream.
Definition: codec_par.h:47
rtpdec_formats.h
ff_parse_fmtp
int ff_parse_fmtp(AVFormatContext *s, AVStream *stream, PayloadContext *data, const char *p, int(*parse_fmtp)(AVFormatContext *s, AVStream *stream, PayloadContext *data, const char *attr, const char *value))
Definition: rtpdec.c:965
AVPacket::data
uint8_t * data
Definition: packet.h:539
data
const char data[16]
Definition: mxf.c:149
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
ff_rtp_finalize_packet
int ff_rtp_finalize_packet(AVPacket *pkt, AVIOContext **dyn_buf, int stream_idx)
Close the dynamic buffer and make a packet from it.
Definition: rtpdec.c:1003
PayloadContext::timestamp
uint32_t timestamp
current frame timestamp
Definition: rtpdec_ac3.c:31
RTPDynamicProtocolHandler::enc_name
const char * enc_name
Definition: rtpdec.h:117
parse_packed_headers
static int parse_packed_headers(AVFormatContext *s, const uint8_t *packed_headers, const uint8_t *packed_headers_end, AVCodecParameters *par, PayloadContext *xiph_data)
Based off parse_packed_headers in Vorbis RTP.
Definition: rtpdec_xiph.c:225
avassert.h
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
PayloadContext::split_buf
uint8_t * split_buf
Definition: rtpdec_mpa_robust.c:33
avio_open_dyn_buf
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1362
PayloadContext::fragment
AVIOContext * fragment
buffer for split payloads
Definition: rtpdec_ac3.c:32
s
#define s(width, name)
Definition: cbs_vp9.c:198
av_new_packet
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: packet.c:98
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AVCodecParameters::width
int width
Video only.
Definition: codec_par.h:134
ctx
AVFormatContext * ctx
Definition: movenc.c:49
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
AVFormatContext
Format I/O context.
Definition: avformat.h:1300
internal.h
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:771
result
and forward the result(frame or status change) to the corresponding input. If nothing is possible
PayloadContext::ident
unsigned ident
24-bit stream configuration identifier
Definition: rtpdec_xiph.c:46
PTRDIFF_SPECIFIER
#define PTRDIFF_SPECIFIER
Definition: internal.h:128
NULL
#define NULL
Definition: coverity.c:32
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
PayloadContext::split_buf_len
int split_buf_len
Definition: rtpdec_xiph.c:50
av_base64_decode
int av_base64_decode(uint8_t *out, const char *in_str, int out_size)
Decode a base64-encoded string.
Definition: base64.c:81
base64.h
rtpdec.h
AVCodecParameters::extradata_size
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:73
xiph_close_context
static void xiph_close_context(PayloadContext *data)
Definition: rtpdec_xiph.c:54
PayloadContext::split_pos
int split_pos
Definition: rtpdec_mpa_robust.c:34
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
avpriv_report_missing_feature
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
av_xiphlacing
unsigned int av_xiphlacing(unsigned char *s, unsigned int v)
Encode extradata length to a buffer.
Definition: utils.c:812
avio_write
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:201
line
Definition: graph2dot.c:48
attributes.h
av_strstart
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:36
ff_vorbis_dynamic_handler
const RTPDynamicProtocolHandler ff_vorbis_dynamic_handler
Definition: rtpdec_xiph.c:380
avio_internal.h
AV_CODEC_ID_THEORA
@ AV_CODEC_ID_THEORA
Definition: codec_id.h:82
AVCodecParameters::height
int height
Definition: codec_par.h:135
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:56
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
PayloadContext::split_pkts
int split_pkts
Definition: rtpdec_mpa_robust.c:34
len
int len
Definition: vorbis_enc_data.h:426
ffio_free_dyn_buf
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition: aviobuf.c:1435
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:748
AVSTREAM_PARSE_HEADERS
@ AVSTREAM_PARSE_HEADERS
Only parse headers, do not repack.
Definition: avformat.h:594
xiph_handle_packet
static int xiph_handle_packet(AVFormatContext *ctx, PayloadContext *data, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, uint16_t seq, int flags)
Definition: rtpdec_xiph.c:61
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: defs.h:40
AVStream::index
int index
stream index in AVFormatContext
Definition: avformat.h:754
AVPacket::stream_index
int stream_index
Definition: packet.h:541
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:78
parse_packet
static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index, int flush)
Parse a packet, add all split parts to parse_queue.
Definition: demux.c:1162
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AV_PIX_FMT_YUV422P
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:77
mem.h
AVCodecParameters::format
int format
Definition: codec_par.h:92
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
AVPacket
This structure stores compressed data.
Definition: packet.h:516
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
bytestream.h
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
AV_CODEC_ID_VORBIS
@ AV_CODEC_ID_VORBIS
Definition: codec_id.h:451
avstring.h
PayloadContext
RTP/JPEG specific private data.
Definition: rdt.c:85
AV_RB24
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_RB24
Definition: bytestream.h:97
xiph_parse_fmtp_pair
static int xiph_parse_fmtp_pair(AVFormatContext *s, AVStream *stream, PayloadContext *xiph_data, const char *attr, const char *value)
Definition: rtpdec_xiph.c:286
RTPDynamicProtocolHandler
Definition: rtpdec.h:116
AV_RB16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:98
ff_alloc_extradata
int ff_alloc_extradata(AVCodecParameters *par, int size)
Allocate extradata with additional AV_INPUT_BUFFER_PADDING_SIZE at end which is always set to 0.
Definition: utils.c:227