rtpmanager: Update codes based on 1.18.4
[platform/upstream/gst-plugins-good.git] / gst / rtpmanager / gstrtpptdemux.c
index d764bee..d8d54ba 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * RTP Demux element
  *
  * Copyright (C) 2005 Nokia Corporation.
 
 /**
  * SECTION:element-rtpptdemux
+ * @title: rtpptdemux
  *
  * rtpptdemux acts as a demuxer for RTP packets based on the payload type of
  * the packets. Its main purpose is to allow an application to easily receive
  * and decode an RTP stream with multiple payload types.
- * 
+ *
  * For each payload type that is detected, a new pad will be created and the
  * #GstRtpPtDemux::new-payload-type signal will be emitted. When the payload for
  * the RTP stream changes, the #GstRtpPtDemux::payload-type-change signal will be
  * emitted.
- * 
+ *
  * The element will try to set complete and unique application/x-rtp caps
  * on the output pads based on the result of the #GstRtpPtDemux::request-pt-map
  * signal.
- * 
- * <refsect2>
- * <title>Example pipelines</title>
+ *
+ * ## Example pipelines
  * |[
  * gst-launch-1.0 udpsrc caps="application/x-rtp" ! rtpptdemux ! fakesink
  * ]| Takes an RTP stream and send the RTP packets with the first detected
  * payload type to fakesink, discarding the other payload types.
- * </refsect2>
+ *
  */
 
 /*
@@ -99,8 +99,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_rtp_pt_demux_debug);
  */
 struct _GstRtpPtDemuxPad
 {
-  GstPad *pad;        /**< pointer to the actual pad */
-  gint pt;             /**< RTP payload-type attached to pad */
+  GstPad *pad;                  /*< pointer to the actual pad */
+  gint pt;                      /*< RTP payload-type attached to pad */
   gboolean newcaps;
 };
 
@@ -114,6 +114,12 @@ enum
   LAST_SIGNAL
 };
 
+enum
+{
+  PROP_0,
+  PROP_IGNORED_PTS,
+};
+
 #define gst_rtp_pt_demux_parent_class parent_class
 G_DEFINE_TYPE (GstRtpPtDemux, gst_rtp_pt_demux, GST_TYPE_ELEMENT);
 
@@ -139,6 +145,38 @@ static gboolean gst_rtp_pt_demux_src_event (GstPad * pad, GstObject * parent,
 static guint gst_rtp_pt_demux_signals[LAST_SIGNAL] = { 0 };
 
 static void
+gst_rtp_pt_demux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpPtDemux *rtpptdemux = GST_RTP_PT_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_IGNORED_PTS:
+      g_value_copy (value, &rtpptdemux->ignored_pts);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_pt_demux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpPtDemux *rtpptdemux = GST_RTP_PT_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_IGNORED_PTS:
+      g_value_copy (&rtpptdemux->ignored_pts, value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
 gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
 {
   GObjectClass *gobject_klass;
@@ -157,7 +195,7 @@ gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
   gst_rtp_pt_demux_signals[SIGNAL_REQUEST_PT_MAP] =
       g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, request_pt_map),
-      NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_CAPS, 1, G_TYPE_UINT);
+      NULL, NULL, NULL, GST_TYPE_CAPS, 1, G_TYPE_UINT);
 
   /**
    * GstRtpPtDemux::new-payload-type:
@@ -165,26 +203,24 @@ gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
    * @pt: the payload type
    * @pad: the pad with the new payload
    *
-   * Emited when a new payload type pad has been created in @demux.
+   * Emitted when a new payload type pad has been created in @demux.
    */
   gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE] =
       g_signal_new ("new-payload-type", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass, new_payload_type),
