[Decoder] Decode tensors to octet stream.
authorGichan Jang <gichan2.jang@samsung.com>
Thu, 4 Nov 2021 06:41:15 +0000 (15:41 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Mon, 13 Dec 2021 07:36:16 +0000 (16:36 +0900)
Decode tensors to octet stream.
If tensor format is flexible, remove the header.

Signed-off-by: gichan <gichan2.jang@samsung.com>
debian/nnstreamer-core.install
ext/nnstreamer/tensor_decoder/meson.build
ext/nnstreamer/tensor_decoder/tensordec-octetstream.c [new file with mode: 0644]
jni/Android.mk
jni/nnstreamer.mk
packaging/nnstreamer.spec
tests/nnstreamer_octet_stream/runTest.sh [new file with mode: 0755]

index 85e1f7b..9072a90 100644 (file)
@@ -3,6 +3,7 @@
 /usr/lib/nnstreamer/decoders/libnnstreamer_decoder_image_segment.so
 /usr/lib/nnstreamer/decoders/libnnstreamer_decoder_image_labeling.so
 /usr/lib/nnstreamer/decoders/libnnstreamer_decoder_direct_video.so
+/usr/lib/nnstreamer/decoders/libnnstreamer_decoder_octet_stream.so
 /usr/lib/nnstreamer/filters/libnnstreamer_filter_cpp.so
 /usr/lib/*/libnnstreamer.so
 /usr/lib/*/gstreamer-1.0/libnnstreamer.so
index 2ca1834..2b434a0 100644 (file)
@@ -200,3 +200,27 @@ if have_python3
     install_dir: nnstreamer_libdir
   )
 endif
