rtphdrext: Set caps without attributes as the default
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-base / gst-libs / gst / rtp / gstrtphdrext.c
1 /* GStreamer
2  * Copyright (C) <2012> Wim Taymans <wim.taymans@gmail.com>
3  * Copyright (C) <2020> Matthew Waters <matthew@centricular.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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * SECTION:gstrtphdrext
23  * @title: GstRtphdrext
24  * @short_description: Helper methods for dealing with RTP header extensions
25  * @see_also: #GstRTPBasePayload, #GstRTPBaseDepayload, gstrtpbuffer
26  *
27  */
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "gstrtphdrext.h"
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 static gboolean
38 gst_rtp_header_extension_set_caps_from_attributes_default (GstRTPHeaderExtension
39     * ext, GstCaps * caps);
40
41 GST_DEBUG_CATEGORY_STATIC (rtphderext_debug);
42 #define GST_CAT_DEFAULT (rtphderext_debug)
43
44 #define MAX_RTP_EXT_ID 256
45
46 typedef struct
47 {
48   guint ext_id;
49   gboolean wants_update_non_rtp_src_caps;
50 } GstRTPHeaderExtensionPrivate;
51
52 /**
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
57  *
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.
60  *
61  * Returns: %TRUE on success.
62  */
63 gboolean
64 gst_rtp_hdrext_set_ntp_64 (gpointer data, guint size, guint64 ntptime)
65 {
66   g_return_val_if_fail (data != NULL, FALSE);
67   g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_64_SIZE, FALSE);
68
69   GST_WRITE_UINT64_BE (data, ntptime);
70
71   return TRUE;
72 }
73
74 /**
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
79  *
80  * Reads the NTP time from the @size NTP-64 extension bytes in @data and store the
81  * result in @ntptime.
82  *
83  * Returns: %TRUE on success.
84  */
85 gboolean
86 gst_rtp_hdrext_get_ntp_64 (gpointer data, guint size, guint64 * ntptime)
87 {
88   g_return_val_if_fail (data != NULL, FALSE);
89   g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_64_SIZE, FALSE);
90
91   if (ntptime)
92     *ntptime = GST_READ_UINT64_BE (data);
93
94   return TRUE;
95 }
96
97 /**
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
102  *
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.
105  *
106  * Returns: %TRUE on success.
107  */
108 gboolean
109 gst_rtp_hdrext_set_ntp_56 (gpointer data, guint size, guint64 ntptime)
110 {
111   guint8 *d = data;
112   gint i;
113
114   g_return_val_if_fail (data != NULL, FALSE);
115   g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_56_SIZE, FALSE);
116
117   for (i = 0; i < 7; i++) {
118     d[6 - i] = ntptime & 0xff;
119     ntptime >>= 8;
120   }
121   return TRUE;
122 }
123
124 /**
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
129  *
130  * Reads the NTP time from the @size NTP-56 extension bytes in @data and store the
131  * result in @ntptime.
132  *
133  * Returns: %TRUE on success.
134  */
135 gboolean
136 gst_rtp_hdrext_get_ntp_56 (gpointer data, guint size, guint64 * ntptime)
137 {
138   guint8 *d = data;
139
140   g_return_val_if_fail (data != NULL, FALSE);
141   g_return_val_if_fail (size >= GST_RTP_HDREXT_NTP_56_SIZE, FALSE);
142
143   if (ntptime) {
144     gint i;
145
146     *ntptime = 0;
147     for (i = 0; i < 7; i++) {
148       *ntptime <<= 8;
149       *ntptime |= d[i];
150     }
151   }
152   return TRUE;
153 }
154
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")
161     );
162
163 /**
164  * gst_rtp_header_extension_class_set_uri:
165  * @klass: the #GstRTPHeaderExtensionClass
166  * @uri: the RTP Header extension uri for @klass
167  *
168  * Set the URI for this RTP header extension implementation.
169  *
170  * Since: 1.20
171  */
172 void
173 gst_rtp_header_extension_class_set_uri (GstRTPHeaderExtensionClass * klass,
174     const gchar * uri)
175 {
176   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
177
178   gst_element_class_add_static_metadata (element_class,
179       GST_RTP_HEADER_EXTENSION_URI_METADATA_KEY, uri);
180 }
181
182 static void
183 gst_rtp_header_extension_class_init (GstRTPHeaderExtensionClass * klass)
184 {
185   klass->set_caps_from_attributes =
186       gst_rtp_header_extension_set_caps_from_attributes_default;
187 }
188
189 static void
190 gst_rtp_header_extension_init (GstRTPHeaderExtension * ext)
191 {
192   GstRTPHeaderExtensionPrivate *priv =
193       gst_rtp_header_extension_get_instance_private (ext);
194
195   priv->ext_id = G_MAXUINT32;
196 }
197
198 /**
199  * gst_rtp_header_extension_get_uri:
200  * @ext: a #GstRTPHeaderExtension
201  *
202  * Returns: the RTP extension URI for this object
203  *
204  * Since: 1.20
205  */
206 const gchar *
207 gst_rtp_header_extension_get_uri (GstRTPHeaderExtension * ext)
208 {
209   GstRTPHeaderExtensionClass *klass;
210   GstElementClass *element_class;
211
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);
215
216   return gst_element_class_get_metadata (element_class,
217       GST_RTP_HEADER_EXTENSION_URI_METADATA_KEY);
218 }
219
220 /**
221  * gst_rtp_header_extension_get_supported_flags:
222  * @ext: a #GstRTPHeaderExtension
223  *
224  * Returns: the flags supported by this instance of @ext
225  *
226  * Since: 1.20
227  */
228 GstRTPHeaderExtensionFlags
229 gst_rtp_header_extension_get_supported_flags (GstRTPHeaderExtension * ext)
230 {
231   GstRTPHeaderExtensionClass *klass;
232
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);
236
237   return klass->get_supported_flags (ext);
238 }
239
240 /**
241  * gst_rtp_header_extension_get_max_size:
242  * @ext: a #GstRTPHeaderExtension
243  * @input_meta: a #GstBuffer
244  *
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
247  * be generated.
248  *
249  * Implementations should return as accurate a value as is possible using the
250  * information given in the input @buffer.
251  *
252  * Returns: the maximum size of the data written by this extension
253  *
254  * Since: 1.20
255  */
256 gsize
257 gst_rtp_header_extension_get_max_size (GstRTPHeaderExtension * ext,
258     const GstBuffer * input_meta)
259 {
260   GstRTPHeaderExtensionClass *klass;
261
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);
266
267   return klass->get_max_size (ext, input_meta);
268 }
269
270 /**
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
275  *               be written
276  * @output: output RTP #GstBuffer
277  * @data: (array length=size): location to write the rtp header extension into
278  * @size: size of @data
279  *
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().
283  *
284  * Returns: the size of the data written, < 0 on failure
285  *
286  * Since: 1.20
287  */
288 gssize
289 gst_rtp_header_extension_write (GstRTPHeaderExtension * ext,
290     const GstBuffer * input_meta, GstRTPHeaderExtensionFlags write_flags,
291     GstBuffer * output, guint8 * data, gsize size)
292 {
293   GstRTPHeaderExtensionPrivate *priv =
294       gst_rtp_header_extension_get_instance_private (ext);
295   GstRTPHeaderExtensionClass *klass;
296
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);
305
306   return klass->write (ext, input_meta, write_flags, output, data, size);
307 }
308
309 /**
310  * gst_rtp_header_extension_read:
311  * @ext: a #GstRTPHeaderExtension
312  * @read_flags: #GstRTPHeaderExtensionFlags for how the extension should
313  *               be written
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
317  *
318  * Read the RTP header extension from @data.
319  *
320  * Returns: whether the extension could be read from @data
321  *
322  * Since: 1.20
323  */
324 gboolean
325 gst_rtp_header_extension_read (GstRTPHeaderExtension * ext,
326     GstRTPHeaderExtensionFlags read_flags, const guint8 * data, gsize size,
327     GstBuffer * buffer)
328 {
329   GstRTPHeaderExtensionPrivate *priv =
330       gst_rtp_header_extension_get_instance_private (ext);
331   GstRTPHeaderExtensionClass *klass;
332
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);
340
341   return klass->read (ext, read_flags, data, size, buffer);
342 }
343
344 /**
345  * gst_rtp_header_extension_get_id:
346  * @ext: a #GstRTPHeaderExtension
347  *
348  * Returns: the RTP extension id configured on @ext
349  *
350  * Since: 1.20
351  */
352 guint
353 gst_rtp_header_extension_get_id (GstRTPHeaderExtension * ext)
354 {
355   GstRTPHeaderExtensionPrivate *priv =
356       gst_rtp_header_extension_get_instance_private (ext);
357
358   g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), 0);
359
360   return priv->ext_id;
361 }
362
363 /**
364  * gst_rtp_header_extension_set_id:
365  * @ext: a #GstRTPHeaderExtension
366  * @ext_id: The id of this extension
367  *
368  * sets the RTP extension id on @ext
369  *
370  * Since: 1.20
371  */
372 void
373 gst_rtp_header_extension_set_id (GstRTPHeaderExtension * ext, guint ext_id)
374 {
375   GstRTPHeaderExtensionPrivate *priv =
376       gst_rtp_header_extension_get_instance_private (ext);
377
378   g_return_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext));
379   g_return_if_fail (ext_id < MAX_RTP_EXT_ID);
380
381   priv->ext_id = ext_id;
382 }
383
384 /**
385  * gst_rtp_header_extension_set_attributes_from_caps:
386  * @ext: a #GstRTPHeaderExtension
387  * @caps: the #GstCaps to configure this extension with
388  *
389  * gst_rtp_header_extension_set_id() must have been called with a valid
390  * extension id that is contained in these caps.
391  *
392  * The only current known caps format is based on the SDP standard as produced
393  * by gst_sdp_media_attributes_to_caps().
394  *
395  * Returns: whether the @caps could be successfully set on @ext.
396  *
397  * Since: 1.20
398  */
399 gboolean
400 gst_rtp_header_extension_set_attributes_from_caps (GstRTPHeaderExtension * ext,
401     const GstCaps * caps)
402 {
403   GstRTPHeaderExtensionPrivate *priv =
404       gst_rtp_header_extension_get_instance_private (ext);
405   GstRTPHeaderExtensionClass *klass;
406   GstStructure *structure;
407   gchar *field_name;
408   const GValue *val;
409
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);
415
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);
420
421   val = gst_structure_get_value (structure, field_name);
422   g_free (field_name);
423
424   if (G_VALUE_HOLDS_STRING (val)) {
425     const gchar *ext_uri = g_value_get_string (val);
426
427     if (g_strcmp0 (ext_uri, gst_rtp_header_extension_get_uri (ext)) != 0) {
428       /* incompatible extension uri for this instance */
429       goto error;
430     }
431   } else if (GST_VALUE_HOLDS_ARRAY (val)
432       && gst_value_array_get_size (val) == 3) {
433     const GValue *inner_val;
434
435     inner_val = gst_value_array_get_value (val, 1);
436     if (!G_VALUE_HOLDS_STRING (inner_val))
437       goto error;
438     if (g_strcmp0 (g_value_get_string (inner_val),
439             gst_rtp_header_extension_get_uri (ext)) != 0)
440       goto error;
441
442     inner_val = gst_value_array_get_value (val, 2);
443     if (!G_VALUE_HOLDS_STRING (inner_val))
444       goto error;
445   } else {
446     /* unknown caps format */
447     goto error;
448   }
449
450   if (klass->set_attributes_from_caps)
451     return klass->set_attributes_from_caps (ext, caps);
452   else
453     return TRUE;
454
455 error:
456   return FALSE;
457 }
458
459 /**
460  * gst_rtp_header_extension_wants_update_non_rtp_src_caps:
461  * @ext: a #GstRTPHeaderExtension
462  *
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
465  * packet.
466  *
467  * Returns: Whether @ext wants to update depayloader's src caps.
468  *
469  * Since: 1.20
470  */
471 gboolean
472 gst_rtp_header_extension_wants_update_non_rtp_src_caps (GstRTPHeaderExtension *
473     ext)
474 {
475   GstRTPHeaderExtensionPrivate *priv =
476       gst_rtp_header_extension_get_instance_private (ext);
477
478   g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
479
480   return priv->wants_update_non_rtp_src_caps;
481 }
482
483 /**
484  * gst_rtp_header_extension_set_wants_update_non_rtp_src_caps:
485  * @ext: a #GstRTPHeaderExtension
486  * @state: TRUE if caps update is needed
487  *
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.
494  *
495  * Since: 1.20
496  */
497 void gst_rtp_header_extension_set_wants_update_non_rtp_src_caps
498     (GstRTPHeaderExtension * ext, gboolean state)
499 {
500   GstRTPHeaderExtensionPrivate *priv =
501       gst_rtp_header_extension_get_instance_private (ext);
502
503   g_return_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext));
504
505   priv->wants_update_non_rtp_src_caps = state;
506 }
507
508 /**
509  * gst_rtp_header_extension_set_non_rtp_sink_caps:
510  * @ext: a #GstRTPHeaderExtension
511  * @caps: sink #GstCaps
512  *
513  * Passes RTP payloader's sink (i.e. not payloaded) @caps to the header
514  * extension.
515  *
516  * Returns: Whether @caps could be read successfully
517  *
518  * Since: 1.20
519  */
520 gboolean
521 gst_rtp_header_extension_set_non_rtp_sink_caps (GstRTPHeaderExtension * ext,
522     const GstCaps * caps)
523 {
524   GstRTPHeaderExtensionPrivate *priv =
525       gst_rtp_header_extension_get_instance_private (ext);
526   GstRTPHeaderExtensionClass *klass;
527
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);
532
533   if (klass->set_non_rtp_sink_caps) {
534     return klass->set_non_rtp_sink_caps (ext, caps);
535   }
536
537   return TRUE;
538 }
539
540 /**
541  * gst_rtp_header_extension_update_non_rtp_src_caps:
542  * @ext: a #GstRTPHeaderExtension
543  * @caps: src #GstCaps to modify
544  *
545  * Updates depayloader src caps based on the information received in RTP header.
546  * @caps must be writable as this function may modify them.
547  *
548  * Returns: whether @caps were modified successfully
549  *
550  * Since: 1.20
551  */
552 gboolean
553 gst_rtp_header_extension_update_non_rtp_src_caps (GstRTPHeaderExtension * ext,
554     GstCaps * caps)
555 {
556   GstRTPHeaderExtensionPrivate *priv =
557       gst_rtp_header_extension_get_instance_private (ext);
558   GstRTPHeaderExtensionClass *klass;
559
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);
565
566   priv->wants_update_non_rtp_src_caps = FALSE;
567
568   if (klass->update_non_rtp_src_caps) {
569     return klass->update_non_rtp_src_caps (ext, caps);
570   }
571
572   return TRUE;
573 }
574
575 /**
576  * gst_rtp_header_extension_set_caps_from_attributes:
577  * @ext: a #GstRTPHeaderExtension
578  * @caps: writable #GstCaps to modify
579  *
580  * gst_rtp_header_extension_set_id() must have been called with a valid
581  * extension id that is contained in these caps.
582  *
583  * The only current known caps format is based on the SDP standard as produced
584  * by gst_sdp_media_attributes_to_caps().
585  *
586  * Returns: whether the configured attributes on @ext can successfully be set on
587  *      @caps
588  *
589  * Since: 1.20
590  */
591 gboolean
592 gst_rtp_header_extension_set_caps_from_attributes (GstRTPHeaderExtension * ext,
593     GstCaps * caps)
594 {
595   GstRTPHeaderExtensionPrivate *priv =
596       gst_rtp_header_extension_get_instance_private (ext);
597   GstRTPHeaderExtensionClass *klass;
598
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);
605
606   return klass->set_caps_from_attributes (ext, caps);
607 }
608
609 /**
610  * gst_rtp_header_extension_get_sdp_caps_field_name:
611  * @ext: the #GstRTPHeaderExtension
612  *
613  * Returns: (transfer full): the #GstStructure field name used in SDP-like #GstCaps for this @ext configuration
614  *
615  * Since: 1.20
616  */
617 gchar *
618 gst_rtp_header_extension_get_sdp_caps_field_name (GstRTPHeaderExtension * ext)
619 {
620   GstRTPHeaderExtensionPrivate *priv =
621       gst_rtp_header_extension_get_instance_private (ext);
622
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);
625
626   return g_strdup_printf ("extmap-%u", priv->ext_id);
627 }
628
629 /*
630  * gst_rtp_header_extension_set_caps_from_attributes_default
631  * @ext: the #GstRTPHeaderExtension
632  * @caps: #GstCaps to write fields into
633  *
634  * Helper implementation for GstRTPExtensionClass::set_caps_from_attributes
635  * that sets the @ext uri on caps with the specified extension id as required
636  * for sdp #GstCaps.
637  *
638  * Requires that the extension does not have any attributes or direction
639  * advertised in @caps.
640  *
641  * Returns: whether the @ext attributes could be set on @caps.
642  */
643 static gboolean
644 gst_rtp_header_extension_set_caps_from_attributes_default (GstRTPHeaderExtension
645     * ext, GstCaps * caps)
646 {
647   gchar *field_name = gst_rtp_header_extension_get_sdp_caps_field_name (ext);
648   GstStructure *s = gst_caps_get_structure (caps, 0);
649
650   gst_structure_set (s, field_name, G_TYPE_STRING,
651       gst_rtp_header_extension_get_uri (ext), NULL);
652
653   g_free (field_name);
654   return TRUE;
655 }
656
657 static gboolean
658 gst_rtp_ext_list_filter (GstPluginFeature * feature, gpointer user_data)
659 {
660   GstElementFactory *factory;
661   gchar *uri = user_data;
662   const gchar *klass, *factory_uri;
663   guint rank;
664
665   /* we only care about element factories */
666   if (!GST_IS_ELEMENT_FACTORY (feature))
667     return FALSE;
668
669   factory = GST_ELEMENT_FACTORY (feature);
670
671   /* only select elements with autoplugging rank */
672   rank = gst_plugin_feature_get_rank (feature);
673   if (rank < GST_RANK_MARGINAL)
674     return FALSE;
675
676   klass =
677       gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
678   if (!strstr (klass, "Network") || !strstr (klass, "Extension") ||
679       !strstr (klass, "RTPHeader"))
680     return FALSE;
681
682   factory_uri =
683       gst_element_factory_get_metadata (factory,
684       GST_RTP_HEADER_EXTENSION_URI_METADATA_KEY);
685   if (!factory_uri)
686     return FALSE;
687
688   if (uri && g_strcmp0 (uri, factory_uri) != 0)
689     return FALSE;
690
691   return TRUE;
692 }
693
694 /**
695  * gst_rtp_get_header_extension_list:
696  *
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.
700  *
701  * Returns: (transfer full) (element-type GstElementFactory): a #GList of
702  *     #GstElementFactory's. Use gst_plugin_feature_list_free() after use
703  *
704  * Since: 1.20
705  */
706 GList *
707 gst_rtp_get_header_extension_list (void)
708 {
709   return gst_registry_feature_filter (gst_registry_get (),
710       (GstPluginFeatureFilter) gst_rtp_ext_list_filter, FALSE, NULL);
711 }
712
713 /**
714  * gst_rtp_header_extension_create_from_uri:
715  * @uri: the rtp header extension URI to search for
716  *
717  * Returns: (transfer full) (nullable): the #GstRTPHeaderExtension for @uri or %NULL
718  *
719  * Since: 1.20
720  */
721 GstRTPHeaderExtension *
722 gst_rtp_header_extension_create_from_uri (const gchar * uri)
723 {
724   GList *l;
725
726   l = gst_registry_feature_filter (gst_registry_get (),
727       (GstPluginFeatureFilter) gst_rtp_ext_list_filter, TRUE, (gpointer) uri);
728   if (l) {
729     GstElementFactory *factory = GST_ELEMENT_FACTORY (l->data);
730     GstElement *element = gst_element_factory_create (factory, NULL);
731
732     g_list_free_full (l, (GDestroyNotify) gst_object_unref);
733
734     return GST_RTP_HEADER_EXTENSION (element);
735   }
736
737   return NULL;
738 }