-      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_UINT,
-      GST_TYPE_PAD);
+      NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD);
 
   /**
    * GstRtpPtDemux::payload-type-change:
    * @demux: the object which received the signal
    * @pt: the new payload type
    *
-   * Emited when the payload type changed.
+   * Emitted when the payload type changed.
    */
   gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE] =
       g_signal_new ("payload-type-change", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
-          payload_type_change), NULL, NULL, g_cclosure_marshal_VOID__UINT,
-      G_TYPE_NONE, 1, G_TYPE_UINT);
+          payload_type_change), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
 
   /**
    * GstRtpPtDemux::clear-pt-map:
@@ -196,8 +232,32 @@ gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
   gst_rtp_pt_demux_signals[SIGNAL_CLEAR_PT_MAP] =
       g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpPtDemuxClass,
-          clear_pt_map), NULL, NULL, g_cclosure_marshal_VOID__VOID,
-      G_TYPE_NONE, 0, G_TYPE_NONE);
+          clear_pt_map), NULL, NULL, NULL, G_TYPE_NONE, 0, G_TYPE_NONE);
+
+  gobject_klass->set_property = gst_rtp_pt_demux_set_property;
+  gobject_klass->get_property = gst_rtp_pt_demux_get_property;
+
+  /**
+   * GstRtpPtDemux:ignored-payload-types:
+   *
+   * If specified, packets with an ignored payload type will be dropped,
+   * instead of causing a new pad to be exposed for these to be pushed on.
+   *
+   * This is for example useful to drop FEC protection packets, as they
+   * need to go through the #GstRtpJitterBuffer, but cease to be useful
+   * past that point, #GstRtpBin will make use of this property for that
+   * purpose.
+   *
+   * Since: 1.14
+   */
+  g_object_class_install_property (gobject_klass, PROP_IGNORED_PTS,
+      gst_param_spec_array ("ignored-payload-types",
+          "Ignored payload types",
+          "Packets with these payload types will be dropped",
+          g_param_spec_int ("payload-types", "payload-types", "Payload types",
+              0, G_MAXINT, 0,
+              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gobject_klass->finalize = gst_rtp_pt_demux_finalize;
 
@@ -206,10 +266,10 @@ gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
 
   klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_pt_demux_clear_pt_map);
 
-  gst_element_class_add_pad_template (gstelement_klass,
-      gst_static_pad_template_get (&rtp_pt_demux_sink_template));
-  gst_element_class_add_pad_template (gstelement_klass,
-      gst_static_pad_template_get (&rtp_pt_demux_src_template));
+  gst_element_class_add_static_pad_template (gstelement_klass,
+      &rtp_pt_demux_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_klass,
+      &rtp_pt_demux_src_template);
 
   gst_element_class_set_static_metadata (gstelement_klass, "RTP Demux",
       "Demux/Network/RTP",
@@ -218,6 +278,8 @@ gst_rtp_pt_demux_class_init (GstRtpPtDemuxClass * klass)
 
   GST_DEBUG_CATEGORY_INIT (gst_rtp_pt_demux_debug,
       "rtpptdemux", 0, "RTP codec demuxer");
+
+  GST_DEBUG_REGISTER_FUNCPTR (gst_rtp_pt_demux_chain);
 }
 
 static void
@@ -234,6 +296,8 @@ gst_rtp_pt_demux_init (GstRtpPtDemux * ptdemux)
   gst_pad_set_event_function (ptdemux->sink, gst_rtp_pt_demux_sink_event);
 
   gst_element_add_pad (GST_ELEMENT (ptdemux), ptdemux->sink);
+
+  g_value_init (&ptdemux->ignored_pts, GST_TYPE_ARRAY);
 }
 
 static void
@@ -241,13 +305,17 @@ gst_rtp_pt_demux_finalize (GObject * object)
 {
   gst_rtp_pt_demux_release (GST_RTP_PT_DEMUX (object));
 
+  g_value_unset (&GST_RTP_PT_DEMUX (object)->ignored_pts);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static GstCaps *
 gst_rtp_pt_demux_get_caps (GstRtpPtDemux * rtpdemux, guint pt)
 {
-  GstCaps *caps;
+  guint32 ssrc = 0;
+  gboolean have_ssrc = FALSE;
+  GstCaps *caps, *sink_caps;
   GValue ret = { 0 };
   GValue args[2] = { {0}, {0} };
 
@@ -266,12 +334,26 @@ gst_rtp_pt_demux_get_caps (GstRtpPtDemux * rtpdemux, guint pt)
   g_value_unset (&args[0]);
   g_value_unset (&args[1]);
   caps = g_value_dup_boxed (&ret);
+  sink_caps = gst_pad_get_current_caps (rtpdemux->sink);
   g_value_unset (&ret);
+
   if (caps == NULL) {
-    caps = gst_pad_get_current_caps (rtpdemux->sink);
+    caps = sink_caps;
+  } else if (sink_caps) {
+    have_ssrc =
+        gst_structure_get_uint (gst_caps_get_structure (sink_caps, 0), "ssrc",
+        &ssrc);
+    gst_caps_unref (sink_caps);
   }
 
-  GST_DEBUG ("pt %d, got caps %" GST_PTR_FORMAT, pt, caps);
+  if (caps != NULL) {
+    caps = gst_caps_make_writable (caps);
+    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
+    if (have_ssrc)
+      gst_caps_set_simple (caps, "ssrc", G_TYPE_UINT, ssrc, NULL);
+  }
+
+  GST_DEBUG_OBJECT (rtpdemux, "pt %d, got caps %" GST_PTR_FORMAT, pt, caps);
 
   return caps;
 }
@@ -282,7 +364,7 @@ gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux)
   GSList *walk;
 
   GST_OBJECT_LOCK (rtpdemux);
-  GST_DEBUG ("clearing pt map");
+  GST_DEBUG_OBJECT (rtpdemux, "clearing pt map");
   for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) {
     GstRtpPtDemuxPad *pad = walk->data;
 
@@ -340,6 +422,24 @@ forward_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
   return TRUE;
 }
 
