Doxygen Book
gstdatareposink.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: LGPL-2.1-only */
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 #include <gst/gst.h>
28 #include <gst/video/video-info.h>
29 #include <gst/audio/audio-info.h>
30 #include <glib/gstdio.h>
31 #include <sys/types.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <nnstreamer_plugin_api.h>
35 #include <tensor_common.h>
36 #include <nnstreamer_util.h>
37 #include "gstdatareposink.h"
38 
42 #define TENSOR_CAPS GST_TENSORS_CAP_MAKE ("{ static, flexible, sparse }")
43 
46 #define SUPPORTED_VIDEO_FORMAT \
47  "{RGB, BGR, RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, GRAY8}"
48 #define VIDEO_CAPS GST_VIDEO_CAPS_MAKE (SUPPORTED_VIDEO_FORMAT) "," \
49  "interlace-mode = (string) progressive"
50 
53 #define SUPPORTED_AUDIO_FORMAT \
54  "{S8, U8, S16LE, S16BE, U16LE, U16BE, S32LE, S32BE, U32LE, U32BE, F32LE, F32BE, F64LE, F64BE}"
55 #define AUDIO_CAPS GST_AUDIO_CAPS_MAKE (SUPPORTED_AUDIO_FORMAT) "," \
56  "layout = (string) interleaved"
57 
60 #define TEXT_CAPS "text/x-raw, format = (string) utf8"
61 
64 #define OCTET_CAPS "application/octet-stream"
65 
68 #define IMAGE_CAPS \
69  "image/png, width = (int) [ 16, 1000000 ], height = (int) [ 16, 1000000 ], framerate = (fraction) [ 0/1, MAX];" \
70  "image/jpeg, width = (int) [ 16, 65535 ], height = (int) [ 16, 65535 ], framerate = (fraction) [ 0/1, MAX], sof-marker = (int) { 0, 1, 2, 4, 9 };" \
71  "image/tiff, endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN };" \
72  "image/gif;" \
73  "image/bmp"
74 
75 static GstStaticPadTemplate sinktemplate =
76  GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
77  GST_STATIC_CAPS (TENSOR_CAPS ";" VIDEO_CAPS ";" AUDIO_CAPS ";" IMAGE_CAPS
78  ";" TEXT_CAPS ";" OCTET_CAPS));
79 
83 enum
84 {
88 };
89 
90 GST_DEBUG_CATEGORY_STATIC (gst_data_repo_sink_debug);
91 #define GST_CAT_DEFAULT gst_data_repo_sink_debug
92 #define _do_init \
93  GST_DEBUG_CATEGORY_INIT (gst_data_repo_sink_debug, "datareposink", 0, "datareposink element");
94 #define gst_data_repo_sink_parent_class parent_class
95 G_DEFINE_TYPE_WITH_CODE (GstDataRepoSink, gst_data_repo_sink,
96  GST_TYPE_BASE_SINK, _do_init);
97 
98 static void gst_data_repo_sink_set_property (GObject * object, guint prop_id,
99  const GValue * value, GParamSpec * pspec);
100 static void gst_data_repo_sink_get_property (GObject * object, guint prop_id,
101  GValue * value, GParamSpec * pspec);
102 static void gst_data_repo_sink_finalize (GObject * object);
103 static gboolean gst_data_repo_sink_stop (GstBaseSink * basesink);
104 static GstStateChangeReturn gst_data_repo_sink_change_state (GstElement *
105  element, GstStateChange transition);
106 static GstFlowReturn gst_data_repo_sink_render (GstBaseSink * bsink,
107  GstBuffer * buffer);
108 static GstCaps *gst_data_repo_sink_get_caps (GstBaseSink * bsink,
109  GstCaps * filter);
110 static gboolean gst_data_repo_sink_set_caps (GstBaseSink * bsink,
111  GstCaps * caps);
112 static gboolean gst_data_repo_sink_query (GstBaseSink * sink, GstQuery * query);
113 
117 static void
119 {
120  GObjectClass *gobject_class;
121  GstElementClass *gstelement_class;
122  GstBaseSinkClass *gstbasesink_class;
123 
124  gobject_class = G_OBJECT_CLASS (klass);
125  gstelement_class = GST_ELEMENT_CLASS (klass);
126  gstbasesink_class = GST_BASE_SINK_CLASS (klass);
127 
128  gobject_class->set_property = gst_data_repo_sink_set_property;
129  gobject_class->get_property = gst_data_repo_sink_get_property;
130  gobject_class->finalize = gst_data_repo_sink_finalize;
131 
132  g_object_class_install_property (gobject_class, PROP_LOCATION,
133  g_param_spec_string ("location", "File Location",
134  "Location to write files to MLOps Data Repository. "
135  "if the files are images, use placeholder in indexes for filename"
136  "(e.g., filenmae%04d.png).",
137  NULL,
138  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
139  GST_PARAM_MUTABLE_READY));
140 
141  g_object_class_install_property (gobject_class, PROP_JSON,
142  g_param_spec_string ("json", "JSON file path",
143  "JSON file path to write the meta information of a sample", NULL,
144  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
145  GST_PARAM_MUTABLE_READY));
146 
147  gst_element_class_set_static_metadata (gstelement_class,
148  "NNStreamer MLOps Data Repository Sink",
149  "Sink/File",
150  "Write files to MLOps Data Repository", "Samsung Electronics Co., Ltd.");
151 
152  gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
153 
154  gstelement_class->change_state =
155  GST_DEBUG_FUNCPTR (gst_data_repo_sink_change_state);
156  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_data_repo_sink_render);
157  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_data_repo_sink_get_caps);
158  gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_data_repo_sink_set_caps);
159  gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_data_repo_sink_query);
160  gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_data_repo_sink_stop);
161 
162  /*A value of 8 typically indicates a 64-bit system. */
163  if (sizeof (off_t) < 8) {
164  GST_WARNING
165  ("64-bit file support unavailable due to system limitations, sizeof (off_t) = %"
166  G_GSIZE_FORMAT "!", sizeof (off_t));
167  }
168 }
169 
173 static void
175 {
176  sink->filename = NULL;
177  sink->fd = 0;
178  sink->fd_offset = 0;
180  sink->is_static_tensors = FALSE;
181  sink->fixed_caps = NULL;
182  sink->json_object = NULL;
183  sink->total_samples = 0;
184  sink->cumulative_tensors = 0;
185  sink->json_object = json_object_new ();
186  sink->sample_offset_array = json_array_new ();
187  sink->tensor_size_array = json_array_new ();
188  sink->tensor_count_array = json_array_new ();
189 }
190 
194 static void
195 gst_data_repo_sink_finalize (GObject * object)
196 {
197  GstDataRepoSink *sink = GST_DATA_REPO_SINK (object);
198 
199  g_free (sink->filename);
200  g_free (sink->json_filename);
201 
202  if (sink->fd) {
203  g_close (sink->fd, NULL);
204  sink->fd = 0;
205  }
206 
207  if (sink->fixed_caps)
208  gst_caps_unref (sink->fixed_caps);
209 
210  if (sink->sample_offset_array)
211  json_array_unref (sink->sample_offset_array);
212  if (sink->tensor_size_array)
213  json_array_unref (sink->tensor_size_array);
214  if (sink->tensor_count_array)
215  json_array_unref (sink->tensor_count_array);
216  if (sink->json_object) {
217  json_object_unref (sink->json_object);
218  sink->json_object = NULL;
219  }
220  G_OBJECT_CLASS (parent_class)->finalize (object);
221 }
222 
226 static void
227 gst_data_repo_sink_set_property (GObject * object, guint prop_id,
228  const GValue * value, GParamSpec * pspec)
229 {
230  GstDataRepoSink *sink = GST_DATA_REPO_SINK (object);
231 
232  switch (prop_id) {
233  case PROP_LOCATION:
234  sink->filename = g_value_dup_string (value);
235  GST_INFO_OBJECT (sink, "filename: %s", sink->filename);
236  break;
237  case PROP_JSON:
238  sink->json_filename = g_value_dup_string (value);
239  GST_INFO_OBJECT (sink, "JSON filename: %s", sink->json_filename);
240  break;
241  default:
242  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
243  break;
244  }
245 }
246 
250 static void
251 gst_data_repo_sink_get_property (GObject * object, guint prop_id,
252  GValue * value, GParamSpec * pspec)
253 {
254  GstDataRepoSink *sink;
255 
256  sink = GST_DATA_REPO_SINK (object);
257 
258  switch (prop_id) {
259  case PROP_LOCATION:
260  g_value_set_string (value, sink->filename);
261  break;
262  case PROP_JSON:
263  g_value_set_string (value, sink->json_filename);
264  break;
265  default:
266  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267  break;
268  }
269 }
270 
274 static GstFlowReturn
276 {
277  ssize_t write_size = 0;
278  GstMapInfo info;
279  GstFlowReturn ret = GST_FLOW_OK;
280 
281  g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR);
282  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
283  g_return_val_if_fail (sink->fd != 0, GST_FLOW_ERROR);
284 
285  if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
286  GST_ERROR_OBJECT (sink, "Failed to map the incoming buffer.");
287  return GST_FLOW_ERROR;
288  }
289 
290  GST_OBJECT_LOCK (sink);
291  sink->sample_size = info.size;
292 
293  GST_LOG_OBJECT (sink,
294  "Writing %lld bytes at offset 0x%" G_GINT64_MODIFIER "x (%lld size)",
295  (long long) info.size, sink->fd_offset, (long long) sink->fd_offset);
296 
297  write_size = write (sink->fd, info.data, info.size);
298 
299  if ((write_size == -1) || (write_size != (ssize_t) info.size)) {
300  GST_ERROR_OBJECT (sink, "Error writing data to file");
301  ret = GST_FLOW_ERROR;
302  } else {
303  sink->fd_offset += write_size;
304  sink->total_samples++;
305  }
306 
307  GST_OBJECT_UNLOCK (sink);
308  gst_buffer_unmap (buffer, &info);
309 
310  return ret;
311 }
312 
316 static GstFlowReturn
318  GstBuffer * buffer)
319 {
320  guint num_tensors, i;
321  gsize total_write = 0, tensor_size;
322  ssize_t write_size = 0;
323  GstMapInfo info;
324  GstMemory *mem = NULL;
325  GstTensorMetaInfo meta;
326 
327  g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR);
328  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
329  g_return_val_if_fail (sink->fd != 0, GST_FLOW_ERROR);
330  g_return_val_if_fail (sink->json_object != NULL, GST_FLOW_ERROR);
331  g_return_val_if_fail (sink->sample_offset_array != NULL, GST_FLOW_ERROR);
332  g_return_val_if_fail (sink->tensor_size_array != NULL, GST_FLOW_ERROR);
333  g_return_val_if_fail (sink->tensor_count_array != NULL, GST_FLOW_ERROR);
334 
335  GST_OBJECT_LOCK (sink);
336 
337  num_tensors = gst_tensor_buffer_get_count (buffer);
338  GST_INFO_OBJECT (sink, "num_tensors: %u", num_tensors);
339 
340  for (i = 0; i < num_tensors; i++) {
341  mem = gst_tensor_buffer_get_nth_memory (buffer, i);
342  if (!gst_memory_map (mem, &info, GST_MAP_READ)) {
343  GST_ERROR_OBJECT (sink, "Failed to map memory");
344  goto mem_map_error;
345  }
346 
347  if (!gst_tensor_meta_info_parse_header (&meta, info.data)) {
348  GST_ERROR_OBJECT (sink,
349  "Invalid format of tensors, the format is static.");
350  goto error;
351  }
352  tensor_size = info.size;
353 
354  GST_LOG_OBJECT (sink, "tensor[%u] size: %zd", i, tensor_size);
355  GST_LOG_OBJECT (sink,
356  "Writing %lld bytes at offset 0x%" G_GINT64_MODIFIER "x (%lld size)",
357  (long long) tensor_size, sink->fd_offset + total_write,
358  (long long) sink->fd_offset + total_write);
359 
360  write_size = write (sink->fd, info.data, tensor_size);
361  if ((write_size == -1) || (write_size != (ssize_t) tensor_size)) {
362  GST_ERROR_OBJECT (sink, "Error writing data to file");
363  goto error;
364  }
365 
366  json_array_add_int_element (sink->tensor_size_array, tensor_size);
367  total_write += (gsize) write_size;
368 
369  gst_memory_unmap (mem, &info);
370  gst_memory_unref (mem);
371  }
372 
373  json_array_add_int_element (sink->sample_offset_array, sink->fd_offset);
374  sink->fd_offset += total_write;
375 
376  GST_LOG_OBJECT (sink, "cumulative_tensors: %u", sink->cumulative_tensors);
377  json_array_add_int_element (sink->tensor_count_array,
378  sink->cumulative_tensors);
379  sink->cumulative_tensors += num_tensors;
380 
381  sink->total_samples++;
382 
383  GST_OBJECT_UNLOCK (sink);
384 
385  return GST_FLOW_OK;
386 
387 error:
388  gst_memory_unmap (mem, &info);
389 mem_map_error:
390  gst_memory_unref (mem);
391  GST_OBJECT_UNLOCK (sink);
392 
393  return GST_FLOW_ERROR;
394 }
395 
399 static gchar *
401 {
402  gchar *filename = NULL;
403 
404  g_return_val_if_fail (sink != NULL, NULL);
405  g_return_val_if_fail (sink->data_type == GST_DATA_REPO_DATA_IMAGE, NULL);
406  g_return_val_if_fail (sink->filename != NULL, NULL);
407 
408 #ifdef __GNUC__
409 #pragma GCC diagnostic push
410 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
411 #endif
412  filename = g_strdup_printf (sink->filename, sink->total_samples);
413 #ifdef __GNUC__
414 #pragma GCC diagnostic pop
415 #endif
416 
417  return filename;
418 }
419 
423 static GstFlowReturn
425  GstBuffer * buffer)
426 {
427  g_autofree gchar *filename = NULL;
428  GstFlowReturn ret = GST_FLOW_OK;
429  GError *error = NULL;
430  GstMapInfo info;
431 
432  g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR);
433  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
434 
435  if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
436  GST_ERROR_OBJECT (sink, "Failed to map the incoming buffer.");
437  return GST_FLOW_ERROR;
438  }
439 
440  filename = gst_data_repo_sink_get_image_filename (sink);
441 
442  GST_OBJECT_LOCK (sink);
443  sink->sample_size = info.size;
444 
445  GST_DEBUG_OBJECT (sink, "Writing to file \"%s\", size(%zd)", filename,
446  info.size);
447 
448  if (!g_file_set_contents (filename, (char *) info.data, info.size, &error)) {
449  GST_ERROR_OBJECT (sink, "Could not write data to file: %s",
450  error ? error->message : "unknown error");
451  g_clear_error (&error);
452  ret = GST_FLOW_ERROR;
453  } else {
454  sink->total_samples++;
455  }
456 
457  GST_OBJECT_UNLOCK (sink);
458  gst_buffer_unmap (buffer, &info);
459 
460  return ret;
461 }
462 
466 static GstFlowReturn
467 gst_data_repo_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
468 {
470 
471  switch (sink->data_type) {
476  return gst_data_repo_sink_write_others (sink, buffer);
478  {
479  if (sink->is_static_tensors)
480  return gst_data_repo_sink_write_others (sink, buffer);
482  }
484  return gst_data_repo_sink_write_multi_images (sink, buffer);
485  default:
486  return GST_FLOW_ERROR;
487  }
488 }
489 
493 static GstCaps *
494 gst_data_repo_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
495 {
496  GstDataRepoSink *sink = GST_DATA_REPO_SINK (bsink);
497  GstCaps *caps = NULL;
498 
499  GST_OBJECT_LOCK (sink);
500  caps = sink->fixed_caps;
501 
502  GST_INFO_OBJECT (sink, "Got caps %" GST_PTR_FORMAT, caps);
503  if (caps) {
504  if (filter)
505  caps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
506  else
507  caps = gst_caps_ref (caps);
508  }
509 
510  GST_DEBUG_OBJECT (sink, "result get caps: %" GST_PTR_FORMAT, caps);
511  GST_OBJECT_UNLOCK (sink);
512 
513  return caps;
514 }
515 
519 static void
521 {
522  GstStructure *structure;
523  GstTensorsConfig config;
524 
525  g_return_if_fail (sink != NULL);
526  g_return_if_fail (sink->fixed_caps != NULL);
527  g_return_if_fail (sink->data_type == GST_DATA_REPO_DATA_TENSOR);
528 
529  structure = gst_caps_get_structure (sink->fixed_caps, 0);
530  gst_tensors_config_from_structure (&config, structure);
532  gst_tensors_config_free (&config);
533 }
534 
538 static gboolean
539 gst_data_repo_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
540 {
541  GstDataRepoSink *sink;
542 
543  sink = GST_DATA_REPO_SINK (bsink);
544  GST_INFO_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
545 
546  if (sink->fixed_caps) {
547  gst_caps_unref (sink->fixed_caps);
548  sink->fixed_caps = NULL;
549  }
550 
552  sink->fixed_caps = gst_caps_copy (caps);
553 
555 
556  GST_DEBUG_OBJECT (sink, "data type: %d", sink->data_type);
557  return (sink->data_type != GST_DATA_REPO_DATA_UNKNOWN);
558 }
559 
563 static gboolean
564 gst_data_repo_sink_query (GstBaseSink * bsink, GstQuery * query)
565 {
566  gboolean ret;
567 
568  switch (GST_QUERY_TYPE (query)) {
569  case GST_QUERY_SEEKING:{
570  GstFormat fmt;
571 
572  /* we don't supporting seeking */
573  gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
574  gst_query_set_seeking (query, fmt, FALSE, 0, -1);
575  ret = TRUE;
576  break;
577  }
578  default:
579  ret = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
580  break;
581  }
582 
583  return ret;
584 }
585 
589 static gboolean
591 {
592  gchar *filename = NULL;
593  int flags = O_CREAT | O_WRONLY;
594 
595  g_return_val_if_fail (sink != NULL, FALSE);
596  g_return_val_if_fail (sink->data_type != GST_DATA_REPO_DATA_UNKNOWN, FALSE);
597 
598  if (sink->filename == NULL || sink->filename[0] == '\0')
599  goto no_filename;
600 
601  if (sink->data_type == GST_DATA_REPO_DATA_IMAGE) {
602  return TRUE;
603  }
604 
605  /* need to get filename by media type */
606  filename = g_strdup (sink->filename);
607 
608  GST_INFO_OBJECT (sink, "opening file %s", filename);
609 
610  flags |= O_TRUNC; /* "wb" */
611  sink->fd = g_open (filename, flags, 0644);
612 
613  if (sink->fd < 0)
614  goto open_failed;
615 
616  g_free (filename);
617 
618  return TRUE;
619 
620 no_filename:
621  {
622  GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
623  (("No file name specified for writing.")), (NULL));
624  goto error_exit;
625  }
626 open_failed:
627  {
628  switch (errno) {
629  case ENOENT:
630  GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, (NULL),
631  ("No such file \"%s\"", sink->filename));
632  break;
633  default:
634  GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ,
635  (("Could not open file \"%s\" for reading."), sink->filename),
636  GST_ERROR_SYSTEM);
637  break;
638  }
639  goto error_exit;
640  }
641 
642 error_exit:
643  g_free (filename);
644 
645  return FALSE;
646 }
647 
651 static gboolean
652 gst_data_repo_sink_stop (GstBaseSink * basesink)
653 {
654  GstDataRepoSink *sink;
655 
656  sink = GST_DATA_REPO_SINK_CAST (basesink);
657 
658  g_close (sink->fd, NULL);
659  sink->fd = 0;
660 
661  return TRUE;
662 }
663 
667 static gboolean
668 __write_json (JsonObject * object, const gchar * filename)
669 {
670  JsonNode *root;
671  JsonGenerator *generator;
672  gboolean ret = TRUE;
673 
674  g_return_val_if_fail (object != NULL, FALSE);
675  g_return_val_if_fail (filename != NULL, FALSE);
676 
677  root = json_node_init_object (json_node_alloc (), object);
678  generator = json_generator_new ();
679  json_generator_set_root (generator, root);
680  json_generator_set_pretty (generator, TRUE);
681  ret = json_generator_to_file (generator, filename, NULL);
682  if (!ret) {
683  GST_ERROR ("Failed to write JSON to file %s", filename);
684  }
685 
686  g_object_unref (generator);
687  json_node_free (root);
688 
689  return ret;
690 }
691 
695 static gboolean
697 {
698  gchar *caps_str = NULL;
699  gboolean ret = TRUE;
700 
701  g_return_val_if_fail (sink != NULL, FALSE);
702  g_return_val_if_fail (sink->json_filename != NULL, FALSE);
703  g_return_val_if_fail (sink->data_type != GST_DATA_REPO_DATA_UNKNOWN, FALSE);
704  g_return_val_if_fail (sink->fixed_caps != NULL, FALSE);
705  g_return_val_if_fail (sink->json_object != NULL, FALSE);
706  g_return_val_if_fail (sink->sample_offset_array != NULL, FALSE);
707  g_return_val_if_fail (sink->tensor_size_array != NULL, FALSE);
708  g_return_val_if_fail (sink->tensor_count_array != NULL, GST_FLOW_ERROR);
709 
710  caps_str = gst_caps_to_string (sink->fixed_caps);
711  GST_DEBUG_OBJECT (sink, "caps string: %s", caps_str);
712 
713  json_object_set_string_member (sink->json_object, "gst_caps", caps_str);
714 
715  json_object_set_int_member (sink->json_object, "total_samples",
716  sink->total_samples);
717 
718  if (sink->data_type == GST_DATA_REPO_DATA_TENSOR && !sink->is_static_tensors) {
719  json_object_set_array_member (sink->json_object, "sample_offset",
720  sink->sample_offset_array);
721  json_object_set_array_member (sink->json_object, "tensor_size",
722  sink->tensor_size_array);
723  json_object_set_array_member (sink->json_object, "tensor_count",
724  sink->tensor_count_array);
725 
726  sink->sample_offset_array = NULL;
727  sink->tensor_size_array = NULL;
728  sink->tensor_count_array = NULL;
729  } else {
730  json_object_set_int_member (sink->json_object, "sample_size",
731  sink->sample_size);
732  }
733  ret = __write_json (sink->json_object, sink->json_filename);
734  if (!ret) {
735  GST_ERROR_OBJECT (sink, "Failed to write json meta file: %s",
736  sink->json_filename);
737  }
738 
739  json_object_unref (sink->json_object);
740  g_free (caps_str);
741  sink->json_object = NULL;
742 
743  return ret;
744 }
745 
749 static GstStateChangeReturn
750 gst_data_repo_sink_change_state (GstElement * element,
751  GstStateChange transition)
752 {
753  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
754  GstDataRepoSink *sink = GST_DATA_REPO_SINK (element);
755 
756  switch (transition) {
757  case GST_STATE_CHANGE_NULL_TO_READY:
758  GST_INFO_OBJECT (sink, "NULL_TO_READY");
759  if (sink->filename == NULL || sink->json_filename == NULL) {
760  GST_ERROR_OBJECT (sink, "Set filenmae and json");
761  goto state_change_failed;
762  }
763  break;
764 
765  case GST_STATE_CHANGE_READY_TO_PAUSED:
766  GST_INFO_OBJECT (sink, "READY_TO_PAUSED");
767  break;
768 
769  case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
770  GST_INFO_OBJECT (sink, "PAUSED_TO_PLAYING");
771  if (!gst_data_repo_sink_open_file (sink))
772  goto state_change_failed;
773  break;
774 
775  default:
776  break;
777  }
778 
779  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
780 
781  switch (transition) {
782  case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
783  GST_INFO_OBJECT (sink, "PLAYING_TO_PAUSED");
784  break;
785 
786  case GST_STATE_CHANGE_PAUSED_TO_READY:
787  GST_INFO_OBJECT (sink, "PAUSED_TO_READY");
788  break;
789 
790  case GST_STATE_CHANGE_READY_TO_NULL:
791  GST_INFO_OBJECT (sink, "READY_TO_NULL");
793  goto state_change_failed;
794  break;
795 
796  default:
797  break;
798  }
799  return ret;
800 
801 state_change_failed:
802  GST_ERROR_OBJECT (sink, "state change failed");
803 
804  return GST_STATE_CHANGE_FAILURE;
805 }
GST_DATA_REPO_DATA_VIDEO
@ GST_DATA_REPO_DATA_VIDEO
Definition: gstdatarepo.h:26
GST_DEBUG_CATEGORY_STATIC
GST_DEBUG_CATEGORY_STATIC(gst_data_repo_sink_debug)
gstdatareposink.h
G_DEFINE_TYPE_WITH_CODE
G_DEFINE_TYPE_WITH_CODE(GstDataRepoSink, gst_data_repo_sink, GST_TYPE_BASE_SINK, _do_init)
gst_data_repo_sink_get_property
static void gst_data_repo_sink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
Getter datareposink properties.
Definition: gstdatareposink.c:251
GST_DATA_REPO_SINK
#define GST_DATA_REPO_SINK(obj)
Definition: gstdatareposink.h:24
_GstDataRepoSink::json_filename
gchar * json_filename
Definition: gstdatareposink.h:60
_GstDataRepoSink::is_static_tensors
gboolean is_static_tensors
Definition: gstdatareposink.h:51
PROP_JSON
@ PROP_JSON
Definition: gstdatareposink.c:87
FALSE
return FALSE
Definition: gsttensor_transform.c:590
_GstDataRepoSinkClass
GstDataRepoSinkClass data structure.
Definition: gstdatareposink.h:66
GST_DATA_REPO_SINK_CAST
#define GST_DATA_REPO_SINK_CAST(obj)
Definition: gstdatareposink.h:32
gst_data_repo_sink_open_file
static gboolean gst_data_repo_sink_open_file(GstDataRepoSink *sink)
Function to open file.
Definition: gstdatareposink.c:590
_do_init
#define _do_init
Definition: gstdatareposink.c:92
gst_data_repo_sink_stop
static gboolean gst_data_repo_sink_stop(GstBaseSink *basesink)
Stop datareposink.
Definition: gstdatareposink.c:652
_GstDataRepoSink
GstDataRepoSink data structure.
Definition: gstdatareposink.h:40
GstTensorMetaInfo
Data structure to describe a tensor data. This represents the basic information of a memory block for...
Definition: tensor_typedef.h:310
sinktemplate
static GstStaticPadTemplate sinktemplate
Definition: gstdatareposink.c:75
gst_data_repo_sink_set_is_static_tensors
static void gst_data_repo_sink_set_is_static_tensors(GstDataRepoSink *sink)
Set whether the given pad caps are static or not.
Definition: gstdatareposink.c:520
_GstDataRepoSink::cumulative_tensors
guint cumulative_tensors
Definition: gstdatareposink.h:49
TEXT_CAPS
#define TEXT_CAPS
Text caps.
Definition: gstdatareposink.c:60
GST_DATA_REPO_DATA_IMAGE
@ GST_DATA_REPO_DATA_IMAGE
Definition: gstdatarepo.h:31
GST_DATA_REPO_DATA_TEXT
@ GST_DATA_REPO_DATA_TEXT
Definition: gstdatarepo.h:28
TENSOR_CAPS
#define TENSOR_CAPS
Tensors caps.
Definition: gstdatareposink.c:42
_GstDataRepoSink::json_object
JsonObject * json_object
Definition: gstdatareposink.h:45
g_free
g_free(self->option[(opnum) - 1])
opnum: \
gst_data_repo_sink_write_flexible_or_sparse_tensors
static GstFlowReturn gst_data_repo_sink_write_flexible_or_sparse_tensors(GstDataRepoSink *sink, GstBuffer *buffer)
Function to write flexible tensors or sparse tensors.
Definition: gstdatareposink.c:317
gst_data_repo_sink_write_multi_images
static GstFlowReturn gst_data_repo_sink_write_multi_images(GstDataRepoSink *sink, GstBuffer *buffer)
Function to read multi image files.
Definition: gstdatareposink.c:424
g_value_set_string
g_value_set_string(value, self->option[opnum - 1])
opnum: \
gst_data_repo_sink_get_image_filename
static gchar * gst_data_repo_sink_get_image_filename(GstDataRepoSink *sink)
Get image filename.
Definition: gstdatareposink.c:400
gst_tensor_meta_info_parse_header
gboolean gst_tensor_meta_info_parse_header(GstTensorMetaInfo *meta, gpointer header)
Parse header and fill the tensor meta.
Definition: nnstreamer_plugin_api_util_impl.c:1527
_GstDataRepoSink::total_samples
gint total_samples
Definition: gstdatareposink.h:54
gst_data_repo_sink_init
static void gst_data_repo_sink_init(GstDataRepoSink *sink)
Initialize datareposink.
Definition: gstdatareposink.c:174
GST_DATA_REPO_DATA_UNKNOWN
@ GST_DATA_REPO_DATA_UNKNOWN
Definition: gstdatarepo.h:25
PROP_LOCATION
@ PROP_LOCATION
Definition: gstdatareposink.c:86
gst_data_repo_get_data_type_from_caps
GstDataRepoDataType gst_data_repo_get_data_type_from_caps(const GstCaps *caps)
Get data type from caps.
Definition: gstdatarepo.c:21
gst_tensors_config_free
void gst_tensors_config_free(GstTensorsConfig *config)
Free allocated data in tensors config structure.
Definition: nnstreamer_plugin_api_util_impl.c:845
_GstDataRepoSink::sample_offset_array
JsonArray * sample_offset_array
Definition: gstdatareposink.h:46
_GstDataRepoSink::tensor_count_array
JsonArray * tensor_count_array
Definition: gstdatareposink.h:48
_GstDataRepoSink::tensor_size_array
JsonArray * tensor_size_array
Definition: gstdatareposink.h:47
_GstDataRepoSink::data_type
GstDataRepoDataType data_type
Definition: gstdatareposink.h:53
gst_data_repo_sink_set_property
static void gst_data_repo_sink_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
Setter for datareposink properties.
Definition: gstdatareposink.c:227
PROP_0
@ PROP_0
Definition: gstdatareposink.c:85
_GstDataRepoSink::filename
gchar * filename
Definition: gstdatareposink.h:59
GstTensorsConfig
Internal data structure for configured tensors info (for other/tensors).
Definition: tensor_typedef.h:284
_GstDataRepoSink::fd_offset
guint64 fd_offset
Definition: gstdatareposink.h:55
gst_data_repo_sink_write_json_meta_file
static gboolean gst_data_repo_sink_write_json_meta_file(GstDataRepoSink *sink)
write the meta information to a JSON file
Definition: gstdatareposink.c:696
OCTET_CAPS
#define OCTET_CAPS
Octet caps.
Definition: gstdatareposink.c:64
TRUE
return TRUE
Definition: gsttensor_if.c:897
AUDIO_CAPS
#define AUDIO_CAPS
Definition: gstdatareposink.c:55
nnstreamer_util.h
Optional NNStreamer utility functions for sub-plugin writers and users.
gst_data_repo_sink_class_init
static void gst_data_repo_sink_class_init(GstDataRepoSinkClass *klass)
Initialize datareposink class.
Definition: gstdatareposink.c:118
_GstDataRepoSink::fixed_caps
GstCaps * fixed_caps
Definition: gstdatareposink.h:44
_GstDataRepoSink::sample_size
gsize sample_size
Definition: gstdatareposink.h:56
gst_data_repo_sink_finalize
static void gst_data_repo_sink_finalize(GObject *object)
finalize datareposink.
Definition: gstdatareposink.c:195
gst_data_repo_sink_write_others
static GstFlowReturn gst_data_repo_sink_write_others(GstDataRepoSink *sink, GstBuffer *buffer)
Function to write others media type (tensors(fixed), video, audio, octet and text)
Definition: gstdatareposink.c:275
tensor_common.h
Common header file for NNStreamer, the GStreamer plugin for neural networks.
IMAGE_CAPS
#define IMAGE_CAPS
Image caps.
Definition: gstdatareposink.c:68
gst_data_repo_sink_get_caps
static GstCaps * gst_data_repo_sink_get_caps(GstBaseSink *bsink, GstCaps *filter)
Get caps of datareposink.
Definition: gstdatareposink.c:494
GST_DATA_REPO_DATA_OCTET
@ GST_DATA_REPO_DATA_OCTET
Definition: gstdatarepo.h:29
GST_DATA_REPO_DATA_TENSOR
@ GST_DATA_REPO_DATA_TENSOR
Definition: gstdatarepo.h:30
gst_data_repo_sink_render
static GstFlowReturn gst_data_repo_sink_render(GstBaseSink *bsink, GstBuffer *buffer)
Called when a buffer should be presented or output.
Definition: gstdatareposink.c:467
gst_tensor_buffer_get_nth_memory
GstMemory * gst_tensor_buffer_get_nth_memory(GstBuffer *buffer, const guint index)
Get the nth GstMemory from given buffer.
Definition: nnstreamer_plugin_api_impl.c:1586
_GstDataRepoSink::fd
gint fd
Definition: gstdatareposink.h:52
gst_data_repo_sink_change_state
static GstStateChangeReturn gst_data_repo_sink_change_state(GstElement *element, GstStateChange transition)
Change state of datareposink.
Definition: gstdatareposink.c:750
gst_tensor_buffer_get_count
guint gst_tensor_buffer_get_count(GstBuffer *buffer)
Get the number of tensors in the buffer.
Definition: nnstreamer_plugin_api_impl.c:1813
gst_data_repo_sink_set_caps
static gboolean gst_data_repo_sink_set_caps(GstBaseSink *bsink, GstCaps *caps)
Set caps of datareposink.
Definition: gstdatareposink.c:539
__write_json
static gboolean __write_json(JsonObject *object, const gchar *filename)
Write json to file.
Definition: gstdatareposink.c:668
GST_DATA_REPO_DATA_AUDIO
@ GST_DATA_REPO_DATA_AUDIO
Definition: gstdatarepo.h:27
gst_tensors_config_from_structure
gboolean gst_tensors_config_from_structure(GstTensorsConfig *config, const GstStructure *structure)
Parse structure and set tensors config (for other/tensors)
Definition: nnstreamer_plugin_api_impl.c:1413
gst_tensors_config_is_static
#define gst_tensors_config_is_static(c)
Macro to check stream format (static tensors for caps negotiation)
Definition: nnstreamer_plugin_api_util.h:274
GST_ERROR
GST_ERROR("Failed to register nnstreamer plugin : tensor_" # name)
type)) { \
nnstreamer_plugin_api.h
Optional/Additional NNStreamer APIs for sub-plugin writers. (Need Gst devel)
VIDEO_CAPS
#define VIDEO_CAPS
Definition: gstdatareposink.c:48
gst_data_repo_sink_query
static gboolean gst_data_repo_sink_query(GstBaseSink *sink, GstQuery *query)
Perform a GstQuery on datareposink.
Definition: gstdatareposink.c:564