vrawpay: Error out cleanly if mapping the video frame fails
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpvrawpay.c
index f4b78ca..9368936 100644 (file)
 #include <string.h>
 
 #include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
 
 #include "gstrtpvrawpay.h"
+#include "gstrtputils.h"
+
+enum
+{
+  PROP_CHUNKS_PER_FRAME = 1
+};
+
+#define DEFAULT_CHUNKS_PER_FRAME 10
 
 GST_DEBUG_CATEGORY_STATIC (rtpvrawpay_debug);
 #define GST_CAT_DEFAULT (rtpvrawpay_debug)
@@ -70,6 +79,10 @@ static gboolean gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload,
     GstCaps * caps);
 static GstFlowReturn gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload *
     payload, GstBuffer * buffer);
+static void gst_rtp_vraw_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtp_vraw_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
 
 G_DEFINE_TYPE (GstRtpVRawPay, gst_rtp_vraw_pay, GST_TYPE_RTP_BASE_PAYLOAD)
 
@@ -77,17 +90,30 @@ G_DEFINE_TYPE (GstRtpVRawPay, gst_rtp_vraw_pay, GST_TYPE_RTP_BASE_PAYLOAD)
 {
   GstRTPBasePayloadClass *gstrtpbasepayload_class;
   GstElementClass *gstelement_class;
+  GObjectClass *gobject_class;
 
+  gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
   gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
 
+  gobject_class->set_property = gst_rtp_vraw_pay_set_property;
+  gobject_class->get_property = gst_rtp_vraw_pay_get_property;
+
+  g_object_class_install_property (gobject_class,
+      PROP_CHUNKS_PER_FRAME,
+      g_param_spec_int ("chunks-per-frame", "Chunks per Frame",
+          "Split and send out each frame in multiple chunks to reduce overhead",
+          1, G_MAXINT, DEFAULT_CHUNKS_PER_FRAME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
   gstrtpbasepayload_class->set_caps = gst_rtp_vraw_pay_setcaps;
   gstrtpbasepayload_class->handle_buffer = gst_rtp_vraw_pay_handle_buffer;
 
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&gst_rtp_vraw_pay_src_template));
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&gst_rtp_vraw_pay_sink_template));
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vraw_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_vraw_pay_sink_template);
 
   gst_element_class_set_static_metadata (gstelement_class,
       "RTP Raw Video payloader", "Codec/Payloader/Network/RTP",
@@ -101,6 +127,7 @@ G_DEFINE_TYPE (GstRtpVRawPay, gst_rtp_vraw_pay, GST_TYPE_RTP_BASE_PAYLOAD)
 static void
 gst_rtp_vraw_pay_init (GstRtpVRawPay * rtpvrawpay)
 {
+  rtpvrawpay->chunks_per_frame = DEFAULT_CHUNKS_PER_FRAME;
 }
 
 static gboolean
@@ -111,7 +138,6 @@ gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
   gint pgroup, xinc, yinc;
   const gchar *depthstr, *samplingstr, *colorimetrystr;
   gchar *wstr, *hstr;
-  gint depth;
   GstVideoInfo info;
 
   rtpvrawpay = GST_RTP_VRAW_PAY (payload);
@@ -138,7 +164,6 @@ gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
 
   /* these values are the only thing we can do */
   depthstr = "8";
-  depth = 8;
 
   switch (GST_VIDEO_INFO_FORMAT (&info)) {
     case GST_VIDEO_FORMAT_RGBA:
@@ -180,7 +205,6 @@ gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
       samplingstr = "YCbCr-4:2:2";
       pgroup = 5;
       xinc = 2;
-      depth = 10;
       depthstr = "10";
       break;
     default:
@@ -195,7 +219,6 @@ gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
   rtpvrawpay->pgroup = pgroup;
   rtpvrawpay->xinc = xinc;
   rtpvrawpay->yinc = yinc;
-  rtpvrawpay->depth = depth;
 
   GST_DEBUG_OBJECT (payload, "width %d, height %d, sampling %s",
       GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info), samplingstr);
@@ -239,6 +262,9 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
 {
   GstRtpVRawPay *rtpvrawpay;
   GstFlowReturn ret = GST_FLOW_OK;
+  gfloat packets_per_packline;
+  guint pgroups_per_packet;
+  guint packlines_per_list, buffers_per_list;
   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;
@@ -252,12 +278,16 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
   GstVideoFormat format;
   GstVideoFrame frame;
   gint interlaced;
-  GstBufferList *list;
+  gboolean use_buffer_lists;
+  GstBufferList *list = NULL;
   GstRTPBuffer rtp = { NULL, };
 
   rtpvrawpay = GST_RTP_VRAW_PAY (payload);
 
-  gst_video_frame_map (&frame, &rtpvrawpay->vinfo, buffer, GST_MAP_READ);
+  if (!gst_video_frame_map (&frame, &rtpvrawpay->vinfo, buffer, GST_MAP_READ)) {
+    gst_buffer_unref (buffer);
+    return GST_FLOW_ERROR;
+  }
 
   GST_LOG_OBJECT (rtpvrawpay, "new frame of %" G_GSIZE_FORMAT " bytes",
       gst_buffer_get_size (buffer));
@@ -286,7 +316,16 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
   xinc = rtpvrawpay->xinc;
 
   /* after how many packed lines we push out a buffer list */
-  lines_delay = GST_ROUND_UP_4 (height / 10);
+  lines_delay = GST_ROUND_UP_4 (height / rtpvrawpay->chunks_per_frame);
+
+  /* calculate how many buffers we expect to store in a single buffer list */
+  pgroups_per_packet = (mtu - (12 + 14)) / pgroup;
+  packets_per_packline = width / (xinc * pgroups_per_packet * 1.0);
+  packlines_per_list = height / (yinc * rtpvrawpay->chunks_per_frame);
+  buffers_per_list = packlines_per_list * packets_per_packline;
+  buffers_per_list = GST_ROUND_UP_8 (buffers_per_list);
+
+  use_buffer_lists = (rtpvrawpay->chunks_per_frame < (height / yinc));
 
   fields = 1 + interlaced;
 
@@ -296,7 +335,8 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
     offset = 0;
     last_line = 0;
 
-    list = gst_buffer_list_new ();
+    if (use_buffer_lists)
+      list = gst_buffer_list_new_sized (buffers_per_list);
 
     /* write all lines */
     while (line < height) {
@@ -311,9 +351,9 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
       out = gst_rtp_buffer_new_allocate (left, 0, 0);
 
       if (field == 0) {
-        GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (buffer);
+        GST_BUFFER_PTS (out) = GST_BUFFER_PTS (buffer);
       } else {
-        GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (buffer) +
+        GST_BUFFER_PTS (out) = GST_BUFFER_PTS (buffer) +
             GST_BUFFER_DURATION (buffer) / 2;
       }
 
@@ -520,17 +560,28 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
         gst_buffer_resize (out, 0, gst_buffer_get_size (out) - left);
       }
 
+      gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpvrawpay), out, buffer,
+          g_quark_from_static_string (GST_META_TAG_VIDEO_STR));
+
+
+      /* Now either push out the buffer directly */
+      if (!use_buffer_lists) {
+        ret = gst_rtp_base_payload_push (payload, out);
+        continue;
+      }
+
+      /* or add the buffer to buffer list ... */
       gst_buffer_list_add (list, out);
 
+      /* .. and check if we need to push out the list */
       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 ();
+          list = gst_buffer_list_new_sized (buffers_per_list);
         last_line = pack_line;
       }
     }
@@ -561,6 +612,42 @@ too_small:
   }
 }
 
+static void
+gst_rtp_vraw_pay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpVRawPay *rtpvrawpay;
+
+  rtpvrawpay = GST_RTP_VRAW_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CHUNKS_PER_FRAME:
+      rtpvrawpay->chunks_per_frame = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_vraw_pay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpVRawPay *rtpvrawpay;
+
+  rtpvrawpay = GST_RTP_VRAW_PAY (object);
+
+  switch (prop_id) {
+    case PROP_CHUNKS_PER_FRAME:
+      g_value_set_int (value, rtpvrawpay->chunks_per_frame);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
 gboolean
 gst_rtp_vraw_pay_plugin_init (GstPlugin * plugin)
 {