+
+# octet stream
+decoder_sub_octet_stream_sources = [
+  'tensordec-octetstream.c',
+  'tensordecutil.c'
+]
+
+nnstreamer_decoder_octet_stream_sources = []
+foreach s : decoder_sub_octet_stream_sources
+  nnstreamer_decoder_octet_stream_sources += join_paths(meson.current_source_dir(), s)
+endforeach
+
+shared_library('nnstreamer_decoder_octet_stream',
+  nnstreamer_decoder_octet_stream_sources,
+  dependencies: [nnstreamer_dep, glib_dep, gst_dep],
+  install: true,
+  install_dir: decoder_subplugin_install_dir
+)
+static_library('nnstreamer_decoder_octet_stream',
+  nnstreamer_decoder_octet_stream_sources,
+  dependencies: [nnstreamer_dep, glib_dep, gst_dep],
+  install: true,
+  install_dir: nnstreamer_libdir
+)
diff --git a/ext/nnstreamer/tensor_decoder/tensordec-octetstream.c b/ext/nnstreamer/tensor_decoder/tensordec-octetstream.c
new file mode 100644 (file)
index 0000000..26aaef1
--- /dev/null
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/**
+ * GStreamer/NNStreamer Tensor-Decoder
+ * Copyright (C) 2021 Gichan Jang <gichan2.jang@samsung.com>
+ */
+/**
+ * @file       tensordec-octetstream.c
+ * @date       04 Nov 2021
+ * @brief      NNStreamer tensor-decoder subplugin, "octet stream",
+ *              which converts tensors to octet stream.
+ * @see                https://github.com/nnstreamer/nnstreamer
+ * @author     Gichan Jang <gichan2.jang@samsung.com>
+ * @bug                No known bugs except for NYI items
+ *
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <nnstreamer_plugin_api_decoder.h>
+#include <nnstreamer_plugin_api.h>
+#include <nnstreamer_log.h>
+#include <nnstreamer_util.h>
+#include "tensordecutil.h"
+
+void init_os (void) __attribute__ ((constructor));
+void fini_os (void) __attribute__ ((destructor));
+
+#define OCTET_CAPS_STR "application/octet-stream"
+
+/** @brief tensordec-plugin's GstTensorDecoderDef callback */
+static int
+os_init (void **pdata)
+{
+  *pdata = NULL;
+  return TRUE;
+}
+
+/** @brief tensordec-plugin's GstTensorDecoderDef callback */
+static void
+os_exit (void **pdata)
+{
+  UNUSED (pdata);
+  return;
+}
+
+/** @brief tensordec-plugin's GstTensorDecoderDef callback */
+static int
+os_setOption (void **pdata, int opNum, const char *param)
+{
+  UNUSED (pdata);
+  UNUSED (opNum);
+  UNUSED (param);
+  return TRUE;
+}
+
+/** @brief tensordec-plugin's GstTensorDecoderDef callback */
+static GstCaps *
+os_getOutCaps (void **pdata, const GstTensorsConfig * config)
+{
+  GstCaps *caps;
+  UNUSED (pdata);
+
+  caps = gst_caps_from_string (OCTET_CAPS_STR);
+  setFramerateFromConfig (caps, config);
+  return caps;
+}
+
+/** @brief tensordec-plugin's GstTensorDecoderDef callback */
+static GstFlowReturn
+os_decode (void **pdata, const GstTensorsConfig * config,
+    const GstTensorMemory * input, GstBuffer * outbuf)
+{
+  guint i;
+  gboolean is_flexible;
+  GstTensorMetaInfo meta;
+  gpointer mem_data;
+  UNUSED (pdata);
+
+  if (!config || !input || !outbuf) {
+    ml_loge ("NULL parameter is passed to tensor_decoder::octet_stream");
+    return GST_FLOW_ERROR;
+  }
+  is_flexible = gst_tensors_config_is_flexible (config);
+
+  for (i = 0; i < config->info.num_tensors; i++) {
+    gsize offset = 0, data_size = 0;
+    GstMemory *mem = NULL;
+
+    if (is_flexible) {
+      gst_tensor_meta_info_parse_header (&meta, input[i].data);
+      offset = gst_tensor_meta_info_get_header_size (&meta);
+      data_size = gst_tensor_meta_info_get_data_size (&meta);
+    } else {
+      data_size = gst_tensors_info_get_size (&config->info, i);
+    }
+    mem_data = _g_memdup ((guint8 *) input[i].data + offset, data_size);
+    mem = gst_memory_new_wrapped ((GstMemoryFlags) 0, mem_data, data_size,
+          0, data_size, NULL, g_free);
+    gst_buffer_append_memory (outbuf, mem);
+  }
+
+  return GST_FLOW_OK;
+}
+
+static gchar decoder_subplugin_octet_stream[] = "octet_stream";
+
+/** @brief octet stream tensordec-plugin GstTensorDecoderDef instance */
+static GstTensorDecoderDef octetSTream = {
+  .modename = decoder_subplugin_octet_stream,
+  .init = os_init,
+  .exit = os_exit,
+  .setOption = os_setOption,
+  .getOutCaps = os_getOutCaps,
+  .getTransformSize = NULL,
+  .decode = os_decode
+};
+
+/** @brief Initialize this object for tensordec-plugin */
+void
+init_os (void)
+{
+  nnstreamer_decoder_probe (&octetSTream);
+}
+
+/** @brief Destruct this object for tensordec-plugin */
+void
+fini_os (void)
+{
+  nnstreamer_decoder_exit (octetSTream.modename);
+}
index 49c9380..34a83f4 100644 (file)
@@ -218,4 +218,20 @@ LOCAL_C_INCLUDES += $(GST_HEADERS_COMMON)
 
 include $(BUILD_SHARED_LIBRARY)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := nnstreamer_decoder_octet_stream
