1 /* GStreamer
2 * Copyright (C) <2005> Philippe Khalaf <burger@speedy.org>
3 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 /**
22 * SECTION:gstrtpbuffer
23 * @title: GstRTPBuffer
24 * @short_description: Helper methods for dealing with RTP buffers
25 * @see_also: #GstRTPBasePayload, #GstRTPBaseDepayload, gstrtcpbuffer
26 *
27 * The GstRTPBuffer helper functions makes it easy to parse and create regular
28 * #GstBuffer objects that contain RTP payloads. These buffers are typically of
29 * 'application/x-rtp' #GstCaps.
30 *
31 */
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include "gstrtpbuffer.h"
37
38 #include <stdlib.h>
39 #include <string.h>
40
41 #define GST_RTP_HEADER_LEN 12
42
43 /* Note: we use bitfields here to make sure the compiler doesn't add padding
44 * between fields on certain architectures; can't assume aligned access either
45 */
46 typedef struct _GstRTPHeader
47 {
48 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
49 unsigned int csrc_count:4; /* CSRC count */
50 unsigned int extension:1; /* header extension flag */
51 unsigned int padding:1; /* padding flag */
52 unsigned int version:2; /* protocol version */
53 unsigned int payload_type:7; /* payload type */
54 unsigned int marker:1; /* marker bit */
55 #elif G_BYTE_ORDER == G_BIG_ENDIAN
56 unsigned int version:2; /* protocol version */
57 unsigned int padding:1; /* padding flag */
58 unsigned int extension:1; /* header extension flag */
59 unsigned int csrc_count:4; /* CSRC count */
60 unsigned int marker:1; /* marker bit */
61 unsigned int payload_type:7; /* payload type */
62 #else
63 #error "G_BYTE_ORDER should be big or little endian."
64 #endif
65 unsigned int seq:16; /* sequence number */
66 unsigned int timestamp:32; /* timestamp */
67 unsigned int ssrc:32; /* synchronization source */
68 guint8 csrclist[4]; /* optional CSRC list, 32 bits each */
69 } GstRTPHeader;
70
71 #define GST_RTP_HEADER_VERSION(data) (((GstRTPHeader *)(data))->version)
72 #define GST_RTP_HEADER_PADDING(data) (((GstRTPHeader *)(data))->padding)
73 #define GST_RTP_HEADER_EXTENSION(data) (((GstRTPHeader *)(data))->extension)
74 #define GST_RTP_HEADER_CSRC_COUNT(data) (((GstRTPHeader *)(data))->csrc_count)
75 #define GST_RTP_HEADER_MARKER(data) (((GstRTPHeader *)(data))->marker)
76 #define GST_RTP_HEADER_PAYLOAD_TYPE(data) (((GstRTPHeader *)(data))->payload_type)
77 #define GST_RTP_HEADER_SEQ(data) (((GstRTPHeader *)(data))->seq)
78 #define GST_RTP_HEADER_TIMESTAMP(data) (((GstRTPHeader *)(data))->timestamp)
79 #define GST_RTP_HEADER_SSRC(data) (((GstRTPHeader *)(data))->ssrc)
80 #define GST_RTP_HEADER_CSRC_LIST_OFFSET(data,i) \
81 data + G_STRUCT_OFFSET(GstRTPHeader, csrclist) + \
82 ((i) * sizeof(guint32))
83 #define GST_RTP_HEADER_CSRC_SIZE(data) (GST_RTP_HEADER_CSRC_COUNT(data) * sizeof (guint32))
84
85 /**
86 * gst_rtp_buffer_allocate_data:
87 * @buffer: a #GstBuffer
88 * @payload_len: the length of the payload
89 * @pad_len: the amount of padding
90 * @csrc_count: the number of CSRC entries
91 *
92 * Allocate enough data in @buffer to hold an RTP packet with @csrc_count CSRCs,
93 * a payload length of @payload_len and padding of @pad_len.
94 * @buffer must be writable and all previous memory in @buffer will be freed.
95 * If @pad_len is >0, the padding bit will be set. All other RTP header fields
96 * will be set to 0/FALSE.
97 */
98 void
gst_rtp_buffer_allocate_data(GstBuffer * buffer,guint payload_len,guint8 pad_len,guint8 csrc_count)99 gst_rtp_buffer_allocate_data (GstBuffer * buffer, guint payload_len,
100 guint8 pad_len, guint8 csrc_count)
101 {
102 GstMapInfo map;
103 GstMemory *mem;
104 gsize hlen;
105
106 g_return_if_fail (csrc_count <= 15);
107 g_return_if_fail (GST_IS_BUFFER (buffer));
108 g_return_if_fail (gst_buffer_is_writable (buffer));
109
110 gst_buffer_remove_all_memory (buffer);
111
112 hlen = GST_RTP_HEADER_LEN + csrc_count * sizeof (guint32);
113
114 mem = gst_allocator_alloc (NULL, hlen, NULL);
115
116 gst_memory_map (mem, &map, GST_MAP_WRITE);
117 /* fill in defaults */
118 GST_RTP_HEADER_VERSION (map.data) = GST_RTP_VERSION;
119 if (pad_len)
120 GST_RTP_HEADER_PADDING (map.data) = TRUE;
121 else
122 GST_RTP_HEADER_PADDING (map.data) = FALSE;
123 GST_RTP_HEADER_EXTENSION (map.data) = FALSE;
124 GST_RTP_HEADER_CSRC_COUNT (map.data) = csrc_count;
125 memset (GST_RTP_HEADER_CSRC_LIST_OFFSET (map.data, 0), 0,
126 csrc_count * sizeof (guint32));
127 GST_RTP_HEADER_MARKER (map.data) = FALSE;
128 GST_RTP_HEADER_PAYLOAD_TYPE (map.data) = 0;
129 GST_RTP_HEADER_SEQ (map.data) = 0;
130 GST_RTP_HEADER_TIMESTAMP (map.data) = 0;
131 GST_RTP_HEADER_SSRC (map.data) = 0;
132 gst_memory_unmap (mem, &map);
133
134 gst_buffer_append_memory (buffer, mem);
135
136 if (payload_len) {
137 mem = gst_allocator_alloc (NULL, payload_len, NULL);
138 gst_buffer_append_memory (buffer, mem);
139 }
140 if (pad_len) {
141 mem = gst_allocator_alloc (NULL, pad_len, NULL);
142
143 gst_memory_map (mem, &map, GST_MAP_WRITE);
144 map.data[pad_len - 1] = pad_len;
145 gst_memory_unmap (mem, &map);
146
147 gst_buffer_append_memory (buffer, mem);
148 }
149 }
150
151 /**
152 * gst_rtp_buffer_new_take_data:
153 * @data: (array length=len) (transfer full) (element-type guint8):
154 * data for the new buffer
155 * @len: the length of data
156 *
157 * Create a new buffer and set the data and size of the buffer to @data and @len
158 * respectively. @data will be freed when the buffer is unreffed, so this
159 * function transfers ownership of @data to the new buffer.
160 *
161 * Returns: A newly allocated buffer with @data and of size @len.
162 */
163 GstBuffer *
gst_rtp_buffer_new_take_data(gpointer data,gsize len)164 gst_rtp_buffer_new_take_data (gpointer data, gsize len)
165 {
166 g_return_val_if_fail (data != NULL, NULL);
167 g_return_val_if_fail (len > 0, NULL);
168
169 return gst_buffer_new_wrapped (data, len);
170 }
171
172 /**
173 * gst_rtp_buffer_new_copy_data:
174 * @data: (array length=len) (element-type guint8): data for the new
175 * buffer
176 * @len: the length of data
177 *
178 * Create a new buffer and set the data to a copy of @len
179 * bytes of @data and the size to @len. The data will be freed when the buffer
180 * is freed.
181 *
182 * Returns: A newly allocated buffer with a copy of @data and of size @len.
183 */
184 GstBuffer *
gst_rtp_buffer_new_copy_data(gconstpointer data,gsize len)185 gst_rtp_buffer_new_copy_data (gconstpointer data, gsize len)
186 {
187 return gst_rtp_buffer_new_take_data (g_memdup (data, len), len);
188 }
189
190 /**
191 * gst_rtp_buffer_new_allocate:
192 * @payload_len: the length of the payload
193 * @pad_len: the amount of padding
194 * @csrc_count: the number of CSRC entries
195 *
196 * Allocate a new #GstBuffer with enough data to hold an RTP packet with
197 * @csrc_count CSRCs, a payload length of @payload_len and padding of @pad_len.
198 * All other RTP header fields will be set to 0/FALSE.
199 *
200 * Returns: A newly allocated buffer that can hold an RTP packet with given
201 * parameters.
202 */
203 GstBuffer *
gst_rtp_buffer_new_allocate(guint payload_len,guint8 pad_len,guint8 csrc_count)204 gst_rtp_buffer_new_allocate (guint payload_len, guint8 pad_len,
205 guint8 csrc_count)
206 {
207 GstBuffer *result;
208
209 g_return_val_if_fail (csrc_count <= 15, NULL);
210
211 result = gst_buffer_new ();
212 gst_rtp_buffer_allocate_data (result, payload_len, pad_len, csrc_count);
213
214 return result;
215 }
216
217 /**
218 * gst_rtp_buffer_new_allocate_len:
219 * @packet_len: the total length of the packet
220 * @pad_len: the amount of padding
221 * @csrc_count: the number of CSRC entries
222 *
223 * Create a new #GstBuffer that can hold an RTP packet that is exactly
224 * @packet_len long. The length of the payload depends on @pad_len and
225 * @csrc_count and can be calculated with gst_rtp_buffer_calc_payload_len().
226 * All RTP header fields will be set to 0/FALSE.
227 *
228 * Returns: A newly allocated buffer that can hold an RTP packet of @packet_len.
229 */
230 GstBuffer *
gst_rtp_buffer_new_allocate_len(guint packet_len,guint8 pad_len,guint8 csrc_count)231 gst_rtp_buffer_new_allocate_len (guint packet_len, guint8 pad_len,
232 guint8 csrc_count)
233 {
234 guint len;
235
236 g_return_val_if_fail (csrc_count <= 15, NULL);
237
238 len = gst_rtp_buffer_calc_payload_len (packet_len, pad_len, csrc_count);
239
240 return gst_rtp_buffer_new_allocate (len, pad_len, csrc_count);
241 }
242
243 /**
244 * gst_rtp_buffer_calc_header_len:
245 * @csrc_count: the number of CSRC entries
246 *
247 * Calculate the header length of an RTP packet with @csrc_count CSRC entries.
248 * An RTP packet can have at most 15 CSRC entries.
249 *
250 * Returns: The length of an RTP header with @csrc_count CSRC entries.
251 */
252 guint
gst_rtp_buffer_calc_header_len(guint8 csrc_count)253 gst_rtp_buffer_calc_header_len (guint8 csrc_count)
254 {
255 g_return_val_if_fail (csrc_count <= 15, 0);
256
257 return GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32));
258 }
259
260 /**
261 * gst_rtp_buffer_calc_packet_len:
262 * @payload_len: the length of the payload
263 * @pad_len: the amount of padding
264 * @csrc_count: the number of CSRC entries
265 *
266 * Calculate the total length of an RTP packet with a payload size of @payload_len,
267 * a padding of @pad_len and a @csrc_count CSRC entries.
268 *
269 * Returns: The total length of an RTP header with given parameters.
270 */
271 guint
gst_rtp_buffer_calc_packet_len(guint payload_len,guint8 pad_len,guint8 csrc_count)272 gst_rtp_buffer_calc_packet_len (guint payload_len, guint8 pad_len,
273 guint8 csrc_count)
274 {
275 g_return_val_if_fail (csrc_count <= 15, 0);
276
277 return payload_len + GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32))
278 + pad_len;
279 }
280
281 /**
282 * gst_rtp_buffer_calc_payload_len:
283 * @packet_len: the length of the total RTP packet
284 * @pad_len: the amount of padding
285 * @csrc_count: the number of CSRC entries
286 *
287 * Calculate the length of the payload of an RTP packet with size @packet_len,
288 * a padding of @pad_len and a @csrc_count CSRC entries.
289 *
290 * Returns: The length of the payload of an RTP packet with given parameters.
291 */
292 guint
gst_rtp_buffer_calc_payload_len(guint packet_len,guint8 pad_len,guint8 csrc_count)293 gst_rtp_buffer_calc_payload_len (guint packet_len, guint8 pad_len,
294 guint8 csrc_count)
295 {
296 g_return_val_if_fail (csrc_count <= 15, 0);
297
298 if (packet_len <
299 GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32)) + pad_len)
300 return 0;
301
302 return packet_len - GST_RTP_HEADER_LEN - (csrc_count * sizeof (guint32))
303 - pad_len;
304 }
305
306 /**
307 * gst_rtp_buffer_map:
308 * @buffer: a #GstBuffer
309 * @flags: #GstMapFlags
310 * @rtp: (out): a #GstRTPBuffer
311 *
312 * Map the contents of @buffer into @rtp.
313 *
314 * Returns: %TRUE if @buffer could be mapped.
315 */
316 gboolean
gst_rtp_buffer_map(GstBuffer * buffer,GstMapFlags flags,GstRTPBuffer * rtp)317 gst_rtp_buffer_map (GstBuffer * buffer, GstMapFlags flags, GstRTPBuffer * rtp)
318 {
319 guint8 padding;
320 guint8 csrc_count;
321 guint header_len;
322 guint8 version, pt;
323 guint8 *data;
324 guint size;
325 gsize bufsize, skip;
326 guint idx, length;
327 guint n_mem;
328
329 g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
330 g_return_val_if_fail (rtp != NULL, FALSE);
331 g_return_val_if_fail (rtp->buffer == NULL, FALSE);
332
333 n_mem = gst_buffer_n_memory (buffer);
334 if (n_mem < 1)
335 goto no_memory;
336
337 /* map first memory, this should be the header */
338 if (!gst_buffer_map_range (buffer, 0, 1, &rtp->map[0], flags))
339 goto map_failed;
340
341 data = rtp->data[0] = rtp->map[0].data;
342 size = rtp->map[0].size;
343
344 /* the header must be completely in the first buffer */
345 header_len = GST_RTP_HEADER_LEN;
346 if (G_UNLIKELY (size < header_len))
347 goto wrong_length;
348
349 /* check version */
350 version = (data[0] & 0xc0);
351 if (G_UNLIKELY (version != (GST_RTP_VERSION << 6)))
352 goto wrong_version;
353
354 /* check reserved PT and marker bit, this is to check for RTCP
355 * packets. We do a relaxed check, you can still use 72-76 as long
356 * as the marker bit is cleared. */
357 pt = data[1];
358 if (G_UNLIKELY (pt >= 200 && pt <= 204))
359 goto reserved_pt;
360
361 /* calc header length with csrc */
362 csrc_count = (data[0] & 0x0f);
363 header_len += csrc_count * sizeof (guint32);
364
365 rtp->size[0] = header_len;
366
367 bufsize = gst_buffer_get_size (buffer);
368
369 /* calc extension length when present. */
370 if (data[0] & 0x10) {
371 guint8 *extdata;
372 guint16 extlen;
373
374 /* find memory for the extension bits, we find the block for the first 4
375 * bytes, all other extension bytes should also be in this block */
376 if (!gst_buffer_find_memory (buffer, header_len, 4, &idx, &length, &skip))
377 goto wrong_length;
378
379 if (!gst_buffer_map_range (buffer, idx, length, &rtp->map[1], flags))
380 goto map_failed;
381
382 extdata = rtp->data[1] = rtp->map[1].data + skip;
383 /* skip id */
384 extdata += 2;
385 /* read length as the number of 32 bits words */
386 extlen = GST_READ_UINT16_BE (extdata);
387 extlen *= sizeof (guint32);
388 /* add id and length */
389 extlen += 4;
390
391 /* all extension bytes must be in this block */
392 if (G_UNLIKELY (rtp->map[1].size < extlen))
393 goto wrong_length;
394
395 rtp->size[1] = extlen;
396
397 header_len += rtp->size[1];
398 } else {
399 rtp->data[1] = NULL;
400 rtp->size[1] = 0;
401 }
402
403 /* check for padding unless flags says to skip */
404 if ((data[0] & 0x20) != 0 &&
405 (flags & GST_RTP_BUFFER_MAP_FLAG_SKIP_PADDING) == 0) {
406 /* find memory for the padding bits */
407 if (!gst_buffer_find_memory (buffer, bufsize - 1, 1, &idx, &length, &skip))
408 goto wrong_length;
409
410 if (!gst_buffer_map_range (buffer, idx, length, &rtp->map[3], flags))
411 goto map_failed;
412
413 padding = rtp->map[3].data[skip];
414 rtp->data[3] = rtp->map[3].data + skip + 1 - padding;
415 rtp->size[3] = padding;
416
417 if (skip + 1 < padding)
418 goto wrong_length;
419 } else {
420 rtp->data[3] = NULL;
421 rtp->size[3] = 0;
422 padding = 0;
423 }
424
425 /* check if padding and header not bigger than packet length */
426 if (G_UNLIKELY (bufsize < padding + header_len))
427 goto wrong_padding;
428
429 rtp->buffer = buffer;
430
431 if (n_mem == 1) {
432 /* we have mapped the buffer already, so might just as well fill in the
433 * payload pointer and size and avoid another buffer map/unmap later */
434 rtp->data[2] = rtp->map[0].data + header_len;
435 rtp->size[2] = bufsize - header_len - padding;
436 } else {
437 /* we have not yet mapped the payload */
438 rtp->data[2] = NULL;
439 rtp->size[2] = 0;
440 }
441
442 /* rtp->state = 0; *//* unused */
443
444 return TRUE;
445
446 /* ERRORS */
447 no_memory:
448 {
449 GST_ERROR ("buffer without memory");
450 return FALSE;
451 }
452 map_failed:
453 {
454 GST_ERROR ("failed to map memory");
455 return FALSE;
456 }
457 wrong_length:
458 {
459 GST_DEBUG ("length check failed");
460 goto dump_packet;
461 }
462 wrong_version:
463 {
464 GST_DEBUG ("version check failed (%d != %d)", version, GST_RTP_VERSION);
465 goto dump_packet;
466 }
467 reserved_pt:
468 {
469 GST_DEBUG ("reserved PT %d found", pt);
470 goto dump_packet;
471 }
472 wrong_padding:
473 {
474 GST_DEBUG ("padding check failed (%" G_GSIZE_FORMAT " - %d < %d)", bufsize,
475 header_len, padding);
476 goto dump_packet;
477 }
478 dump_packet:
479 {
480 gint i;
481
482 GST_MEMDUMP ("buffer", data, size);
483
484 for (i = 0; i < G_N_ELEMENTS (rtp->map); ++i) {
485 if (rtp->map[i].memory != NULL)
486 gst_buffer_unmap (buffer, &rtp->map[i]);
487 }
488 return FALSE;
489 }
490 }
491
492 /**
493 * gst_rtp_buffer_unmap:
494 * @rtp: a #GstRTPBuffer
495 *
496 * Unmap @rtp previously mapped with gst_rtp_buffer_map().
497 */
498 void
gst_rtp_buffer_unmap(GstRTPBuffer * rtp)499 gst_rtp_buffer_unmap (GstRTPBuffer * rtp)
500 {
501 gint i;
502
503 g_return_if_fail (rtp != NULL);
504 g_return_if_fail (rtp->buffer != NULL);
505
506 for (i = 0; i < 4; i++) {
507 if (rtp->map[i].memory != NULL) {
508 gst_buffer_unmap (rtp->buffer, &rtp->map[i]);
509 rtp->map[i].memory = NULL;
510 }
511 rtp->data[i] = NULL;
512 rtp->size[i] = 0;
513 }
514 rtp->buffer = NULL;
515 }
516
517
518 /**
519 * gst_rtp_buffer_set_packet_len:
520 * @rtp: the RTP packet
521 * @len: the new packet length
522 *
523 * Set the total @rtp size to @len. The data in the buffer will be made
524 * larger if needed. Any padding will be removed from the packet.
525 */
526 void
gst_rtp_buffer_set_packet_len(GstRTPBuffer * rtp,guint len)527 gst_rtp_buffer_set_packet_len (GstRTPBuffer * rtp, guint len)
528 {
529 guint8 *data;
530
531 data = rtp->data[0];
532
533 /* FIXME */
534
535 if (rtp->map[0].maxsize <= len) {
536 /* FIXME, realloc bigger space */
537 g_warning ("not implemented");
538 }
539
540 gst_buffer_set_size (rtp->buffer, len);
541 rtp->map[0].size = len;
542
543 /* remove any padding */
544 GST_RTP_HEADER_PADDING (data) = FALSE;
545 }
546
547 /**
548 * gst_rtp_buffer_get_packet_len:
549 * @rtp: the RTP packet
550 *
551 * Return the total length of the packet in @buffer.
552 *
553 * Returns: The total length of the packet in @buffer.
554 */
555 guint
gst_rtp_buffer_get_packet_len(GstRTPBuffer * rtp)556 gst_rtp_buffer_get_packet_len (GstRTPBuffer * rtp)
557 {
558 return gst_buffer_get_size (rtp->buffer);
559 }
560
561 /**
562 * gst_rtp_buffer_get_header_len:
563 * @rtp: the RTP packet
564 *
565 * Return the total length of the header in @buffer. This include the length of
566 * the fixed header, the CSRC list and the extension header.
567 *
568 * Returns: The total length of the header in @buffer.
569 */
570 guint
gst_rtp_buffer_get_header_len(GstRTPBuffer * rtp)571 gst_rtp_buffer_get_header_len (GstRTPBuffer * rtp)
572 {
573 return rtp->size[0] + rtp->size[1];
574 }
575
576 /**
577 * gst_rtp_buffer_get_version:
578 * @rtp: the RTP packet
579 *
580 * Get the version number of the RTP packet in @buffer.
581 *
582 * Returns: The version of @buffer.
583 */
584 guint8
gst_rtp_buffer_get_version(GstRTPBuffer * rtp)585 gst_rtp_buffer_get_version (GstRTPBuffer * rtp)
586 {
587 return GST_RTP_HEADER_VERSION (rtp->data[0]);
588 }
589
590 /**
591 * gst_rtp_buffer_set_version:
592 * @rtp: the RTP packet
593 * @version: the new version
594 *
595 * Set the version of the RTP packet in @buffer to @version.
596 */
597 void
gst_rtp_buffer_set_version(GstRTPBuffer * rtp,guint8 version)598 gst_rtp_buffer_set_version (GstRTPBuffer * rtp, guint8 version)
599 {
600 g_return_if_fail (version < 0x04);
601
602 GST_RTP_HEADER_VERSION (rtp->data[0]) = version;
603 }
604
605 /**
606 * gst_rtp_buffer_get_padding:
607 * @rtp: the RTP packet
608 *
609 * Check if the padding bit is set on the RTP packet in @buffer.
610 *
611 * Returns: TRUE if @buffer has the padding bit set.
612 */
613 gboolean
gst_rtp_buffer_get_padding(GstRTPBuffer * rtp)614 gst_rtp_buffer_get_padding (GstRTPBuffer * rtp)
615 {
616 return GST_RTP_HEADER_PADDING (rtp->data[0]);
617 }
618
619 /**
620 * gst_rtp_buffer_set_padding:
621 * @rtp: the buffer
622 * @padding: the new padding
623 *
624 * Set the padding bit on the RTP packet in @buffer to @padding.
625 */
626 void
gst_rtp_buffer_set_padding(GstRTPBuffer * rtp,gboolean padding)627 gst_rtp_buffer_set_padding (GstRTPBuffer * rtp, gboolean padding)
628 {
629 GST_RTP_HEADER_PADDING (rtp->data[0]) = padding;
630 }
631
632 /**
633 * gst_rtp_buffer_pad_to:
634 * @rtp: the RTP packet
635 * @len: the new amount of padding
636 *
637 * Set the amount of padding in the RTP packet in @buffer to
638 * @len. If @len is 0, the padding is removed.
639 *
640 * NOTE: This function does not work correctly.
641 */
642 void
gst_rtp_buffer_pad_to(GstRTPBuffer * rtp,guint len)643 gst_rtp_buffer_pad_to (GstRTPBuffer * rtp, guint len)
644 {
645 guint8 *data;
646
647 data = rtp->data[0];
648
649 if (len > 0)
650 GST_RTP_HEADER_PADDING (data) = TRUE;
651 else
652 GST_RTP_HEADER_PADDING (data) = FALSE;
653
654 /* FIXME, set the padding byte at the end of the payload data */
655 }
656
657 /**
658 * gst_rtp_buffer_get_extension:
659 * @rtp: the RTP packet
660 *
661 * Check if the extension bit is set on the RTP packet in @buffer.
662 *
663 * Returns: TRUE if @buffer has the extension bit set.
664 */
665 gboolean
gst_rtp_buffer_get_extension(GstRTPBuffer * rtp)666 gst_rtp_buffer_get_extension (GstRTPBuffer * rtp)
667 {
668 return GST_RTP_HEADER_EXTENSION (rtp->data[0]);
669 }
670
671 /**
672 * gst_rtp_buffer_set_extension:
673 * @rtp: the RTP packet
674 * @extension: the new extension
675 *
676 * Set the extension bit on the RTP packet in @buffer to @extension.
677 */
678 void
gst_rtp_buffer_set_extension(GstRTPBuffer * rtp,gboolean extension)679 gst_rtp_buffer_set_extension (GstRTPBuffer * rtp, gboolean extension)
680 {
681 GST_RTP_HEADER_EXTENSION (rtp->data[0]) = extension;
682 }
683
684 /**
685 * gst_rtp_buffer_get_extension_data: (skip)
686 * @rtp: the RTP packet
687 * @bits: (out): location for result bits
688 * @data: (out) (array) (element-type guint8) (transfer none): location for data
689 * @wordlen: (out): location for length of @data in 32 bits words
690 *
691 * Get the extension data. @bits will contain the extension 16 bits of custom
692 * data. @data will point to the data in the extension and @wordlen will contain
693 * the length of @data in 32 bits words.
694 *
695 * If @buffer did not contain an extension, this function will return %FALSE
696 * with @bits, @data and @wordlen unchanged.
697 *
698 * Returns: TRUE if @buffer had the extension bit set.
699 */
700 gboolean
gst_rtp_buffer_get_extension_data(GstRTPBuffer * rtp,guint16 * bits,gpointer * data,guint * wordlen)701 gst_rtp_buffer_get_extension_data (GstRTPBuffer * rtp, guint16 * bits,
702 gpointer * data, guint * wordlen)
703 {
704 guint8 *pdata;
705
706 /* move to the extension */
707 pdata = rtp->data[1];
708 if (!pdata)
709 return FALSE;
710
711 if (bits)
712 *bits = GST_READ_UINT16_BE (pdata);
713 if (wordlen)
714 *wordlen = GST_READ_UINT16_BE (pdata + 2);
715 pdata += 4;
716 if (data)
717 *data = (gpointer *) pdata;
718
719 return TRUE;
720 }
721
722 /**
723 * gst_rtp_buffer_get_extension_bytes: (rename-to gst_rtp_buffer_get_extension_data)
724 * @rtp: the RTP packet
725 * @bits: (out): location for header bits
726 *
727 * Similar to gst_rtp_buffer_get_extension_data, but more suitable for language
728 * bindings usage. @bits will contain the extension 16 bits of custom data and
729 * the extension data (not including the extension header) is placed in a new
730 * #GBytes structure.
731 *
732 * If @rtp did not contain an extension, this function will return %NULL, with
733 * @bits unchanged. If there is an extension header but no extension data then
734 * an empty #GBytes will be returned.
735 *
736 * Returns: (transfer full): A new #GBytes if an extension header was present
737 * and %NULL otherwise.
738 *
739 * Since: 1.2
740 */
741 GBytes *
gst_rtp_buffer_get_extension_bytes(GstRTPBuffer * rtp,guint16 * bits)742 gst_rtp_buffer_get_extension_bytes (GstRTPBuffer * rtp, guint16 * bits)
743 {
744 gpointer buf_data = NULL;
745 guint buf_len;
746
747 g_return_val_if_fail (rtp != NULL, FALSE);
748
749 if (!gst_rtp_buffer_get_extension_data (rtp, bits, &buf_data, &buf_len))
750 return NULL;
751
752 if (buf_len == 0) {
753 /* if no extension data is present return an empty GBytes */
754 buf_data = NULL;
755 }
756
757 /* multiply length with 4 to get length in bytes */
758 return g_bytes_new (buf_data, 4 * buf_len);
759 }
760
761 static gboolean
gst_rtp_buffer_map_payload(GstRTPBuffer * rtp)762 gst_rtp_buffer_map_payload (GstRTPBuffer * rtp)
763 {
764 guint hlen, plen;
765 guint idx, length;
766 gsize skip;
767
768 if (rtp->map[2].memory != NULL)
769 return TRUE;
770
771 hlen = gst_rtp_buffer_get_header_len (rtp);
772 plen = gst_buffer_get_size (rtp->buffer) - hlen - rtp->size[3];
773
774 if (!gst_buffer_find_memory (rtp->buffer, hlen, plen, &idx, &length, &skip))
775 return FALSE;
776
777 if (!gst_buffer_map_range (rtp->buffer, idx, length, &rtp->map[2],
778 rtp->map[0].flags))
779 return FALSE;
780
781 rtp->data[2] = rtp->map[2].data + skip;
782 rtp->size[2] = plen;
783
784 return TRUE;
785 }
786
787 /* ensure header, payload and padding are in separate buffers */
788 static void
ensure_buffers(GstRTPBuffer * rtp)789 ensure_buffers (GstRTPBuffer * rtp)
790 {
791 guint i, pos;
792 gboolean changed = FALSE;
793
794 /* make sure payload is mapped */
795 gst_rtp_buffer_map_payload (rtp);
796
797 for (i = 0, pos = 0; i < 4; i++) {
798 if (rtp->size[i]) {
799 gsize offset = (guint8 *) rtp->data[i] - rtp->map[i].data;
800
801 if (offset != 0 || rtp->map[i].size != rtp->size[i]) {
802 GstMemory *mem;
803
804 /* make copy */
805 mem = gst_memory_copy (rtp->map[i].memory, offset, rtp->size[i]);
806
807 /* insert new memory */
808 gst_buffer_insert_memory (rtp->buffer, pos, mem);
809
810 changed = TRUE;
811 }
812 pos++;
813 }
814 }
815
816 if (changed) {
817 GstBuffer *buf = rtp->buffer;
818
819 gst_rtp_buffer_unmap (rtp);
820 gst_buffer_remove_memory_range (buf, pos, -1);
821 gst_rtp_buffer_map (buf, GST_MAP_READWRITE, rtp);
822 }
823 }
824
825 /**
826 * gst_rtp_buffer_set_extension_data:
827 * @rtp: the RTP packet
828 * @bits: the bits specific for the extension
829 * @length: the length that counts the number of 32-bit words in
830 * the extension, excluding the extension header ( therefore zero is a valid length)
831 *
832 * Set the extension bit of the rtp buffer and fill in the @bits and @length of the
833 * extension header. If the existing extension data is not large enough, it will
834 * be made larger.
835 *
836 * Returns: True if done.
837 */
838 gboolean
gst_rtp_buffer_set_extension_data(GstRTPBuffer * rtp,guint16 bits,guint16 length)839 gst_rtp_buffer_set_extension_data (GstRTPBuffer * rtp, guint16 bits,
840 guint16 length)
841 {
842 guint32 min_size = 0;
843 guint8 *data;
844 GstMemory *mem = NULL;
845
846 ensure_buffers (rtp);
847
848 /* this is the size of the extension data we need */
849 min_size = 4 + length * sizeof (guint32);
850
851 /* we should allocate and map the extension data */
852 if (rtp->data[1] == NULL || min_size > rtp->size[1]) {
853 GstMapInfo map;
854
855 /* we don't have (enough) extension data, make some */
856 mem = gst_allocator_alloc (NULL, min_size, NULL);
857
858 if (rtp->data[1]) {
859 /* copy old data */
860 gst_memory_map (mem, &map, GST_MAP_WRITE);
861 memcpy (map.data, rtp->data[1], rtp->size[1]);
862 gst_memory_unmap (mem, &map);
863
864 /* unmap old */
865 gst_buffer_unmap (rtp->buffer, &rtp->map[1]);
866 gst_buffer_replace_memory (rtp->buffer, 1, mem);
867 } else {
868 /* we didn't have extension data, add */
869 gst_buffer_insert_memory (rtp->buffer, 1, mem);
870 }
871
872 /* map new */
873 gst_memory_map (mem, &rtp->map[1], GST_MAP_READWRITE);
874 gst_memory_ref (mem);
875 rtp->data[1] = rtp->map[1].data;
876 rtp->size[1] = rtp->map[1].size;
877 }
878
879 /* now we can set the extension bit */
880 data = rtp->data[0];
881 GST_RTP_HEADER_EXTENSION (data) = TRUE;
882
883 data = rtp->data[1];
884 GST_WRITE_UINT16_BE (data, bits);
885 GST_WRITE_UINT16_BE (data + 2, length);
886
887 return TRUE;
888 }
889
890 /**
891 * gst_rtp_buffer_get_ssrc:
892 * @rtp: the RTP packet
893 *
894 * Get the SSRC of the RTP packet in @buffer.
895 *
896 * Returns: the SSRC of @buffer in host order.
897 */
898 guint32
gst_rtp_buffer_get_ssrc(GstRTPBuffer * rtp)899 gst_rtp_buffer_get_ssrc (GstRTPBuffer * rtp)
900 {
901 return g_ntohl (GST_RTP_HEADER_SSRC (rtp->data[0]));
902 }
903
904 /**
905 * gst_rtp_buffer_set_ssrc:
906 * @rtp: the RTP packet
907 * @ssrc: the new SSRC
908 *
909 * Set the SSRC on the RTP packet in @buffer to @ssrc.
910 */
911 void
gst_rtp_buffer_set_ssrc(GstRTPBuffer * rtp,guint32 ssrc)912 gst_rtp_buffer_set_ssrc (GstRTPBuffer * rtp, guint32 ssrc)
913 {
914 GST_RTP_HEADER_SSRC (rtp->data[0]) = g_htonl (ssrc);
915 }
916
917 /**
918 * gst_rtp_buffer_get_csrc_count:
919 * @rtp: the RTP packet
920 *
921 * Get the CSRC count of the RTP packet in @buffer.
922 *
923 * Returns: the CSRC count of @buffer.
924 */
925 guint8
gst_rtp_buffer_get_csrc_count(GstRTPBuffer * rtp)926 gst_rtp_buffer_get_csrc_count (GstRTPBuffer * rtp)
927 {
928 return GST_RTP_HEADER_CSRC_COUNT (rtp->data[0]);
929 }
930
931 /**
932 * gst_rtp_buffer_get_csrc:
933 * @rtp: the RTP packet
934 * @idx: the index of the CSRC to get
935 *
936 * Get the CSRC at index @idx in @buffer.
937 *
938 * Returns: the CSRC at index @idx in host order.
939 */
940 guint32
gst_rtp_buffer_get_csrc(GstRTPBuffer * rtp,guint8 idx)941 gst_rtp_buffer_get_csrc (GstRTPBuffer * rtp, guint8 idx)
942 {
943 guint8 *data;
944
945 data = rtp->data[0];
946
947 g_return_val_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data), 0);
948
949 return GST_READ_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx));
950 }
951
952 /**
953 * gst_rtp_buffer_set_csrc:
954 * @rtp: the RTP packet
955 * @idx: the CSRC index to set
956 * @csrc: the CSRC in host order to set at @idx
957 *
958 * Modify the CSRC at index @idx in @buffer to @csrc.
959 */
960 void
gst_rtp_buffer_set_csrc(GstRTPBuffer * rtp,guint8 idx,guint32 csrc)961 gst_rtp_buffer_set_csrc (GstRTPBuffer * rtp, guint8 idx, guint32 csrc)
962 {
963 guint8 *data;
964
965 data = rtp->data[0];
966
967 g_return_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data));
968
969 GST_WRITE_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx), csrc);
970 }
971
972 /**
973 * gst_rtp_buffer_get_marker:
974 * @rtp: the RTP packet
975 *
976 * Check if the marker bit is set on the RTP packet in @buffer.
977 *
978 * Returns: TRUE if @buffer has the marker bit set.
979 */
980 gboolean
gst_rtp_buffer_get_marker(GstRTPBuffer * rtp)981 gst_rtp_buffer_get_marker (GstRTPBuffer * rtp)
982 {
983 return GST_RTP_HEADER_MARKER (rtp->data[0]);
984 }
985
986 /**
987 * gst_rtp_buffer_set_marker:
988 * @rtp: the RTP packet
989 * @marker: the new marker
990 *
991 * Set the marker bit on the RTP packet in @buffer to @marker.
992 */
993 void
gst_rtp_buffer_set_marker(GstRTPBuffer * rtp,gboolean marker)994 gst_rtp_buffer_set_marker (GstRTPBuffer * rtp, gboolean marker)
995 {
996 GST_RTP_HEADER_MARKER (rtp->data[0]) = marker;
997 }
998
999 /**
1000 * gst_rtp_buffer_get_payload_type:
1001 * @rtp: the RTP packet
1002 *
1003 * Get the payload type of the RTP packet in @buffer.
1004 *
1005 * Returns: The payload type.
1006 */
1007 guint8
gst_rtp_buffer_get_payload_type(GstRTPBuffer * rtp)1008 gst_rtp_buffer_get_payload_type (GstRTPBuffer * rtp)
1009 {
1010 return GST_RTP_HEADER_PAYLOAD_TYPE (rtp->data[0]);
1011 }
1012
1013 /**
1014 * gst_rtp_buffer_set_payload_type:
1015 * @rtp: the RTP packet
1016 * @payload_type: the new type
1017 *
1018 * Set the payload type of the RTP packet in @buffer to @payload_type.
1019 */
1020 void
gst_rtp_buffer_set_payload_type(GstRTPBuffer * rtp,guint8 payload_type)1021 gst_rtp_buffer_set_payload_type (GstRTPBuffer * rtp, guint8 payload_type)
1022 {
1023 g_return_if_fail (payload_type < 0x80);
1024
1025 GST_RTP_HEADER_PAYLOAD_TYPE (rtp->data[0]) = payload_type;
1026 }
1027
1028 /**
1029 * gst_rtp_buffer_get_seq:
1030 * @rtp: the RTP packet
1031 *
1032 * Get the sequence number of the RTP packet in @buffer.
1033 *
1034 * Returns: The sequence number in host order.
1035 */
1036 guint16
gst_rtp_buffer_get_seq(GstRTPBuffer * rtp)1037 gst_rtp_buffer_get_seq (GstRTPBuffer * rtp)
1038 {
1039 return g_ntohs (GST_RTP_HEADER_SEQ (rtp->data[0]));
1040 }
1041
1042 /**
1043 * gst_rtp_buffer_set_seq:
1044 * @rtp: the RTP packet
1045 * @seq: the new sequence number
1046 *
1047 * Set the sequence number of the RTP packet in @buffer to @seq.
1048 */
1049 void
gst_rtp_buffer_set_seq(GstRTPBuffer * rtp,guint16 seq)1050 gst_rtp_buffer_set_seq (GstRTPBuffer * rtp, guint16 seq)
1051 {
1052 GST_RTP_HEADER_SEQ (rtp->data[0]) = g_htons (seq);
1053 }
1054
1055 /**
1056 * gst_rtp_buffer_get_timestamp:
1057 * @rtp: the RTP packet
1058 *
1059 * Get the timestamp of the RTP packet in @buffer.
1060 *
1061 * Returns: The timestamp in host order.
1062 */
1063 guint32
gst_rtp_buffer_get_timestamp(GstRTPBuffer * rtp)1064 gst_rtp_buffer_get_timestamp (GstRTPBuffer * rtp)
1065 {
1066 return g_ntohl (GST_RTP_HEADER_TIMESTAMP (rtp->data[0]));
1067 }
1068
1069 /**
1070 * gst_rtp_buffer_set_timestamp:
1071 * @rtp: the RTP packet
1072 * @timestamp: the new timestamp
1073 *
1074 * Set the timestamp of the RTP packet in @buffer to @timestamp.
1075 */
1076 void
gst_rtp_buffer_set_timestamp(GstRTPBuffer * rtp,guint32 timestamp)1077 gst_rtp_buffer_set_timestamp (GstRTPBuffer * rtp, guint32 timestamp)
1078 {
1079 GST_RTP_HEADER_TIMESTAMP (rtp->data[0]) = g_htonl (timestamp);
1080 }
1081
1082
1083 /**
1084 * gst_rtp_buffer_get_payload_subbuffer:
1085 * @rtp: the RTP packet
1086 * @offset: the offset in the payload
1087 * @len: the length in the payload
1088 *
1089 * Create a subbuffer of the payload of the RTP packet in @buffer. @offset bytes
1090 * are skipped in the payload and the subbuffer will be of size @len.
1091 * If @len is -1 the total payload starting from @offset is subbuffered.
1092 *
1093 * Returns: A new buffer with the specified data of the payload.
1094 */
1095 GstBuffer *
gst_rtp_buffer_get_payload_subbuffer(GstRTPBuffer * rtp,guint offset,guint len)1096 gst_rtp_buffer_get_payload_subbuffer (GstRTPBuffer * rtp, guint offset,
1097 guint len)
1098 {
1099 guint poffset, plen;
1100
1101 plen = gst_rtp_buffer_get_payload_len (rtp);
1102 /* we can't go past the length */
1103 if (G_UNLIKELY (offset > plen))
1104 goto wrong_offset;
1105
1106 /* apply offset */
1107 poffset = gst_rtp_buffer_get_header_len (rtp) + offset;
1108 plen -= offset;
1109
1110 /* see if we need to shrink the buffer based on @len */
1111 if (len != -1 && len < plen)
1112 plen = len;
1113
1114 return gst_buffer_copy_region (rtp->buffer, GST_BUFFER_COPY_ALL, poffset,
1115 plen);
1116
1117 /* ERRORS */
1118 wrong_offset:
1119 {
1120 g_warning ("offset=%u should be less than plen=%u", offset, plen);
1121 return NULL;
1122 }
1123 }
1124
1125 /**
1126 * gst_rtp_buffer_get_payload_buffer:
1127 * @rtp: the RTP packet
1128 *
1129 * Create a buffer of the payload of the RTP packet in @buffer. This function
1130 * will internally create a subbuffer of @buffer so that a memcpy can be
1131 * avoided.
1132 *
1133 * Returns: A new buffer with the data of the payload.
1134 */
1135 GstBuffer *
gst_rtp_buffer_get_payload_buffer(GstRTPBuffer * rtp)1136 gst_rtp_buffer_get_payload_buffer (GstRTPBuffer * rtp)
1137 {
1138 return gst_rtp_buffer_get_payload_subbuffer (rtp, 0, -1);
1139 }
1140
1141 /**
1142 * gst_rtp_buffer_get_payload_len:
1143 * @rtp: the RTP packet
1144 *
1145 * Get the length of the payload of the RTP packet in @buffer.
1146 *
1147 * Returns: The length of the payload in @buffer.
1148 */
1149 guint
gst_rtp_buffer_get_payload_len(GstRTPBuffer * rtp)1150 gst_rtp_buffer_get_payload_len (GstRTPBuffer * rtp)
1151 {
1152 return gst_buffer_get_size (rtp->buffer) - gst_rtp_buffer_get_header_len (rtp)
1153 - rtp->size[3];
1154 }
1155
1156 /**
1157 * gst_rtp_buffer_get_payload: (skip)
1158 * @rtp: the RTP packet
1159 *
1160 * Get a pointer to the payload data in @buffer. This pointer is valid as long
1161 * as a reference to @buffer is held.
1162 *
1163 * Returns: (array) (element-type guint8) (transfer none): A pointer
1164 * to the payload data in @buffer.
1165 */
1166 gpointer
gst_rtp_buffer_get_payload(GstRTPBuffer * rtp)1167 gst_rtp_buffer_get_payload (GstRTPBuffer * rtp)
1168 {
1169 if (rtp->data[2])
1170 return rtp->data[2];
1171
1172 if (!gst_rtp_buffer_map_payload (rtp))
1173 return NULL;
1174
1175 return rtp->data[2];
1176 }
1177
1178 /**
1179 * gst_rtp_buffer_get_payload_bytes: (rename-to gst_rtp_buffer_get_payload)
1180 * @rtp: the RTP packet
1181 *
1182 * Similar to gst_rtp_buffer_get_payload, but more suitable for language
1183 * bindings usage. The return value is a pointer to a #GBytes structure
1184 * containing the payload data in @rtp.
1185 *
1186 * Returns: (transfer full): A new #GBytes containing the payload data in @rtp.
1187 *
1188 * Since: 1.2
1189 */
1190 GBytes *
gst_rtp_buffer_get_payload_bytes(GstRTPBuffer * rtp)1191 gst_rtp_buffer_get_payload_bytes (GstRTPBuffer * rtp)
1192 {
1193 gpointer data;
1194
1195 g_return_val_if_fail (rtp != NULL, NULL);
1196
1197 data = gst_rtp_buffer_get_payload (rtp);
1198 if (data == NULL)
1199 return NULL;
1200
1201 return g_bytes_new (data, gst_rtp_buffer_get_payload_len (rtp));
1202 }
1203
1204 /**
1205 * gst_rtp_buffer_default_clock_rate:
1206 * @payload_type: the static payload type
1207 *
1208 * Get the default clock-rate for the static payload type @payload_type.
1209 *
1210 * Returns: the default clock rate or -1 if the payload type is not static or
1211 * the clock-rate is undefined.
1212 */
1213 guint32
gst_rtp_buffer_default_clock_rate(guint8 payload_type)1214 gst_rtp_buffer_default_clock_rate (guint8 payload_type)
1215 {
1216 const GstRTPPayloadInfo *info;
1217 guint32 res;
1218
1219 info = gst_rtp_payload_info_for_pt (payload_type);
1220 if (!info)
1221 return -1;
1222
1223 res = info->clock_rate;
1224 /* 0 means unknown so we have to return -1 from this function */
1225 if (res == 0)
1226 res = -1;
1227
1228 return res;
1229 }
1230
1231 /**
1232 * gst_rtp_buffer_compare_seqnum:
1233 * @seqnum1: a sequence number
1234 * @seqnum2: a sequence number
1235 *
1236 * Compare two sequence numbers, taking care of wraparounds. This function
1237 * returns the difference between @seqnum1 and @seqnum2.
1238 *
1239 * Returns: a negative value if @seqnum1 is bigger than @seqnum2, 0 if they
1240 * are equal or a positive value if @seqnum1 is smaller than @segnum2.
1241 */
1242 gint
gst_rtp_buffer_compare_seqnum(guint16 seqnum1,guint16 seqnum2)1243 gst_rtp_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2)
1244 {
1245 /* See http://en.wikipedia.org/wiki/Serial_number_arithmetic
1246 * for an explanation why this does the right thing even for
1247 * wraparounds, under the assumption that the difference is
1248 * never bigger than 2**15 sequence numbers
1249 */
1250 return (gint16) (seqnum2 - seqnum1);
1251 }
1252
1253 /**
1254 * gst_rtp_buffer_ext_timestamp:
1255 * @exttimestamp: (inout): a previous extended timestamp
1256 * @timestamp: a new timestamp
1257 *
1258 * Update the @exttimestamp field with the extended timestamp of @timestamp
1259 * For the first call of the method, @exttimestamp should point to a location
1260 * with a value of -1.
1261 *
1262 * This function is able to handle both forward and backward timestamps taking
1263 * into account:
1264 * - timestamp wraparound making sure that the returned value is properly increased.
1265 * - timestamp unwraparound making sure that the returned value is properly decreased.
1266 *
1267 * Returns: The extended timestamp of @timestamp or 0 if the result can't go anywhere backwards.
1268 */
1269 guint64
gst_rtp_buffer_ext_timestamp(guint64 * exttimestamp,guint32 timestamp)1270 gst_rtp_buffer_ext_timestamp (guint64 * exttimestamp, guint32 timestamp)
1271 {
1272 guint64 result, ext;
1273
1274 g_return_val_if_fail (exttimestamp != NULL, -1);
1275
1276 ext = *exttimestamp;
1277
1278 if (ext == -1) {
1279 result = timestamp;
1280 } else {
1281 /* pick wraparound counter from previous timestamp and add to new timestamp */
1282 result = timestamp + (ext & ~(G_GUINT64_CONSTANT (0xffffffff)));
1283
1284 /* check for timestamp wraparound */
1285 if (result < ext) {
1286 guint64 diff = ext - result;
1287
1288 if (diff > G_MAXINT32) {
1289 /* timestamp went backwards more than allowed, we wrap around and get
1290 * updated extended timestamp. */
1291 result += (G_GUINT64_CONSTANT (1) << 32);
1292 }
1293 } else {
1294 guint64 diff = result - ext;
1295
1296 if (diff > G_MAXINT32) {
1297 if (result < (G_GUINT64_CONSTANT (1) << 32)) {
1298 GST_WARNING
1299 ("Cannot unwrap, any wrapping took place yet. Returning 0 without updating extended timestamp.");
1300 return 0;
1301 } else {
1302 /* timestamp went forwards more than allowed, we unwrap around and get
1303 * updated extended timestamp. */
1304 result -= (G_GUINT64_CONSTANT (1) << 32);
1305 /* We don't want the extended timestamp storage to go back, ever */
1306 return result;
1307 }
1308 }
1309 }
1310 }
1311
1312 *exttimestamp = result;
1313
1314 return result;
1315 }
1316
1317 /**
1318 * gst_rtp_buffer_get_extension_onebyte_header:
1319 * @rtp: the RTP packet
1320 * @id: The ID of the header extension to be read (between 1 and 14).
1321 * @nth: Read the nth extension packet with the requested ID
1322 * @data: (out) (array length=size) (element-type guint8) (transfer none):
1323 * location for data
1324 * @size: (out): the size of the data in bytes
1325 *
1326 * Parses RFC 5285 style header extensions with a one byte header. It will
1327 * return the nth extension with the requested id.
1328 *
1329 * Returns: TRUE if @buffer had the requested header extension
1330 */
1331
1332 gboolean
gst_rtp_buffer_get_extension_onebyte_header(GstRTPBuffer * rtp,guint8 id,guint nth,gpointer * data,guint * size)1333 gst_rtp_buffer_get_extension_onebyte_header (GstRTPBuffer * rtp, guint8 id,
1334 guint nth, gpointer * data, guint * size)
1335 {
1336 guint16 bits;
1337 guint8 *pdata;
1338 guint wordlen;
1339 gulong offset = 0;
1340 guint count = 0;
1341
1342 g_return_val_if_fail (id > 0 && id < 15, FALSE);
1343
1344 if (!gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer) & pdata,
1345 &wordlen))
1346 return FALSE;
1347
1348 if (bits != 0xBEDE)
1349 return FALSE;
1350
1351 for (;;) {
1352 guint8 read_id, read_len;
1353
1354 if (offset + 1 >= wordlen * 4)
1355 break;
1356
1357 read_id = GST_READ_UINT8 (pdata + offset) >> 4;
1358 read_len = (GST_READ_UINT8 (pdata + offset) & 0x0F) + 1;
1359 offset += 1;
1360
1361 /* ID 0 means its padding, skip */
1362 if (read_id == 0)
1363 continue;
1364
1365 /* ID 15 is special and means we should stop parsing */
1366 if (read_id == 15)
1367 break;
1368
1369 /* Ignore extension headers where the size does not fit */
1370 if (offset + read_len > wordlen * 4)
1371 break;
1372
1373 /* If we have the right one */
1374 if (id == read_id) {
1375 if (nth == count) {
1376 if (data)
1377 *data = pdata + offset;
1378 if (size)
1379 *size = read_len;
1380
1381 return TRUE;
1382 }
1383
1384 count++;
1385 }
1386 offset += read_len;
1387
1388 if (offset >= wordlen * 4)
1389 break;
1390 }
1391
1392 return FALSE;
1393 }
1394
1395 /**
1396 * gst_rtp_buffer_get_extension_twobytes_header:
1397 * @rtp: the RTP packet
1398 * @appbits: (out): Application specific bits
1399 * @id: The ID of the header extension to be read (between 1 and 14).
1400 * @nth: Read the nth extension packet with the requested ID
1401 * @data: (out) (array length=size) (element-type guint8) (transfer none):
1402 * location for data
1403 * @size: (out): the size of the data in bytes
1404 *
1405 * Parses RFC 5285 style header extensions with a two bytes header. It will
1406 * return the nth extension with the requested id.
1407 *
1408 * Returns: TRUE if @buffer had the requested header extension
1409 */
1410
1411 gboolean
gst_rtp_buffer_get_extension_twobytes_header(GstRTPBuffer * rtp,guint8 * appbits,guint8 id,guint nth,gpointer * data,guint * size)1412 gst_rtp_buffer_get_extension_twobytes_header (GstRTPBuffer * rtp,
1413 guint8 * appbits, guint8 id, guint nth, gpointer * data, guint * size)
1414 {
1415 guint16 bits;
1416 guint8 *pdata = NULL;
1417 guint wordlen;
1418 guint bytelen;
1419 gulong offset = 0;
1420 guint count = 0;
1421
1422 if (!gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer *) & pdata,
1423 &wordlen))
1424 return FALSE;
1425
1426 if (bits >> 4 != 0x100)
1427 return FALSE;
1428
1429 bytelen = wordlen * 4;
1430
1431 for (;;) {
1432 guint8 read_id, read_len;
1433
1434 if (offset + 2 >= bytelen)
1435 break;
1436
1437 read_id = GST_READ_UINT8 (pdata + offset);
1438 offset += 1;
1439
1440 if (read_id == 0)
1441 continue;
1442
1443 read_len = GST_READ_UINT8 (pdata + offset);
1444 offset += 1;
1445
1446 /* Ignore extension headers where the size does not fit */
1447 if (offset + read_len > bytelen)
1448 break;
1449
1450 /* If we have the right one, return it */
1451 if (id == read_id) {
1452 if (nth == count) {
1453 if (data)
1454 *data = pdata + offset;
1455 if (size)
1456 *size = read_len;
1457 if (appbits)
1458 *appbits = bits;
1459
1460 return TRUE;
1461 }
1462
1463 count++;
1464 }
1465 offset += read_len;
1466 }
1467
1468 return FALSE;
1469 }
1470
1471 static guint
get_onebyte_header_end_offset(guint8 * pdata,guint wordlen)1472 get_onebyte_header_end_offset (guint8 * pdata, guint wordlen)
1473 {
1474 guint offset = 0;
1475 guint bytelen = wordlen * 4;
1476 guint paddingcount = 0;
1477
1478 while (offset + 1 < bytelen) {
1479 guint8 read_id, read_len;
1480
1481 read_id = GST_READ_UINT8 (pdata + offset) >> 4;
1482 read_len = (GST_READ_UINT8 (pdata + offset) & 0x0F) + 1;
1483 offset += 1;
1484
1485 /* ID 0 means its padding, skip */
1486 if (read_id == 0) {
1487 paddingcount++;
1488 continue;
1489 }
1490
1491 paddingcount = 0;
1492
1493 /* ID 15 is special and means we should stop parsing */
1494 /* It also means we can't add an extra packet */
1495 if (read_id == 15)
1496 return 0;
1497
1498 /* Ignore extension headers where the size does not fit */
1499 if (offset + read_len > bytelen)
1500 return 0;
1501
1502 offset += read_len;
1503 }
1504
1505 return offset - paddingcount;
1506 }
1507
1508 /**
1509 * gst_rtp_buffer_add_extension_onebyte_header:
1510 * @rtp: the RTP packet
1511 * @id: The ID of the header extension (between 1 and 14).
1512 * @data: (array length=size) (element-type guint8): location for data
1513 * @size: the size of the data in bytes
1514 *
1515 * Adds a RFC 5285 header extension with a one byte header to the end of the
1516 * RTP header. If there is already a RFC 5285 header extension with a one byte
1517 * header, the new extension will be appended.
1518 * It will not work if there is already a header extension that does not follow
1519 * the mecanism described in RFC 5285 or if there is a header extension with
1520 * a two bytes header as described in RFC 5285. In that case, use
1521 * gst_rtp_buffer_add_extension_twobytes_header()
1522 *
1523 * Returns: %TRUE if header extension could be added
1524 */
1525
1526 gboolean
gst_rtp_buffer_add_extension_onebyte_header(GstRTPBuffer * rtp,guint8 id,gconstpointer data,guint size)1527 gst_rtp_buffer_add_extension_onebyte_header (GstRTPBuffer * rtp, guint8 id,
1528 gconstpointer data, guint size)
1529 {
1530 guint16 bits;
1531 guint8 *pdata = 0;
1532 guint wordlen;
1533 gboolean has_bit;
1534 guint extlen, offset = 0;
1535
1536 g_return_val_if_fail (id > 0 && id < 15, FALSE);
1537 g_return_val_if_fail (size >= 1 && size <= 16, FALSE);
1538 g_return_val_if_fail (gst_buffer_is_writable (rtp->buffer), FALSE);
1539
1540 has_bit = gst_rtp_buffer_get_extension_data (rtp, &bits,
1541 (gpointer) & pdata, &wordlen);
1542
1543 if (has_bit) {
1544 if (bits != 0xBEDE)
1545 return FALSE;
1546
1547 offset = get_onebyte_header_end_offset (pdata, wordlen);
1548 if (offset == 0)
1549 return FALSE;
1550 }
1551
1552 /* the required size of the new extension data */
1553 extlen = offset + size + 1;
1554 /* calculate amount of words */
1555 wordlen = extlen / 4 + ((extlen % 4) ? 1 : 0);
1556
1557 gst_rtp_buffer_set_extension_data (rtp, 0xBEDE, wordlen);
1558 gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer) & pdata, &wordlen);
1559
1560 pdata += offset;
1561
1562 pdata[0] = (id << 4) | (0x0F & (size - 1));
1563 memcpy (pdata + 1, data, size);
1564
1565 if (extlen % 4)
1566 memset (pdata + 1 + size, 0, 4 - (extlen % 4));
1567
1568 return TRUE;
1569 }
1570
1571
1572 static guint
get_twobytes_header_end_offset(const guint8 * pdata,guint wordlen)1573 get_twobytes_header_end_offset (const guint8 * pdata, guint wordlen)
1574 {
1575 guint offset = 0;
1576 guint bytelen = wordlen * 4;
1577 guint paddingcount = 0;
1578
1579 while (offset + 2 < bytelen) {
1580 guint8 read_id, read_len;
1581
1582 read_id = GST_READ_UINT8 (pdata + offset);
1583 offset += 1;
1584
1585 /* ID 0 means its padding, skip */
1586 if (read_id == 0) {
1587 paddingcount++;
1588 continue;
1589 }
1590
1591 paddingcount = 0;
1592
1593 read_len = GST_READ_UINT8 (pdata + offset);
1594 offset += 1;
1595
1596 /* Ignore extension headers where the size does not fit */
1597 if (offset + read_len > bytelen)
1598 return 0;
1599
1600 offset += read_len;
1601 }
1602
1603 return offset - paddingcount;
1604 }
1605
1606 /**
1607 * gst_rtp_buffer_add_extension_twobytes_header:
1608 * @rtp: the RTP packet
1609 * @appbits: Application specific bits
1610 * @id: The ID of the header extension
1611 * @data: (array length=size) (element-type guint8): location for data
1612 * @size: the size of the data in bytes
1613 *
1614 * Adds a RFC 5285 header extension with a two bytes header to the end of the
1615 * RTP header. If there is already a RFC 5285 header extension with a two bytes
1616 * header, the new extension will be appended.
1617 * It will not work if there is already a header extension that does not follow
1618 * the mecanism described in RFC 5285 or if there is a header extension with
1619 * a one byte header as described in RFC 5285. In that case, use
1620 * gst_rtp_buffer_add_extension_onebyte_header()
1621 *
1622 * Returns: %TRUE if header extension could be added
1623 */
1624
1625 gboolean
gst_rtp_buffer_add_extension_twobytes_header(GstRTPBuffer * rtp,guint8 appbits,guint8 id,gconstpointer data,guint size)1626 gst_rtp_buffer_add_extension_twobytes_header (GstRTPBuffer * rtp,
1627 guint8 appbits, guint8 id, gconstpointer data, guint size)
1628 {
1629 guint16 bits;
1630 guint8 *pdata = 0;
1631 guint wordlen;
1632 gboolean has_bit;
1633 gulong offset = 0;
1634 guint extlen;
1635
1636 g_return_val_if_fail ((appbits & 0xF0) == 0, FALSE);
1637 g_return_val_if_fail (size < 256, FALSE);
1638 g_return_val_if_fail (gst_buffer_is_writable (rtp->buffer), FALSE);
1639
1640 has_bit = gst_rtp_buffer_get_extension_data (rtp, &bits,
1641 (gpointer) & pdata, &wordlen);
1642
1643 if (has_bit) {
1644 if (bits != ((0x100 << 4) | (appbits & 0x0f)))
1645 return FALSE;
1646
1647 offset = get_twobytes_header_end_offset (pdata, wordlen);
1648 if (offset == 0)
1649 return FALSE;
1650 }
1651
1652 /* the required size of the new extension data */
1653 extlen = offset + size + 2;
1654 /* calculate amount of words */
1655 wordlen = extlen / 4 + ((extlen % 4) ? 1 : 0);
1656
1657 gst_rtp_buffer_set_extension_data (rtp, (0x100 << 4) | (appbits & 0x0F),
1658 wordlen);
1659 gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer) & pdata, &wordlen);
1660
1661 pdata += offset;
1662
1663 pdata[0] = id;
1664 pdata[1] = size;
1665 memcpy (pdata + 2, data, size);
1666 if (extlen % 4)
1667 memset (pdata + 2 + size, 0, 4 - (extlen % 4));
1668
1669 return TRUE;
1670 }
1671