[datareposrc] For caps negotiation, use the caps of the JSON file
authorhyunil park <hyunil46.park@samsung.com>
Wed, 26 Apr 2023 06:14:26 +0000 (15:14 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Thu, 1 Jun 2023 11:40:59 +0000 (20:40 +0900)
- For caps negotiation, use the caps of the JSON file
- Remove supportable caps and add 'ANY'
- Add caps property for setting caps of unregistered file (have not JSON)
- Add unittest

Signed-off-by: hyunil park <hyunil46.park@samsung.com>
gst/datarepo/gstdatareposink.c
gst/datarepo/gstdatareposrc.c
gst/datarepo/gstdatareposrc.h
tests/nnstreamer_datarepo/unittest_datareposink.cc
tests/nnstreamer_datarepo/unittest_datareposrc.cc

index 43c148b..2fd92cb 100644 (file)
@@ -69,7 +69,8 @@
   "image/png, width = (int) [ 16, 1000000 ], height = (int) [ 16, 1000000 ], framerate = (fraction) [ 0/1, MAX];" \
   "image/jpeg, width = (int) [ 16, 65535 ], height = (int) [ 16, 65535 ], framerate = (fraction) [ 0/1, MAX], sof-marker = (int) { 0, 1, 2, 4, 9 };" \
   "image/tiff, endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN };" \
-  "image/gif"
+  "image/gif;" \
+  "image/bmp"
 
 static GstStaticPadTemplate sinktemplate =
     GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
index 3fd94b9..7b96682 100644 (file)
  *
  * ## Example launch line
  * |[
- * gst-launch-1.0 datareposrc location=mnist_trainingSet.dat json=mnist.json start-sample-index=3 stop-sample-index=202 epochs=5 ! \
- * other/tensors, format=static, num_tensors=2, framerate=0/1, \
- * dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! tensor_sink
- * ]|
+ * gst-launch-1.0 datareposrc location=mnist.data json=mnist.json start-sample-index=3 stop-sample-index=202 epochs=5 ! \
+ * ! tensor_sink
+ * gst-launch-1.0 datareposrc location=image_%02ld.png json=image.json start-sample-index=3 stop-sample-index=9 epochs=2 ! fakesink
+ * gst-launch-1.0 datareposrc location=audiofile json=audio.json ! fakesink
+ * gst-launch-1.0 datareposrc location=videofile json=video.json ! fakesink
+ * |]
+ * |[ Unknown sample file(has not JSON) need to set caps and blocksize or set caps to tensors type without blocksize
+ * gst-launch-1.0 datareposrc blocksize=3176 location=unknown.data start-sample-index=3 stop-sample-index=202 epochs=5 \
+ * caps ="application/octet-stream" ! tensor_converter input-dim=1:1:784:1,1:1:10:1 input-type=float32,float32 ! fakesink
+ * |]
+ * or
  * |[
- * gst-launch-1.0 datareposrc location=image_%02ld.png json=image.json start-sample-index=3 stop-sample-index=9 epochs=2 ! pngdec ! fakesink
- * gst-launch-1.0 datareposrc location=audiofile json=audio.json ! audio/x-raw, format=S8, rate=48000, channels=2 ! fakesink
- * gst-launch-1.0 datareposrc location=videofile json=video.json ! video/x-raw, format=RGB, width=320, height=240 ! fakesink
+ * gst-launch-1.0 datareposrc location=unknown.data start-sample-index=3 stop-sample-index=202 epochs=5 \
+ * caps ="other/tensors, format=(string)static, framerate=(fraction)0/1, num_tensors=(int)2, dimensions=(string)1:1:784:1.1:1:10:1, types=(string)float32.float32" \
+ * ! fakesink
  * ]|
  */
 
 #define O_BINARY (0)
 #endif
 
-/**
- * @brief Default blocksize for reading
- */
-#define DEFAULT_BLOCKSIZE       4*1024
-
-/**
- * @brief Tensors caps
- */
-#define TENSOR_CAPS GST_TENSORS_CAP_MAKE ("{ static, flexible }")
-/**
- * @brief Video caps
- */
-#define SUPPORTED_VIDEO_FORMAT \
-  "{RGB, BGR, RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, GRAY8}"
-#define VIDEO_CAPS GST_VIDEO_CAPS_MAKE (SUPPORTED_VIDEO_FORMAT) "," \
-  "interlace-mode = (string) progressive"
-/**
- * @brief Audio caps
- */
-#define SUPPORTED_AUDIO_FORMAT \
-  "{S8, U8, S16LE, S16BE, U16LE, U16BE, S32LE, S32BE, U32LE, U32BE, F32LE, F32BE, F64LE, F64BE}"
-#define AUDIO_CAPS GST_AUDIO_CAPS_MAKE (SUPPORTED_AUDIO_FORMAT) "," \
-  "layout = (string) interleaved"
-/**
- * @brief Text caps
- */
-#define TEXT_CAPS "text/x-raw, format = (string) utf8"
-/**
- * @brief Octet caps
- */
-#define OCTET_CAPS "application/octet-stream"
-
-/**
- * @brief Image caps
- */
-#define IMAGE_CAPS \
-  "image/png, width = (int) [ 16, 1000000 ], height = (int) [ 16, 1000000 ], framerate = (fraction) [ 0/1, MAX];" \
-  "image/jpeg, width = (int) [ 16, 65535 ], height = (int) [ 16, 65535 ], framerate = (fraction) [ 0/1, MAX], sof-marker = (int) { 0, 1, 2, 4, 9 };" \
-  "image/tiff, endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN };" \
-  "image/gif"
-
-static GstStaticPadTemplate srctemplate =
-    GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (TENSOR_CAPS ";" VIDEO_CAPS ";" AUDIO_CAPS ";" IMAGE_CAPS
-        ";" TEXT_CAPS ";" OCTET_CAPS));
-
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS_ANY);
 
 GST_DEBUG_CATEGORY_STATIC (gst_data_repo_src_debug);
 #define GST_CAT_DEFAULT gst_data_repo_src_debug