+LOCAL_SRC_FILES := $(NNSTREAMER_DECODER_OS_SRCS)
+LOCAL_C_INCLUDES    := $(NNSTREAMER_INCLUDES)
+
+LOCAL_SHARED_LIBRARIES := $(GST_BUILDING_BLOCK_LIST) nnstreamer
+
+LOCAL_ARM_NEON      := true
+LOCAL_CFLAGS        += -O0 -DVERSION=\"$(NNSTREAMER_VERSION)\"
+LOCAL_CXXFLAGS      += -std=c++11 -DVERSION=\"$(NNSTREAMER_VERSION)\"
+LOCAL_CFLAGS        += -pthread -fopenmp
+
+LOCAL_C_INCLUDES += $(GST_HEADERS_COMMON)
+
+include $(BUILD_SHARED_LIBRARY)
+
 $(call import-module, android/cpufeatures)
index c6b1ca0..2497cea 100644 (file)
@@ -154,6 +154,11 @@ NNSTREAMER_DECODER_IS_SRCS := \
     $(NNSTREAMER_EXT_HOME)/tensor_decoder/tensordec-imagesegment.c \
     $(NNSTREAMER_EXT_HOME)/tensor_decoder/tensordecutil.c
 
+# decoder octet-stream
+NNSTREAMER_DECODER_OS_SRCS := \
+    $(NNSTREAMER_EXT_HOME)/tensor_decoder/tensordec-octetstream.c \
+    $(NNSTREAMER_EXT_HOME)/tensor_decoder/tensordecutil.c
+
 # gstreamer join element
 NNSTREAMER_JOIN_SRCS := \
     $(NNSTREAMER_ROOT)/gst/join/gstjoin.c
index 6e6a9e3..ef0da2a 100644 (file)
@@ -906,6 +906,7 @@ cp -r result %{buildroot}%{_datadir}/nnstreamer/unittest/
 %{_prefix}/lib/nnstreamer/decoders/libnnstreamer_decoder_image_segment.so
 %{_prefix}/lib/nnstreamer/decoders/libnnstreamer_decoder_image_labeling.so
 %{_prefix}/lib/nnstreamer/decoders/libnnstreamer_decoder_direct_video.so
+%{_prefix}/lib/nnstreamer/decoders/libnnstreamer_decoder_octet_stream.so
 %{_prefix}/lib/nnstreamer/filters/libnnstreamer_filter_cpp.so
 %{gstlibdir}/libnnstreamer.so
 %{_libdir}/libnnstreamer.so