+static gboolean
+gst_rtp_pt_demux_pt_is_ignored (GstRtpPtDemux * ptdemux, guint8 pt)
+{
+  gboolean ret = FALSE;
+  guint i;
+
+  for (i = 0; i < gst_value_array_get_size (&ptdemux->ignored_pts); i++) {
+    const GValue *tmp = gst_value_array_get_value (&ptdemux->ignored_pts, i);
+
+    if (g_value_get_int (tmp) == pt) {
+      ret = TRUE;
+      break;
+    }
+  }
+
+  return ret;
+}
+
 static GstFlowReturn
 gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 {
@@ -358,6 +458,9 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
   pt = gst_rtp_buffer_get_payload_type (&rtp);
   gst_rtp_buffer_unmap (&rtp);
 
+  if (gst_rtp_pt_demux_pt_is_ignored (rtpdemux, pt))
+    goto ignored;
+
   GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt);
 
   srcpad = find_pad_for_pt (rtpdemux, pt);
@@ -372,6 +475,9 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
     if (!caps)
       goto no_caps;
 
+    if (gst_rtp_pt_demux_pt_is_ignored (rtpdemux, pt))
+      goto ignored;
+
     klass = GST_ELEMENT_GET_CLASS (rtpdemux);
     templ = gst_element_class_get_pad_template (klass, "src_%u");
     padname = g_strdup_printf ("src_%u", pt);
@@ -380,7 +486,7 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
     g_free (padname);
     gst_pad_set_event_function (srcpad, gst_rtp_pt_demux_src_event);
 
-    GST_DEBUG ("Adding pt=%d to the list.", pt);
+    GST_DEBUG_OBJECT (rtpdemux, "Adding pt=%d to the list.", pt);
     rtpdemuxpad = g_slice_new0 (GstRtpPtDemuxPad);
     rtpdemuxpad->pt = pt;
     rtpdemuxpad->newcaps = FALSE;
@@ -392,14 +498,11 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 
     gst_pad_set_active (srcpad, TRUE);
 
-
     /* First push the stream-start event, it must always come first */
     gst_pad_push_event (srcpad,
         gst_pad_get_sticky_event (rtpdemux->sink, GST_EVENT_STREAM_START, 0));
 
     /* Then caps event is sent */
-    caps = gst_caps_make_writable (caps);
-    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
     gst_pad_set_caps (srcpad, caps);
     gst_caps_unref (caps);
 
@@ -409,7 +512,7 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 
     gst_element_add_pad (GST_ELEMENT_CAST (rtpdemux), srcpad);
 
-    GST_DEBUG ("emitting new-payload-type for pt %d", pt);
+    GST_DEBUG_OBJECT (rtpdemux, "emitting new-payload-type for pt %d", pt);
     g_signal_emit (G_OBJECT (rtpdemux),
         gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad);
   }
@@ -419,21 +522,20 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 
     /* our own signal with an extra flag that this is the only pad */
     rtpdemux->last_pt = pt;
-    GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt);
+    GST_DEBUG_OBJECT (rtpdemux, "emitting payload-type-changed for pt %d",
+        emit_pt);
     g_signal_emit (G_OBJECT (rtpdemux),
         gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt);
   }
 
   while (need_caps_for_pt (rtpdemux, pt)) {
-    GST_DEBUG ("need new caps for %d", pt);
+    GST_DEBUG_OBJECT (rtpdemux, "need new caps for %d", pt);
     caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
     if (!caps)
       goto no_caps;
 
     clear_newcaps_for_pt (rtpdemux, pt);
 
-    caps = gst_caps_make_writable (caps);
-    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
     gst_pad_set_caps (srcpad, caps);
     gst_caps_unref (caps);
   }
@@ -445,6 +547,13 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 
   return ret;
 
+ignored:
+  {
+    GST_DEBUG_OBJECT (rtpdemux, "Dropped buffer for pt %d", pt);
+    gst_buffer_unref (buf);
+    return GST_FLOW_OK;
+  }
+
   /* ERRORS */
 invalid_buffer:
   {