@@ -120,6 +85,7 @@ enum
   PROP_EPOCHS,
   PROP_IS_SHUFFLE,
   PROP_TENSORS_SEQUENCE,
+  PROP_CAPS,                    /* for setting caps of sample data directly */
 };
 
 #define DEFAULT_INDEX 0
@@ -140,7 +106,6 @@ static gboolean gst_data_repo_src_set_caps (GstBaseSrc * basesrc,
     GstCaps * caps);
 static GstFlowReturn gst_data_repo_src_create (GstPushSrc * pushsrc,
     GstBuffer ** buffer);
-
 #define _do_init \
   GST_DEBUG_CATEGORY_INIT (gst_data_repo_src_debug, "datareposrc", 0, "datareposrc element");
 
@@ -220,7 +185,16 @@ gst_data_repo_src_class_init (GstDataRepoSrcClass * klass)
   g_object_class_install_property (gobject_class, PROP_IS_SHUFFLE,
       g_param_spec_boolean ("is-shuffle", "Is shuffle",
           "If the value is true, samples index are shuffled",
-          DEFAULT_IS_SHUFFLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          DEFAULT_IS_SHUFFLE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_READY));
+
+  g_object_class_install_property (gobject_class, PROP_CAPS,
+      g_param_spec_boxed ("caps", "Caps",
+          "Optional property, Caps describing the format of the sample data.",
+          GST_TYPE_CAPS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+          GST_PARAM_MUTABLE_READY));
 
   gobject_class->finalize = gst_data_repo_src_finalize;
   gstelement_class->change_state = gst_data_repo_src_change_state;
@@ -270,6 +244,9 @@ gst_data_repo_src_init (GstDataRepoSrc * src)
   src->num_samples = 0;
   src->total_samples = 0;
   src->tensors_seq_cnt = 0;
+  src->caps = NULL;
+  src->sample_size = 0;
+  src->need_changed_caps = FALSE;
 
   /* Filling the buffer should be pending until set_caps() */
   gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
@@ -291,6 +268,12 @@ gst_data_repo_src_finalize (GObject * object)
   if (src->shuffled_index_array)
     g_array_free (src->shuffled_index_array, TRUE);
 
+  /* Check for gst-inspect log */
+  if (src->caps) {
+    gst_caps_unref (src->caps);
+    src->caps = NULL;
+  }
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -361,6 +344,8 @@ gst_data_repo_src_set_tensors_sequence (GstDataRepoSrc * src)
   g_return_val_if_fail (src != NULL, FALSE);
   g_return_val_if_fail (src->tensors_seq_str != NULL, FALSE);
 
+  GST_INFO_OBJECT (src, "tensors sequence = %s", src->tensors_seq_str);
+
   /* not use NNS_TENSOR_SIZE_LIMIT */
   strv = g_strsplit (src->tensors_seq_str, ",", -1);
 
@@ -378,7 +363,7 @@ gst_data_repo_src_set_tensors_sequence (GstDataRepoSrc * src)
           src->num_tensors - 1);
       goto error;
     }
-    GST_ERROR ("%d", src->tensors_seq[i]);
+    GST_INFO_OBJECT (src, "%d", src->tensors_seq[i]);
     i++;
   }
   src->tensors_seq_cnt = i;
@@ -398,97 +383,12 @@ gst_data_repo_src_set_tensors_sequence (GstDataRepoSrc * src)
   return TRUE;
 
 error:
