[Converter] Change tensor config to tensors config
authorgichan-jang <gichan2.jang@samsung.com>
Thu, 28 May 2020 01:45:33 +0000 (10:45 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Wed, 10 Jun 2020 13:10:17 +0000 (22:10 +0900)
Change tensor config to tensors config. Assume single tensor only except subplugin.

Signed-off-by: gichan-jang <gichan2.jang@samsung.com>
gst/nnstreamer/include/nnstreamer_plugin_api_converter.h
gst/nnstreamer/tensor_converter/tensor_converter.c
gst/nnstreamer/tensor_converter/tensor_converter.h

index 5358828..0ea89ec 100644 (file)
@@ -43,30 +43,32 @@ typedef struct _NNStreamerExternalConverter
   const char *media_type_name;
 
   /** 1. chain func, data handling. */
-  GstBuffer *(*convert) (GstBuffer * buf, gsize * frame_size,
+  GstBuffer *(*convert) (GstBuffer * in_buf, gsize * frame_size,
       guint * frames_in, GstTensorsConfig * config);
   /**< Convert the given input stream to tensor/tensors stream.
    * @param[in] buf The input stream buffer
    * @param[out] frame_size The size of each frame (output buffer)
    * @param[out] frames_in The number of frames in the given input buffer.
    * @param[out] config tensors config structure to be filled
-   * @retval Return inbuf if the data is to be kept untouched.
+   * @retval Return input buffer(in_buf) if the data is to be kept untouched.
    * @retval Retrun a new GstBuf if the data is to be modified.
    */
 
-  /** 2. get_caps (type conv, input(media) to output(tensor)) */
-  gboolean (*get_caps) (const GstStructure * st, GstTensorConfig * config);
+  /** 2. get_caps (type conf, input(media) to output(tensor)) */
+  gboolean (*get_caps) (const GstStructure * st, GstTensorsConfig * config);
   /**< Set the tensor config structure from the given stream frame
     * @param[in] st The input (original/media data) stream's metadata
     * @param[out] config The output (tensor/tensors) metadata
+    * @retval Retrun True if get caps successfully, FALSE if not.
     */
 
-  /** 3. query_cap (tpye conf, output(tensor) to input(media)) */
-  GstCaps * (*query_caps) (const GstTensorConfig * config,
+  /** 3. query_cap (type conf, output(tensor) to input(media)) */
+  GstCaps * (*query_caps) (const GstTensorsConfig * config,
     GstStructure * st);
   /**< Filters (narrows down) the GstCap (st) with the given config.
     * @param[in] config The config of output tensor/tensors
     * @param[in/out] st The gstcap of input to be filtered with config.
+    * @retval Retrun subplugin default caps
     */
   } NNStreamerExternalConverter;
 
index 3779c38..459e6f8 100644 (file)
@@ -30,7 +30,7 @@
  * SECTION:element-tensor_converter
  *
  * A filter that converts media stream to tensor stream for NN frameworks.
- * The output is always in the format of other/tensor.
+ * The output is always in the format of other/tensor or other/tensors.
  *
  * <refsect2>
  * <title>Example launch line</title>
@@ -176,7 +176,8 @@ static GstCaps *gst_tensor_converter_query_caps (GstTensorConverter * self,
     GstPad * pad, GstCaps * filter);
 static gboolean gst_tensor_converter_parse_caps (GstTensorConverter * self,
     const GstCaps * caps);
-
+static gboolean gst_tensor_converter_update_caps (GstTensorConverter * self,
+    GstPad * pad, GstTensorsConfig * config);
 static const NNStreamerExternalConverter *findExternalConverter (const char
     *media_type_name);
 static const gchar *getExternalConverterName (const char *name);
@@ -454,22 +455,15 @@ gst_tensor_converter_sink_event (GstPad * pad, GstObject * parent,
     case GST_EVENT_CAPS:
     {
       GstCaps *in_caps;
-      GstCaps *out_caps;
 
       gst_event_parse_caps (event, &in_caps);
       silent_debug_caps (in_caps, "in-caps");
 
       if (gst_tensor_converter_parse_caps (self, in_caps)) {
-        out_caps = gst_tensor_caps_from_config (&self->tensor_config);
-        silent_debug_caps (out_caps, "out-caps");
-
-        gst_pad_set_caps (self->srcpad, out_caps);
-
+        gboolean ret = gst_tensor_converter_update_caps (self, self->srcpad,
+            &self->tensors_config);
         gst_event_unref (event);
-        event = gst_event_new_caps (out_caps);
-
-        gst_caps_unref (out_caps);
-        return gst_pad_push_event (self->srcpad, event);
+        return ret;
       }
       break;
     }
@@ -599,7 +593,7 @@ gst_tensor_converter_src_query (GstPad * pad, GstObject * parent,
 /** @brief Chain function's private routine */
 static void
 _gst_tensor_converter_chain_segment (GstTensorConverter * self,
-    gboolean have_framerate, GstTensorConfig * config, gsize frame_size)
+    gboolean have_framerate, GstTensorsConfig * config, gsize frame_size)
 {
   if (self->need_segment) {
     GstSegment seg;
@@ -627,7 +621,7 @@ _gst_tensor_converter_chain_segment (GstTensorConverter * self,
 /** @brief Chain function's private routine */
 static void
 _gst_tensor_converter_chain_timestamp (GstTensorConverter * self,
-    gboolean have_framerate, GstTensorConfig * config, GstBuffer * inbuf,
+    gboolean have_framerate, GstTensorsConfig * config, GstBuffer * inbuf,
     GstClockTime * duration, GstClockTime * pts, guint frames_in)
 {
   if (self->set_timestamp) {
@@ -682,8 +676,7 @@ static GstFlowReturn
 gst_tensor_converter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 {
   GstTensorConverter *self;
-  GstTensorConfig *config;
-  GstTensorsConfig tensors_config;
+  GstTensorsConfig *config;
   GstAdapter *adapter;
   GstBuffer *inbuf;
   gsize avail, buf_size, frame_size, out_size;
@@ -691,7 +684,6 @@ gst_tensor_converter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
   GstFlowReturn ret = GST_FLOW_OK;
   GstClockTime pts, dts, duration;
   gboolean have_framerate;
-  GstCaps *curr_caps, *peer_caps, *out_caps = NULL;
 
   buf_size = gst_buffer_get_size (buf);
   g_return_val_if_fail (buf_size > 0, GST_FLOW_ERROR);
@@ -699,8 +691,8 @@ gst_tensor_converter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
   self = GST_TENSOR_CONVERTER (parent);
 
   /** This is an internal logic error. */
-  g_assert (self->tensor_configured);
-  config = &self->tensor_config;
+  g_assert (self->tensors_configured);
+  config = &self->tensors_config;
 
   have_framerate = (config->rate_n > 0 && config->rate_d > 0);
 
@@ -713,10 +705,10 @@ gst_tensor_converter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
       guint color, width, height;
       gsize type;
 
-      color = config->info.dimension[0];
-      width = config->info.dimension[1];
-      height = config->info.dimension[2];
-      type = gst_tensor_get_element_size (config->info.type);
+      color = config->info.info[0].dimension[0];
+      width = config->info.info[0].dimension[1];
+      height = config->info.info[0].dimension[2];
+      type = gst_tensor_get_element_size (config->info.info[0].type);
 
       /** colorspace * width * height * type */
       frame_size = color * width * height * type;
@@ -823,47 +815,29 @@ gst_tensor_converter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
       break;
     case _NNS_MEDIA_PLUGINS:
     {
+      GstTensorsConfig new_config;
+
       if (self->externalConverter == NULL ||
           self->externalConverter->convert == NULL)
         return GST_FLOW_NOT_SUPPORTED;
       inbuf =
           self->externalConverter->convert (buf, &frame_size, &frames_in,
-          &tensors_config);
-
-      self->tensors_config = tensors_config;
-      if (tensors_config.info.num_tensors == 1) {
-        GstStructure *st;
-
-        peer_caps = gst_pad_peer_query_caps (self->srcpad, NULL);
-        silent_debug_caps (peer_caps, "peer caps");
+          &new_config);
 
-        st = gst_caps_get_structure (peer_caps, 0);
-
-        if (g_strcmp0 (gst_structure_get_name (st), "other/tensor") == 0) {
-          self->tensor_config.info = tensors_config.info.info[0];
-          self->tensor_config.rate_n = tensors_config.rate_n;
-          self->tensor_config.rate_d = tensors_config.rate_d;
-          out_caps = gst_tensor_caps_from_config (&self->tensor_config);
+      if (gst_tensors_config_is_equal (config, &new_config) != TRUE) {
+        if (gst_tensor_converter_update_caps (self, self->srcpad,
+                &new_config) == TRUE) {
+          self->tensors_config = new_config;
+        } else {
+          return GST_FLOW_ERROR;
         }
       }
 
-      /* caps for tensors */
-      if (out_caps == NULL)
-        out_caps = gst_tensors_caps_from_config (&self->tensors_config);
-
-      silent_debug_caps (out_caps, "out-caps");
-
-      /* Update source pad caps. If it is different */
-      curr_caps = gst_pad_get_current_caps (self->srcpad);
-      if (gst_caps_is_equal (curr_caps, out_caps) != TRUE) {
-        gst_pad_set_caps (self->srcpad, out_caps);
-      }
       g_assert (inbuf != NULL);
       g_assert (frame_size > 0);
 
-      gst_caps_unref (curr_caps);
-      gst_caps_unref (out_caps);
-      gst_buffer_unref (buf);
+      if (inbuf != buf)
+        gst_buffer_unref (buf);
 
       break;
     }
@@ -988,8 +962,8 @@ gst_tensor_converter_reset (GstTensorConverter * self)
     gst_adapter_clear (self->adapter);
   }
 
-  self->tensor_configured = FALSE;
-  gst_tensor_config_init (&self->tensor_config);
+  self->tensors_configured = FALSE;
+  gst_tensors_config_init (&self->tensors_config);
 
   self->have_segment = FALSE;
   self->need_segment = FALSE;
@@ -1049,16 +1023,16 @@ gst_tensor_converter_video_stride (GstVideoFormat format, gint width)
 }
 
 /**
- * @brief Set the tensor config structure from video info (internal static function)
+ * @brief Set the tensors config structure from video info (internal static function)
  * @param self this pointer to GstTensorConverter
- * @param config tensor config structure to be filled
+ * @param config tensors config structure to be filled
  * @param info video info structure
  * @note Change dimension if tensor contains N frames.
  * @return TRUE if supported type
  */
 static gboolean
 gst_tensor_converter_parse_video (GstTensorConverter * self,
-    GstTensorConfig * config, const GstVideoInfo * info)
+    GstTensorsConfig * config, const GstVideoInfo * info)
 {
   /**
    * Refer: https://www.tensorflow.org/api_docs/python/tf/summary/image
@@ -1069,7 +1043,8 @@ gst_tensor_converter_parse_video (GstTensorConverter * self,
   guint i;
 
   g_return_val_if_fail (config != NULL, FALSE);
-  gst_tensor_config_init (config);
+  gst_tensors_config_init (config);
+  config->info.num_tensors = 1;
 
   g_return_val_if_fail (info != NULL, FALSE);
 
@@ -1078,13 +1053,13 @@ gst_tensor_converter_parse_video (GstTensorConverter * self,
   /* [color-space][width][height][frames] */
   switch (format) {
     case GST_VIDEO_FORMAT_GRAY8:
-      config->info.type = _NNS_UINT8;
-      config->info.dimension[0] = 1;
+      config->info.info[0].type = _NNS_UINT8;
+      config->info.info[0].dimension[0] = 1;
       break;
     case GST_VIDEO_FORMAT_RGB:
     case GST_VIDEO_FORMAT_BGR:
-      config->info.type = _NNS_UINT8;
-      config->info.dimension[0] = 3;
+      config->info.info[0].type = _NNS_UINT8;
+      config->info.info[0].dimension[0] = 3;
       break;
     case GST_VIDEO_FORMAT_RGBx:
     case GST_VIDEO_FORMAT_BGRx:
@@ -1094,8 +1069,8 @@ gst_tensor_converter_parse_video (GstTensorConverter * self,
     case GST_VIDEO_FORMAT_BGRA:
     case GST_VIDEO_FORMAT_ARGB:
     case GST_VIDEO_FORMAT_ABGR:
-      config->info.type = _NNS_UINT8;
-      config->info.dimension[0] = 4;
+      config->info.info[0].type = _NNS_UINT8;
+      config->info.info[0].dimension[0] = 4;
       break;
     default:
       /* unsupported format */
@@ -1104,31 +1079,31 @@ gst_tensor_converter_parse_video (GstTensorConverter * self,
       break;
   }
 
-  config->info.dimension[1] = GST_VIDEO_INFO_WIDTH (info);
-  config->info.dimension[2] = GST_VIDEO_INFO_HEIGHT (info);
+  config->info.info[0].dimension[1] = GST_VIDEO_INFO_WIDTH (info);
+  config->info.info[0].dimension[2] = GST_VIDEO_INFO_HEIGHT (info);
 
   /* Supposed 1 frame in tensor, change dimension[3] if tensor contains N frames. */
   for (i = 3; i < NNS_TENSOR_RANK_LIMIT; i++) {
-    config->info.dimension[i] = 1;
+    config->info.info[0].dimension[i] = 1;
   }
 
   config->rate_n = GST_VIDEO_INFO_FPS_N (info);
   config->rate_d = GST_VIDEO_INFO_FPS_D (info);
 
-  return (config->info.type != _NNS_END);
+  return (config->info.info[0].type != _NNS_END);
 }
 
 /**
- * @brief Set the tensor config structure from audio info (internal static function)
+ * @brief Set the tensors config structure from audio info (internal static function)
  * @param self this pointer to GstTensorConverter
- * @param config tensor config structure to be filled
+ * @param config tensors config structure to be filled
  * @param info audio info structure
  * @note Change dimension if tensor contains N frames.
  * @return TRUE if supported type
  */
 static gboolean
 gst_tensor_converter_parse_audio (GstTensorConverter * self,
-    GstTensorConfig * config, const GstAudioInfo * info)
+    GstTensorsConfig * config, const GstAudioInfo * info)
 {
   /**
    * Refer: https://www.tensorflow.org/api_docs/python/tf/summary/audio
@@ -1139,7 +1114,8 @@ gst_tensor_converter_parse_audio (GstTensorConverter * self,
   guint i;
 
   g_return_val_if_fail (config != NULL, FALSE);
-  gst_tensor_config_init (config);
+  gst_tensors_config_init (config);
+  config->info.num_tensors = 1;
 
   g_return_val_if_fail (info != NULL, FALSE);
 
@@ -1148,28 +1124,28 @@ gst_tensor_converter_parse_audio (GstTensorConverter * self,
   /* [channels][frames] */
   switch (format) {
     case GST_AUDIO_FORMAT_S8:
-      config->info.type = _NNS_INT8;
+      config->info.info[0].type = _NNS_INT8;
       break;
     case GST_AUDIO_FORMAT_U8:
-      config->info.type = _NNS_UINT8;
+      config->info.info[0].type = _NNS_UINT8;
       break;
     case GST_AUDIO_FORMAT_S16:
-      config->info.type = _NNS_INT16;
+      config->info.info[0].type = _NNS_INT16;
       break;
     case GST_AUDIO_FORMAT_U16:
-      config->info.type = _NNS_UINT16;
+      config->info.info[0].type = _NNS_UINT16;
       break;
     case GST_AUDIO_FORMAT_S32:
-      config->info.type = _NNS_INT32;
+      config->info.info[0].type = _NNS_INT32;
       break;
     case GST_AUDIO_FORMAT_U32:
-      config->info.type = _NNS_UINT32;
+      config->info.info[0].type = _NNS_UINT32;
       break;
     case GST_AUDIO_FORMAT_F32:
-      config->info.type = _NNS_FLOAT32;
+      config->info.info[0].type = _NNS_FLOAT32;
       break;
     case GST_AUDIO_FORMAT_F64:
-      config->info.type = _NNS_FLOAT64;
+      config->info.info[0].type = _NNS_FLOAT64;
       break;
     default:
       /* unsupported format */
@@ -1178,30 +1154,30 @@ gst_tensor_converter_parse_audio (GstTensorConverter * self,
       break;
   }
 
-  config->info.dimension[0] = GST_AUDIO_INFO_CHANNELS (info);
+  config->info.info[0].dimension[0] = GST_AUDIO_INFO_CHANNELS (info);
 
   /* Supposed 1 frame in tensor, change dimension[1] if tensor contains N frames. */
   for (i = 1; i < NNS_TENSOR_RANK_LIMIT; i++) {
-    config->info.dimension[i] = 1;
+    config->info.info[0].dimension[i] = 1;
   }
 
   config->rate_n = GST_AUDIO_INFO_RATE (info);
   config->rate_d = 1;
 
-  return (config->info.type != _NNS_END);
+  return (config->info.info[0].type != _NNS_END);
 }
 
 /**
- * @brief Set the tensor config structure from text info (internal static function)
+ * @brief Set the tensors config structure from text info (internal static function)
  * @param self this pointer to GstTensorConverter
- * @param config tensor config structure to be filled
+ * @param config tensors config structure to be filled
  * @param structure caps structure
- * @note Change dimension if tensor contains N frames.
+ * @note Change dimension if tensors contains N frames.
  * @return TRUE if supported type
  */
 static gboolean
 gst_tensor_converter_parse_text (GstTensorConverter * self,
-    GstTensorConfig * config, const GstStructure * structure)
+    GstTensorsConfig * config, const GstStructure * structure)
 {
   /**
    * Refer: https://www.tensorflow.org/api_docs/python/tf/summary/text
@@ -1211,14 +1187,15 @@ gst_tensor_converter_parse_text (GstTensorConverter * self,
   guint i;
 
   g_return_val_if_fail (config != NULL, FALSE);
-  gst_tensor_config_init (config);
+  gst_tensors_config_init (config);
+  config->info.num_tensors = 1;
 
   g_return_val_if_fail (structure != NULL, FALSE);
 
   format_string = gst_structure_get_string (structure, "format");
   if (format_string) {
     if (g_ascii_strcasecmp (format_string, "utf8") == 0) {
-      config->info.type = _NNS_UINT8;
+      config->info.info[0].type = _NNS_UINT8;
     } else {
       /* unsupported format */
       GST_WARNING_OBJECT (self, "Unsupported format = %s\n", format_string);
@@ -1227,11 +1204,11 @@ gst_tensor_converter_parse_text (GstTensorConverter * self,
 
   /* [size][frames] */
   /* Fixed size of string, we cannot get the size from caps. */
-  config->info.dimension[0] = 0;
+  config->info.info[0].dimension[0] = 0;
 
   /* Supposed 1 frame in tensor, change dimension[1] if tensor contains N frames. */
   for (i = 1; i < NNS_TENSOR_RANK_LIMIT; i++) {
-    config->info.dimension[i] = 1;
+    config->info.info[0].dimension[i] = 1;
   }
 
   if (gst_structure_has_field (structure, "framerate")) {
@@ -1243,32 +1220,33 @@ gst_tensor_converter_parse_text (GstTensorConverter * self,
     config->rate_d = 1;
   }
 
-  return (config->info.type != _NNS_END);
+  return (config->info.info[0].type != _NNS_END);
 }
 
 /**
- * @brief Set the tensor config structure from octet stream (internal static function)
+ * @brief Set the tensors configs structure from octet stream (internal static function)
  * @param self this pointer to GstTensorConverter
- * @param config tensor config structure to be filled
+ * @param config tensors config structure to be filled
  * @param structure caps structure
- * @note Change tensor dimension and type.
+ * @note Change tensors dimension and type.
  * @return TRUE if supported type
  */
 static gboolean
 gst_tensor_converter_parse_octet (GstTensorConverter * self,
-    GstTensorConfig * config, const GstStructure * structure)
+    GstTensorsConfig * config, const GstStructure * structure)
 {
   g_return_val_if_fail (config != NULL, FALSE);
-  gst_tensor_config_init (config);
+  gst_tensors_config_init (config);
+  config->info.num_tensors = 1;
 
   g_return_val_if_fail (structure != NULL, FALSE);
 
   /**
    * Raw byte-stream (application/octet-stream)
-   * We cannot get the exact tensor info from caps.
-   * All tensor info should be updated.
+   * We cannot get the exact tensors info from caps.
+   * All tensors info should be updated.
    */
-  config->info.type = _NNS_UINT8;
+  config->info.info[0].type = _NNS_UINT8;
 
   if (gst_structure_has_field (structure, "framerate")) {
     gst_structure_get_fraction (structure, "framerate", &config->rate_n,
@@ -1279,7 +1257,7 @@ gst_tensor_converter_parse_octet (GstTensorConverter * self,
     config->rate_d = 1;
   }
 
-  return (config->info.type != _NNS_END);
+  return (config->info.info[0].type != _NNS_END);
 }
 
 /**
@@ -1342,14 +1320,14 @@ gst_tensor_converter_get_possible_media_caps (GstTensorConverter * self)
     silent_debug_caps (peer_caps, "peer caps");
 
     if (gst_caps_get_size (peer_caps) > 0) {
-      GstTensorConfig config;
+      GstTensorsConfig config;
       GstStructure *st;
       guint i, caps_len;
       media_type type;
 
-      /* get tensor info from peer caps */
+      /* get tensors info from peer caps */
       st = gst_caps_get_structure (peer_caps, 0);
-      gst_tensor_config_from_structure (&config, st);
+      gst_tensors_config_from_structure (&config, st);
 
       /* convert peer caps to possible media caps */
       caps_len = gst_caps_get_size (media_caps);
@@ -1361,11 +1339,12 @@ gst_tensor_converter_get_possible_media_caps (GstTensorConverter * self)
         switch (type) {
           case _NNS_VIDEO:
             /* video caps from tensor info */
-            if (is_video_supported (self) && config.info.type == _NNS_UINT8) {
+            if (is_video_supported (self)
+                && config.info.info[0].type == _NNS_UINT8) {
               GValue supported_formats = G_VALUE_INIT;
               gint colorspace, width, height;
 
-              colorspace = config.info.dimension[0];
+              colorspace = config.info.info[0].dimension[0];
               switch (colorspace) {
                 case 1:
                   gst_tensor_converter_get_format_list (&supported_formats,
@@ -1391,11 +1370,11 @@ gst_tensor_converter_get_possible_media_caps (GstTensorConverter * self)
               }
               g_value_unset (&supported_formats);
 
-              if ((width = config.info.dimension[1]) > 0) {
+              if ((width = config.info.info[0].dimension[1]) > 0) {
                 gst_structure_set (st, "width", G_TYPE_INT, width, NULL);
               }
 
-              if ((height = config.info.dimension[2]) > 0) {
+              if ((height = config.info.info[0].dimension[2]) > 0) {
                 gst_structure_set (st, "height", G_TYPE_INT, height, NULL);
               }
 
@@ -1407,11 +1386,12 @@ gst_tensor_converter_get_possible_media_caps (GstTensorConverter * self)
             break;
           case _NNS_AUDIO:
             /* audio caps from tensor info */
-            if (is_audio_supported (self) && config.info.type != _NNS_END) {
+            if (is_audio_supported (self)
+                && config.info.info[0].type != _NNS_END) {
               gint ch, rate;
               GstAudioFormat aformat;
 
-              switch (config.info.type) {
+              switch (config.info.info[0].type) {
                 case _NNS_INT8:
                   aformat = GST_AUDIO_FORMAT_S8;
                   break;
@@ -1446,7 +1426,7 @@ gst_tensor_converter_get_possible_media_caps (GstTensorConverter * self)
                 gst_structure_set (st, "format", G_TYPE_STRING,
                     gst_audio_format_to_string (aformat), NULL);
 
-                if ((ch = config.info.dimension[0]) > 0) {
+                if ((ch = config.info.info[0].dimension[0]) > 0) {
                   gst_structure_set (st, "channels", G_TYPE_INT, ch, NULL);
                 }
 
@@ -1516,16 +1496,16 @@ gst_tensor_converter_query_caps (GstTensorConverter * self, GstPad * pad,
 }
 
 /**
- * @brief Parse caps and set tensor info.
+ * @brief Parse caps and set tensors info.
  */
 static gboolean
 gst_tensor_converter_parse_caps (GstTensorConverter * self,
     const GstCaps * caps)
 {
   GstStructure *structure;
-  GstTensorConfig config;
+  GstTensorsConfig config;
   media_type in_type;
-  gint frames_dim = -1; /** dimension index of frames in configured tensor */
+  gint frames_dim = -1; /** dimension index of frames in configured tensors */
 
   g_return_val_if_fail (caps != NULL, FALSE);
   g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
@@ -1614,15 +1594,15 @@ gst_tensor_converter_parse_caps (GstTensorConverter * self,
         return FALSE;
       }
 
-      config.info.dimension[0] = self->tensor_info.dimension[0];
+      config.info.info[0].dimension[0] = self->tensor_info.dimension[0];
       frames_dim = 1;
-      self->frame_size = gst_tensor_info_get_size (&config.info);
+      self->frame_size = gst_tensor_info_get_size (&config.info.info[0]);
       break;
     }
     case _NNS_OCTET:
     {
       if (!gst_tensor_converter_parse_octet (self, &config, structure)) {
-        GST_ERROR_OBJECT (self, "Failed to configure tensor from octet info.");
+        GST_ERROR_OBJECT (self, "Failed to configure tensors from octet info.");
         return FALSE;
       }
 
@@ -1637,8 +1617,8 @@ gst_tensor_converter_parse_caps (GstTensorConverter * self,
         return FALSE;
       }
 
-      config.info = self->tensor_info;
-      self->frame_size = gst_tensor_info_get_size (&config.info);
+      config.info.info[0] = self->tensor_info;
+      self->frame_size = gst_tensor_info_get_size (&config.info.info[0]);
       break;
     }
     default:
@@ -1660,7 +1640,7 @@ gst_tensor_converter_parse_caps (GstTensorConverter * self,
 
           if (NULL == ex->get_caps || !ex->get_caps (structure, &config)) {
             GST_ERROR_OBJECT (self,
-                "Failed to get tensor info from %s. Check the given options.",
+                "Failed to get tensors info from %s. Check the given options.",
                 ext_conv_name);
             ml_loge ("Please set the options property correctly.\n");
             self->externalConverter = NULL;
@@ -1676,26 +1656,73 @@ gst_tensor_converter_parse_caps (GstTensorConverter * self,
 
   /** set the number of frames in dimension */
   if (frames_dim >= 0) {
-    config.info.dimension[frames_dim] = self->frames_per_tensor;
+    config.info.info[0].dimension[frames_dim] = self->frames_per_tensor;
   }
 
-  if (!gst_tensor_config_validate (&config)) {
+  if (!gst_tensors_config_validate (&config)) {
     /** not fully configured */
-    GST_ERROR_OBJECT (self, "Failed to configure tensor info.\n");
+    GST_ERROR_OBJECT (self, "Failed to configure tensors info.\n");
     return FALSE;
   }
-
   if (gst_tensor_info_validate (&self->tensor_info)) {
     /** compare tensor info */
-    if (!gst_tensor_info_is_equal (&self->tensor_info, &config.info)) {
+    if (!gst_tensor_info_is_equal (&self->tensor_info, &config.info.info[0])) {
       GST_ERROR_OBJECT (self, "Failed, mismatched tensor info.\n");
       return FALSE;
     }
   }
 
   self->in_media_type = in_type;
-  self->tensor_configured = TRUE;
-  self->tensor_config = config;
+  self->tensors_configured = TRUE;
+  self->tensors_config = config;
+  return TRUE;
+}
+
+/**
+ * @brief Update pas caps from tensors config
+ */
+static gboolean
+gst_tensor_converter_update_caps (GstTensorConverter * self,
+    GstPad * pad, GstTensorsConfig * config)
+{
+  GstStructure *st;
+  GstCaps *curr_caps, *out_caps = NULL;
+
+  if (config->info.num_tensors == 1) {
+    GstCaps *peer_caps = gst_pad_peer_query_caps (pad, NULL);
+    silent_debug_caps (peer_caps, "peer caps");
+
+    if (peer_caps != NULL) {
+      st = gst_caps_get_structure (peer_caps, 0);
+
+      if (g_strcmp0 (gst_structure_get_name (st), "other/tensor") == 0) {
+        GstTensorConfig tensor_config;
+
+        tensor_config.info = config->info.info[0];
+        tensor_config.rate_n = config->rate_n;
+        tensor_config.rate_d = config->rate_d;
+        out_caps = gst_tensor_caps_from_config (&tensor_config);
+      }
+      gst_caps_unref (peer_caps);
+    } else {
+      GST_WARNING_OBJECT (self, "Failed to get peer caps \n");
+      return FALSE;
+    }
+  }
+
+  /* caps for tensors */
+  if (out_caps == NULL)
+    out_caps = gst_tensors_caps_from_config (config);
+  silent_debug_caps (out_caps, "out-caps");
+
+  /* Update pad caps. If it is different */
+  curr_caps = gst_pad_get_current_caps (pad);
+  if (gst_caps_is_equal (curr_caps, out_caps) != TRUE) {
+    gst_pad_set_caps (pad, out_caps);
+  }
+  gst_caps_unref (out_caps);
+  gst_caps_unref (curr_caps);
+
   return TRUE;
 }
 
index 343b2bc..25483d4 100644 (file)
@@ -37,7 +37,7 @@
 #include <gst/gst.h>
 #include <gst/base/gstadapter.h>
 #include <tensor_common.h>
-#include <nnstreamer_plugin_api_converter.h>
+#include "nnstreamer_plugin_api_converter.h"
 
 G_BEGIN_DECLS
 
@@ -78,8 +78,7 @@ struct _GstTensorConverter
 
   gsize frame_size; /**< size of one frame */
   gboolean remove_padding; /**< If true, zero-padding must be removed */
-  gboolean tensor_configured; /**< True if already successfully configured tensor metadata */
-  GstTensorConfig tensor_config; /**< output tensor info */
+  gboolean tensors_configured; /**< True if already successfully configured tensors metadata */
   GstTensorsConfig tensors_config; /**< output tensors info */
 
   gboolean have_segment; /**< True if received segment */