rtpulpfecdec: add property for passthrough
authorMatthew Waters <matthew@centricular.com>
Tue, 18 Oct 2022 05:51:39 +0000 (16:51 +1100)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Sun, 23 Oct 2022 23:44:07 +0000 (23:44 +0000)
Support for enabling and disabling decoding of FEC data decoding on
packet loss events and unconditional seqnum rewriting of packets.

See
https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/581
for background.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3212>

subprojects/gst-plugins-good/docs/gst_plugins_cache.json
subprojects/gst-plugins-good/gst/rtp/gstrtpulpfecdec.c
subprojects/gst-plugins-good/gst/rtp/gstrtpulpfecdec.h

index b7949c6..e45e8a7 100644 (file)
                     }
                 },
                 "properties": {
+                    "passthrough": {
+                        "blurb": "Whether to passthrough all data as-is without modification and never attempt to recover packets",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
                     "pt": {
                         "blurb": "FEC packets payload type",
                         "conditionally-available": false,
index cfc2229..beb0432 100644 (file)
@@ -85,10 +85,12 @@ enum
   PROP_STORAGE,
   PROP_RECOVERED,
   PROP_UNRECOVERED,
+  PROP_PASSTHROUGH,
   N_PROPERTIES
 };
 
 #define DEFAULT_FEC_PT 0
+#define DEFAULT_PASSTHROUGH FALSE
 
 static GParamSpec *klass_properties[N_PROPERTIES] = { NULL, };
 
@@ -378,6 +380,7 @@ gst_rtp_ulpfec_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 
   if (G_LIKELY (GST_FLOW_OK == self->chain_return_val)) {
     GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+    gboolean passthrough;
     buf = gst_buffer_make_writable (buf);
 
     if (G_UNLIKELY (self->unset_discont_flag)) {
@@ -385,8 +388,20 @@ gst_rtp_ulpfec_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
     }
 
+    GST_OBJECT_LOCK (self);
+    if (G_UNLIKELY (self->needs_discont)) {
+      self->needs_discont = FALSE;
+      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+    }
+    passthrough = self->passthrough;
+    GST_OBJECT_UNLOCK (self);
+
     gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtp);
-    gst_rtp_buffer_set_seq (&rtp, self->next_seqnum++);
+    if (passthrough) {
+      self->next_seqnum = gst_rtp_buffer_get_seq (&rtp) + 1;
+    } else {
+      gst_rtp_buffer_set_seq (&rtp, self->next_seqnum++);
+    }
     gst_rtp_buffer_unmap (&rtp);
 
     return gst_pad_push (self->srcpad, buf);
@@ -442,6 +457,13 @@ gst_rtp_ulpfec_dec_handle_packet_loss (GstRtpUlpFecDec * self, guint16 seqnum,
         gst_rtp_buffer_set_seq (&rtp, self->next_seqnum++);
         gst_rtp_buffer_unmap (&rtp);
 
+        GST_OBJECT_LOCK (self);
+        if (G_UNLIKELY (self->needs_discont)) {
+          self->needs_discont = FALSE;
+          GST_BUFFER_FLAG_SET (sent_buffer, GST_BUFFER_FLAG_DISCONT);
+        }
+        GST_OBJECT_UNLOCK (self);
+
         ret = FALSE;
         self->unset_discont_flag = TRUE;
         self->chain_return_val = gst_pad_push (self->srcpad, sent_buffer);
@@ -481,6 +503,18 @@ gst_rtp_ulpfec_dec_handle_sink_event (GstPad * pad, GstObject * parent,
     guint seqnum;
     GstClockTime timestamp, duration;
     GstStructure *s;
+    gboolean passthrough;
+
+    GST_OBJECT_LOCK (self);
+    passthrough = self->passthrough;
+    GST_OBJECT_UNLOCK (self);
+
+    if (passthrough) {
+      GST_TRACE_OBJECT (self,
+          "in passthrough mode, ignoring packet loss event");
+      forward = TRUE;
+      goto out;
+    }
 
     event = gst_event_make_writable (event);
     s = gst_event_writable_structure (event);
@@ -555,6 +589,7 @@ gst_rtp_ulpfec_dec_handle_sink_event (GstPad * pad, GstObject * parent,
     self->caps_pt = caps_pt;
   }
 
+out:
   if (forward)
     return gst_pad_push_event (self->srcpad, event);
   gst_event_unref (event);
@@ -577,6 +612,7 @@ gst_rtp_ulpfec_dec_init (GstRtpUlpFecDec * self)
   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
 
   self->fec_pt = DEFAULT_FEC_PT;
+  self->passthrough = DEFAULT_PASSTHROUGH;
 
   self->next_seqnum = g_random_int_range (0, G_MAXINT16);
 
@@ -642,6 +678,20 @@ gst_rtp_ulpfec_dec_set_property (GObject * object, guint prop_id,
       if (self->storage)
         g_object_ref (self->storage);
       break;
+    case PROP_PASSTHROUGH:{
+      gboolean newval = g_value_get_boolean (value);
+      GST_OBJECT_LOCK (self);
+      /* if we changing into non-passthrough mode, then the sequence numbers may
+       * be completely different and we need to advertise that with a discont */
+      GST_INFO_OBJECT (self, "passthrough changing from %u to %u",
+          self->passthrough, newval);
+      if (self->passthrough && !newval) {
+        self->needs_discont = TRUE;
+      }
+      self->passthrough = newval;
+      GST_OBJECT_UNLOCK (self);
+      break;
+    }
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -667,6 +717,9 @@ gst_rtp_ulpfec_dec_get_property (GObject * object, guint prop_id,
     case PROP_UNRECOVERED:
       g_value_set_uint (value, (guint) self->packets_unrecovered);
       break;
+    case PROP_PASSTHROUGH:
+      g_value_set_boolean (value, self->passthrough);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -712,6 +765,19 @@ gst_rtp_ulpfec_dec_class_init (GstRtpUlpFecDecClass * klass)
       g_param_spec_uint ("unrecovered", "unrecovered",
       "The number of unrecovered packets", 0, G_MAXUINT, 0,
       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  /**
+   * GstRtpUlpFecDec:passthrough:
+   *
+   * Whether to push data through without any modification.  If passthrough is
+   * enabled, then no packets will ever be recovered.
+   *
+   * Since: 1.22
+   */
+  klass_properties[PROP_PASSTHROUGH] =
+      g_param_spec_boolean ("passthrough", "Passthrough",
+      "Whether to passthrough all data as-is without modification and "
+      "never attempt to recover packets", DEFAULT_PASSTHROUGH,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (gobject_class, N_PROPERTIES,
       klass_properties);
index f9b10b0..b54e82e 100644 (file)
@@ -55,10 +55,12 @@ struct _GstRtpUlpFecDec {
   RtpStorage *storage;
   gsize packets_recovered;
   gsize packets_unrecovered;
+  gboolean passthrough;
 
   /* internal stuff */
   GstFlowReturn chain_return_val;
   gboolean unset_discont_flag;
+  gboolean needs_discont;
   gboolean have_caps_ssrc;
   gboolean have_caps_pt;
   guint32 caps_ssrc;