+  src->tensors_seq_cnt = 0;
   g_strfreev (strv);
   return FALSE;
 }
 
 /**
- * @brief Setter for datareposrc properties.
- */
-static void
-gst_data_repo_src_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstDataRepoSrc *src;
-
-  g_return_if_fail (GST_IS_DATA_REPO_SRC (object));
-
-  src = GST_DATA_REPO_SRC (object);
-
-  switch (prop_id) {
-    case PROP_LOCATION:
-      gst_data_repo_src_set_file_path (src, PROP_LOCATION,
-          g_value_get_string (value), NULL);
-      break;
-    case PROP_JSON:
-      gst_data_repo_src_set_file_path (src, PROP_JSON,
-          g_value_get_string (value), NULL);
-      break;
-    case PROP_START_SAMPLE_INDEX:
-      src->start_sample_index = g_value_get_uint (value);
-      break;
-    case PROP_STOP_SAMPLE_INDEX:
-      src->stop_sample_index = g_value_get_uint (value);
-      break;
-    case PROP_EPOCHS:
-      src->epochs = g_value_get_uint (value);
-      break;
-    case PROP_IS_SHUFFLE:
-      src->is_shuffle = g_value_get_boolean (value);
-      break;
-    case PROP_TENSORS_SEQUENCE:
-      g_free (src->tensors_seq_str);
-      src->tensors_seq_str = g_value_dup_string (value);
-      GST_INFO_OBJECT (src, "tensors sequence = %s", src->tensors_seq_str);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-/**
- * @brief Getter datareposrc properties
- */
-static void
-gst_data_repo_src_get_property (GObject * object, guint prop_id, GValue * value,
-    GParamSpec * pspec)
-{
-  GstDataRepoSrc *src;
-
-  g_return_if_fail (GST_IS_DATA_REPO_SRC (object));
-
-  src = GST_DATA_REPO_SRC (object);
-
-  switch (prop_id) {
-    case PROP_LOCATION:
-      g_value_set_string (value, src->filename);
-      break;
-    case PROP_JSON:
-      g_value_set_string (value, src->json_filename);
-      break;
-    case PROP_START_SAMPLE_INDEX:
-      g_value_set_uint (value, src->start_sample_index);
-      break;
-    case PROP_STOP_SAMPLE_INDEX:
-      g_value_set_uint (value, src->stop_sample_index);
-      break;
-    case PROP_EPOCHS:
-      g_value_set_uint (value, src->epochs);
-      break;
-    case PROP_IS_SHUFFLE:
-      g_value_set_boolean (value, src->is_shuffle);
-      break;
-    case PROP_TENSORS_SEQUENCE:
-      g_value_set_string (value, src->tensors_seq_str);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-/**
  * @brief Function to get file offset with sample index
  */
 static guint64
@@ -1076,29 +976,79 @@ gst_data_repo_src_stop (GstBaseSrc * basesrc)
 }
 
 /**
+ * @brief Get caps with tensors_sequence applied
+ */
+static gboolean
+gst_data_repo_get_caps_by_tensors_sequence (GstDataRepoSrc * src)
+{
+  GstStructure *s;
+  GstTensorsConfig src_config, dst_config;
+  guint i;
+  guint seq_num = 0;
+  GstCaps *new_caps;
+
+  g_return_val_if_fail (src != NULL, FALSE);
+  g_return_val_if_fail (src->caps != NULL, FALSE);
+
+  s = gst_caps_get_structure (src->caps, 0);
+  if (!gst_tensors_config_from_structure (&src_config, s))
+    return FALSE;
+
+  gst_tensors_config_init (&dst_config);
+
+  /* Copy selected tensors in sequence */
+  for (i = 0; i < src->tensors_seq_cnt; i++) {
+    seq_num = src->tensors_seq[i];
+    gst_tensor_info_copy (&dst_config.info.info[i],
+        &src_config.info.info[seq_num]);
+  }
+  dst_config.rate_n = src_config.rate_n;
+  dst_config.rate_d = src_config.rate_d;
+  dst_config.info.format = src_config.info.format;
+  dst_config.info.num_tensors = src->tensors_seq_cnt;
+
+  new_caps = gst_tensors_caps_from_config (&dst_config);
+
+  GST_DEBUG_OBJECT (src,
+      "datareposrc caps by tensors_sequence %" GST_PTR_FORMAT, new_caps);
+
+  gst_caps_replace (&src->caps, new_caps);
+
+  gst_caps_unref (new_caps);
+  gst_tensors_config_free (&dst_config);
+  gst_tensors_config_free (&src_config);
+
+  return TRUE;
+}
+
+/**
  * @brief Get caps for caps negotiation
  */
 static GstCaps *
 gst_data_repo_src_get_caps (GstBaseSrc * basesrc, GstCaps * filter)
 {
   GstDataRepoSrc *src = GST_DATA_REPO_SRC (basesrc);
-  GstCaps *caps = NULL;
 
-  caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (src));
-  caps = gst_caps_make_writable (caps);
-
-  GST_DEBUG_OBJECT (src, "get caps: %" GST_PTR_FORMAT, caps);
+  if (src->media_type == _NNS_TENSOR && src->need_changed_caps) {
+    gst_data_repo_get_caps_by_tensors_sequence (src);
+    src->need_changed_caps = FALSE;
+  }
 
-  if (filter) {
-    GstCaps *intersection;
+  GST_DEBUG_OBJECT (src, "Current datareposrc caps %" GST_PTR_FORMAT,
+      src->caps);
 
-    intersection =
-        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
-    gst_caps_unref (caps);
-    caps = intersection;
+  if (src->caps) {
+    if (filter)
+      return gst_caps_intersect_full (filter, src->caps,
+          GST_CAPS_INTERSECT_FIRST);
+    else
+      return gst_caps_ref (src->caps);
+  } else {
+    if (filter)
+      return gst_caps_ref (filter);
+    else
+      return gst_caps_new_any ();
   }
-  GST_DEBUG_OBJECT (src, "get caps: %" GST_PTR_FORMAT, caps);
-  return caps;
 }
 
 /**
@@ -1234,12 +1184,14 @@ gst_data_repo_src_get_media_type_and_size (GstDataRepoSrc * src, GstCaps * caps)
   } else if (gst_structure_has_name (s, "application/octet-stream")) {
     src->media_type = _NNS_OCTET;
   } else if (gst_structure_has_name (s, "image/png")
+      || gst_structure_has_name (s, "image/bmp")
       || gst_structure_has_name (s, "image/jpeg")
       || gst_structure_has_name (s, "image/tiff")
       || gst_structure_has_name (s, "image/gif")) {
     src->media_type = _NNS_IMAGE;
   } else {
     GST_ERROR_OBJECT (src, "Could not get a media type from caps");
+    src->media_type = _NNS_MEDIA_INVALID;
     return FALSE;
   }
 
@@ -1260,8 +1212,8 @@ gst_data_repo_src_read_json_file (GstDataRepoSrc * src)
   JsonParser *parser;
   JsonNode *root;
   JsonObject *object;
-  GstCaps *get_caps = NULL;
   const gchar *caps_str = NULL;
+  GstCaps *new_caps;
 
   g_return_val_if_fail (src != NULL, FALSE);
   g_return_val_if_fail (src->json_filename != NULL, FALSE);
@@ -1305,11 +1257,13 @@ gst_data_repo_src_read_json_file (GstDataRepoSrc * src)
   caps_str = json_object_get_string_member (object, "gst_caps");
   GST_INFO_OBJECT (src, "caps_str : %s", caps_str);
 
-  get_caps = gst_caps_from_string (caps_str);
-  GST_INFO_OBJECT (src, "gst_caps : %" GST_PTR_FORMAT, get_caps);
+  new_caps = gst_caps_from_string (caps_str);
+  gst_caps_replace (&src->caps, new_caps);
+  GST_INFO_OBJECT (src, "gst_caps : %" GST_PTR_FORMAT, src->caps);
+  gst_caps_unref (new_caps);
 
   /* calculate media size from gst caps */
-  if (!gst_data_repo_src_get_media_type_and_size (src, get_caps))
+  if (!gst_data_repo_src_get_media_type_and_size (src, src->caps))
     goto error;
 
   /* In the case of below media type, get sample_size from JSON */
@@ -1334,24 +1288,142 @@ gst_data_repo_src_read_json_file (GstDataRepoSrc * src)
   src->total_samples = json_object_get_int_member (object, "total_samples");
   GST_INFO_OBJECT (src, "total_samples: %d", src->total_samples);
 
+  if (src->total_samples == 0)
+    goto error;
+
   g_free (contents);
   g_object_unref (parser);
-  gst_caps_unref (get_caps);
   g_object_unref (file);
 
   return TRUE;
 
 error:
+  src->media_type = _NNS_MEDIA_INVALID;
   GST_ERROR_OBJECT (src, "Failed to parse %s", src->json_filename);
   g_free (contents);
   g_object_unref (parser);
-  gst_caps_unref (get_caps);
   g_object_unref (file);
 
   return FALSE;
 }
 
 /**
+ * @brief Setter for datareposrc properties.
+ */
+static void
+gst_data_repo_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDataRepoSrc *src;
+  const GstCaps *caps;
+  GstCaps *new_caps;
+
+  g_return_if_fail (GST_IS_DATA_REPO_SRC (object));
+
+  src = GST_DATA_REPO_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      gst_data_repo_src_set_file_path (src, PROP_LOCATION,
+          g_value_get_string (value), NULL);
+      break;
+    case PROP_JSON:
+      gst_data_repo_src_set_file_path (src, PROP_JSON,
+          g_value_get_string (value), NULL);
+      /** To get caps, read JSON before Caps negotiation,
+          to get information on sample data */
+      if (!gst_data_repo_src_read_json_file (src)) {
+        GST_ERROR_OBJECT (src, "Faild to get data format");
+      }
+      break;
+    case PROP_START_SAMPLE_INDEX:
+      src->start_sample_index = g_value_get_uint (value);
+      break;
+    case PROP_STOP_SAMPLE_INDEX:
+      src->stop_sample_index = g_value_get_uint (value);
+      break;
+    case PROP_EPOCHS:
+      src->epochs = g_value_get_uint (value);
+      break;
+    case PROP_IS_SHUFFLE:
+      src->is_shuffle = g_value_get_boolean (value);
+      break;
+    case PROP_TENSORS_SEQUENCE:
+      g_free (src->tensors_seq_str);
+      src->tensors_seq_str = g_value_dup_string (value);
+      if (!gst_data_repo_src_set_tensors_sequence (src)) {
+        GST_ERROR_OBJECT (src, "Faild to set tensors sequence");
+      } else {
+        src->need_changed_caps = TRUE;
+      }
+      break;
+    case PROP_CAPS:
+      caps = gst_value_get_caps (value);
+      if (caps) {
+        new_caps = gst_caps_copy (caps);
+        gst_caps_replace (&src->caps, new_caps);
+        gst_data_repo_src_get_media_type_and_size (src, src->caps);
+        gst_caps_unref (new_caps);
+      }
+      /** let's retry set tensors-sequence.
+          if caps property is set later than tensors-sequence property,
+          setting tensors-sequence fails because caps information is unknown.*/
+      if (src->tensors_seq_str) {
+        if (gst_data_repo_src_set_tensors_sequence (src))
+          src->need_changed_caps = TRUE;
+      }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/**
+ * @brief Getter datareposrc properties
+ */
+static void
+gst_data_repo_src_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstDataRepoSrc *src;
+
+  g_return_if_fail (GST_IS_DATA_REPO_SRC (object));
+
+  src = GST_DATA_REPO_SRC (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, src->filename);
+      break;
+    case PROP_JSON:
+      g_value_set_string (value, src->json_filename);
+      break;
+    case PROP_START_SAMPLE_INDEX:
+      g_value_set_uint (value, src->start_sample_index);
+      break;
+    case PROP_STOP_SAMPLE_INDEX:
+      g_value_set_uint (value, src->stop_sample_index);
+      break;
+    case PROP_EPOCHS:
+      g_value_set_uint (value, src->epochs);
+      break;
+    case PROP_IS_SHUFFLE:
+      g_value_set_boolean (value, src->is_shuffle);
+      break;
+    case PROP_TENSORS_SEQUENCE:
+      g_value_set_string (value, src->tensors_seq_str);
+      break;
+    case PROP_CAPS:
+      gst_value_set_caps (value, src->caps);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/**
  * @brief Change state of datareposrc.
  */
 static GstStateChangeReturn
@@ -1360,13 +1432,39 @@ gst_data_repo_src_change_state (GstElement * element, GstStateChange transition)
   guint i;
   GstDataRepoSrc *src = GST_DATA_REPO_SRC (element);
   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstBaseSrc *basesrc = NULL;
+  gint blocksize;
 
   switch (transition) {
     case GST_STATE_CHANGE_NULL_TO_READY:
       GST_INFO_OBJECT (src, "NULL_TO_READY");
-      if (!gst_data_repo_src_read_json_file (src))
+
+      if (src->media_type == _NNS_MEDIA_INVALID)
         goto state_change_failed;
 
+      /** if media_type is not _NNS_MEDIA_INVALID and sample_size is 0 then
+          'caps' is set by property and sample size needs to be set by blocksize
+          (in the case of otect and text) */
+      if (src->sample_size == 0) {
+        basesrc = GST_BASE_SRC (src);
+        g_object_get (G_OBJECT (basesrc), "blocksize", &blocksize, NULL);
+        GST_DEBUG_OBJECT (src, "blocksize = %d", blocksize);
+        if (blocksize == 0) {
+          GST_ERROR_OBJECT (src, "Please set the 'blocksize' property "
+              "when using the 'caps' property to set the sample format without JSON.");
+          goto state_change_failed;
+        }
+        src->sample_size = blocksize;
+      }
+
+      /** A case of importing a sample format using 'caps' property without JSON. */
+      if (src->total_samples == 0 && src->stop_sample_index == 0) {
+        GST_ERROR_OBJECT (src, "Please set the 'stop-sample-index' property "
+            "when using the 'caps' property to set the sample format without JSON.");
+        goto state_change_failed;
+      }
+
+      /* total_samples -1 is the default value of 'stop-sample-index' property */
       if (src->stop_sample_index == 0)
         src->stop_sample_index = src->total_samples - 1;
 
@@ -1387,9 +1485,10 @@ gst_data_repo_src_change_state (GstElement * element, GstStateChange transition)
               _NNS_TENSOR, src->media_type);
           goto state_change_failed;
         }
