mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-09 05:38:58 +00:00
Facilitates the creation of rtp header extension implementations that can be reused across applications. Implementations are registered into the GStreamer registry as elements (idea from GstRTSPExtension) and can be retrieved by URI or filtered manually. RTP header extensions must have the classification "Network/Extension/RTPHeader" to be considered as a RTP Header extension. Fixes: https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/issues/777 Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/748>
590 lines
17 KiB
C
590 lines
17 KiB
C
/* GStreamer
|
|
* Copyright (C) <2012> Wim Taymans <wim.taymans@gmail.com>
|
|
* Copyright (C) <2020> Matthew Waters <matthew@centricular.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:gstrtphdrext
|
|
* @title: GstRtphdrext
|
|
* @short_description: Helper methods for dealing with RTP header extensions
|
|
* @see_also: #GstRTPBasePayload, #GstRTPBaseDepayload, gstrtpbuffer
|
|
*
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gstrtphdrext.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
GST_DEBUG_CATEGORY_STATIC (rtphderext_debug);
|
|
#define GST_CAT_DEFAULT (rtphderext_debug)
|
|
|
|
#define MAX_RTP_EXT_ID 256
|
|
|
|
/**
|
|
* gst_rtp_hdrext_set_ntp_64:
|
|
* @data: the data to write to
|
|
* @size: the size of @data
|
|
* @ntptime: the NTP time
|
|
*
|
|
* Writes the NTP time in @ntptime to the format required for the NTP-64 header
|
|
* extension. @data must hold at least #GST_RTP_HDREXT_NTP_64_SIZE bytes.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
gst_rtp_hdrext_set_ntp_64 (gpointer data, guint size, guint64 ntptime)
|
|
{
|
|
g_return_val_if_fail (data != NULL, FALSE);
|
|
g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_64_SIZE, FALSE);
|
|
|
|
GST_WRITE_UINT64_BE (data, ntptime);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_hdrext_get_ntp_64:
|
|
* @data: (array length=size) (element-type guint8): the data to read from
|
|
* @size: the size of @data
|
|
* @ntptime: (out): the result NTP time
|
|
*
|
|
* Reads the NTP time from the @size NTP-64 extension bytes in @data and store the
|
|
* result in @ntptime.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
gst_rtp_hdrext_get_ntp_64 (gpointer data, guint size, guint64 * ntptime)
|
|
{
|
|
g_return_val_if_fail (data != NULL, FALSE);
|
|
g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_64_SIZE, FALSE);
|
|
|
|
if (ntptime)
|
|
*ntptime = GST_READ_UINT64_BE (data);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_hdrext_set_ntp_56:
|
|
* @data: the data to write to
|
|
* @size: the size of @data
|
|
* @ntptime: the NTP time
|
|
*
|
|
* Writes the NTP time in @ntptime to the format required for the NTP-56 header
|
|
* extension. @data must hold at least #GST_RTP_HDREXT_NTP_56_SIZE bytes.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
gst_rtp_hdrext_set_ntp_56 (gpointer data, guint size, guint64 ntptime)
|
|
{
|
|
guint8 *d = data;
|
|
gint i;
|
|
|
|
g_return_val_if_fail (data != NULL, FALSE);
|
|
g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_56_SIZE, FALSE);
|
|
|
|
for (i = 0; i < 7; i++) {
|
|
d[6 - i] = ntptime & 0xff;
|
|
ntptime >>= 8;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_hdrext_get_ntp_56:
|
|
* @data: (array length=size) (element-type guint8): the data to read from
|
|
* @size: the size of @data
|
|
* @ntptime: (out): the result NTP time
|
|
*
|
|
* Reads the NTP time from the @size NTP-56 extension bytes in @data and store the
|
|
* result in @ntptime.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
gst_rtp_hdrext_get_ntp_56 (gpointer data, guint size, guint64 * ntptime)
|
|
{
|
|
guint8 *d = data;
|
|
|
|
g_return_val_if_fail (data != NULL, FALSE);
|
|
g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_56_SIZE, FALSE);
|
|
|
|
if (ntptime) {
|
|
gint i;
|
|
|
|
*ntptime = 0;
|
|
for (i = 0; i < 7; i++) {
|
|
*ntptime <<= 8;
|
|
*ntptime |= d[i];
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#define gst_rtp_header_extension_parent_class parent_class
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstRTPHeaderExtension,
|
|
gst_rtp_header_extension, GST_TYPE_ELEMENT,
|
|
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "rtphdrext", 0,
|
|
"RTP Header Extensions");
|
|
);
|
|
|
|
/**
|
|
* gst_rtp_header_extension_class_set_uri:
|
|
* @klass: the #GstRTPHeaderExtensionClass
|
|
* @uri: the RTP Header extension uri for @klass
|
|
*
|
|
* Set the URI for this RTP header extension implementation.
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
void
|
|
gst_rtp_header_extension_class_set_uri (GstRTPHeaderExtensionClass * klass,
|
|
const gchar * uri)
|
|
{
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
|
|
|
gst_element_class_add_static_metadata (element_class,
|
|
GST_RTP_HEADER_EXTENSION_URI_METADATA_KEY, uri);
|
|
}
|
|
|
|
static void
|
|
gst_rtp_header_extension_class_init (GstRTPHeaderExtensionClass * klass)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gst_rtp_header_extension_init (GstRTPHeaderExtension * ext)
|
|
{
|
|
ext->ext_id = G_MAXUINT32;
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_get_uri:
|
|
* @ext: a #GstRTPHeaderExtension
|
|
*
|
|
* Returns: the RTP extension URI for this object
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
const gchar *
|
|
gst_rtp_header_extension_get_uri (GstRTPHeaderExtension * ext)
|
|
{
|
|
GstRTPHeaderExtensionClass *klass;
|
|
GstElementClass *element_class;
|
|
|
|
g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), NULL);
|
|
klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
|
|
element_class = GST_ELEMENT_CLASS (klass);
|
|
|
|
return gst_element_class_get_metadata (element_class,
|
|
GST_RTP_HEADER_EXTENSION_URI_METADATA_KEY);
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_get_supported_flags:
|
|
* @ext: a #GstRTPHeaderExtension
|
|
*
|
|
* Returns: the flags supported by this instance of @ext
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
GstRTPHeaderExtensionFlags
|
|
gst_rtp_header_extension_get_supported_flags (GstRTPHeaderExtension * ext)
|
|
{
|
|
GstRTPHeaderExtensionClass *klass;
|
|
|
|
g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), 0);
|
|
klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
|
|
g_return_val_if_fail (klass->get_supported_flags != NULL, 0);
|
|
|
|
return klass->get_supported_flags (ext);
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_get_max_size:
|
|
* @ext: a #GstRTPHeaderExtension
|
|
* @input_meta: a #GstBuffer
|
|
*
|
|
* This is used to know how much data a certain header extension will need for
|
|
* both allocating the resulting data, and deciding how much payload data can
|
|
* be generated.
|
|
*
|
|
* Implemntations should return as accurate a value as is possible using the
|
|
* information given in the input @buffer.
|
|
*
|
|
* Returns: the maximum size of the data written by this extension
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gsize
|
|
gst_rtp_header_extension_get_max_size (GstRTPHeaderExtension * ext,
|
|
const GstBuffer * input_meta)
|
|
{
|
|
GstRTPHeaderExtensionClass *klass;
|
|
|
|
g_return_val_if_fail (GST_IS_BUFFER (input_meta), 0);
|
|
g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), 0);
|
|
klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
|
|
g_return_val_if_fail (klass->get_max_size != NULL, 0);
|
|
|
|
return klass->get_max_size (ext, input_meta);
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_write:
|
|
* @ext: a #GstRTPHeaderExtension
|
|
* @input_meta: the input #GstBuffer to read information from if necessary
|
|
* @write_flags: #GstRTPHeaderExtensionFlags for how the extension should
|
|
* be written
|
|
* @output: output RTP #GstBuffer
|
|
* @data: location to write the rtp header extension into
|
|
* @size: size of @data
|
|
*
|
|
* Writes the RTP header extension to @data using information available from
|
|
* the @input_meta. @data will be sized to be at least the value returned
|
|
* from gst_rtp_header_extension_get_max_size().
|
|
*
|
|
* Returns: the size of the data written, < 0 on failure
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gsize
|
|
gst_rtp_header_extension_write (GstRTPHeaderExtension * ext,
|
|
const GstBuffer * input_meta, GstRTPHeaderExtensionFlags write_flags,
|
|
GstBuffer * output, guint8 * data, gsize size)
|
|
{
|
|
GstRTPHeaderExtensionClass *klass;
|
|
|
|
g_return_val_if_fail (GST_IS_BUFFER (input_meta), -1);
|
|
g_return_val_if_fail (GST_IS_BUFFER (output), -1);
|
|
g_return_val_if_fail (gst_buffer_is_writable (output), -1);
|
|
g_return_val_if_fail (data != NULL, -1);
|
|
g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), -1);
|
|
g_return_val_if_fail (ext->ext_id <= MAX_RTP_EXT_ID, -1);
|
|
klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
|
|
g_return_val_if_fail (klass->write != NULL, -1);
|
|
|
|
return klass->write (ext, input_meta, write_flags, output, data, size);
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_read:
|
|
* @ext: a #GstRTPHeaderExtension
|
|
* @read_flags: #GstRTPHeaderExtensionFlags for how the extension should
|
|
* be written
|
|
* @data: location to read the rtp header extension from
|
|
* @size: size of @data
|
|
* @buffer: a #GstBuffer to modify if necessary
|
|
*
|
|
* Read the RTP header extension from @data.
|
|
*
|
|
* Returns: whether the extension could be read from @data
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gboolean
|
|
gst_rtp_header_extension_read (GstRTPHeaderExtension * ext,
|
|
GstRTPHeaderExtensionFlags read_flags, const guint8 * data, gsize size,
|
|
GstBuffer * buffer)
|
|
{
|
|
GstRTPHeaderExtensionClass *klass;
|
|
|
|
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
|
|
g_return_val_if_fail (gst_buffer_is_writable (buffer), FALSE);
|
|
g_return_val_if_fail (data != NULL, FALSE);
|
|
g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
|
|
g_return_val_if_fail (ext->ext_id <= MAX_RTP_EXT_ID, FALSE);
|
|
klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
|
|
g_return_val_if_fail (klass->read != NULL, FALSE);
|
|
|
|
return klass->read (ext, read_flags, data, size, buffer);
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_get_id:
|
|
* @ext: a #GstRTPHeaderExtension
|
|
*
|
|
* Returns: the RTP extension id configured on @ext
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
guint
|
|
gst_rtp_header_extension_get_id (GstRTPHeaderExtension * ext)
|
|
{
|
|
g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), 0);
|
|
|
|
return ext->ext_id;
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_set_id:
|
|
* @ext: a #GstRTPHeaderExtension
|
|
* @ext_id: The id of this extension
|
|
*
|
|
* sets the RTP extension id on @ext
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
void
|
|
gst_rtp_header_extension_set_id (GstRTPHeaderExtension * ext, guint ext_id)
|
|
{
|
|
g_return_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext));
|
|
g_return_if_fail (ext_id < MAX_RTP_EXT_ID);
|
|
|
|
ext->ext_id = ext_id;
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_set_attributes_from_caps:
|
|
* @ext: a #GstRTPHeaderExtension
|
|
* @caps: the #GstCaps to configure this extension with
|
|
*
|
|
* gst_rtp_header_extension_set_id() must have been called with a valid
|
|
* extension id that is contained in these caps.
|
|
*
|
|
* The only current known caps format is based on the SDP standard as produced
|
|
* by gst_sdp_media_attributes_to_caps().
|
|
*
|
|
* Returns: whether the @caps could be successfully set on @ext.
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gboolean
|
|
gst_rtp_header_extension_set_attributes_from_caps (GstRTPHeaderExtension * ext,
|
|
const GstCaps * caps)
|
|
{
|
|
GstRTPHeaderExtensionClass *klass;
|
|
GstStructure *structure;
|
|
gchar *field_name;
|
|
|
|
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
|
|
g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
|
|
g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
|
|
g_return_val_if_fail (ext->ext_id <= MAX_RTP_EXT_ID, FALSE);
|
|
klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
|
|
g_return_val_if_fail (klass->set_attributes_from_caps != NULL, FALSE);
|
|
|
|
structure = gst_caps_get_structure (caps, 0);
|
|
g_return_val_if_fail (structure != NULL, FALSE);
|
|
field_name = g_strdup_printf ("extmap-%u", ext->ext_id);
|
|
g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
|
|
g_free (field_name);
|
|
|
|
return klass->set_attributes_from_caps (ext, caps);
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_set_caps_from_attributes:
|
|
* @ext: a #GstRTPHeaderExtension
|
|
* @caps: writable #GstCaps to modify
|
|
*
|
|
* gst_rtp_header_extension_set_id() must have been called with a valid
|
|
* extension id that is contained in these caps.
|
|
*
|
|
* The only current known caps format is based on the SDP standard as produced
|
|
* by gst_sdp_media_attributes_to_caps().
|
|
*
|
|
* Returns: whether the configured attributes on @ext can successfully be set on
|
|
* @caps
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gboolean
|
|
gst_rtp_header_extension_set_caps_from_attributes (GstRTPHeaderExtension * ext,
|
|
GstCaps * caps)
|
|
{
|
|
GstRTPHeaderExtensionClass *klass;
|
|
|
|
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
|
|
g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
|
|
g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
|
|
g_return_val_if_fail (ext->ext_id <= MAX_RTP_EXT_ID, FALSE);
|
|
klass = GST_RTP_HEADER_EXTENSION_GET_CLASS (ext);
|
|
g_return_val_if_fail (klass->set_caps_from_attributes != NULL, FALSE);
|
|
|
|
return klass->set_caps_from_attributes (ext, caps);
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_get_sdp_caps_field_name:
|
|
* @ext: the #GstRTPHeaderExtension
|
|
*
|
|
* Returns: (transfer full): the #GstStructure field name used in SDP-like #GstCaps for this @ext configuration
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gchar *
|
|
gst_rtp_header_extension_get_sdp_caps_field_name (GstRTPHeaderExtension * ext)
|
|
{
|
|
g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), NULL);
|
|
g_return_val_if_fail (ext->ext_id <= MAX_RTP_EXT_ID, NULL);
|
|
|
|
return g_strdup_printf ("extmap-%u", ext->ext_id);
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_set_attributes_from_caps_simple_sdp:
|
|
* @ext: the #GstRTPHeaderExtension
|
|
* @caps: #GstCaps to read attributes from
|
|
*
|
|
* Helper implementation for GstRTPExtensionClass::set_attributes_from_caps
|
|
* that retrieves the configured extension id and checks that the
|
|
* corresponding field in the sdp caps is configured for this extension uri.
|
|
* Requires that the extension does not have any attributes or direction
|
|
* advertised in the caps.
|
|
*
|
|
* Returns: whether the attributes in the @caps could be set on @ext successfully
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gboolean
|
|
gst_rtp_header_extension_set_attributes_from_caps_simple_sdp
|
|
(GstRTPHeaderExtension * ext, const GstCaps * caps) {
|
|
gchar *field_name = gst_rtp_header_extension_get_sdp_caps_field_name (ext);
|
|
GstStructure *s = gst_caps_get_structure (caps, 0);
|
|
const gchar *ext_uri;
|
|
|
|
if (!(ext_uri = gst_structure_get_string (s, field_name)))
|
|
goto error;
|
|
|
|
if (g_strcmp0 (ext_uri, gst_rtp_header_extension_get_uri (ext)) != 0)
|
|
goto error;
|
|
|
|
g_free (field_name);
|
|
return TRUE;
|
|
|
|
error:
|
|
g_free (field_name);
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_set_caps_from_attributes_simple_sdp:
|
|
* @ext: the #GstRTPHeaderExtension
|
|
* @caps: #GstCaps to write fields into
|
|
*
|
|
* Helper implementation for GstRTPExtensionClass::set_caps_from_attributes
|
|
* that sets the @ext uri on caps with the specified extension id as required
|
|
* for sdp #GstCaps.
|
|
*
|
|
* Requires that the extension does not have any attributes or direction
|
|
* advertised in @caps.
|
|
*
|
|
* Returns: whether the @ext attributes could be set on @caps.
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
gboolean
|
|
gst_rtp_header_extension_set_caps_from_attributes_simple_sdp
|
|
(GstRTPHeaderExtension * ext, GstCaps * caps) {
|
|
gchar *field_name = gst_rtp_header_extension_get_sdp_caps_field_name (ext);
|
|
GstStructure *s = gst_caps_get_structure (caps, 0);
|
|
|
|
gst_structure_set (s, field_name, G_TYPE_STRING,
|
|
gst_rtp_header_extension_get_uri (ext), NULL);
|
|
|
|
g_free (field_name);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
gst_rtp_ext_list_filter (GstPluginFeature * feature, gpointer user_data)
|
|
{
|
|
GstElementFactory *factory;
|
|
gchar *uri = user_data;
|
|
const gchar *klass, *factory_uri;
|
|
guint rank;
|
|
|
|
/* we only care about element factories */
|
|
if (!GST_IS_ELEMENT_FACTORY (feature))
|
|
return FALSE;
|
|
|
|
factory = GST_ELEMENT_FACTORY (feature);
|
|
|
|
/* only select elements with autoplugging rank */
|
|
rank = gst_plugin_feature_get_rank (feature);
|
|
if (rank < GST_RANK_MARGINAL)
|
|
return FALSE;
|
|
|
|
klass =
|
|
gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
|
|
if (!strstr (klass, "Network") || !strstr (klass, "Extension") ||
|
|
!strstr (klass, "RTPHeader"))
|
|
return FALSE;
|
|
|
|
factory_uri =
|
|
gst_element_factory_get_metadata (factory,
|
|
GST_RTP_HEADER_EXTENSION_URI_METADATA_KEY);
|
|
if (!factory_uri)
|
|
return FALSE;
|
|
|
|
if (uri && g_strcmp0 (uri, factory_uri) != 0)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_get_header_extension_list:
|
|
*
|
|
* Retrieve all the currently registered RTP header extensions
|
|
*
|
|
* Returns: (transfer full) (element-type GstRTPHeaderExtension): a #GList of
|
|
* #GstRTPHeaderExtension. Use gst_plugin_feature_list_free() after use
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
GList *
|
|
gst_rtp_get_header_extension_list (void)
|
|
{
|
|
return gst_registry_feature_filter (gst_registry_get (),
|
|
(GstPluginFeatureFilter) gst_rtp_ext_list_filter, FALSE, NULL);
|
|
}
|
|
|
|
/**
|
|
* gst_rtp_header_extension_create_from_uri:
|
|
* @uri: the rtp header extension URI to search for
|
|
*
|
|
* Returns: (transfer full) (nullable): the #GstRTPHeaderExtension for @uri or %NULL
|
|
*
|
|
* Since: 1.20
|
|
*/
|
|
GstRTPHeaderExtension *
|
|
gst_rtp_header_extension_create_from_uri (const gchar * uri)
|
|
{
|
|
GList *l;
|
|
|
|
l = gst_registry_feature_filter (gst_registry_get (),
|
|
(GstPluginFeatureFilter) gst_rtp_ext_list_filter, TRUE, (gpointer) uri);
|
|
if (l) {
|
|
GstElementFactory *factory = GST_ELEMENT_FACTORY (l->data);
|
|
GstElement *element = gst_element_factory_create (factory, NULL);
|
|
|
|
g_list_free_full (l, (GDestroyNotify) gst_object_unref);
|
|
|
|
return GST_RTP_HEADER_EXTENSION (element);
|
|
}
|
|
|
|
return NULL;
|
|
}
|