[TensorDemux] Implement Chain function
authorjijoong.moon <jijoong.moon@samsung.com>
Wed, 25 Jul 2018 00:33:08 +0000 (09:33 +0900)
committer함명주/동작제어Lab(SR)/Principal Engineer/삼성전자 <myungjoo.ham@samsung.com>
Thu, 26 Jul 2018 04:20:52 +0000 (13:20 +0900)
Add chain function to create source pad for each tensor in tensors. In
order to do it, created source pad is stored in srcpads list and
compared with order of tensor to identify if created one or not.

- Add gst_tensor_demux_chain
- Add gst_get_tensor_pad
- Add gst_tensor_demux_event
- Add gst_tensor_demux_get_capsparam

Signed-off-by: jijoong.moon <jijoong.moon@samsung.com>
gst/tensor_demux/gsttensordemux.c
gst/tensor_demux/gsttensordemux.h

index 957276b..3aa3aa3 100644 (file)
@@ -151,17 +151,21 @@ gst_tensor_demux_init (GstTensorDemux * tensor_demux)
       GST_DEBUG_FUNCPTR (gst_tensor_demux_event));
 
   tensor_demux->num_tensors = 0;
+  tensor_demux->num_srcpads = 0;
   tensor_demux->silent = FALSE;
   tensor_demux->singleStream = FALSE;
+  tensor_demux->have_group_id = FALSE;
+  tensor_demux->group_id = G_MAXUINT;
+  tensor_demux->srcpads = NULL;
 }
 
 /**
- * @brief function to remove srcpad listfor sink (gst element vmethod)
+ * @brief function to remove srcpad list for sink (gst element vmethod)
  */
 static void
 gst_tensor_demux_remove_src_pads (GstTensorDemux * tensor_demux)
 {
-  while (tensor_demux != NULL) {
+  while (tensor_demux->srcpads != NULL) {
     GstTensorPad *tensor_pad = tensor_demux->srcpads->data;
     gst_element_remove_pad (GST_ELEMENT (tensor_demux), tensor_pad->pad);
     g_free (tensor_pad);
@@ -170,10 +174,11 @@ gst_tensor_demux_remove_src_pads (GstTensorDemux * tensor_demux)
   }
   tensor_demux->srcpads = NULL;
   tensor_demux->num_tensors = 0;
+  tensor_demux->num_srcpads = 0;
 }
 
 /**
- * @brief dispose function for sink (gst element vmethod)
+ * @brief dispose function for tensor demux (gst element vmethod)
  */
 static void
 gst_tensor_demux_dispose (GObject * object)
@@ -186,6 +191,28 @@ gst_tensor_demux_dispose (GObject * object)
 }
 
 /**
+ * @brief Set Caps in pad.
+ * @param tensor_demux GstTensorDemux Ojbect
+ * @param caps incomming capablity
+ * @return TRUE/FALSE (if successfully generate & set cap, return TRUE)
+ */
+static gboolean
+gst_tensor_demux_get_capsparam (GstTensorDemux * tensor_demux, GstCaps * caps)
+{
+  gboolean ret = FALSE;
+
+  GstStructure *s = gst_caps_get_structure (caps, 0);
+  if (gst_structure_get_int (s, "num_tensors",
+          (int *) &tensor_demux->num_tensors)
+      && gst_structure_get_fraction (s, "framerate",
+          &tensor_demux->framerate_numerator,
+          &tensor_demux->framerate_denominator))
+    ret = TRUE;
+
+  return ret;
+}
+
+/**
  * @brief event function for sink (gst element vmethod)
  */
 static gboolean
