rtpvrawpay: use buffer lists
authorTim-Philipp Müller <tim@centricular.com>
Mon, 16 Jun 2014 12:38:47 +0000 (13:38 +0100)
committerTim-Philipp Müller <tim@centricular.com>
Wed, 18 Jun 2014 13:54:58 +0000 (14:54 +0100)
Collect buffers to send out in buffer lists instead of
pushing out single buffers one at a time. For HD video
each frame might easily add up to a couple of thousand
packets, multiply that by the frame rate and that's a
lot of push() and sendmsg() calls per second.

A good reason to push out buffers as early as possible is
latency, so we don't accumulate the whole frame in a single
buffer list, but instead push it out in a few chunks, which
is hopefully a reasonable compromise.

gst/rtp/gstrtpvrawpay.c

index cade178..4242c0d 100644 (file)
@@ -239,15 +239,18 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
 {
   GstRtpVRawPay *rtpvrawpay;
   GstFlowReturn ret = GST_FLOW_OK;
+  guint lines_delay;            /* after how many packed lines we push out a buffer list */
+  guint last_line;              /* last pack line number we pushed out a buffer list     */
   guint line, offset;
   guint8 *p0, *yp, *up, *vp;
   guint ystride, uvstride;
   guint pgroup;
   guint mtu;
   guint width, height;
-  gint field;
+  gint field, fields;
   GstVideoFrame frame;
   gint interlaced;
+  GstBufferList *list;
   GstRTPBuffer rtp = { NULL, };
 
   rtpvrawpay = GST_RTP_VRAW_PAY (payload);
@@ -275,17 +278,25 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
 
   interlaced = GST_VIDEO_INFO_IS_INTERLACED (&rtpvrawpay->vinfo);
 
+  /* after how many packed lines we push out a buffer list */
+  lines_delay = GST_ROUND_UP_4 (height / 10);
+
+  fields = 1 + interlaced;
+
   /* start with line 0, offset 0 */
-  for (field = 0; field < 1 + interlaced; field++) {
+  for (field = 0; field < fields; field++) {
     line = field;
     offset = 0;
+    last_line = 0;
+
+    list = gst_buffer_list_new ();
 
     /* write all lines */
     while (line < height) {
-      guint left;
+      guint left, pack_line;
       GstBuffer *out;
       guint8 *outdata, *headers;
-      gboolean next_line;
+      gboolean next_line, complete = FALSE;
       guint length, cont, pixels;
 
       /* get the max allowed payload length size, we try to fill the complete MTU */
@@ -496,6 +507,7 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
       if (line >= height) {
         GST_LOG_OBJECT (rtpvrawpay, "field/frame complete, set marker");
         gst_rtp_buffer_set_marker (&rtp, TRUE);
+        complete = TRUE;
       }
       gst_rtp_buffer_unmap (&rtp);
       if (left > 0) {
@@ -503,8 +515,19 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
         gst_buffer_resize (out, 0, gst_buffer_get_size (out) - left);
       }
 
-      /* push buffer */
-      ret = gst_rtp_base_payload_push (payload, out);
+      gst_buffer_list_add (list, out);
+
+      pack_line = (line - field) / fields;
+      if (complete || (pack_line > last_line && pack_line % lines_delay == 0)) {
+        /* push buffers */
+        GST_LOG_OBJECT (rtpvrawpay, "pushing list of %u buffers up to pack "
+            "line %u", gst_buffer_list_length (list), pack_line);
+        ret = gst_rtp_base_payload_push_list (payload, list);
+        list = NULL;
+        if (!complete)
+          list = gst_buffer_list_new ();
+        last_line = pack_line;
+      }
     }
 
   }