diff --git a/tests/nnstreamer_octet_stream/runTest.sh b/tests/nnstreamer_octet_stream/runTest.sh
new file mode 100755 (executable)
index 0000000..e899d0b
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/env bash
+##
+## SPDX-License-Identifier: LGPL-2.1-only
+##
+## @file runTest.sh
+## @author Gichan Jang <gichan2.jang@samsung.com>
+## @date Nov 08 2021
+## @brief SSAT Test Cases for octet stream subplugin of tensor decoder
+##
+if [[ "$SSATAPILOADED" != "1" ]]; then
+    SILENT=0
+    INDEPENDENT=1
+    search="ssat-api.sh"
+    source $search
+    printf "${Blue}Independent Mode${NC}"
+fi
+
+# This is compatible with SSAT (https://github.com/myungjoo/SSAT)
+testInit $1
+
+PATH_TO_PLUGIN="../../build"
+
+# Test static tensor
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} \
+    videotestsrc num-buffers=3 pattern=13 ! video/x-raw,format=RGB,width=640,height=480,framerate=5/1 ! \
+        tee name=t ! queue ! tensor_converter ! multifilesink location=octet_raw_1_%1d.log \
+        t. ! queue ! tensor_converter ! tensor_decoder mode=octet_stream ! application/octet-stream ! multifilesink location=octet_decoded_1_%1d.log" 1 0 0 $PERFORMANCE
+callCompareTest octet_raw_1_0.log octet_decoded_1_0.log 1-0 "tensor_decoder::octet_stream compare test 1-0" 0 0
+callCompareTest octet_raw_1_1.log octet_decoded_1_1.log 1-1 "tensor_decoder::octet_stream compare test 1-1" 0 0
+callCompareTest octet_raw_1_2.log octet_decoded_1_2.log 1-2 "tensor_decoder::octet_stream compare test 1-2" 0 0
+
+# Test flexible tensor
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} \
+    videotestsrc num-buffers=3 pattern=13 ! video/x-raw,format=RGB,width=640,height=480,framerate=5/1 ! \
+        tee name=t ! queue ! tensor_converter ! multifilesink location=octet_raw_2_%1d.log \
+        t. ! queue ! tensor_converter ! other/tensors,format=flexible ! tensor_decoder mode=octet_stream ! application/octet-stream,framerate=5/1 ! multifilesink location=octet_decoded_2_%1d.log" 2 0 0 $PERFORMANCE
+callCompareTest octet_raw_2_0.log octet_decoded_2_0.log 2-0 "tensor_decoder::octet_stream compare test 2-0" 0 0
+callCompareTest octet_raw_2_1.log octet_decoded_2_1.log 2-1 "tensor_decoder::octet_stream compare test 2-1" 0 0
+callCompareTest octet_raw_2_2.log octet_decoded_2_2.log 2-2 "tensor_decoder::octet_stream compare test 2-2" 0 0
+
+# Test static tensors
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} \
+    videotestsrc num-buffers=3 pattern=13 ! video/x-raw,format=RGB,width=640,height=480,framerate=5/1 ! tensor_converter ! raw_tensor.sink_0 \
+    videotestsrc num-buffers=3 pattern=18 ! video/x-raw,format=RGB,width=320,height=240,framerate=5/1 ! tensor_converter ! raw_tensor.sink_1 \
+    tensor_mux name=raw_tensor ! \
+        tee name=t ! queue ! multifilesink location=octet_raw_3_%1d.log \
+        t. ! queue ! tensor_decoder mode=octet_stream ! application/octet-stream ! multifilesink location=octet_decoded_3_%1d.log" 3 0 0 $PERFORMANCE
+callCompareTest octet_raw_3_0.log octet_decoded_3_0.log 3-0 "tensor_decoder::octet_stream compare test 3-0" 0 0
+callCompareTest octet_raw_3_1.log octet_decoded_3_1.log 3-1 "tensor_decoder::octet_stream compare test 3-1" 0 0
+callCompareTest octet_raw_3_2.log octet_decoded_3_2.log 3-2 "tensor_decoder::octet_stream compare test 3-2" 0 0
+
+# Test flexible tensors
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} \
+    videotestsrc num-buffers=3 pattern=13 ! video/x-raw,format=RGB,width=640,height=480,framerate=5/1 ! tensor_converter ! other/tensors,format=flexible ! raw_tensor.sink_0 \
+    videotestsrc num-buffers=3 pattern=18 ! video/x-raw,format=RGB,width=320,height=240,framerate=5/1 ! tensor_converter ! other/tensors,format=flexible ! raw_tensor.sink_1 \
+    tensor_mux name=raw_tensor ! \
+        tee name=t ! queue ! multifilesink location=octet_raw_4_%1d.log \
+        t. ! queue ! tensor_decoder mode=octet_stream ! application/octet-stream ! multifilesink location=octet_decoded_4_%1d.log" 4 0 0 $PERFORMANCE
+# Compare with the results of test 3 (static tensors)
+callCompareTest octet_raw_3_0.log octet_decoded_4_0.log 4-0 "tensor_decoder::octet_stream compare test 4-0" 0 0
+callCompareTest octet_raw_3_1.log octet_decoded_4_1.log 4-1 "tensor_decoder::octet_stream compare test 4-1" 0 0
+callCompareTest octet_raw_3_2.log octet_decoded_4_2.log 4-2 "tensor_decoder::octet_stream compare test 4-2" 0 0
+
+rm *.log
+
+report