@@ -193,7 +220,15 @@ gst_tensor_demux_event (GstPad * pad, GstObject * parent, GstEvent * event)
 {
   GstTensorDemux *tensor_demux;
   tensor_demux = GST_TENSOR_DEMUX (parent);
+
   switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+      gst_event_parse_caps (event, &caps);
+      gst_tensor_demux_get_capsparam (tensor_demux, caps);
+      return gst_pad_event_default (pad, parent, event);
+    }
     case GST_EVENT_EOS:
       if (!tensor_demux->srcpads) {
         GST_ELEMENT_ERROR (tensor_demux, STREAM, WRONG_TYPE,
@@ -211,17 +246,215 @@ gst_tensor_demux_event (GstPad * pad, GstObject * parent, GstEvent * event)
 }
 
 /**
+ * @brief Checking if the source pad is created and if not, create TensorPad
+ * @param tesnor_demux TensorDemux Object
+ * @param inbuf inputbuf GstBuffer Object including GstMeta
+ * @param[out] created will be updated in this function
+ * @param nth source ordering
+ * @return TensorPad if pad is already created, then return created pad.
+ *         If not return new pad after creation.
+ */
+static GstTensorPad *
+gst_get_tensor_pad (GstTensorDemux * tensor_demux, GstBuffer * inbuf,
+    gboolean * created, gint nth)
+{
+  GSList *walk;
+  walk = tensor_demux->srcpads;
+  while (walk) {
+    GstTensorPad *pad = (GstTensorPad *) walk->data;
+    if (nth == pad->nth) {
+      if (created) {
+        *created = FALSE;
+      }
+      return pad;
+    }
+    walk = walk->next;
+  }
+
+  GstPad *pad;
+  GstTensorPad *tensorpad;
+  gchar *name;
+  GstEvent *event;
+  gchar *stream_id;
+  GstCaps *caps;
+  gchar *caps_string;
+  tensor_dim *dim;
+  tensor_type type;
+
+  tensorpad = g_new0 (GstTensorPad, 1);
+  GST_DEBUG_OBJECT (tensor_demux, "createing pad: %d",
+      tensor_demux->num_srcpads);
+
+  name = g_strdup_printf ("src_%u", tensor_demux->num_srcpads);
+  pad = gst_pad_new_from_static_template (&src_templ, name);
+  g_free (name);
+
+  tensorpad->pad = pad;
+  tensorpad->nth = nth;
+  tensorpad->last_ret = GST_FLOW_OK;
+  tensorpad->last_ts = GST_CLOCK_TIME_NONE;
+  tensorpad->discont = TRUE;
+
+  tensor_demux->srcpads = g_slist_append (tensor_demux->srcpads, tensorpad);
+  dim = gst_get_tensordim (inbuf, tensor_demux->num_srcpads);
+  type = gst_get_tensortype (inbuf, tensor_demux->num_srcpads);
+
+  tensor_demux->num_srcpads++;
+
+  gst_pad_use_fixed_caps (pad);
+  gst_pad_set_active (pad, TRUE);
+
+
+  if (!tensor_demux->have_group_id) {
+    event =
+        gst_pad_get_sticky_event (tensor_demux->sinkpad, GST_EVENT_STREAM_START,
+        0);
+    if (event) {
+      tensor_demux->have_group_id =
+          gst_event_parse_group_id (event, &tensor_demux->group_id);
+      gst_event_unref (event);
+    } else if (!tensor_demux->have_group_id) {
+      tensor_demux->have_group_id = TRUE;
+      tensor_demux->group_id = gst_util_group_id_next ();
+    }
+  }
+
+  stream_id =
+      gst_pad_create_stream_id (pad, GST_ELEMENT_CAST (tensor_demux),
+      "other/tensors");
+
+  event = gst_event_new_stream_start (stream_id);
+  if (tensor_demux->have_group_id)
+    gst_event_set_group_id (event, tensor_demux->group_id);
+
+  gst_pad_store_sticky_event (pad, event);
+  g_free (stream_id);
+  gst_event_unref (event);
+
+  caps_string = g_strdup_printf ("other/tensor, "
+      "rank = (int)4, "
+      "type = (string)%s,"
+      "framerate = (fraction) %d/%d, "
+      "dim1 = (int) %d, "
+      "dim2 = (int) %d, "
+      "dim3 = (int) %d, "
+      "dim4 = (int) %d", tensor_element_typename[type],
+      tensor_demux->framerate_numerator, tensor_demux->framerate_denominator,
+      (*dim)[0], (*dim)[1], (*dim)[2], (*dim)[3]);
+
+  caps = gst_caps_from_string (caps_string);
+  GST_DEBUG_OBJECT (tensor_demux, "caps for pad : %s", caps_string);
+
+  g_free (caps_string);
+  gst_pad_set_caps (pad, caps);
+  gst_element_add_pad (GST_ELEMENT_CAST (tensor_demux), pad);
+
+  gst_caps_unref (caps);
+
+  if (created) {
+    *created = TRUE;
+  }
+
+  if (tensor_demux->singleStream) {
+    gst_element_no_more_pads (GST_ELEMENT_CAST (tensor_demux));
+  }
+
+  return tensorpad;
+}
+
+/**
+ * @brief Check the status among sources in demux
+ * @param tensor_demux TensorDemux Object
+ * @param TensorPad Tensorpad
+ * @param ret return status of current pad
+ * @return return status after check sources
+ */
+static GstFlowReturn
+gst_tensordemux_combine_flows (GstTensorDemux * tensor_demux,
+    GstTensorPad * pad, GstFlowReturn ret)
+{
+  GSList *walk;
+  pad->last_ret = ret;
+
+  if (ret != GST_FLOW_NOT_LINKED)
+    goto done;
+
+  for (walk = tensor_demux->srcpads; walk; walk = g_slist_next (walk)) {
+    GstTensorPad *opad = (GstTensorPad *) walk->data;
+    ret = opad->last_ret;
+    if (ret != GST_FLOW_NOT_LINKED)
+      goto done;
+  }
+done:
+  return ret;
+}
+
+/**
  * @brief chain function for sink (gst element vmethod)
  */
 static GstFlowReturn
 gst_tensor_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 {
+  gint num_tensors, i;
   GstFlowReturn res = GST_FLOW_OK;
+  GstTensorDemux *tensor_demux;
+  tensor_demux = GST_TENSOR_DEMUX (parent);
 
-  /* GstTensorDemux *tensor_demux; */
-  /* tensor_demux = GST_TENSOR_DEMUX (parent); */
+  if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
+    GSList *l;
+    for (l = tensor_demux->srcpads; l != NULL; l = l->next) {
+      GstTensorPad *srcpad = l->data;
+      srcpad->discont = TRUE;
+    }
+  }
 
-  /* NYI */
+  num_tensors = gst_get_num_tensors (buf);
+
+  GST_DEBUG_OBJECT (tensor_demux, " Number or Tensors: %d", num_tensors);
+
+  for (i = 0; i < num_tensors; i++) {
+    GstTensorPad *srcpad;
+    GstBuffer *outbuf;
+    GstMemory *mem;
+    gboolean created;
+    GstClockTime ts;
+    srcpad = gst_get_tensor_pad (tensor_demux, buf, &created, i);
+
+    outbuf = gst_buffer_new ();
+    mem = gst_get_tensor (buf, i);
+    gst_buffer_append_memory (outbuf, mem);
+    ts = GST_BUFFER_PTS (buf);
+
+    if (created) {
+      GstSegment segment;
+      gst_segment_init (&segment, GST_FORMAT_TIME);
+      gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
+    }
+
+    outbuf = gst_buffer_make_writable (outbuf);
+    if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
+      GST_BUFFER_TIMESTAMP (outbuf) = ts;
+      srcpad->last_ts = ts;
+    } else {
+      GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
+    }
+
+    if (srcpad->discont) {
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+      srcpad->discont = FALSE;
+    } else {
+      GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DISCONT);
+    }
+
+    GST_DEBUG_OBJECT (tensor_demux,
+        "pushing buffer with timestamp %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
+    res = gst_pad_push (srcpad->pad, outbuf);
+    res = gst_tensordemux_combine_flows (tensor_demux, srcpad, res);
+
+    if (res != GST_FLOW_OK)
+      break;
+  }
 
   return res;
 }
