rtphdrext: allow updating depayloader src caps
authorJakub Adam <jakub.adam@collabora.com>
Thu, 4 Feb 2021 16:08:04 +0000 (17:08 +0100)
committerJakub Adam <jakub.adam@collabora.com>
Fri, 12 Mar 2021 17:45:04 +0000 (18:45 +0100)
Add overridable method that updates depayloader's src caps based on
the data from RTP header.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/1011>

gst-libs/gst/rtp/gstrtpbasedepayload.c
gst-libs/gst/rtp/gstrtphdrext.c
gst-libs/gst/rtp/gstrtphdrext.h

index 68b5760..edb12a2 100644 (file)
@@ -60,6 +60,8 @@ struct _GstRTPBaseDepayloadPrivate
   gboolean negotiated;
 
   GstCaps *last_caps;
+  gboolean needs_src_caps_update;
+
   GstEvent *segment_event;
   guint32 segment_seqnum;       /* Note: this is a GstEvent seqnum */
 
@@ -1241,6 +1243,10 @@ read_rtp_header_extensions (GstRTPBaseDepayload * depayload,
           goto out;
         }
 
+        if (gst_rtp_header_extension_wants_update_non_rtp_src_caps (ext)) {
+          depayload->priv->needs_src_caps_update = TRUE;
+        }
+
         gst_object_unref (ext);
       }
       GST_OBJECT_UNLOCK (depayload);
@@ -1307,6 +1313,46 @@ gst_rtp_base_depayload_prepare_push (GstRTPBaseDepayload * filter,
     set_headers (buf, 0, filter);
   }
 
+  /* header extensions may want to update src caps */
+  if (G_UNLIKELY (filter->priv->needs_src_caps_update)) {
+    GstCaps *src_caps = gst_pad_get_current_caps (filter->srcpad);
+
+    if (src_caps) {
+      GstCaps *new_caps;
+      gboolean update_ok = TRUE;
+      gint i;
+
+      new_caps = gst_caps_copy (src_caps);
+      for (i = 0; i < filter->priv->header_exts->len; i++) {
+        GstRTPHeaderExtension *ext;
+
+        ext = g_ptr_array_index (filter->priv->header_exts, i);
+        update_ok =
+            gst_rtp_header_extension_update_non_rtp_src_caps (ext, new_caps);
+
+        if (!update_ok) {
+          GST_ELEMENT_ERROR (filter, STREAM, DECODE,
+              ("RTP header extension (%s) could not update src caps",
+                  GST_OBJECT_NAME (ext)), (NULL));
+          break;
+        }
+      }
+
+      if (G_UNLIKELY (update_ok && !gst_caps_is_equal (src_caps, new_caps))) {
+        gst_pad_set_caps (filter->srcpad, new_caps);
+      }
+
+      gst_caps_unref (src_caps);
+      gst_caps_unref (new_caps);
+
+      if (!update_ok) {
+        return GST_FLOW_ERROR;
+      }
+    }
+
+    filter->priv->needs_src_caps_update = FALSE;
+  }
+
   /* if this is the first buffer send a NEWSEGMENT */
   if (G_UNLIKELY (filter->priv->segment_event)) {
     gst_pad_push_event (filter->srcpad, filter->priv->segment_event);
index 1988e44..e324359 100644 (file)
@@ -395,6 +395,49 @@ gst_rtp_header_extension_set_attributes_from_caps (GstRTPHeaderExtension * ext,
 }
 
 /**
+ * gst_rtp_header_extension_wants_update_non_rtp_src_caps:
+ * @ext: a #GstRTPHeaderExtension
+ *
+ * Call this function after gst_rtp_header_extension_read() to check if
+ * the depayloader's src caps need updating with data received in the last RTP
+ * packet.
+ *
+ * Returns: Whether @ext wants to update depayloader's src caps.
+ *
+ * Since: 1.20
+ */
+gboolean
+gst_rtp_header_extension_wants_update_non_rtp_src_caps (GstRTPHeaderExtension *
+    ext)
+{
+  g_return_val_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext), FALSE);
+
+  return ext->wants_update_non_rtp_src_caps;
+}
+
+/**
+ * gst_rtp_header_extension_set_wants_update_non_rtp_src_caps:
+ * @ext: a #GstRTPHeaderExtension
+ * @state: TRUE if caps update is needed
+ *
+ * Call this function in a subclass from #GstRTPHeaderExtensionClass::read to
+ * tell the depayloader whether the data just parsed from RTP packet require
+ * updating its src (non-RTP) caps. If @state is TRUE, #GstRTPBaseDepayload will
+ * eventually invoke gst_rtp_header_extension_update_non_rtp_src_caps() to
+ * have the caps update applied. Applying the update also flips the internal
+ * "wants update" flag back to FALSE.
+ *
+ * Since: 1.20
+ */
+void gst_rtp_header_extension_set_wants_update_non_rtp_src_caps
+    (GstRTPHeaderExtension * ext, gboolean state)
+{
+  g_return_if_fail (GST_IS_RTP_HEADER_EXTENSION (ext));
+
+  ext->wants_update_non_rtp_src_caps = state;
+}
+
+/**
  * gst_rtp_header_extension_set_non_rtp_sink_caps:
  * @ext: a #GstRTPHeaderExtension
  * @caps: sink #GstCaps
@@ -425,6 +468,39 @@ gst_rtp_header_extension_set_non_rtp_sink_caps (GstRTPHeaderExtension * ext,
 }
 
 /**
+ * gst_rtp_header_extension_update_non_rtp_src_caps:
+ * @ext: a #GstRTPHeaderExtension
+ * @caps: src #GstCaps to modify
+ *
+ * Updates depayloader src caps based on the information received in RTP header.
+ * @caps must be writable as this function may modify them.
+ *
+ * Returns: whether @caps were modified successfully
+ *
+ * Since: 1.20
+ */
+gboolean
+gst_rtp_header_extension_update_non_rtp_src_caps (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);
+
+  ext->wants_update_non_rtp_src_caps = FALSE;
+
+  if (klass->update_non_rtp_src_caps) {
+    return klass->update_non_rtp_src_caps (ext, caps);
+  }
+
+  return TRUE;
+}
+
+/**
  * gst_rtp_header_extension_set_caps_from_attributes:
  * @ext: a #GstRTPHeaderExtension
  * @caps: writable #GstCaps to modify
index 1f0e9b1..cdfefd4 100644 (file)
@@ -117,6 +117,7 @@ struct _GstRTPHeaderExtension
   GstElement parent;
 
   guint ext_id;
+  gboolean wants_update_non_rtp_src_caps;
 
   /*< private >*/
   gpointer _gst_reserved[GST_PADDING];
