Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1-only */
2 : /**
3 : * Copyright (C) 2022 Samsung Electronics Co., Ltd.
4 : *
5 : * @file gstdatareposrc.c
6 : * @date 31 January 2023
7 : * @brief GStreamer plugin to read file in MLOps Data repository into buffers
8 : * @see https://github.com/nnstreamer/nnstreamer
9 : * @author Hyunil Park <hyunil46.park@samsung.com>
10 : * @bug No known bugs except for NYI items
11 : *
12 : *
13 : * ## Example launch line
14 : * |[
15 : * gst-launch-1.0 datareposrc location=mnist.data json=mnist.json start-sample-index=3 stop-sample-index=202 epochs=5 ! \
16 : * ! tensor_sink
17 : * gst-launch-1.0 datareposrc location=image_%02ld.png json=image.json start-sample-index=3 stop-sample-index=9 epochs=2 ! fakesink
18 : * gst-launch-1.0 datareposrc location=audiofile json=audio.json ! fakesink
19 : * gst-launch-1.0 datareposrc location=videofile json=video.json ! fakesink
20 : * |]
21 : * |[ Unknown sample file(has not JSON) need to set caps and blocksize or set caps to tensors type without blocksize
22 : * gst-launch-1.0 datareposrc blocksize=3176 location=unknown.data start-sample-index=3 stop-sample-index=202 epochs=5 \
23 : * caps ="application/octet-stream" ! tensor_converter input-dim=1:1:784:1,1:1:10:1 input-type=float32,float32 ! fakesink
24 : * |]
25 : * or
26 : * |[
27 : * gst-launch-1.0 datareposrc location=unknown.data start-sample-index=3 stop-sample-index=202 epochs=5 \
28 : * 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" \
29 : * ! fakesink
30 : * ]|
31 : */
32 :
33 : #ifdef HAVE_CONFIG_H
34 : #include <config.h>
35 : #endif
36 : #include <gst/gst.h>
37 : #include <gst/video/video-info.h>
38 : #include <gst/audio/audio-info.h>
39 : #include <glib/gstdio.h>
40 : #include <nnstreamer_plugin_api.h>
41 : #include <nnstreamer_util.h>
42 : #include <stdio.h>
43 : #include <fcntl.h>
44 : #include <unistd.h>
45 : #include <errno.h>
46 : #include <string.h>
47 : #include <sys/types.h>
48 : #include <sys/stat.h>
49 : #include <inttypes.h>
50 : #include "gstdatareposrc.h"
51 :
52 : #define struct_stat struct stat
53 : #ifndef S_ISREG
54 : /* regular file */
55 : #define S_ISREG(mode) ((mode)&_S_IFREG)
56 : #endif
57 : #ifndef S_ISDIR
58 : #define S_ISDIR(mode) ((mode)&_S_IFDIR)
59 : #endif
60 : /* socket */
61 : #ifndef S_ISSOCK
62 : #define S_ISSOCK(x) (0)
63 : #endif
64 : #ifndef O_BINARY
65 : #define O_BINARY (0)
66 : #endif
67 :
68 : static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
69 : GST_PAD_SRC,
70 : GST_PAD_ALWAYS,
71 : GST_STATIC_CAPS_ANY);
72 :
73 : GST_DEBUG_CATEGORY_STATIC (gst_data_repo_src_debug);
74 : #define GST_CAT_DEFAULT gst_data_repo_src_debug
75 :
76 : /* datareposrc signals and args */
77 : enum
78 : {
79 : PROP_0,
80 : PROP_LOCATION,
81 : PROP_JSON,
82 : PROP_START_SAMPLE_INDEX,
83 : PROP_STOP_SAMPLE_INDEX,
84 : PROP_EPOCHS,
85 : PROP_IS_SHUFFLE,
86 : PROP_TENSORS_SEQUENCE,
87 : PROP_CAPS, /* for setting caps of sample data directly */
88 : };
89 :
90 : #define DEFAULT_INDEX 0
91 : #define DEFAULT_EPOCHS 1
92 : #define DEFAULT_IS_SHUFFLE TRUE
93 :
94 : static void gst_data_repo_src_finalize (GObject * object);
95 : static GstStateChangeReturn gst_data_repo_src_change_state (GstElement *
96 : element, GstStateChange transition);
97 : static void gst_data_repo_src_set_property (GObject * object, guint prop_id,
98 : const GValue * value, GParamSpec * pspec);
99 : static void gst_data_repo_src_get_property (GObject * object, guint prop_id,
100 : GValue * value, GParamSpec * pspec);
101 : static gboolean gst_data_repo_src_stop (GstBaseSrc * basesrc);
102 : static GstCaps *gst_data_repo_src_get_caps (GstBaseSrc * basesrc,
103 : GstCaps * filter);
104 : static gboolean gst_data_repo_src_set_caps (GstBaseSrc * basesrc,
105 : GstCaps * caps);
106 : static GstFlowReturn gst_data_repo_src_create (GstPushSrc * pushsrc,
107 : GstBuffer ** buffer);
108 : #define _do_init \
109 : GST_DEBUG_CATEGORY_INIT (gst_data_repo_src_debug, "datareposrc", 0, "datareposrc element");
110 :
111 : #define gst_data_repo_src_parent_class parent_class
112 926 : G_DEFINE_TYPE_WITH_CODE (GstDataRepoSrc, gst_data_repo_src, GST_TYPE_PUSH_SRC,
113 : _do_init);
114 :
115 : /**
116 : * @brief initialize the datareposrc's class
117 : */
118 : static void
119 23 : gst_data_repo_src_class_init (GstDataRepoSrcClass * klass)
120 : {
121 23 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
122 23 : GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
123 23 : GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
124 23 : GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
125 :
126 23 : gobject_class->set_property =
127 23 : GST_DEBUG_FUNCPTR (gst_data_repo_src_set_property);
128 23 : gobject_class->get_property =
129 23 : GST_DEBUG_FUNCPTR (gst_data_repo_src_get_property);
130 :
131 23 : g_object_class_install_property (gobject_class, PROP_LOCATION,
132 : g_param_spec_string ("location", "File Location",
133 : "Location of the file to read that is stored in MLOps Data Repository, "
134 : "if the files are images, write the index of filename name "
135 : "like %04ld or %04lld (e.g., filenmae%04ld.png)",
136 : NULL,
137 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
138 : GST_PARAM_MUTABLE_READY));
139 :
140 23 : g_object_class_install_property (gobject_class, PROP_JSON,
141 : g_param_spec_string ("json", "Json file path",
142 : "Json file path containing the meta information of the file "
143 : "specified as location", NULL,
144 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
145 : GST_PARAM_MUTABLE_READY));
146 :
147 23 : g_object_class_install_property (gobject_class, PROP_START_SAMPLE_INDEX,
148 : g_param_spec_uint ("start-sample-index", "Start index of samples",
149 : "Start index of sample to read, in case of image, "
150 : "the starting index of the numbered files. start at 0."
151 : "Set start index of range of samples or files to read",
152 : 0, G_MAXINT, DEFAULT_INDEX,
153 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
154 : GST_PARAM_MUTABLE_READY));
155 :
156 23 : g_object_class_install_property (gobject_class, PROP_STOP_SAMPLE_INDEX,
157 : g_param_spec_uint ("stop-sample-index", "Stop index of samples",
158 : "Stop index of sample to read, in case of image, "
159 : "the stopping index of the numbered files. start at 0."
160 : "Set stop index of range of samples or files to read",
161 : 0, G_MAXINT, DEFAULT_INDEX,
162 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
163 : GST_PARAM_MUTABLE_READY));
164 :
165 23 : g_object_class_install_property (gobject_class, PROP_EPOCHS,
166 : g_param_spec_uint ("epochs", "Epochs",
167 : "Repetition of range of files or samples to read, set number of repetitions",
168 : 0, G_MAXINT, DEFAULT_EPOCHS,
169 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
170 : GST_PARAM_MUTABLE_READY));
171 :
172 23 : g_object_class_install_property (gobject_class, PROP_TENSORS_SEQUENCE,
173 : g_param_spec_string ("tensors-sequence", "Tensors sequence",
174 : "Tensors in a sample are read into gstBuffer according to tensors-sequence."
175 : "Only read the set tensors among all tensors in a sample"
176 : "e.g, if a sample has '1:1:1:1','1:1:10:1','1:1:784:1' and each index is '0,1,2', "
177 : "'tensors-sequence=2,1' means that only '1:1:784:1' then '1:1:10:1' are read. "
178 : "Use for other/tensors and the default value is NULL"
179 : "(all tensors are read in the order stored in a sample).",
180 : NULL,
181 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
182 : GST_PARAM_MUTABLE_READY));
183 :
184 23 : g_object_class_install_property (gobject_class, PROP_IS_SHUFFLE,
185 : g_param_spec_boolean ("is-shuffle", "Is shuffle",
186 : "If the value is true, samples are shuffled",
187 : DEFAULT_IS_SHUFFLE,
188 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
189 : GST_PARAM_MUTABLE_READY));
190 :
191 23 : g_object_class_install_property (gobject_class, PROP_CAPS,
192 : g_param_spec_boxed ("caps", "Caps",
193 : "Optional property, Caps describing the format of the sample data.",
194 : GST_TYPE_CAPS,
195 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
196 : GST_PARAM_MUTABLE_READY));
197 :
198 23 : gobject_class->finalize = gst_data_repo_src_finalize;
199 23 : gstelement_class->change_state = gst_data_repo_src_change_state;
200 :
201 23 : gst_element_class_set_static_metadata (gstelement_class,
202 : "NNStreamer MLOps Data Repository Source",
203 : "Source/File",
204 : "Read files in MLOps Data Repository into buffers",
205 : "Samsung Electronics Co., Ltd.");
206 23 : gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
207 :
208 23 : gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_data_repo_src_stop);
209 23 : gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_data_repo_src_get_caps);
210 23 : gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_data_repo_src_set_caps);
211 23 : gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_data_repo_src_create);
212 :
213 : if (sizeof (off_t) < 8) {
214 : GST_LOG ("No large file support, sizeof (off_t) = %" G_GSIZE_FORMAT "!",
215 : sizeof (off_t));
216 : }
217 23 : }
218 :
219 : /**
220 : * @brief Initialize datareposrc
221 : */
222 : static void
223 38 : gst_data_repo_src_init (GstDataRepoSrc * src)
224 : {
225 38 : src->filename = NULL;
226 38 : src->json_filename = NULL;
227 38 : src->tensors_seq_str = NULL;
228 38 : src->file_size = 0;
229 38 : src->fd = 0;
230 38 : src->data_type = GST_DATA_REPO_DATA_UNKNOWN;
231 38 : src->fd_offset = 0;
232 38 : src->start_offset = 0;
233 38 : src->last_offset = 0;
234 38 : src->successful_read = FALSE;
235 38 : src->is_start = FALSE;
236 38 : src->current_sample_index = 0;
237 38 : src->start_sample_index = 0;
238 38 : src->stop_sample_index = 0;
239 38 : src->epochs = DEFAULT_EPOCHS;
240 38 : src->shuffled_index_array = g_array_new (FALSE, FALSE, sizeof (guint));
241 38 : src->array_index = 0;
242 38 : src->sample_offset_array = NULL;
243 38 : src->sample_offset_array_len = 0;
244 38 : src->tensor_size_array = NULL;
245 38 : src->tensor_size_array_len = 0;
246 38 : src->tensor_count_array = NULL;
247 38 : src->tensor_count_array_len = 0;
248 38 : src->first_epoch_is_done = FALSE;
249 38 : src->is_shuffle = DEFAULT_IS_SHUFFLE;
250 38 : src->num_samples = 0;
251 38 : src->total_samples = 0;
252 38 : src->tensors_seq_cnt = 0;
253 38 : src->caps = NULL;
254 38 : src->sample_size = 0;
255 38 : src->need_changed_caps = FALSE;
256 38 : src->n_frame = 0;
257 38 : src->running_time = 0;
258 38 : src->parser = NULL;
259 38 : gst_tensors_config_init (&src->config);
260 :
261 : /* Filling the buffer should be pending until set_caps() */
262 38 : gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
263 38 : gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
264 38 : }
265 :
266 : /**
267 : * @brief Function to finalize instance.
268 : */
269 : static void
270 35 : gst_data_repo_src_finalize (GObject * object)
271 : {
272 35 : GstDataRepoSrc *src = GST_DATA_REPO_SRC (object);
273 :
274 35 : g_free (src->filename);
275 35 : g_free (src->json_filename);
276 35 : g_free (src->tensors_seq_str);
277 :
278 : /* close the file */
279 35 : if (src->fd) {
280 0 : g_close (src->fd, NULL);
281 0 : src->fd = 0;
282 : }
283 :
284 35 : if (src->parser)
285 27 : g_object_unref (src->parser);
286 :
287 35 : if (src->shuffled_index_array)
288 35 : g_array_free (src->shuffled_index_array, TRUE);
289 :
290 35 : if (src->caps)
291 28 : gst_caps_replace (&src->caps, NULL);
292 :
293 35 : gst_tensors_config_free (&src->config);
294 :
295 35 : G_OBJECT_CLASS (parent_class)->finalize (object);
296 35 : }
297 :
298 : /**
299 : * @brief Parse gst-caps to get media type and data size.
300 : * @note This function always takes the ownership of gst-caps.
301 : */
302 : static gboolean
303 48 : gst_data_repo_src_parse_caps (GstDataRepoSrc * src, GstCaps * caps)
304 : {
305 : GstStructure *s;
306 :
307 48 : g_return_val_if_fail (src != NULL, FALSE);
308 48 : g_return_val_if_fail (caps != NULL, FALSE);
309 :
310 48 : src->data_type = gst_data_repo_get_data_type_from_caps (caps);
311 48 : s = gst_caps_get_structure (caps, 0);
312 :
313 48 : switch (src->data_type) {
314 1 : case GST_DATA_REPO_DATA_VIDEO:
315 : {
316 : GstVideoInfo video_info;
317 :
318 1 : gst_video_info_init (&video_info);
319 1 : gst_video_info_from_caps (&video_info, caps);
320 :
321 : /* https://gstreamer.freedesktop.org/documentation/additional/design/mediatype-video-raw.html?gi-language=c */
322 1 : src->sample_size = (guint) GST_VIDEO_INFO_SIZE (&video_info);
323 :
324 1 : GST_DEBUG_OBJECT (src, "format(%s), width(%d), height(%d): %zd byte/frame",
325 : gst_structure_get_string (s, "format"),
326 : GST_VIDEO_INFO_WIDTH (&video_info),
327 : GST_VIDEO_INFO_HEIGHT (&video_info), src->sample_size);
328 1 : break;
329 : }
330 1 : case GST_DATA_REPO_DATA_AUDIO:
331 : {
332 : GstAudioInfo audio_info;
333 : gint rate, channel, depth;
334 :
335 1 : gst_audio_info_init (&audio_info);
336 1 : gst_audio_info_from_caps (&audio_info, caps);
337 :
338 1 : rate = GST_AUDIO_INFO_RATE (&audio_info);
339 1 : channel = GST_AUDIO_INFO_CHANNELS (&audio_info);
340 1 : depth = GST_AUDIO_INFO_DEPTH (&audio_info);
341 :
342 1 : src->sample_size = (gsize) channel * (depth / 8) * rate;
343 :
344 1 : GST_DEBUG_OBJECT (src,
345 : "format(%s), depth(%d), rate(%d), channel(%d): %zd bps",
346 : gst_structure_get_string (s, "format"), depth, rate, channel,
347 : src->sample_size);
348 1 : break;
349 : }
350 45 : case GST_DATA_REPO_DATA_TENSOR:
351 : {
352 : GstTensorInfo *_info;
353 : guint i;
354 :
355 : /* Set current tensors information if given data type is tensor. */
356 45 : gst_tensors_config_free (&src->config);
357 45 : gst_tensors_config_from_structure (&src->config, s);
358 45 : src->sample_size = 0;
359 :
360 123 : for (i = 0; i < src->config.info.num_tensors; i++) {
361 78 : src->tensors_offset[i] = src->sample_size;
362 78 : _info = gst_tensors_info_get_nth_info (&src->config.info, i);
363 78 : src->tensors_size[i] = gst_tensor_info_get_size (_info);
364 78 : GST_DEBUG_OBJECT (src, "offset[%u]: %zd", i, src->tensors_offset[i]);
365 78 : GST_DEBUG_OBJECT (src, "size[%u]: %zd", i, src->tensors_size[i]);
366 78 : src->sample_size += src->tensors_size[i];
367 : }
368 45 : break;
369 : }
370 1 : default:
371 1 : break;
372 : }
373 :
374 48 : src->rate_n = 0;
375 48 : src->rate_d = 1;
376 48 : if (gst_structure_has_field (s, "framerate")) {
377 47 : gst_structure_get_fraction (s, "framerate", &src->rate_n, &src->rate_d);
378 : }
379 :
380 48 : GST_LOG_OBJECT (src, "framerate %d/%d", src->rate_n, src->rate_d);
381 48 : GST_LOG_OBJECT (src, "data type: %d", src->data_type);
382 :
383 : /* This function always takes caps. */
384 48 : if (src->data_type != GST_DATA_REPO_DATA_UNKNOWN)
385 48 : gst_caps_take (&src->caps, caps);
386 : else
387 0 : gst_caps_unref (caps);
388 :
389 48 : return (src->data_type != GST_DATA_REPO_DATA_UNKNOWN);
390 : }
391 :
392 : /**
393 : * @brief Function to set file path.
394 : */
395 : static gboolean
396 74 : gst_data_repo_src_set_file_path (GstDataRepoSrc * src, const int prop,
397 : const gchar * file_path, GError ** err)
398 : {
399 74 : gchar *filename = NULL;
400 : GstState state;
401 :
402 74 : g_return_val_if_fail (prop == PROP_LOCATION || prop == PROP_JSON, FALSE);
403 :
404 : /* the element must be stopped in order to do this */
405 74 : GST_OBJECT_LOCK (src);
406 74 : state = GST_STATE (src);
407 74 : if (state != GST_STATE_READY && state != GST_STATE_NULL)
408 0 : goto wrong_state;
409 74 : GST_OBJECT_UNLOCK (src);
410 :
411 : /* clear the filename if we get a NULL */
412 74 : if (file_path == NULL) {
413 2 : filename = NULL;
414 : } else {
415 : /* should be UTF8 */
416 72 : filename = g_strdup (file_path);
417 72 : GST_INFO_OBJECT (src, "%sname : %s",
418 : (prop == PROP_LOCATION) ? "file" : "json_file", filename);
419 : }
420 :
421 74 : if (prop == PROP_LOCATION) {
422 38 : g_free (src->filename);
423 38 : src->filename = filename;
424 : } else { /* PROP_JSON */
425 36 : g_free (src->json_filename);
426 36 : src->json_filename = filename;
427 : }
428 :
429 74 : return TRUE;
430 :
431 : /* ERROR */
432 0 : wrong_state:
433 : {
434 0 : g_warning
435 : ("Changing the `location or json' property on datareposrc when a file is "
436 : "open is not supported.");
437 0 : if (err)
438 0 : g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_STATE,
439 : "Changing the `location or json' property on datareposrc when a file is "
440 : "open is not supported.");
441 0 : GST_OBJECT_UNLOCK (src);
442 0 : return FALSE;
443 : }
444 : }
445 :
446 : /**
447 : * @brief Function to set tensors sequence
448 : */
449 : static gboolean
450 21 : gst_data_repo_src_set_tensors_sequence (GstDataRepoSrc * src)
451 : {
452 21 : g_auto (GStrv) strv = NULL;
453 : guint length;
454 21 : guint i = 0;
455 :
456 21 : g_return_val_if_fail (src != NULL, FALSE);
457 21 : g_return_val_if_fail (src->tensors_seq_str != NULL, FALSE);
458 :
459 21 : GST_INFO_OBJECT (src, "tensors sequence = %s", src->tensors_seq_str);
460 :
461 : /* not use NNS_TENSOR_SIZE_LIMIT */
462 21 : strv = g_strsplit (src->tensors_seq_str, ",", -1);
463 :
464 21 : length = g_strv_length (strv);
465 21 : if (length > NNS_TENSOR_SIZE_LIMIT) {
466 0 : GST_ERROR_OBJECT (src, "The total number of indices exceeded %d.",
467 : NNS_TENSOR_SIZE_LIMIT);
468 0 : goto error;
469 : }
470 :
471 63 : while (strv[i] != NULL && strlen (strv[i]) > 0) {
472 43 : src->tensors_seq[i] = (guint) g_ascii_strtoull (strv[i], NULL, 10);
473 43 : if (src->tensors_seq[i] > src->config.info.num_tensors - 1) {
474 1 : GST_ERROR_OBJECT (src, "Invalid index %d, max is %d", src->tensors_seq[i],
475 : src->config.info.num_tensors - 1);
476 1 : goto error;
477 : }
478 42 : GST_INFO_OBJECT (src, "%d", src->tensors_seq[i]);
479 42 : i++;
480 : }
481 20 : src->tensors_seq_cnt = i;
482 20 : GST_INFO_OBJECT (src, "The number of selected tensors is %d",
483 : src->tensors_seq_cnt);
484 :
485 : /* num_tensors was calculated from JSON file */
486 20 : if (src->config.info.num_tensors < src->tensors_seq_cnt) {
487 3 : GST_ERROR_OBJECT (src,
488 : "The number of tensors selected(%d) "
489 : "is greater than the total number of tensors(%d) in a sample.",
490 : src->tensors_seq_cnt, src->config.info.num_tensors);
491 3 : goto error;
492 : }
493 17 : return TRUE;
494 :
495 4 : error:
496 4 : src->tensors_seq_cnt = 0;
497 4 : return FALSE;
498 : }
499 :
500 : /**
501 : * @brief Function to get file offset with sample index
502 : */
503 : static guint64
504 119 : gst_data_repo_src_get_file_offset (GstDataRepoSrc * src, guint sample_index)
505 : {
506 : guint64 offset;
507 :
508 119 : g_return_val_if_fail (src != NULL, 0);
509 119 : g_return_val_if_fail (src->data_type != GST_DATA_REPO_DATA_IMAGE, 0);
510 119 : g_return_val_if_fail (src->fd != 0, 0);
511 :
512 119 : offset = src->sample_size * sample_index;
513 :
514 119 : return offset;
515 : }
516 :
517 : /**
518 : * @brief Function to shuffle samples index
519 : */
520 : static void
521 2 : gst_data_repo_src_shuffle_samples_index (GstDataRepoSrc * src)
522 : {
523 : guint i, j;
524 : guint value_i, value_j;
525 2 : g_return_if_fail (src != NULL);
526 2 : g_return_if_fail (src->shuffled_index_array != NULL);
527 :
528 2 : GST_LOG_OBJECT (src, "samples index are shuffled");
529 : /* Fisher-Yates algorithm */
530 : /* The last index is the number of samples - 1. */
531 20 : for (i = src->num_samples - 1; i > 0; i--) {
532 18 : j = g_random_int_range (0, src->num_samples);
533 18 : value_i = g_array_index (src->shuffled_index_array, guint, i);
534 18 : value_j = g_array_index (src->shuffled_index_array, guint, j);
535 :
536 : /* shuffled_index_array->data type is gchar * */
537 18 : *(guint *) (src->shuffled_index_array->data + (sizeof (guint) * i)) =
538 : value_j;
539 18 : *(guint *) (src->shuffled_index_array->data + (sizeof (guint) * j)) =
540 : value_i;
541 : }
542 :
543 22 : for (i = 0; i < src->shuffled_index_array->len; i++) {
544 20 : GST_DEBUG_OBJECT (src, "%u -> %u", i,
545 : g_array_index (src->shuffled_index_array, guint, i));
546 : }
547 : }
548 :
549 : /**
550 : * @brief Function to check epoch and EOS
551 : */
552 : static gboolean
553 211 : gst_data_repo_src_epoch_is_done (GstDataRepoSrc * src)
554 : {
555 211 : g_return_val_if_fail (src != NULL, FALSE);
556 211 : if (src->num_samples != src->array_index)
557 196 : return FALSE;
558 :
559 15 : src->first_epoch_is_done = TRUE;
560 15 : src->array_index = 0;
561 15 : src->epochs--;
562 :
563 15 : return TRUE;
564 : }
565 :
566 : /**
567 : * @brief Function to read tensors
568 : */
569 : static GstFlowReturn
570 86 : gst_data_repo_src_read_tensors (GstDataRepoSrc * src, GstBuffer ** buffer)
571 : {
572 86 : GstFlowReturn ret = GST_FLOW_OK;
573 86 : guint i = 0, seq_idx = 0;
574 86 : GstBuffer *buf = NULL;
575 : gsize to_read, byte_read;
576 : gssize read_size;
577 : guint8 *data;
578 86 : GstMemory *mem = NULL;
579 : GstMapInfo info;
580 86 : guint shuffled_index = 0;
581 86 : guint64 sample_offset = 0;
582 86 : guint64 offset = 0; /* offset from 0 */
583 :
584 172 : g_return_val_if_fail (src->fd != 0, GST_FLOW_ERROR);
585 86 : g_return_val_if_fail (src->shuffled_index_array != NULL, GST_FLOW_ERROR);
586 :
587 86 : if (gst_data_repo_src_epoch_is_done (src)) {
588 8 : if (src->epochs == 0) {
589 6 : GST_LOG_OBJECT (src, "send EOS");
590 6 : return GST_FLOW_EOS;
591 : }
592 2 : if (src->is_shuffle)
593 2 : gst_data_repo_src_shuffle_samples_index (src);
594 : }
595 :
596 : /* only do for first epoch */
597 80 : if (!src->first_epoch_is_done) {
598 : /* append samples index to array */
599 60 : g_array_append_val (src->shuffled_index_array, src->current_sample_index);
600 60 : src->current_sample_index++;
601 : }
602 80 : shuffled_index =
603 80 : g_array_index (src->shuffled_index_array, guint, src->array_index++);
604 80 : GST_LOG_OBJECT (src, "shuffled_index [%d] -> %d", src->array_index - 1,
605 : shuffled_index);
606 :
607 : /* sample offset from 0 */
608 80 : sample_offset = gst_data_repo_src_get_file_offset (src, shuffled_index);
609 80 : GST_LOG_OBJECT (src, "sample offset 0x%" G_GINT64_MODIFIER "x (%d size)",
610 : sample_offset, (guint) sample_offset);
611 :
612 80 : buf = gst_buffer_new ();
613 :
614 240 : for (i = 0; i < src->tensors_seq_cnt; i++) {
615 160 : seq_idx = src->tensors_seq[i];
616 160 : mem = gst_allocator_alloc (NULL, src->tensors_size[seq_idx], NULL);
617 :
618 160 : if (!gst_memory_map (mem, &info, GST_MAP_WRITE)) {
619 0 : GST_ERROR_OBJECT (src, "Could not map GstMemory[%d]", i);
620 0 : ret = GST_FLOW_ERROR;
621 0 : goto error;
622 : }
623 :
624 160 : GST_INFO_OBJECT (src, "sequence index: %d", seq_idx);
625 160 : GST_INFO_OBJECT (src, "tensor_size[%d]: %zd", seq_idx,
626 : src->tensors_size[seq_idx]);
627 160 : GST_INFO_OBJECT (src, "tensors_offset[%d]: %zd", seq_idx,
628 : src->tensors_offset[seq_idx]);
629 :
630 : /** offset and sample_offset(byte size) are from 0.
631 : if the size of one sample is 6352 and num_tensors is 4,
632 : dimensions are '1:1:784:1' , '1:1:10:1', '1:1:784:1' and '1:1:10:1' with float32.
633 : the offset of the second sample is as follows.
634 : -------------------------------------------------
635 : sample_offset: 6352
636 : tensors index: [ 0 | 1 | 2 | 3 ]
637 : tensors_size: [ 3136 | 40 | 3136 | 40 ]
638 : tensors_offset: [ 0 | 3136 | 3176 | 6312 ]
639 : fd offset: [ 6352 | 9488 | 9528 | 12664 ]
640 : -------------------------------------------------
641 : if user sets "tensor-sequence=2,1", datareposrc read offset 9528 then 9488.
642 : */
643 :
644 160 : data = info.data;
645 :
646 160 : byte_read = 0;
647 160 : to_read = src->tensors_size[seq_idx];
648 160 : offset = sample_offset + src->tensors_offset[seq_idx];
649 160 : src->fd_offset = lseek (src->fd, offset, SEEK_SET);
650 :
651 320 : while (to_read > 0) {
652 160 : GST_LOG_OBJECT (src,
653 : "Reading %zd bytes at offset 0x%" G_GINT64_MODIFIER "x (%zd size)",
654 : to_read, src->fd_offset + byte_read,
655 : (guint) src->fd_offset + byte_read);
656 160 : errno = 0;
657 160 : read_size = read (src->fd, data + byte_read, to_read);
658 160 : GST_LOG_OBJECT (src, "Read: %zd", read_size);
659 160 : if (read_size < 0) {
660 0 : if (errno == EAGAIN || errno == EINTR)
661 0 : continue;
662 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
663 0 : ret = GST_FLOW_ERROR;
664 0 : goto error;
665 : }
666 : /* files should eos if they read 0 and more was requested */
667 160 : if (read_size == 0) {
668 : /* .. but first we should return any remaining data */
669 0 : if (byte_read > 0)
670 0 : break;
671 0 : GST_DEBUG_OBJECT (src, "EOS");
672 0 : ret = GST_FLOW_EOS;
673 0 : goto error;
674 : }
675 160 : to_read -= read_size;
676 160 : byte_read += read_size;
677 :
678 160 : src->read_position += read_size;
679 160 : src->fd_offset += read_size;
680 : }
681 :
682 160 : gst_memory_unmap (mem, &info);
683 :
684 160 : gst_tensor_buffer_append_memory (buf, mem,
685 160 : gst_tensors_info_get_nth_info (&src->config.info, i));
686 160 : mem = NULL;
687 : }
688 :
689 80 : *buffer = buf;
690 :
691 80 : return GST_FLOW_OK;
692 :
693 0 : error:
694 0 : if (mem) {
695 0 : gst_memory_unmap (mem, &info);
696 0 : gst_memory_unref (mem);
697 : }
698 0 : if (buf)
699 0 : gst_buffer_unref (buf);
700 :
701 0 : return ret;
702 : }
703 :
704 : /**
705 : * @brief Function to get num_tensors from tensor_count_array
706 : */
707 : static guint
708 102 : gst_data_repo_src_get_num_tensors (GstDataRepoSrc * src, guint shuffled_index)
709 : {
710 102 : guint num_tensors = 0;
711 102 : guint cur_idx_tensor_cnt = 0;
712 102 : guint next_idx_tensor_cnt = 0;
713 : gint64 val;
714 :
715 102 : g_return_val_if_fail (src != NULL, 0);
716 :
717 102 : val = json_array_get_int_element (src->tensor_count_array, shuffled_index);
718 102 : g_return_val_if_fail (val >= 0, 0);
719 :
720 102 : cur_idx_tensor_cnt = (guint) val;
721 102 : GST_DEBUG_OBJECT (src, "cur_idx_tensor_cnt:%u", cur_idx_tensor_cnt);
722 :
723 102 : if (shuffled_index + 1 == src->tensor_count_array_len) {
724 4 : next_idx_tensor_cnt = src->tensor_size_array_len;
725 : } else {
726 98 : val = json_array_get_int_element (src->tensor_count_array,
727 : shuffled_index + 1);
728 98 : g_return_val_if_fail (val >= 0, 0);
729 :
730 98 : next_idx_tensor_cnt = (guint) val;
731 : }
732 102 : GST_DEBUG_OBJECT (src, "next_idx_tensor_cnt:%u", next_idx_tensor_cnt);
733 :
734 102 : num_tensors = next_idx_tensor_cnt - cur_idx_tensor_cnt;
735 102 : GST_DEBUG_OBJECT (src, "num_tensors:%u", num_tensors);
736 :
737 102 : return num_tensors;
738 : }
739 :
740 : /**
741 : * @brief Function to read flexible or sparse tensors
742 : */
743 : static GstFlowReturn
744 106 : gst_data_repo_src_read_flexible_or_sparse_tensors (GstDataRepoSrc * src,
745 : GstBuffer ** buffer)
746 : {
747 106 : GstFlowReturn ret = GST_FLOW_OK;
748 : guint i;
749 106 : guint shuffled_index = 0;
750 : gint64 val;
751 106 : guint num_tensors = 0;
752 106 : GstBuffer *buf = NULL;
753 106 : GstMemory *mem = NULL;
754 : GstMapInfo info;
755 : GstTensorMetaInfo meta;
756 : GstTensorInfo tinfo;
757 : gsize to_read, byte_read;
758 : gssize read_size;
759 : guint8 *data;
760 : guint tensor_count;
761 : gsize tensor_size;
762 :
763 212 : g_return_val_if_fail (src->fd != 0, GST_FLOW_ERROR);
764 106 : g_return_val_if_fail (src->shuffled_index_array != NULL, GST_FLOW_ERROR);
765 :
766 106 : if (gst_data_repo_src_epoch_is_done (src)) {
767 4 : if (src->epochs == 0) {
768 4 : GST_LOG_OBJECT (src, "send EOS");
769 4 : return GST_FLOW_EOS;
770 : }
771 0 : if (src->is_shuffle)
772 0 : gst_data_repo_src_shuffle_samples_index (src);
773 : }
774 :
775 : /* only do for first epoch */
776 102 : if (!src->first_epoch_is_done) {
777 : /* append samples index to array */
778 102 : g_array_append_val (src->shuffled_index_array, src->current_sample_index);
779 102 : src->current_sample_index++;
780 : }
781 :
782 102 : shuffled_index =
783 102 : g_array_index (src->shuffled_index_array, guint, src->array_index++);
784 102 : GST_LOG_OBJECT (src, "shuffled_index [%d] -> %d", src->array_index - 1,
785 : shuffled_index);
786 :
787 : /* sample offset from 0 */
788 102 : val = json_array_get_int_element (src->sample_offset_array, shuffled_index);
789 102 : if (val < 0) {
790 0 : GST_ERROR_OBJECT (src, "Could not get the sample offset from json.");
791 0 : return GST_FLOW_ERROR;
792 : }
793 :
794 102 : GST_LOG_OBJECT (src, "sample offset 0x%" G_GINT64_MODIFIER "x (%d size)",
795 : val, (guint) val);
796 :
797 102 : src->fd_offset = lseek (src->fd, val, SEEK_SET);
798 :
799 102 : val = json_array_get_int_element (src->tensor_count_array, shuffled_index);
800 102 : if (val < 0) {
801 0 : GST_ERROR_OBJECT (src, "Could not get the tensor count from json.");
802 0 : return GST_FLOW_ERROR;
803 : }
804 102 : tensor_count = (guint) val;
805 :
806 102 : num_tensors = gst_data_repo_src_get_num_tensors (src, shuffled_index);
807 :
808 102 : buf = gst_buffer_new ();
809 :
810 212 : for (i = 0; i < num_tensors; i++) {
811 112 : val = json_array_get_int_element (src->tensor_size_array, tensor_count + i);
812 112 : if (val < 0) {
813 0 : GST_ERROR_OBJECT (src, "Could not get the size of tensor from json.");
814 0 : ret = GST_FLOW_ERROR;
815 0 : goto error;
816 : }
817 :
818 112 : tensor_size = (gsize) val;
819 112 : mem = gst_allocator_alloc (NULL, tensor_size, NULL);
820 :
821 112 : if (!gst_memory_map (mem, &info, GST_MAP_WRITE)) {
822 0 : GST_ERROR_OBJECT (src, "Could not map GstMemory[%d]", i);
823 0 : ret = GST_FLOW_ERROR;
824 0 : goto error;
825 : }
826 :
827 112 : data = info.data;
828 112 : byte_read = 0;
829 112 : to_read = tensor_size;
830 224 : while (to_read > 0) {
831 112 : GST_LOG_OBJECT (src,
832 : "Reading %zd bytes at offset 0x%" G_GINT64_MODIFIER "x (%lld size)",
833 : to_read, src->fd_offset + byte_read, (long long) src->fd_offset);
834 112 : errno = 0;
835 112 : read_size = read (src->fd, data + byte_read, to_read);
836 112 : GST_LOG_OBJECT (src, "Read: %zd", read_size);
837 112 : if (read_size < 0) {
838 0 : if (errno == EAGAIN || errno == EINTR)
839 0 : continue;
840 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
841 0 : ret = GST_FLOW_ERROR;
842 0 : goto error;
843 : }
844 : /* files should eos if they read 0 and more was requested */
845 112 : if (read_size == 0) {
846 : /* .. but first we should return any remaining data */
847 0 : if (byte_read > 0)
848 0 : break;
849 0 : GST_DEBUG_OBJECT (src, "EOS");
850 0 : ret = GST_FLOW_EOS;
851 0 : goto error;
852 : }
853 112 : to_read -= read_size;
854 112 : byte_read += read_size;
855 :
856 112 : src->read_position += read_size;
857 112 : src->fd_offset += read_size;
858 : }
859 :
860 : /* check invalid flexible tensor */
861 112 : if (!gst_tensor_meta_info_parse_header (&meta, info.data)) {
862 2 : GST_ERROR_OBJECT (src, "Invalid flexible tensors");
863 2 : ret = GST_FLOW_ERROR;
864 2 : goto error;
865 : }
866 :
867 110 : gst_memory_unmap (mem, &info);
868 :
869 110 : gst_tensor_meta_info_convert (&meta, &tinfo);
870 110 : gst_tensor_buffer_append_memory (buf, mem, &tinfo);
871 110 : gst_tensor_info_free (&tinfo);
872 110 : mem = NULL;
873 : }
874 :
875 100 : *buffer = buf;
876 :
877 100 : return GST_FLOW_OK;
878 :
879 2 : error:
880 2 : if (mem) {
881 2 : gst_memory_unmap (mem, &info);
882 2 : gst_memory_unref (mem);
883 : }
884 2 : if (buf)
885 2 : gst_buffer_unref (buf);
886 :
887 2 : return ret;
888 : }
889 :
890 : /**
891 : * @brief Get image filename
892 : */
893 : static gchar *
894 6 : gst_data_repo_src_get_image_filename (GstDataRepoSrc * src)
895 : {
896 6 : gchar *filename = NULL;
897 6 : guint shuffled_index = 0;
898 6 : g_return_val_if_fail (src != NULL, NULL);
899 6 : g_return_val_if_fail (src->data_type == GST_DATA_REPO_DATA_IMAGE, NULL);
900 6 : g_return_val_if_fail (src->filename != NULL, NULL);
901 6 : g_return_val_if_fail (src->shuffled_index_array != NULL, NULL);
902 :
903 : /* GST_DATA_REPO_DATA_IMAGE must have %d in src->filename */
904 6 : if (src->shuffled_index_array->len > 0)
905 5 : shuffled_index =
906 5 : g_array_index (src->shuffled_index_array, guint, src->array_index);
907 : else
908 1 : shuffled_index = 0; /* Used for initial file open verification */
909 :
910 : #ifdef __GNUC__
911 : #pragma GCC diagnostic push
912 : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
913 : #endif
914 : /* let's set value by property */
915 6 : filename = g_strdup_printf (src->filename, shuffled_index);
916 : #ifdef __GNUC__
917 : #pragma GCC diagnostic pop
918 : #endif
919 :
920 6 : return filename;
921 : }
922 :
923 : /**
924 : * @brief Function to read multi image files
925 : */
926 : static GstFlowReturn
927 6 : gst_data_repo_src_read_multi_images (GstDataRepoSrc * src, GstBuffer ** buffer)
928 : {
929 6 : g_autofree gchar *filename = NULL;
930 : gsize size;
931 : gchar *data;
932 : GstBuffer *buf;
933 : gboolean read_size;
934 6 : GError *error = NULL;
935 :
936 6 : g_return_val_if_fail (src->shuffled_index_array != NULL, GST_FLOW_ERROR);
937 :
938 6 : if (gst_data_repo_src_epoch_is_done (src)) {
939 1 : if (src->epochs == 0) {
940 1 : GST_LOG_OBJECT (src, "send EOS");
941 1 : return GST_FLOW_EOS;
942 : }
943 0 : if (src->is_shuffle)
944 0 : gst_data_repo_src_shuffle_samples_index (src);
945 : }
946 :
947 : /* only do for first epoch */
948 5 : if (!src->first_epoch_is_done) {
949 : /* append samples index to array */
950 5 : g_array_append_val (src->shuffled_index_array, src->current_sample_index);
951 5 : src->current_sample_index++;
952 : }
953 :
954 5 : filename = gst_data_repo_src_get_image_filename (src);
955 5 : GST_DEBUG_OBJECT (src, "Reading from file \"%s\".", filename);
956 5 : src->array_index++;
957 :
958 : /* Try to read one image */
959 5 : read_size = g_file_get_contents (filename, &data, &size, &error);
960 5 : if (!read_size) {
961 0 : if (src->successful_read) {
962 : /* If we've read at least one buffer successfully, not finding the next file is EOS. */
963 0 : if (error != NULL)
964 0 : g_error_free (error);
965 0 : return GST_FLOW_EOS;
966 : }
967 0 : goto handle_error;
968 : }
969 :
970 : /* Success reading on image */
971 5 : src->successful_read = TRUE;
972 5 : GST_DEBUG_OBJECT (src, "file size is %zd", size);
973 :
974 5 : buf = gst_buffer_new ();
975 5 : gst_buffer_append_memory (buf,
976 : gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
977 :
978 5 : *buffer = buf;
979 :
980 5 : return GST_FLOW_OK;
981 :
982 0 : handle_error:
983 : {
984 0 : if (error != NULL) {
985 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ,
986 : ("Error while reading from file \"%s\".", filename),
987 : ("%s", error->message));
988 0 : g_error_free (error);
989 : } else {
990 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ,
991 : ("Error while reading from file \"%s\".", filename),
992 : ("%s", g_strerror (errno)));
993 : }
994 0 : return GST_FLOW_ERROR;
995 : }
996 : }
997 :
998 : /**
999 : * @brief Function to read others media type (video, audio, octet and text)
1000 : */
1001 : static GstFlowReturn
1002 13 : gst_data_repo_src_read_others (GstDataRepoSrc * src, GstBuffer ** buffer)
1003 : {
1004 13 : GstFlowReturn ret = GST_FLOW_OK;
1005 : GstBuffer *buf;
1006 : gsize to_read, byte_read;
1007 : gssize read_size;
1008 : guint8 *data;
1009 : GstMemory *mem;
1010 : GstMapInfo info;
1011 13 : guint shuffled_index = 0;
1012 13 : guint64 offset = 0;
1013 :
1014 26 : g_return_val_if_fail (src->fd != 0, GST_FLOW_ERROR);
1015 13 : g_return_val_if_fail (src->shuffled_index_array != NULL, GST_FLOW_ERROR);
1016 :
1017 13 : if (gst_data_repo_src_epoch_is_done (src)) {
1018 2 : if (src->epochs == 0) {
1019 2 : GST_LOG_OBJECT (src, "send EOS");
1020 2 : return GST_FLOW_EOS;
1021 : }
1022 0 : if (src->is_shuffle)
1023 0 : gst_data_repo_src_shuffle_samples_index (src);
1024 : }
1025 :
1026 : /* only do for first epoch */
1027 11 : if (!src->first_epoch_is_done) {
1028 : /* append samples index to array */
1029 11 : g_array_append_val (src->shuffled_index_array, src->current_sample_index);
1030 11 : src->current_sample_index++;
1031 : }
1032 :
1033 11 : shuffled_index =
1034 11 : g_array_index (src->shuffled_index_array, guint, src->array_index++);
1035 11 : GST_LOG_OBJECT (src, "shuffled_index [%d] -> %d", src->array_index - 1,
1036 : shuffled_index);
1037 11 : offset = gst_data_repo_src_get_file_offset (src, shuffled_index);
1038 11 : src->fd_offset = lseek (src->fd, offset, SEEK_SET);
1039 :
1040 11 : mem = gst_allocator_alloc (NULL, src->sample_size, NULL);
1041 :
1042 11 : if (!gst_memory_map (mem, &info, GST_MAP_WRITE)) {
1043 0 : GST_ERROR_OBJECT (src, "Could not map GstMemory");
1044 0 : gst_memory_unref (mem);
1045 0 : return GST_FLOW_ERROR;
1046 : }
1047 :
1048 11 : data = info.data;
1049 :
1050 11 : byte_read = 0;
1051 11 : to_read = src->sample_size;
1052 22 : while (to_read > 0) {
1053 11 : GST_LOG_OBJECT (src, "Reading %zd bytes at offset 0x%" G_GINT64_MODIFIER "x",
1054 : to_read, src->fd_offset + byte_read);
1055 11 : errno = 0;
1056 11 : read_size = read (src->fd, data + byte_read, to_read);
1057 11 : GST_LOG_OBJECT (src, "Read: %zd", read_size);
1058 11 : if (read_size < 0) {
1059 0 : if (errno == EAGAIN || errno == EINTR)
1060 0 : continue;
1061 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
1062 0 : ret = GST_FLOW_ERROR;
1063 0 : goto error;
1064 : }
1065 : /* files should eos if they read 0 and more was requested */
1066 11 : if (read_size == 0) {
1067 : /* .. but first we should return any remaining data */
1068 0 : if (byte_read > 0)
1069 0 : break;
1070 0 : GST_DEBUG_OBJECT (src, "EOS");
1071 0 : ret = GST_FLOW_EOS;
1072 0 : goto error;
1073 : }
1074 11 : to_read -= read_size;
1075 11 : byte_read += read_size;
1076 :
1077 11 : src->read_position += read_size;
1078 11 : src->fd_offset += read_size;
1079 : }
1080 :
1081 11 : gst_memory_unmap (mem, &info);
1082 :
1083 11 : buf = gst_buffer_new ();
1084 11 : gst_buffer_append_memory (buf, mem);
1085 :
1086 11 : *buffer = buf;
1087 11 : return GST_FLOW_OK;
1088 :
1089 0 : error:
1090 0 : if (mem) {
1091 0 : gst_memory_unmap (mem, &info);
1092 0 : gst_memory_unref (mem);
1093 : }
1094 :
1095 0 : return ret;
1096 : }
1097 :
1098 : /**
1099 : * @brief Start datareposrc, open the file
1100 : */
1101 : static gboolean
1102 15 : gst_data_repo_src_start (GstDataRepoSrc * src)
1103 : {
1104 15 : g_autofree gchar *filename = NULL;
1105 : struct_stat stat_results;
1106 15 : int flags = O_RDONLY | O_BINARY;
1107 :
1108 15 : g_return_val_if_fail (src != NULL, FALSE);
1109 :
1110 15 : if (src->filename == NULL || src->filename[0] == '\0')
1111 0 : goto no_filename;
1112 :
1113 15 : src->current_sample_index = src->start_sample_index;
1114 15 : src->num_samples = src->stop_sample_index - src->start_sample_index + 1;
1115 15 : GST_INFO_OBJECT (src,
1116 : "The number of samples to be used out of the total samples in the file is %d, [%d] ~ [%d]",
1117 : src->num_samples, src->start_sample_index, src->stop_sample_index);
1118 15 : GST_INFO_OBJECT (src, "data type: %d", src->data_type);
1119 15 : if (src->data_type == GST_DATA_REPO_DATA_IMAGE) {
1120 1 : filename = gst_data_repo_src_get_image_filename (src);
1121 : } else {
1122 28 : filename = g_strdup (src->filename);
1123 : }
1124 :
1125 15 : GST_INFO_OBJECT (src, "opening file %s", filename);
1126 :
1127 : /* open the file */
1128 15 : src->fd = g_open (filename, flags, 0);
1129 :
1130 15 : if (src->fd < 0)
1131 0 : goto open_failed;
1132 :
1133 : /* check if it is a regular file, otherwise bail out */
1134 15 : if (fstat (src->fd, &stat_results) < 0)
1135 0 : goto no_stat;
1136 :
1137 15 : src->file_size = stat_results.st_size;
1138 15 : if (src->file_size == 0)
1139 0 : goto error_close;
1140 :
1141 15 : if (S_ISDIR (stat_results.st_mode))
1142 0 : goto was_directory;
1143 :
1144 15 : if (S_ISSOCK (stat_results.st_mode))
1145 0 : goto was_socket;
1146 :
1147 : /* record if it's a regular (hence seekable and lengthable) file */
1148 15 : if (!S_ISREG (stat_results.st_mode))
1149 0 : goto error_close;
1150 :
1151 15 : src->read_position = 0;
1152 :
1153 15 : if (src->data_type == GST_DATA_REPO_DATA_IMAGE) {
1154 : /* no longer used */
1155 1 : g_close (src->fd, NULL);
1156 1 : src->fd = 0;
1157 : } else {
1158 : /* set start offset and last offset */
1159 14 : src->start_offset =
1160 14 : gst_data_repo_src_get_file_offset (src, src->start_sample_index);
1161 :
1162 : /* If the user does not set stop_sample_index, datareposrc need to calculate the last offset */
1163 14 : src->last_offset =
1164 14 : gst_data_repo_src_get_file_offset (src, src->stop_sample_index);
1165 :
1166 14 : src->fd_offset = lseek (src->fd, src->start_offset, SEEK_SET);
1167 14 : GST_LOG_OBJECT (src, "Start file offset 0x%" G_GINT64_MODIFIER "x",
1168 : src->fd_offset);
1169 : }
1170 :
1171 15 : return TRUE;
1172 :
1173 : /* ERROR */
1174 0 : no_filename:
1175 : {
1176 0 : GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
1177 : ("No file name specified for reading."), (NULL));
1178 0 : goto error_exit;
1179 : }
1180 0 : open_failed:
1181 : {
1182 0 : switch (errno) {
1183 0 : case ENOENT:
1184 0 : GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
1185 : ("No such file \"%s\"", src->filename));
1186 0 : break;
1187 0 : default:
1188 0 : GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
1189 : (("Could not open file \"%s\" for reading."), src->filename),
1190 : GST_ERROR_SYSTEM);
1191 0 : break;
1192 : }
1193 0 : goto error_exit;
1194 : }
1195 0 : no_stat:
1196 : {
1197 0 : GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
1198 : (("Could not get info on \"%s\"."), src->filename), (NULL));
1199 0 : goto error_close;
1200 : }
1201 0 : was_directory:
1202 : {
1203 0 : GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
1204 : (("\"%s\" is a directory."), src->filename), (NULL));
1205 0 : goto error_close;
1206 : }
1207 0 : was_socket:
1208 : {
1209 0 : GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
1210 : (("File \"%s\" is a socket."), src->filename), (NULL));
1211 0 : goto error_close;
1212 : }
1213 :
1214 0 : error_close:
1215 0 : g_close (src->fd, NULL);
1216 0 : src->fd = 0;
1217 0 : error_exit:
1218 0 : return FALSE;
1219 : }
1220 :
1221 : /**
1222 : * @brief Set timestamp
1223 : */
1224 : static void
1225 105 : gst_data_repo_src_set_timestamp (GstDataRepoSrc * src, GstBuffer * buffer)
1226 : {
1227 :
1228 : GstClockTime next_time;
1229 105 : GstClockTime duration = GST_CLOCK_TIME_NONE;
1230 :
1231 105 : g_return_if_fail (src != NULL);
1232 105 : g_return_if_fail (buffer != NULL);
1233 :
1234 : /* Unlike video, audio should control one sample by framerate. */
1235 105 : if (src->data_type == GST_DATA_REPO_DATA_AUDIO) {
1236 0 : GST_WARNING_OBJECT (src,
1237 : "Use audiorate element for the framerate of audio");
1238 0 : return;
1239 : }
1240 :
1241 105 : duration = gst_util_uint64_scale_int (GST_SECOND, src->rate_d, src->rate_n);
1242 105 : GST_BUFFER_DURATION (buffer) = duration;
1243 105 : GST_BUFFER_TIMESTAMP (buffer) = src->running_time;
1244 105 : gst_object_sync_values (GST_OBJECT (src), GST_BUFFER_TIMESTAMP (buffer));
1245 :
1246 : next_time =
1247 210 : gst_util_uint64_scale (src->n_frame++, src->rate_d * GST_SECOND,
1248 105 : src->rate_n);
1249 105 : src->running_time = next_time;
1250 :
1251 105 : GST_LOG_OBJECT (src, "next_time %" GST_TIME_FORMAT "",
1252 : GST_TIME_ARGS (next_time));
1253 105 : GST_LOG_OBJECT (src,
1254 : "timestamp [%" GST_TIME_FORMAT " dur %" GST_TIME_FORMAT "]",
1255 : GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1256 : GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
1257 : }
1258 :
1259 : /**
1260 : * @brief Function to create a buffer
1261 : */
1262 : static GstFlowReturn
1263 211 : gst_data_repo_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
1264 : {
1265 211 : GstFlowReturn ret = GST_FLOW_OK;
1266 : GstDataRepoSrc *src;
1267 211 : src = GST_DATA_REPO_SRC (pushsrc);
1268 :
1269 : /** set_caps is completed after PAUSED_TO_PLAYING, so we cannot use change_state.
1270 : datareposrc can get type and size after set_caps() */
1271 211 : if (!src->is_start) {
1272 15 : if (!gst_data_repo_src_start (src)) {
1273 0 : return GST_FLOW_ERROR;
1274 : }
1275 15 : src->is_start = TRUE;
1276 : }
1277 :
1278 211 : switch (src->data_type) {
1279 13 : case GST_DATA_REPO_DATA_VIDEO:
1280 : case GST_DATA_REPO_DATA_AUDIO:
1281 : case GST_DATA_REPO_DATA_TEXT:
1282 : case GST_DATA_REPO_DATA_OCTET:
1283 13 : ret = gst_data_repo_src_read_others (src, buffer);
1284 13 : break;
1285 192 : case GST_DATA_REPO_DATA_TENSOR:
1286 192 : if (gst_tensors_config_is_static (&src->config))
1287 86 : ret = gst_data_repo_src_read_tensors (src, buffer);
1288 : else
1289 106 : ret = gst_data_repo_src_read_flexible_or_sparse_tensors (src, buffer);
1290 192 : break;
1291 6 : case GST_DATA_REPO_DATA_IMAGE:
1292 6 : ret = gst_data_repo_src_read_multi_images (src, buffer);
1293 6 : break;
1294 0 : default:
1295 0 : return GST_FLOW_ERROR;
1296 : }
1297 :
1298 211 : if (ret != GST_FLOW_OK)
1299 15 : return ret;
1300 :
1301 196 : if (src->rate_n)
1302 105 : gst_data_repo_src_set_timestamp (src, *buffer);
1303 :
1304 196 : return GST_FLOW_OK;
1305 : }
1306 :
1307 : /**
1308 : * @brief Stop datareposrc, unmap and close the file
1309 : */
1310 : static gboolean
1311 16 : gst_data_repo_src_stop (GstBaseSrc * basesrc)
1312 : {
1313 16 : GstDataRepoSrc *src = GST_DATA_REPO_SRC (basesrc);
1314 :
1315 : /* close the file */
1316 16 : g_close (src->fd, NULL);
1317 16 : src->fd = 0;
1318 :
1319 16 : return TRUE;
1320 : }
1321 :
1322 : /**
1323 : * @brief Get caps with tensors_sequence applied
1324 : */
1325 : static gboolean
1326 17 : gst_data_repo_get_caps_by_tensors_sequence (GstDataRepoSrc * src)
1327 : {
1328 : GstStructure *s;
1329 : GstTensorsConfig src_config, dst_config;
1330 : GstTensorInfo *_src_info, *_dst_info;
1331 : guint i;
1332 17 : guint seq_num = 0;
1333 : GstCaps *new_caps;
1334 :
1335 34 : g_return_val_if_fail (src != NULL, FALSE);
1336 17 : g_return_val_if_fail (src->caps != NULL, FALSE);
1337 :
1338 17 : s = gst_caps_get_structure (src->caps, 0);
1339 17 : if (!gst_tensors_config_from_structure (&src_config, s))
1340 0 : return FALSE;
1341 :
1342 17 : gst_tensors_config_init (&dst_config);
1343 :
1344 : /* Copy selected tensors in sequence */
1345 51 : for (i = 0; i < src->tensors_seq_cnt; i++) {
1346 34 : seq_num = src->tensors_seq[i];
1347 34 : _src_info = gst_tensors_info_get_nth_info (&src_config.info, seq_num);
1348 34 : _dst_info = gst_tensors_info_get_nth_info (&dst_config.info, i);
1349 34 : gst_tensor_info_copy (_dst_info, _src_info);
1350 : }
1351 17 : dst_config.rate_n = src_config.rate_n;
1352 17 : dst_config.rate_d = src_config.rate_d;
1353 17 : dst_config.info.format = src_config.info.format;
1354 17 : dst_config.info.num_tensors = src->tensors_seq_cnt;
1355 :
1356 17 : new_caps = gst_tensors_caps_from_config (&dst_config);
1357 :
1358 17 : GST_DEBUG_OBJECT (src,
1359 : "datareposrc caps by tensors_sequence %" GST_PTR_FORMAT, new_caps);
1360 :
1361 17 : gst_tensors_config_free (&dst_config);
1362 17 : gst_tensors_config_free (&src_config);
1363 :
1364 17 : return gst_data_repo_src_parse_caps (src, new_caps);
1365 : }
1366 :
1367 : /**
1368 : * @brief Get caps for caps negotiation
1369 : */
1370 : static GstCaps *
1371 112 : gst_data_repo_src_get_caps (GstBaseSrc * basesrc, GstCaps * filter)
1372 : {
1373 112 : GstDataRepoSrc *src = GST_DATA_REPO_SRC (basesrc);
1374 :
1375 112 : if (src->data_type == GST_DATA_REPO_DATA_TENSOR && src->need_changed_caps) {
1376 17 : gst_data_repo_get_caps_by_tensors_sequence (src);
1377 17 : src->need_changed_caps = FALSE;
1378 : }
1379 :
1380 112 : GST_DEBUG_OBJECT (src, "Current datareposrc caps %" GST_PTR_FORMAT,
1381 : src->caps);
1382 :
1383 112 : if (src->caps) {
1384 98 : if (filter)
1385 0 : return gst_caps_intersect_full (filter, src->caps,
1386 : GST_CAPS_INTERSECT_FIRST);
1387 : else
1388 98 : return gst_caps_ref (src->caps);
1389 : } else {
1390 14 : if (filter)
1391 0 : return gst_caps_ref (filter);
1392 : else
1393 14 : return gst_caps_new_any ();
1394 : }
1395 : }
1396 :
1397 : /**
1398 : * @brief caps after caps negotiation
1399 : */
1400 : static gboolean
1401 18 : gst_data_repo_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps)
1402 : {
1403 18 : GstDataRepoSrc *src = GST_DATA_REPO_SRC (basesrc);
1404 :
1405 18 : GST_INFO_OBJECT (src, "set caps: %" GST_PTR_FORMAT, caps);
1406 :
1407 18 : return TRUE;
1408 : }
1409 :
1410 : /**
1411 : * @brief Read JSON file
1412 : */
1413 : static gboolean
1414 36 : gst_data_repo_src_read_json_file (GstDataRepoSrc * src)
1415 : {
1416 36 : g_autofree gchar *contents = NULL;
1417 36 : GError *error = NULL;
1418 : GFile *file;
1419 : JsonNode *root;
1420 : JsonObject *object;
1421 36 : const gchar *caps_str = NULL;
1422 : GstCaps *new_caps;
1423 : gint64 val;
1424 :
1425 36 : g_return_val_if_fail (src != NULL, FALSE);
1426 36 : g_return_val_if_fail (src->json_filename != NULL, FALSE);
1427 :
1428 35 : if ((file = g_file_new_for_path (src->json_filename)) == NULL) {
1429 0 : GST_ERROR_OBJECT (src, "Failed to get file object of %s.",
1430 : src->json_filename);
1431 0 : return FALSE;
1432 : }
1433 :
1434 35 : if (!g_file_load_contents (file, NULL, &contents, NULL, NULL, &error)) {
1435 5 : GST_ERROR_OBJECT (src, "Failed to open %s: %s", src->json_filename,
1436 : error ? error->message : "Unknown error");
1437 5 : g_clear_error (&error);
1438 5 : g_object_unref (file);
1439 5 : return FALSE;
1440 : }
1441 :
1442 30 : if (src->parser)
1443 0 : g_object_unref (src->parser);
1444 30 : src->parser = json_parser_new ();
1445 :
1446 30 : if (!json_parser_load_from_data (src->parser, contents, -1, NULL)) {
1447 0 : GST_ERROR_OBJECT (src, "Failed to load data from %s", src->json_filename);
1448 0 : goto error;
1449 : }
1450 :
1451 30 : root = json_parser_get_root (src->parser);
1452 30 : if (!JSON_NODE_HOLDS_OBJECT (root)) {
1453 0 : GST_ERROR_OBJECT (src, "it does not contain a JsonObject: %s", contents);
1454 0 : goto error;
1455 : }
1456 :
1457 30 : object = json_node_get_object (root);
1458 :
1459 30 : GST_INFO_OBJECT (src, ">>>>>>> Start parsing JSON file(%s)",
1460 : src->json_filename);
1461 :
1462 30 : if (!json_object_has_member (object, "gst_caps")) {
1463 0 : GST_ERROR_OBJECT (src, "There is no gst_caps field: %s", contents);
1464 0 : goto error;
1465 : }
1466 :
1467 30 : caps_str = json_object_get_string_member (object, "gst_caps");
1468 30 : GST_INFO_OBJECT (src, "caps_str : %s", caps_str);
1469 :
1470 30 : new_caps = gst_caps_from_string (caps_str);
1471 :
1472 : /* calculate media size from gst caps */
1473 30 : if (!gst_data_repo_src_parse_caps (src, new_caps))
1474 0 : goto error;
1475 :
1476 30 : GST_INFO_OBJECT (src, "gst_caps : %" GST_PTR_FORMAT, src->caps);
1477 :
1478 : /* In the case of below media type, get sample_size from JSON */
1479 30 : if (src->data_type == GST_DATA_REPO_DATA_TEXT
1480 30 : || src->data_type == GST_DATA_REPO_DATA_OCTET
1481 30 : || src->data_type == GST_DATA_REPO_DATA_IMAGE) {
1482 1 : if (!json_object_has_member (object, "sample_size")) {
1483 0 : GST_ERROR_OBJECT (src, "There is not sample_size field: %s", contents);
1484 0 : goto error;
1485 : }
1486 :
1487 1 : val = json_object_get_int_member (object, "sample_size");
1488 1 : if (val < 0) {
1489 0 : GST_ERROR_OBJECT (src, "Invalid sample_size: %" G_GINT64_FORMAT, val);
1490 0 : goto error;
1491 : }
1492 :
1493 1 : src->sample_size = (gsize) val;
1494 1 : GST_INFO_OBJECT (src, "sample_size: %zd", src->sample_size);
1495 : }
1496 :
1497 30 : if (src->data_type == GST_DATA_REPO_DATA_TENSOR &&
1498 27 : !gst_tensors_config_is_static (&src->config)) {
1499 6 : if (!json_object_has_member (object, "sample_offset")) {
1500 0 : GST_ERROR_OBJECT (src, "There is no sample_offset field: %s", contents);
1501 0 : goto error;
1502 : }
1503 6 : src->sample_offset_array =
1504 6 : json_object_get_array_member (object, "sample_offset");
1505 6 : src->sample_offset_array_len =
1506 6 : json_array_get_length (src->sample_offset_array);
1507 :
1508 6 : if (!json_object_has_member (object, "tensor_size")) {
1509 0 : GST_ERROR_OBJECT (src, "There is no tensor_size field: %s", contents);
1510 0 : goto error;
1511 : }
1512 6 : src->tensor_size_array =
1513 6 : json_object_get_array_member (object, "tensor_size");
1514 6 : src->tensor_size_array_len = json_array_get_length (src->tensor_size_array);
1515 6 : GST_INFO_OBJECT (src, "tensor_size_array_len:%u",
1516 : src->tensor_size_array_len);
1517 :
1518 6 : if (!json_object_has_member (object, "tensor_count")) {
1519 0 : GST_ERROR_OBJECT (src, "There is no tensor_count field: %s", contents);
1520 0 : goto error;
1521 : }
1522 6 : src->tensor_count_array =
1523 6 : json_object_get_array_member (object, "tensor_count");
1524 6 : src->tensor_count_array_len =
1525 6 : json_array_get_length (src->tensor_count_array);
1526 6 : GST_INFO_OBJECT (src, "tensor_count_array_len:%u",
1527 : src->tensor_count_array_len);
1528 : } else {
1529 24 : if (src->sample_size == 0)
1530 0 : goto error;
1531 : }
1532 :
1533 30 : if (!json_object_has_member (object, "total_samples")) {
1534 0 : GST_ERROR_OBJECT (src, "There is no total_samples field: %s", contents);
1535 0 : goto error;
1536 : }
1537 :
1538 30 : val = json_object_get_int_member (object, "total_samples");
1539 30 : if (val <= 0) {
1540 0 : GST_ERROR_OBJECT (src, "Invalid total_samples: %" G_GINT64_FORMAT, val);
1541 0 : goto error;
1542 : }
1543 :
1544 30 : src->total_samples = (guint) val;
1545 30 : GST_INFO_OBJECT (src, "total_samples: %u", src->total_samples);
1546 :
1547 30 : g_object_unref (file);
1548 :
1549 30 : return TRUE;
1550 0 : error:
1551 0 : src->data_type = GST_DATA_REPO_DATA_UNKNOWN;
1552 0 : GST_ERROR_OBJECT (src, "Failed to parse %s", src->json_filename);
1553 0 : g_object_unref (file);
1554 :
1555 0 : return FALSE;
1556 : }
1557 :
1558 : /**
1559 : * @brief Setter for datareposrc properties.
1560 : */
1561 : static void
1562 160 : gst_data_repo_src_set_property (GObject * object, guint prop_id,
1563 : const GValue * value, GParamSpec * pspec)
1564 : {
1565 : GstDataRepoSrc *src;
1566 : const GstCaps *caps;
1567 :
1568 160 : g_return_if_fail (GST_IS_DATA_REPO_SRC (object));
1569 :
1570 160 : src = GST_DATA_REPO_SRC (object);
1571 :
1572 160 : switch (prop_id) {
1573 38 : case PROP_LOCATION:
1574 38 : gst_data_repo_src_set_file_path (src, PROP_LOCATION,
1575 : g_value_get_string (value), NULL);
1576 38 : break;
1577 36 : case PROP_JSON:
1578 36 : gst_data_repo_src_set_file_path (src, PROP_JSON,
1579 : g_value_get_string (value), NULL);
1580 : /** To get caps, read JSON before Caps negotiation,
1581 : to get information on sample data */
1582 36 : if (!gst_data_repo_src_read_json_file (src)) {
1583 6 : GST_ERROR_OBJECT (src, "Failed to get data format");
1584 : }
1585 36 : break;
1586 22 : case PROP_START_SAMPLE_INDEX:
1587 22 : src->start_sample_index = g_value_get_uint (value);
1588 22 : break;
1589 24 : case PROP_STOP_SAMPLE_INDEX:
1590 24 : src->stop_sample_index = g_value_get_uint (value);
1591 24 : break;
1592 18 : case PROP_EPOCHS:
1593 18 : src->epochs = g_value_get_uint (value);
1594 18 : break;
1595 0 : case PROP_IS_SHUFFLE:
1596 0 : src->is_shuffle = g_value_get_boolean (value);
1597 0 : break;
1598 20 : case PROP_TENSORS_SEQUENCE:
1599 20 : g_free (src->tensors_seq_str);
1600 20 : src->tensors_seq_str = g_value_dup_string (value);
1601 20 : if (!gst_data_repo_src_set_tensors_sequence (src)) {
1602 4 : GST_ERROR_OBJECT (src, "Failed to set tensors sequence");
1603 : } else {
1604 16 : src->need_changed_caps = TRUE;
1605 : }
1606 20 : break;
1607 2 : case PROP_CAPS:
1608 2 : caps = gst_value_get_caps (value);
1609 2 : if (caps) {
1610 1 : gst_data_repo_src_parse_caps (src, gst_caps_copy (caps));
1611 : }
1612 : /** let's retry set tensors-sequence.
1613 : if caps property is set later than tensors-sequence property,
1614 : setting tensors-sequence fails because caps information is unknown.*/
1615 2 : if (src->tensors_seq_str) {
1616 1 : if (gst_data_repo_src_set_tensors_sequence (src))
1617 1 : src->need_changed_caps = TRUE;
1618 : }
1619 2 : break;
1620 0 : default:
1621 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1622 0 : break;
1623 : }
1624 : }
1625 :
1626 : /**
1627 : * @brief Getter datareposrc properties
1628 : */
1629 : static void
1630 10 : gst_data_repo_src_get_property (GObject * object, guint prop_id, GValue * value,
1631 : GParamSpec * pspec)
1632 : {
1633 : GstDataRepoSrc *src;
1634 :
1635 10 : g_return_if_fail (GST_IS_DATA_REPO_SRC (object));
1636 :
1637 10 : src = GST_DATA_REPO_SRC (object);
1638 :
1639 10 : switch (prop_id) {
1640 2 : case PROP_LOCATION:
1641 2 : g_value_set_string (value, src->filename);
1642 2 : break;
1643 1 : case PROP_JSON:
1644 1 : g_value_set_string (value, src->json_filename);
1645 1 : break;
1646 1 : case PROP_START_SAMPLE_INDEX:
1647 1 : g_value_set_uint (value, src->start_sample_index);
1648 1 : break;
1649 1 : case PROP_STOP_SAMPLE_INDEX:
1650 1 : g_value_set_uint (value, src->stop_sample_index);
1651 1 : break;
1652 1 : case PROP_EPOCHS:
1653 1 : g_value_set_uint (value, src->epochs);
1654 1 : break;
1655 2 : case PROP_IS_SHUFFLE:
1656 2 : g_value_set_boolean (value, src->is_shuffle);
1657 2 : break;
1658 2 : case PROP_TENSORS_SEQUENCE:
1659 2 : g_value_set_string (value, src->tensors_seq_str);
1660 2 : break;
1661 0 : case PROP_CAPS:
1662 0 : gst_value_set_caps (value, src->caps);
1663 0 : break;
1664 0 : default:
1665 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1666 0 : break;
1667 : }
1668 : }
1669 :
1670 : /**
1671 : * @brief Change state of datareposrc.
1672 : */
1673 : static GstStateChangeReturn
1674 125 : gst_data_repo_src_change_state (GstElement * element, GstStateChange transition)
1675 : {
1676 : guint i;
1677 125 : GstDataRepoSrc *src = GST_DATA_REPO_SRC (element);
1678 125 : GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1679 125 : GstBaseSrc *basesrc = NULL;
1680 : guint blocksize;
1681 :
1682 125 : switch (transition) {
1683 30 : case GST_STATE_CHANGE_NULL_TO_READY:
1684 30 : GST_INFO_OBJECT (src, "NULL_TO_READY");
1685 :
1686 30 : if (src->data_type == GST_DATA_REPO_DATA_UNKNOWN)
1687 7 : goto state_change_failed;
1688 :
1689 : /** if data_type is not GST_DATA_REPO_DATA_UNKNOWN and sample_size is 0 then
1690 : 'caps' is set by property and sample size needs to be set by blocksize
1691 : (in the case of otect and text) */
1692 23 : if (src->sample_size == 0 && (src->data_type == GST_DATA_REPO_DATA_OCTET
1693 6 : || src->data_type == GST_DATA_REPO_DATA_TEXT)) {
1694 0 : basesrc = GST_BASE_SRC (src);
1695 0 : g_object_get (G_OBJECT (basesrc), "blocksize", &blocksize, NULL);
1696 0 : GST_DEBUG_OBJECT (src, "blocksize = %u", blocksize);
1697 0 : if (blocksize == 0) {
1698 0 : GST_ERROR_OBJECT (src, "Please set the 'blocksize' property "
1699 : "when using the 'caps' property to set the sample format without JSON.");
1700 0 : goto state_change_failed;
1701 : }
1702 0 : src->sample_size = blocksize;
1703 : }
1704 :
1705 : /** A case of importing a sample format using 'caps' property without JSON. */
1706 23 : if (src->total_samples == 0 && src->stop_sample_index == 0) {
1707 0 : GST_ERROR_OBJECT (src, "Please set the 'stop-sample-index' property "
1708 : "when using the 'caps' property to set the sample format without JSON.");
1709 0 : goto state_change_failed;
1710 : }
1711 :
1712 : /* total_samples -1 is the default value of 'stop-sample-index' property */
1713 23 : if (src->stop_sample_index == 0)
1714 8 : src->stop_sample_index = src->total_samples - 1;
1715 :
1716 : /* Check invalid property value */
1717 23 : if (src->start_sample_index > (src->total_samples - 1)
1718 22 : || src->stop_sample_index > (src->total_samples - 1)
1719 21 : || src->epochs == 0) {
1720 3 : GST_ERROR_OBJECT (src, "Check for invalid range values");
1721 :
1722 3 : goto state_change_failed;
1723 : }
1724 :
1725 : /* If tensors-sequence properties is set */
1726 20 : if (src->tensors_seq_str != NULL) {
1727 7 : if (src->data_type != GST_DATA_REPO_DATA_TENSOR) {
1728 0 : GST_ERROR_OBJECT (src,
1729 : "tensors-sequence properties is only for tensor/others type(%d), current type(%d)",
1730 : GST_DATA_REPO_DATA_TENSOR, src->data_type);
1731 0 : goto state_change_failed;
1732 : }
1733 : /* After gst_data_repo_src_set_tensors_sequence() */
1734 7 : if (src->tensors_seq_cnt == 0)
1735 1 : goto state_change_failed;
1736 : } else {
1737 21 : for (i = 0; i < src->config.info.num_tensors; i++)
1738 8 : src->tensors_seq[i] = i;
1739 13 : src->tensors_seq_cnt = i;
1740 : }
1741 :
1742 19 : break;
1743 :
1744 19 : case GST_STATE_CHANGE_READY_TO_PAUSED:
1745 19 : GST_INFO_OBJECT (src, "READY_TO_PAUSED");
1746 19 : break;
1747 :
1748 15 : case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1749 15 : GST_INFO_OBJECT (src, "PAUSED_TO_PLAYING");
1750 15 : break;
1751 :
1752 61 : default:
1753 61 : break;
1754 : }
1755 :
1756 114 : ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1757 :
1758 114 : switch (transition) {
1759 15 : case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1760 15 : GST_INFO_OBJECT (src, "PLAYING_TO_PAUSED");
1761 15 : break;
1762 :
1763 16 : case GST_STATE_CHANGE_PAUSED_TO_READY:
1764 16 : GST_INFO_OBJECT (src, "PAUSED_TO_READY");
1765 16 : break;
1766 :
1767 16 : case GST_STATE_CHANGE_READY_TO_NULL:
1768 16 : GST_INFO_OBJECT (src, "READY_TO_NULL");
1769 16 : break;
1770 :
1771 67 : default:
1772 67 : break;
1773 : }
1774 :
1775 125 : return ret;
1776 :
1777 11 : state_change_failed:
1778 11 : GST_ERROR_OBJECT (src, "state change failed");
1779 :
1780 11 : return GST_STATE_CHANGE_FAILURE;
1781 : }
|