@@ -235,15 +468,15 @@ gst_tensor_demux_change_state (GstElement * element, GstStateChange transition)
   GstTensorDemux *tensor_demux;
   GstStateChangeReturn ret;
   tensor_demux = GST_TENSOR_DEMUX (element);
-
   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
   if (ret == GST_STATE_CHANGE_FAILURE)
     return ret;
-
   switch (transition) {
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
+      tensor_demux->group_id = G_MAXUINT;
+      tensor_demux->have_group_id = FALSE;
       gst_tensor_demux_remove_src_pads (tensor_demux);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
@@ -297,7 +530,6 @@ gst_tensor_demux_get_property (GObject * object, guint prop_id,
   }
 }
 
-
 /**
  * PACKAGE: this is usually set by autotools depending on some _INIT macro
  * in configure.ac and then written into and defined in config.h, but we can
@@ -317,7 +549,7 @@ gboolean
 gst_tensor_demux_plugin_init (GstPlugin * tensordemux)
 {
   /** debug category for fltering log messages
-   * exchange the string 'Template tensor_mux' with your description
+   * exchange the string 'Template tensor_demux' with your description
    */
   GST_DEBUG_CATEGORY_INIT (gst_tensor_demux_debug, "tensordemux", 0,
       "Tensor Demuxer");
index b9a6cf8..5dd371d 100644 (file)
@@ -52,6 +52,7 @@ typedef struct
   GstClockTime last_ts;
   GstFlowReturn last_ret;
   gboolean discont;
+  gint nth;
 } GstTensorPad;
 
 /**
@@ -65,7 +66,12 @@ struct _GstTensorDemux
   GstPad *sinkpad;
   GSList *srcpads;
   guint32 num_tensors;
+  guint32 num_srcpads;
   gboolean singleStream;
+  gboolean have_group_id;
+  guint group_id;
+  gint framerate_numerator;
+  gint framerate_denominator;
 };
 
 /**