@@ -140,6 +141,8 @@ struct _GstRTPHeaderExtension
  *     information, optionally adding some meta onto the output buffer.
  * @set_non_rtp_sink_caps: read any information from sink caps that the header
  *     extension needs for its function.
+ * @update_non_rtp_src_caps: update depayloader non-RTP (depayloaded) caps with
+ *     the information parsed from RTP header.
  * @set_attributes_from_caps: read the caps information to set the necessary
  *     attributes that may be signaled e.g. with an SDP.
  * @set_caps_from_attributes: write the necessary caps field/s for the configured
@@ -173,6 +176,8 @@ struct _GstRTPHeaderExtensionClass
                                                      GstBuffer * buffer);
   gboolean              (*set_non_rtp_sink_caps)    (GstRTPHeaderExtension * ext,
                                                      const GstCaps * caps);
+  gboolean              (*update_non_rtp_src_caps)  (GstRTPHeaderExtension * ext,
+                                                     GstCaps * caps);
   gboolean              (*set_attributes_from_caps) (GstRTPHeaderExtension * ext,
                                                      const GstCaps * caps);
   gboolean              (*set_caps_from_attributes) (GstRTPHeaderExtension * ext,
@@ -224,6 +229,14 @@ GST_RTP_API
 gboolean            gst_rtp_header_extension_set_non_rtp_sink_caps (GstRTPHeaderExtension * ext,
                                                                     const GstCaps * caps);
 GST_RTP_API
+gboolean            gst_rtp_header_extension_wants_update_non_rtp_src_caps (GstRTPHeaderExtension * ext);
+GST_RTP_API
+void                gst_rtp_header_extension_set_wants_update_non_rtp_src_caps (GstRTPHeaderExtension * ext,
+                                                                                gboolean state);
+GST_RTP_API
+gboolean            gst_rtp_header_extension_update_non_rtp_src_caps (GstRTPHeaderExtension * ext,
+                                                                      GstCaps * caps);
+GST_RTP_API
 gboolean            gst_rtp_header_extension_set_caps_from_attributes (GstRTPHeaderExtension * ext,
                                                                        GstCaps * caps);
 GST_RTP_API