-        if (!gst_data_repo_src_set_tensors_sequence (src)) {
+        /* After gst_data_repo_src_set_tensors_sequence() */
+        if (src->tensors_seq_cnt == 0)
           goto state_change_failed;
-        }
+
       } else {
         for (i = 0; i < src->num_tensors; i++)
           src->tensors_seq[i] = i;
index c8fb9b8..d0f95c8 100644 (file)
@@ -44,6 +44,7 @@ typedef struct _GstDataRepoSrcClass GstDataRepoSrcClass;
 struct _GstDataRepoSrc {
 
   GstPushSrc parent;            /**< parent object */
+  GstPad *src_pad;
 
   gboolean is_start;            /**< check if datareposrc is started */
   gboolean successful_read;     /**< used for checking EOS when reading more than one images(multi-files) from a path */
@@ -60,22 +61,24 @@ struct _GstDataRepoSrc {
   guint total_samples;           /**< The number of total samples */
   guint num_samples;             /**< The number of samples to be used out of the total samples in the file */
   guint sample_size;             /**< size of one sample */
-  guint media_type;             /**< media type */
+  gint media_type;               /**< media type */
 
   /* property */
   gchar *filename;              /**< filename */
   gchar *json_filename;         /**< json filename containing meta information of the filename */
   gchar *tensors_seq_str;       /**< tensors in a sample are read into gstBuffer according to tensors_sequence */
-  guint start_sample_index;      /**< start index of sample to read, in case of image, the starting index of the numbered files */
-  guint stop_sample_index;       /**< stop index of sample to read, in case of image, the stoppting index of the numbered files */
-  guint epochs;                  /**< repetition of range of files or samples to read */
+  guint start_sample_index;     /**< start index of sample to read, in case of image, the starting index of the numbered files */
+  guint stop_sample_index;      /**< stop index of sample to read, in case of image, the stoppting index of the numbered files */
+  guint epochs;                 /**< repetition of range of files or samples to read */
   gboolean is_shuffle;          /**< shuffle the sample index */
 
   GArray *shuffled_index_array; /**< shuffled sample index array */
-  guint array_index;             /**< element index of shuffled_index_array */
+  guint array_index;            /**< element index of shuffled_index_array */
 
-  guint tensors_seq[MAX_ITEM]; /**< tensors sequence in a sample that will be read into gstbuffer */
+  guint tensors_seq[MAX_ITEM];  /**< tensors sequence in a sample that will be read into gstbuffer */
   guint tensors_seq_cnt;
+  gboolean need_changed_caps;   /**< When tensors-sequence changes, caps need to be changed */
+  GstCaps *caps;                /**< optional property, datareposrc should get data format from JSON file caps field */
 };
 
 /**
index 206c5c9..42000ba 100644 (file)
@@ -227,8 +227,6 @@ TEST (datareposink, writeTensors)
   gchar *str_pipeline = g_strdup_printf (
       "gst-launch-1.0 datareposrc location=%s json=%s "
       "start-sample-index=0 stop-sample-index=9 ! "
-      "other/tensors, format=static, num_tensors=2, framerate=0/1, "
-      "dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! "
       "datareposink name=datareposink location=mnist.data json=mnist.json",
       file_path, json_path);
 
index f25dbfd..15485a2 100644 (file)
@@ -161,11 +161,9 @@ TEST (datareposrc, readImageFiles)
 
   loop = g_main_loop_new (NULL, FALSE);
 
-  gchar *str_pipeline
-      = g_strdup ("gst-launch-1.0 datareposrc "
-                  "location=img_%02d.png "
-                  "json=img.json "
-                  "start-sample-index=0 stop-sample-index=4 ! pngdec ! fakesink");
+  gchar *str_pipeline = g_strdup (
+      "gst-launch-1.0 datareposrc location=img_%02d.png json=img.json "
+      "start-sample-index=0 stop-sample-index=4 ! pngdec ! fakesink");
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
   ASSERT_NE (pipeline, nullptr);
@@ -197,10 +195,7 @@ TEST (datareposrc, readVideoRaw)
   loop = g_main_loop_new (NULL, FALSE);
 
   gchar *str_pipeline = g_strdup (
-      "gst-launch-1.0 datareposrc "
-      "location=video1.raw "
-      "json=video1.json ! "
-      "video/x-raw, format=RGBx, width=320, height=240, framerate=30/1 ! fakesink");
+      "gst-launch-1.0 datareposrc location=video1.raw json=video1.json ! fakesink");
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
   ASSERT_NE (pipeline, nullptr);
@@ -232,10 +227,7 @@ TEST (datareposrc, readAudioRaw)
   loop = g_main_loop_new (NULL, FALSE);
 
   gchar *str_pipeline = g_strdup (
-      "gst-launch-1.0 datareposrc "
-      "location=audio1.raw "
-      "json=audio1.json ! "
-      "audio/x-raw, format=S16LE, rate=44100, channels=1, layout=interleaved ! fakesink ");
+      "gst-launch-1.0 datareposrc location=audio1.raw json=audio1.json ! fakesink");
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
   ASSERT_NE (pipeline, nullptr);
@@ -261,9 +253,7 @@ TEST (datareposrc, invalidJsonPath0_n)
 {
   GstElement *datareposrc = NULL;
 
-  gchar *str_pipeline = g_strdup (
-      "gst-launch-1.0 datareposrc name=datareposrc ! "
-      "video/x-raw, format=RGBx, width=320, height=240, framerate=30/1 ! fakesink");
+  gchar *str_pipeline = g_strdup ("gst-launch-1.0 datareposrc name=datareposrc ! fakesink");
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
   ASSERT_NE (pipeline, nullptr);
@@ -288,9 +278,7 @@ TEST (datareposrc, invalidJsonPath1_n)
 {
   GstElement *datareposrc = NULL;
 
-  gchar *str_pipeline = g_strdup (
-      "gst-launch-1.0 datareposrc name=datareposrc ! "
-      "video/x-raw, format=RGBx, width=320, height=240, framerate=30/1 ! fakesink");
+  gchar *str_pipeline = g_strdup ("gst-launch-1.0 datareposrc name=datareposrc ! fakesink");
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
   ASSERT_NE (pipeline, nullptr);
@@ -317,9 +305,7 @@ TEST (datareposrc, invalidFilePath0_n)
 {
   GstElement *datareposrc = NULL;
 
-  gchar *str_pipeline = g_strdup (
-      "gst-launch-1.0 datareposrc name=datareposrc ! "
-      "video/x-raw, format=RGBx, width=320, height=240, framerate=30/1 ! fakesink");
+  gchar *str_pipeline = g_strdup ("gst-launch-1.0 datareposrc name=datareposrc ! fakesink");
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
   ASSERT_NE (pipeline, nullptr);
@@ -344,9 +330,7 @@ TEST (datareposrc, invalidFilePath1_n)
 {
   GstElement *datareposrc = NULL;
 
-  gchar *str_pipeline = g_strdup (
-      "gst-launch-1.0 datareposrc name=datareposrc ! "
-      "video/x-raw, format=RGBx, width=320, height=240, framerate=30/1 ! fakesink");
+  gchar *str_pipeline = g_strdup ("gst-launch-1.0 datareposrc name=datareposrc ! fakesink");
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
   ASSERT_NE (pipeline, nullptr);
@@ -365,6 +349,31 @@ TEST (datareposrc, invalidFilePath1_n)
 }
 
 /**
+ * @brief Test for reading a file with invalid param (caps)
+ */
+TEST (datareposrc, invalidCapsWithoutJSON_n)
+{
+  GstElement *datareposrc = NULL;
+
+  gchar *str_pipeline = g_strdup ("gst-launch-1.0 datareposrc name=datareposrc ! fakesink");
+  GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
+  g_free (str_pipeline);
+  ASSERT_NE (pipeline, nullptr);
+
+  datareposrc = gst_bin_get_by_name (GST_BIN (pipeline), "datareposrc");
+  ASSERT_NE (datareposrc, nullptr);
+
+  g_object_set (GST_OBJECT (datareposrc), "location", "video1.raw", NULL);
+  /* set invalid param */
+  g_object_set (GST_OBJECT (datareposrc), "caps", NULL, NULL);
+
+  /* state chagne failure is expected */
+  EXPECT_NE (setPipelineStateSync (pipeline, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0);
+
+  gst_object_unref (pipeline);
+}
+
+/**
  * @brief Test for reading a tensors file
  * the number of total sample(mnist.data) is 10 (0~9)
  * the number tensors is 2 and indices (0,1), default is (0,1)
@@ -389,9 +398,8 @@ TEST (datareposrc, readTensors)
 
   gchar *str_pipeline = g_strdup_printf (
       "gst-launch-1.0 datareposrc name=datareposrc location=%s json=%s "
-      "start-sample-index=0 stop-sample-index=9 epochs=2 tensors-sequence=0,1 !"
-      "other/tensors, format=static, num_tensors=2, framerate=0/1, "
-      "dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! fakesink",
+      "start-sample-index=0 stop-sample-index=9 epochs=2 tensors-sequence=0,1 ! "
+      "fakesink",
       file_path, json_path);
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
@@ -430,6 +438,63 @@ TEST (datareposrc, readTensors)
 }
 
 /**
+ * @brief Test for reading a tensors file with Caps property
+ */
+TEST (datareposrc, readTensorsNoJSONWithCapsParam)
+{
+  GstBus *bus;
+  GMainLoop *loop;
+  gchar *file_path = NULL;
+  gchar *json_path = NULL;
+  GstElement *datareposrc = NULL;
+  gchar *get_str;
+  guint get_value;
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  file_path = get_file_path (filename);
+
+  gchar *str_pipeline = g_strdup_printf (
+      "gst-launch-1.0 datareposrc name=datareposrc location=%s "
+      "start-sample-index=0 stop-sample-index=9 epochs=2 tensors-sequence=0,1 "
+      "caps =\"other/tensors, format=(string)static, framerate=(fraction)0/1, "
+      "num_tensors=(int)2, dimensions=(string)1:1:784:1.1:1:10:1, types=(string)float32.float32\" ! "
+      "fakesink",
+      file_path);
+  GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
+  g_free (str_pipeline);
+  ASSERT_NE (pipeline, nullptr);
+
+  datareposrc = gst_bin_get_by_name (GST_BIN (pipeline), "datareposrc");
+  EXPECT_NE (datareposrc, nullptr);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  ASSERT_NE (bus, nullptr);
+  gst_bus_add_watch (bus, bus_callback, loop);
+  gst_object_unref (bus);
+
+  g_object_get (datareposrc, "location", &get_str, NULL);
+  EXPECT_STREQ (get_str, file_path);
+
+  g_object_get (datareposrc, "tensors-sequence", &get_str, NULL);
+  EXPECT_STREQ (get_str, "0,1");
+
+  g_object_get (datareposrc, "is-shuffle", &get_value, NULL);
+  ASSERT_EQ (get_value, 1U);
+
+  EXPECT_EQ (setPipelineStateSync (pipeline, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0);
+
+  g_main_loop_run (loop);
+
+  setPipelineStateSync (pipeline, GST_STATE_NULL, UNITTEST_STATECHANGE_TIMEOUT);
+
+  gst_object_unref (pipeline);
+  g_main_loop_unref (loop);
+  g_free (file_path);
+  g_free (json_path);
+}
+
+/**
  * @brief Test for reading a file with invalid param (start-sample-index)
  * the number of total sample(mnist.data) is 1000 (0~999)
  */
@@ -445,9 +510,7 @@ TEST (datareposrc, invalidStartSampleIndex0_n)
 
   gchar *str_pipeline = g_strdup_printf (
       "gst-launch-1.0 datareposrc name=datareposrc location=%s json=%s "
-      "stop-sample-index=9 epochs=2 tensors-sequence=0,1 !"
-      "other/tensors, format=static, num_tensors=2, framerate=0/1, "
-      "dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! fakesink",
+      "stop-sample-index=9 epochs=2 tensors-sequence=0,1 ! fakesink",
       file_path, json_path);
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
@@ -484,9 +547,7 @@ TEST (datareposrc, invalidStartSampleIndex1_n)
 
   gchar *str_pipeline = g_strdup_printf (
       "gst-launch-1.0 datareposrc name=datareposrc location=%s json=%s "
-      "stop-sample-index=9 epochs=2 tensors-sequence=0,1 !"
-      "other/tensors, format=static, num_tensors=2, framerate=0/1, "
-      "dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! fakesink",
+      "stop-sample-index=9 epochs=2 tensors-sequence=0,1 ! fakesink",
       file_path, json_path);
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
@@ -523,9 +584,7 @@ TEST (datareposrc, invalidStopSampleIndex0_n)
 
   gchar *str_pipeline = g_strdup_printf (
       "gst-launch-1.0 datareposrc name=datareposrc location=%s json=%s "
-      "start-sample-index=0 epochs=2 tensors-sequence=0,1 !"
-      "other/tensors, format=static, num_tensors=2, framerate=0/1, "
-      "dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! fakesink",
+      "start-sample-index=0 epochs=2 tensors-sequence=0,1 ! fakesink",
       file_path, json_path);
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
@@ -561,9 +620,7 @@ TEST (datareposrc, invalidStopSampleIndex1_n)
 
   gchar *str_pipeline = g_strdup_printf (
       "gst-launch-1.0 datareposrc name=datareposrc location=%s json=%s "
-      "start-sample-index=0 epochs=2 tensors-sequence=0,1 !"
-      "other/tensors, format=static, num_tensors=2, framerate=0/1, "
-      "dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! fakesink",
+      "start-sample-index=0 epochs=2 tensors-sequence=0,1 ! fakesink",
       file_path, json_path);
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
@@ -600,9 +657,7 @@ TEST (datareposrc, invalidEpochs0_n)
 
   gchar *str_pipeline = g_strdup_printf (
       "gst-launch-1.0 datareposrc name=datareposrc location=%s json=%s "
-      "start-sample-index=0 stop-sample-index=9 tensors-sequence=0,1 ! "
-      "other/tensors, format=static, num_tensors=2, framerate=0/1, "
-      "dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! fakesink",
+      "start-sample-index=0 stop-sample-index=9 tensors-sequence=0,1 ! fakesink",
       file_path, json_path);
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
@@ -638,9 +693,7 @@ TEST (datareposrc, invalidEpochs1_n)
 
   gchar *str_pipeline = g_strdup_printf (
       "gst-launch-1.0 datareposrc name=datareposrc location=%s json=%s "
-      "start-sample-index=0 stop-sample-index=9 tensors-sequence=0,1 ! "
-      "other/tensors, format=static, num_tensors=2, framerate=0/1, "
-      "dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! fakesink",
+      "start-sample-index=0 stop-sample-index=9 tensors-sequence=0,1 ! fakesink",
       file_path, json_path);
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
@@ -673,12 +726,10 @@ TEST (datareposrc, invalidTensorsSequence0_n)
   file_path = get_file_path (filename);
   json_path = get_file_path (json);
 
-  gchar *str_pipeline = g_strdup_printf (
-      "gst-launch-1.0 datareposrc name=datareposrc location=%s json=%s "
-      "start-sample-index=0 stop-sample-index=9 ! "
-      "other/tensors, format=static, num_tensors=2, framerate=0/1, "
-      "dimensions=1:1:784:1.1:1:10:1, types=float32.float32 ! fakesink",
-      file_path, json_path);
+  gchar *str_pipeline
+      = g_strdup_printf ("gst-launch-1.0 datareposrc name=datareposrc location=%s json=%s "
+                         "start-sample-index=0 stop-sample-index=9 ! fakesink",
+          file_path, json_path);
   GstElement *pipeline = gst_parse_launch (str_pipeline, NULL);
   g_free (str_pipeline);
   g_free (file_path);