2 * Copyright (C) <2012> Wim Taymans <wim.taymans@gmail.com>
3 * Copyright (C) <2020> Matthew Waters <matthew@centricular.com>
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.
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.
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., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:gstrtphdrext
23 * @title: GstRtphdrext
24 * @short_description: Helper methods for dealing with RTP header extensions
25 * @see_also: #GstRTPBasePayload, #GstRTPBaseDepayload, gstrtpbuffer
32 #include "gstrtphdrext.h"
38 gst_rtp_header_extension_set_caps_from_attributes_default (GstRTPHeaderExtension
39 * ext, GstCaps * caps);
41 GST_DEBUG_CATEGORY_STATIC (rtphderext_debug);
42 #define GST_CAT_DEFAULT (rtphderext_debug)
44 #define MAX_RTP_EXT_ID 256
49 gboolean wants_update_non_rtp_src_caps;
50 } GstRTPHeaderExtensionPrivate;
53 * gst_rtp_hdrext_set_ntp_64:
54 * @data: the data to write to
55 * @size: the size of @data
56 * @ntptime: the NTP time
58 * Writes the NTP time in @ntptime to the format required for the NTP-64 header
59 * extension. @data must hold at least #GST_RTP_HDREXT_NTP_64_SIZE bytes.
61 * Returns: %TRUE on success.
64 gst_rtp_hdrext_set_ntp_64 (gpointer data, guint size, guint64 ntptime)
66 g_return_val_if_fail (data != NULL, FALSE);
67 g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_64_SIZE, FALSE);
69 GST_WRITE_UINT64_BE (data, ntptime);
75 * gst_rtp_hdrext_get_ntp_64:
76 * @data: (array length=size) (element-type guint8): the data to read from
77 * @size: the size of @data
78 * @ntptime: (out): the result NTP time
80 * Reads the NTP time from the @size NTP-64 extension bytes in @data and store the
83 * Returns: %TRUE on success.
86 gst_rtp_hdrext_get_ntp_64 (gpointer data, guint size, guint64 * ntptime)
88 g_return_val_if_fail (data != NULL, FALSE);
89 g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_64_SIZE, FALSE);
92 *ntptime = GST_READ_UINT64_BE (data);
98 * gst_rtp_hdrext_set_ntp_56:
99 * @data: the data to write to
100 * @size: the size of @data
101 * @ntptime: the NTP time
103 * Writes the NTP time in @ntptime to the format required for the NTP-56 header
104 * extension. @data must hold at least #GST_RTP_HDREXT_NTP_56_SIZE bytes.
106 * Returns: %TRUE on success.
109 gst_rtp_hdrext_set_ntp_56 (gpointer data, guint size, guint64 ntptime)
114 g_return_val_if_fail (data != NULL, FALSE);
115 g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_56_SIZE, FALSE);
117 for (i = 0; i < 7; i++) {
118 d[6 - i] = ntptime & 0xff;
125 * gst_rtp_hdrext_get_ntp_56:
126 * @data: (array length=size) (element-type guint8): the data to read from
127 * @size: the size of @data
128 * @ntptime: (out): the result NTP time
130 * Reads the NTP time from the @size NTP-56 extension bytes in @data and store the
131 * result in @ntptime.
133 * Returns: %TRUE on success.
136 gst_rtp_hdrext_get_ntp_56 (gpointer data, guint size, guint64 * ntptime)
140 g_return_val_if_fail (data != NULL, FALSE);
141 g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_56_SIZE, FALSE);
147 for (i = 0; i < 7; i++) {
155 #define gst_rtp_header_extension_parent_class parent_class
156 G_DEFINE_TYPE_EXTENDED (GstRTPHeaderExtension, gst_rtp_header_extension,
157 GST_TYPE_ELEMENT, G_TYPE_FLAG_ABSTRACT,
158 G_ADD_PRIVATE (GstRTPHeaderExtension)
159 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "rtphdrext", 0,
160 "RTP Header Extensions")
164 * gst_rtp_header_extension_class_set_uri:
165 * @klass: the #GstRTPHeaderExtensionClass
166 * @uri: the RTP Header extension uri for @klass
168 * Set the URI for this RTP header extension implementation.
173 gst_rtp_header_extension_class_set_uri (GstRTPHeaderExtensionClass * klass,
176 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
178 gst_element_class_add_static_metadata (element_class,
179 GST_RTP_HEADER_EXTENSION_URI_METADATA_KEY, uri);
183 gst_rtp_header_extension_class_init (GstRTPHeaderExtensionClass * klass)
185 klass->set_caps_from_attributes =
186 gst_rtp_header_extension_set_caps_from_attributes_default;
190 gst_rtp_header_extension_init (GstRTPHeaderExtension * ext)
192 GstRTPHeaderExtensionPrivate *priv =
193 gst_rtp_header_extension_get_instance_private (ext);
195 priv->ext_id = G_MAXUINT32;
199 * gst_rtp_header_extension_get_uri:
200 * @ext: a #GstRTPHeaderExtension
202 * Returns: the RTP extension URI for this object
207 gst_rtp_header_extension_get_uri (GstRTPHeaderExtension * ext)
209 GstRTPHeaderExtensionClass *klass;
210 GstElementClass *element_class;
212 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), NULL);
213 klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
214 element_class = GST_ELEMENT_CLASS (klass);
216 return gst_element_class_get_metadata (element_class,
217 GST_RTP_HEADER_EXTENSION_URI_METADATA_KEY);
221 * gst_rtp_header_extension_get_supported_flags:
222 * @ext: a #GstRTPHeaderExtension
224 * Returns: the flags supported by this instance of @ext
228 GstRTPHeaderExtensionFlags
229 gst_rtp_header_extension_get_supported_flags (GstRTPHeaderExtension * ext)
231 GstRTPHeaderExtensionClass *klass;
233 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), 0);
234 klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
235 g_return_val_if_fail (klass->get_supported_flags != NULL, 0);
237 return klass->get_supported_flags (ext);
241 * gst_rtp_header_extension_get_max_size:
242 * @ext: a #GstRTPHeaderExtension
243 * @input_meta: a #GstBuffer
245 * This is used to know how much data a certain header extension will need for
246 * both allocating the resulting data, and deciding how much payload data can
249 * Implementations should return as accurate a value as is possible using the
250 * information given in the input @buffer.
252 * Returns: the maximum size of the data written by this extension
257 gst_rtp_header_extension_get_max_size (GstRTPHeaderExtension * ext,
258 const GstBuffer * input_meta)
260 GstRTPHeaderExtensionClass *klass;
262 g_return_val_if_fail (GST_IS_BUFFER (input_meta), 0);
263 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), 0);
264 klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
265 g_return_val_if_fail (klass->get_max_size != NULL, 0);
267 return klass->get_max_size (ext, input_meta);
271 * gst_rtp_header_extension_write:
272 * @ext: a #GstRTPHeaderExtension
273 * @input_meta: the input #GstBuffer to read information from if necessary
274 * @write_flags: #GstRTPHeaderExtensionFlags for how the extension should
276 * @output: output RTP #GstBuffer
277 * @data: (array length=size): location to write the rtp header extension into
278 * @size: size of @data
280 * Writes the RTP header extension to @data using information available from
281 * the @input_meta. @data will be sized to be at least the value returned
282 * from gst_rtp_header_extension_get_max_size().
284 * Returns: the size of the data written, < 0 on failure
289 gst_rtp_header_extension_write (GstRTPHeaderExtension * ext,
290 const GstBuffer * input_meta, GstRTPHeaderExtensionFlags write_flags,
291 GstBuffer * output, guint8 * data, gsize size)
293 GstRTPHeaderExtensionPrivate *priv =
294 gst_rtp_header_extension_get_instance_private (ext);
295 GstRTPHeaderExtensionClass *klass;
297 g_return_val_if_fail (GST_IS_BUFFER (input_meta), -1);
298 g_return_val_if_fail (GST_IS_BUFFER (output), -1);
299 g_return_val_if_fail (gst_buffer_is_writable (output), -1);
300 g_return_val_if_fail (data != NULL, -1);
301 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), -1);
302 g_return_val_if_fail (priv->ext_id <= MAX_RTP_EXT_ID, -1);
303 klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
304 g_return_val_if_fail (klass->write != NULL, -1);
306 return klass->write (ext, input_meta, write_flags, output, data, size);
310 * gst_rtp_header_extension_read:
311 * @ext: a #GstRTPHeaderExtension
312 * @read_flags: #GstRTPHeaderExtensionFlags for how the extension should
314 * @data: (array length=size): location to read the rtp header extension from
315 * @size: size of @data
316 * @buffer: a #GstBuffer to modify if necessary
318 * Read the RTP header extension from @data.
320 * Returns: whether the extension could be read from @data
325 gst_rtp_header_extension_read (GstRTPHeaderExtension * ext,
326 GstRTPHeaderExtensionFlags read_flags, const guint8 * data, gsize size,
329 GstRTPHeaderExtensionPrivate *priv =
330 gst_rtp_header_extension_get_instance_private (ext);
331 GstRTPHeaderExtensionClass *klass;
333 g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
334 g_return_val_if_fail (gst_buffer_is_writable (buffer), FALSE);
335 g_return_val_if_fail (data != NULL, FALSE);
336 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
337 g_return_val_if_fail (priv->ext_id <= MAX_RTP_EXT_ID, FALSE);
338 klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
339 g_return_val_if_fail (klass->read != NULL, FALSE);
341 return klass->read (ext, read_flags, data, size, buffer);
345 * gst_rtp_header_extension_get_id:
346 * @ext: a #GstRTPHeaderExtension
348 * Returns: the RTP extension id configured on @ext
353 gst_rtp_header_extension_get_id (GstRTPHeaderExtension * ext)
355 GstRTPHeaderExtensionPrivate *priv =
356 gst_rtp_header_extension_get_instance_private (ext);
358 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), 0);
364 * gst_rtp_header_extension_set_id:
365 * @ext: a #GstRTPHeaderExtension
366 * @ext_id: The id of this extension
368 * sets the RTP extension id on @ext
373 gst_rtp_header_extension_set_id (GstRTPHeaderExtension * ext, guint ext_id)
375 GstRTPHeaderExtensionPrivate *priv =
376 gst_rtp_header_extension_get_instance_private (ext);
378 g_return_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext));
379 g_return_if_fail (ext_id < MAX_RTP_EXT_ID);
381 priv->ext_id = ext_id;
385 * gst_rtp_header_extension_set_attributes_from_caps:
386 * @ext: a #GstRTPHeaderExtension
387 * @caps: the #GstCaps to configure this extension with
389 * gst_rtp_header_extension_set_id() must have been called with a valid
390 * extension id that is contained in these caps.
392 * The only current known caps format is based on the SDP standard as produced
393 * by gst_sdp_media_attributes_to_caps().
395 * Returns: whether the @caps could be successfully set on @ext.
400 gst_rtp_header_extension_set_attributes_from_caps (GstRTPHeaderExtension * ext,
401 const GstCaps * caps)
403 GstRTPHeaderExtensionPrivate *priv =
404 gst_rtp_header_extension_get_instance_private (ext);
405 GstRTPHeaderExtensionClass *klass;
406 GstStructure *structure;
410 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
411 g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
412 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
413 g_return_val_if_fail (priv->ext_id <= MAX_RTP_EXT_ID, FALSE);
414 klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
416 structure = gst_caps_get_structure (caps, 0);
417 g_return_val_if_fail (structure != NULL, FALSE);
418 field_name = g_strdup_printf ("extmap-%u", priv->ext_id);
419 g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
421 val = gst_structure_get_value (structure, field_name);
424 if (G_VALUE_HOLDS_STRING (val)) {
425 const gchar *ext_uri = g_value_get_string (val);
427 if (g_strcmp0 (ext_uri, gst_rtp_header_extension_get_uri (ext)) != 0) {
428 /* incompatible extension uri for this instance */
431 } else if (GST_VALUE_HOLDS_ARRAY (val)
432 && gst_value_array_get_size (val) == 3) {
433 const GValue *inner_val;
435 inner_val = gst_value_array_get_value (val, 1);
436 if (!G_VALUE_HOLDS_STRING (inner_val))
438 if (g_strcmp0 (g_value_get_string (inner_val),
439 gst_rtp_header_extension_get_uri (ext)) != 0)
442 inner_val = gst_value_array_get_value (val, 2);
443 if (!G_VALUE_HOLDS_STRING (inner_val))
446 /* unknown caps format */
450 if (klass->set_attributes_from_caps)
451 return klass->set_attributes_from_caps (ext, caps);
460 * gst_rtp_header_extension_wants_update_non_rtp_src_caps:
461 * @ext: a #GstRTPHeaderExtension
463 * Call this function after gst_rtp_header_extension_read() to check if
464 * the depayloader's src caps need updating with data received in the last RTP
467 * Returns: Whether @ext wants to update depayloader's src caps.
472 gst_rtp_header_extension_wants_update_non_rtp_src_caps (GstRTPHeaderExtension *
475 GstRTPHeaderExtensionPrivate *priv =
476 gst_rtp_header_extension_get_instance_private (ext);
478 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
480 return priv->wants_update_non_rtp_src_caps;
484 * gst_rtp_header_extension_set_wants_update_non_rtp_src_caps:
485 * @ext: a #GstRTPHeaderExtension
486 * @state: TRUE if caps update is needed
488 * Call this function in a subclass from #GstRTPHeaderExtensionClass::read to
489 * tell the depayloader whether the data just parsed from RTP packet require
490 * updating its src (non-RTP) caps. If @state is TRUE, #GstRTPBaseDepayload will
491 * eventually invoke gst_rtp_header_extension_update_non_rtp_src_caps() to
492 * have the caps update applied. Applying the update also flips the internal
493 * "wants update" flag back to FALSE.
497 void gst_rtp_header_extension_set_wants_update_non_rtp_src_caps
498 (GstRTPHeaderExtension * ext, gboolean state)
500 GstRTPHeaderExtensionPrivate *priv =
501 gst_rtp_header_extension_get_instance_private (ext);
503 g_return_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext));
505 priv->wants_update_non_rtp_src_caps = state;
509 * gst_rtp_header_extension_set_non_rtp_sink_caps:
510 * @ext: a #GstRTPHeaderExtension
511 * @caps: sink #GstCaps
513 * Passes RTP payloader's sink (i.e. not payloaded) @caps to the header
516 * Returns: Whether @caps could be read successfully
521 gst_rtp_header_extension_set_non_rtp_sink_caps (GstRTPHeaderExtension * ext,
522 const GstCaps * caps)
524 GstRTPHeaderExtensionPrivate *priv =
525 gst_rtp_header_extension_get_instance_private (ext);
526 GstRTPHeaderExtensionClass *klass;
528 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
529 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
530 g_return_val_if_fail (priv->ext_id <= MAX_RTP_EXT_ID, FALSE);
531 klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
533 if (klass->set_non_rtp_sink_caps) {
534 return klass->set_non_rtp_sink_caps (ext, caps);
541 * gst_rtp_header_extension_update_non_rtp_src_caps:
542 * @ext: a #GstRTPHeaderExtension
543 * @caps: src #GstCaps to modify
545 * Updates depayloader src caps based on the information received in RTP header.
546 * @caps must be writable as this function may modify them.
548 * Returns: whether @caps were modified successfully
553 gst_rtp_header_extension_update_non_rtp_src_caps (GstRTPHeaderExtension * ext,
556 GstRTPHeaderExtensionPrivate *priv =
557 gst_rtp_header_extension_get_instance_private (ext);
558 GstRTPHeaderExtensionClass *klass;
560 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
561 g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
562 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
563 g_return_val_if_fail (priv->ext_id <= MAX_RTP_EXT_ID, FALSE);
564 klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
566 priv->wants_update_non_rtp_src_caps = FALSE;
568 if (klass->update_non_rtp_src_caps) {
569 return klass->update_non_rtp_src_caps (ext, caps);
576 * gst_rtp_header_extension_set_caps_from_attributes:
577 * @ext: a #GstRTPHeaderExtension
578 * @caps: writable #GstCaps to modify
580 * gst_rtp_header_extension_set_id() must have been called with a valid
581 * extension id that is contained in these caps.
583 * The only current known caps format is based on the SDP standard as produced
584 * by gst_sdp_media_attributes_to_caps().
586 * Returns: whether the configured attributes on @ext can successfully be set on
592 gst_rtp_header_extension_set_caps_from_attributes (GstRTPHeaderExtension * ext,
595 GstRTPHeaderExtensionPrivate *priv =
596 gst_rtp_header_extension_get_instance_private (ext);
597 GstRTPHeaderExtensionClass *klass;
599 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
600 g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
601 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
602 g_return_val_if_fail (priv->ext_id <= MAX_RTP_EXT_ID, FALSE);
603 klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
604 g_return_val_if_fail (klass->set_caps_from_attributes != NULL, FALSE);
606 return klass->set_caps_from_attributes (ext, caps);
610 * gst_rtp_header_extension_get_sdp_caps_field_name:
611 * @ext: the #GstRTPHeaderExtension
613 * Returns: (transfer full): the #GstStructure field name used in SDP-like #GstCaps for this @ext configuration
618 gst_rtp_header_extension_get_sdp_caps_field_name (GstRTPHeaderExtension * ext)
620 GstRTPHeaderExtensionPrivate *priv =
621 gst_rtp_header_extension_get_instance_private (ext);
623 g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), NULL);
624 g_return_val_if_fail (priv->ext_id <= MAX_RTP_EXT_ID, NULL);
626 return g_strdup_printf ("extmap-%u", priv->ext_id);
630 * gst_rtp_header_extension_set_caps_from_attributes_default
631 * @ext: the #GstRTPHeaderExtension
632 * @caps: #GstCaps to write fields into
634 * Helper implementation for GstRTPExtensionClass::set_caps_from_attributes
635 * that sets the @ext uri on caps with the specified extension id as required
638 * Requires that the extension does not have any attributes or direction
639 * advertised in @caps.
641 * Returns: whether the @ext attributes could be set on @caps.
644 gst_rtp_header_extension_set_caps_from_attributes_default (GstRTPHeaderExtension
645 * ext, GstCaps * caps)
647 gchar *field_name = gst_rtp_header_extension_get_sdp_caps_field_name (ext);
648 GstStructure *s = gst_caps_get_structure (caps, 0);
650 gst_structure_set (s, field_name, G_TYPE_STRING,
651 gst_rtp_header_extension_get_uri (ext), NULL);
658 gst_rtp_ext_list_filter (GstPluginFeature * feature, gpointer user_data)
660 GstElementFactory *factory;
661 gchar *uri = user_data;
662 const gchar *klass, *factory_uri;
665 /* we only care about element factories */
666 if (!GST_IS_ELEMENT_FACTORY (feature))
669 factory = GST_ELEMENT_FACTORY (feature);
671 /* only select elements with autoplugging rank */
672 rank = gst_plugin_feature_get_rank (feature);
673 if (rank < GST_RANK_MARGINAL)
677 gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
678 if (!strstr (klass, "Network") || !strstr (klass, "Extension") ||
679 !strstr (klass, "RTPHeader"))
683 gst_element_factory_get_metadata (factory,
684 GST_RTP_HEADER_EXTENSION_URI_METADATA_KEY);
688 if (uri && g_strcmp0 (uri, factory_uri) != 0)
695 * gst_rtp_get_header_extension_list:
697 * Retrieve all the factories of the currently registered RTP header
698 * extensions. Call gst_element_factory_create() with each factory to create
699 * the associated #GstRTPHeaderExtension.
701 * Returns: (transfer full) (element-type GstElementFactory): a #GList of
702 * #GstElementFactory's. Use gst_plugin_feature_list_free() after use
707 gst_rtp_get_header_extension_list (void)
709 return gst_registry_feature_filter (gst_registry_get (),
710 (GstPluginFeatureFilter) gst_rtp_ext_list_filter, FALSE, NULL);
714 * gst_rtp_header_extension_create_from_uri:
715 * @uri: the rtp header extension URI to search for
717 * Returns: (transfer full) (nullable): the #GstRTPHeaderExtension for @uri or %NULL
721 GstRTPHeaderExtension *
722 gst_rtp_header_extension_create_from_uri (const gchar * uri)
726 l = gst_registry_feature_filter (gst_registry_get (),
727 (GstPluginFeatureFilter) gst_rtp_ext_list_filter, TRUE, (gpointer) uri);
729 GstElementFactory *factory = GST_ELEMENT_FACTORY (l->data);
730 GstElement *element = gst_element_factory_create (factory, NULL);
732 g_list_free_full (l, (GDestroyNotify) gst_object_unref);
734 return GST_RTP_HEADER_EXTENSION (element);