basertppayload: add support for bufferlists
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 19 Jun 2009 13:52:34 +0000 (15:52 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 19 Jun 2009 13:52:34 +0000 (15:52 +0200)
Based on patch from Ognyan Tonchev.

See #585559

docs/libs/gst-plugins-base-libs-sections.txt
gst-libs/gst/rtp/gstbasertppayload.c
gst-libs/gst/rtp/gstbasertppayload.h
win32/common/libgstrtp.def

index c4ce069..9f42217 100644 (file)
@@ -990,6 +990,7 @@ GST_BASE_RTP_PAYLOAD_SRCPAD
 
 gst_basertppayload_is_filled
 gst_basertppayload_push
+gst_basertppayload_push_list
 gst_basertppayload_set_options
 gst_basertppayload_set_outcaps
 <SUBSECTION Standard>
index 1121cc9..861bb60 100644 (file)
@@ -613,87 +613,177 @@ gst_basertppayload_is_filled (GstBaseRTPPayload * payload,
   return FALSE;
 }
 
-/**
- * gst_basertppayload_push:
- * @payload: a #GstBaseRTPPayload
- * @buffer: a #GstBuffer
- *
- * Push @buffer to the peer element of the payloader. The SSRC, payload type,
- * seqnum and timestamp of the RTP buffer will be updated first.
- * 
- * This function takes ownership of @buffer.
- *
- * Returns: a #GstFlowReturn.
- */
-GstFlowReturn
-gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer)
+typedef struct
 {
-  GstFlowReturn res;
+  GstBaseRTPPayload *payload;
+  guint32 ssrc;
+  guint16 seqnum;
+  guint8 pt;
+  GstCaps *caps;
   GstClockTime timestamp;
   guint32 rtptime;
+} HeaderData;
+
+static GstBufferListItem
+find_timestamp (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
+{
+  data->timestamp = GST_BUFFER_TIMESTAMP (*buffer);
+
+  /* stop when we find a timestamp */
+  if (data->timestamp != -1)
+    return GST_BUFFER_LIST_END;
+  else
+    return GST_BUFFER_LIST_CONTINUE;
+}
+
+static GstBufferListItem
+set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
+{
+  gst_rtp_buffer_set_ssrc (*buffer, data->ssrc);
+  gst_rtp_buffer_set_payload_type (*buffer, data->pt);
+  gst_rtp_buffer_set_seq (*buffer, data->seqnum);
+  gst_rtp_buffer_set_timestamp (*buffer, data->rtptime);
+  gst_buffer_set_caps (*buffer, data->caps);
+  data->seqnum++;
+
+  return GST_BUFFER_LIST_SKIP_GROUP;
+}
+
+/* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer
+ * before the buffer is pushed. */
+static GstFlowReturn
+gst_basertppayload_prepare_push (GstBaseRTPPayload * payload,
+    gpointer obj, gboolean is_list)
+{
   GstBaseRTPPayloadPrivate *priv;
+  HeaderData data;
 
   if (payload->clock_rate == 0)
     goto no_rate;
 
   priv = payload->priv;
 
-  gst_rtp_buffer_set_ssrc (buffer, payload->current_ssrc);
-
-  gst_rtp_buffer_set_payload_type (buffer, payload->pt);
-
   /* update first, so that the property is set to the last
    * seqnum pushed */
   payload->seqnum = priv->next_seqnum;
-  gst_rtp_buffer_set_seq (buffer, payload->seqnum);
 
-  /* can wrap around, which is perfectly fine */
-  priv->next_seqnum++;
-
-  /* add our random offset to the timestamp */
-  rtptime = payload->ts_base;
+  /* fill in the fields we want to set on all headers */
+  data.payload = payload;
+  data.seqnum = payload->seqnum;
+  data.ssrc = payload->current_ssrc;
+  data.pt = payload->pt;
+  data.caps = GST_PAD_CAPS (payload->srcpad);
+  data.timestamp = -1;
+
+  /* find the first buffer with a timestamp */
+  if (is_list) {
+    gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj),
+        (GstBufferListFunc) find_timestamp, &data);
+  } else {
+    data.timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (obj));
+  }
 
-  timestamp = GST_BUFFER_TIMESTAMP (buffer);
-  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+  /* convert to RTP time */
+  if (GST_CLOCK_TIME_IS_VALID (data.timestamp)) {
     gint64 rtime;
 
     rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME,
-        timestamp);
+        data.timestamp);
 
     rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND);
 
     /* add running_time in clock-rate units to the base timestamp */
-    rtptime += rtime;
+    data.rtptime = payload->ts_base + rtime;
   } else {
     /* no timestamp to convert, take previous timestamp */
-    rtptime = payload->timestamp;
+    data.rtptime = payload->timestamp;
   }
-  gst_rtp_buffer_set_timestamp (buffer, rtptime);
 
-  payload->timestamp = rtptime;
+  /* set ssrc, payload type, seq number, caps and rtptime */
+  if (is_list) {
+    gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj),
+        (GstBufferListFunc) set_headers, &data);
+  } else {
+    GstBuffer *buf = GST_BUFFER_CAST (obj);
+    set_headers (&buf, 0, 0, &data);
+  }
 
-  /* set caps */
-  gst_buffer_set_caps (buffer, GST_PAD_CAPS (payload->srcpad));
+  priv->next_seqnum = data.seqnum;
+  payload->timestamp = data.rtptime;
 
   GST_LOG_OBJECT (payload,
-      "Pushing packet size %d, seq=%d, rtptime=%u, timestamp %" GST_TIME_FORMAT,
-      GST_BUFFER_SIZE (buffer), payload->seqnum, rtptime,
-      GST_TIME_ARGS (timestamp));
+      "Preparing to push packet with size %d, seq=%d, rtptime=%u, timestamp %"
+      GST_TIME_FORMAT, (is_list) ? -1 :
+      GST_BUFFER_SIZE (GST_BUFFER (obj)), payload->seqnum, data.rtptime,
+      GST_TIME_ARGS (data.timestamp));
 
-  res = gst_pad_push (payload->srcpad, buffer);
-
-  return res;
+  return GST_FLOW_OK;
 
   /* ERRORS */
 no_rate:
   {
     GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL),
         ("subclass did not specify clock-rate"));
-    gst_buffer_unref (buffer);
     return GST_FLOW_ERROR;
   }
 }
 
+/**
+ * gst_basertppayload_push_list:
+ * @payload: a #GstBaseRTPPayload
+ * @list: a #GstBufferList
+ *
+ * Push @list to the peer element of the payloader. The SSRC, payload type,
+ * seqnum and timestamp of the RTP buffer will be updated first.
+ *
+ * This function takes ownership of @list.
+ *
+ * Returns: a #GstFlowReturn.
+ *
+ * Since: 0.10.24
+ */
+GstFlowReturn
+gst_basertppayload_push_list (GstBaseRTPPayload * payload, GstBufferList * list)
+{
+  GstFlowReturn res;
+
+  res = gst_basertppayload_prepare_push (payload, list, TRUE);
+
+  if (G_LIKELY (res == GST_FLOW_OK))
+    res = gst_pad_push_list (payload->srcpad, list);
+  else
+    gst_buffer_list_unref (list);
+
+  return res;
+}
+
+/**
+ * gst_basertppayload_push:
+ * @payload: a #GstBaseRTPPayload
+ * @buffer: a #GstBuffer
+ *
+ * Push @buffer to the peer element of the payloader. The SSRC, payload type,
+ * seqnum and timestamp of the RTP buffer will be updated first.
+ * 
+ * This function takes ownership of @buffer.
+ *
+ * Returns: a #GstFlowReturn.
+ */
+GstFlowReturn
+gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer)
+{
+  GstFlowReturn res;
+
+  res = gst_basertppayload_prepare_push (payload, buffer, FALSE);
+
+  if (G_LIKELY (res == GST_FLOW_OK))
+    res = gst_pad_push (payload->srcpad, buffer);
+  else
+    gst_buffer_unref (buffer);
+
+  return res;
+}
+
 static void
 gst_basertppayload_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
index 4a1d751..b87534c 100644 (file)
@@ -144,6 +144,9 @@ gboolean        gst_basertppayload_is_filled            (GstBaseRTPPayload *payl
 GstFlowReturn   gst_basertppayload_push                 (GstBaseRTPPayload *payload, 
                                                          GstBuffer *buffer);
 
+GstFlowReturn   gst_basertppayload_push_list            (GstBaseRTPPayload *payload,
+                                                         GstBufferList *list);
+
 G_END_DECLS
 
 #endif /* __GST_BASE_RTP_PAYLOAD_H__ */
index 5fb2b4b..75aaa9b 100644 (file)
@@ -13,6 +13,7 @@ EXPORTS
        gst_basertppayload_get_type
        gst_basertppayload_is_filled
        gst_basertppayload_push
+       gst_basertppayload_push_list
        gst_basertppayload_set_options
        gst_basertppayload_set_outcaps
        gst_rtcp_buffer_add_packet