check returned value from invoke vmethod and return flow-dropped to skip incoming buffer.
TODO:
define status code for NNFW and custom-filter
Signed-off-by: Jaeyun Jung <jy1210.jung@samsung.com>
/* 3. Call the filter-subplugin callback, "invoke" */
gst_tensor_filter_call (self, ret, invoke_NN, in_tensors, out_tensors);
- g_assert (ret == 0);
+ /** @todo define enum to indicate status code */
+ g_assert (ret >= 0);
/* 4. Update result and free map info. */
for (i = 0; i < prop->output_meta.num_tensors; i++) {
}
/* 5. Return result! */
+ if (ret > 0) {
+ /** @todo define enum to indicate status code */
+ /* drop this buffer */
+ return GST_BASE_TRANSFORM_FLOW_DROPPED;
+ }
+
return GST_FLOW_OK;
unknown_format:
GST_ELEMENT_ERROR (self, CORE, NOT_IMPLEMENTED, (NULL), ("unknown format"));
install: false
)
-# This custom filter is used in unittest_sink.
+# These custom filters are used in unittest_sink.
library('nnscustom_framecounter',
join_paths('nnstreamer_sink', 'nnscustom_framecounter.c'),
dependencies: [glib_dep, nnstreamer_dep],
install: false
)
+library('nnscustom_drop_buffer',
+ join_paths('nnstreamer_sink', 'nnscustom_drop_buffer.c'),
+ dependencies: [nnstreamer_dep],
+ install: false
+)
+
# Build and copy exe for ssat
libpng_dep = dependency('libpng', required: false)
if libpng_dep.found()
--- /dev/null
+/**
+ * NNStreamer custom filter to test buffer-drop
+ * Copyright (C) 2018 Jaeyun Jung <jy1210.jung@samsung.com>
+ *
+ * LICENSE: LGPL-2.1
+ *
+ * @file nnscustom_drop_buffer.c
+ * @date 25 Jan 2019
+ * @author Jaeyun Jung <jy1210.jung@samsung.com>
+ * @brief Custom filter to drop incoming buffer (skip 9 buffers, then pass 1 buffer)
+ * @bug No known bugs
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <tensor_filter_custom.h>
+
+/**
+ * @brief nnstreamer custom filter private data
+ */
+typedef struct _pt_data
+{
+ unsigned int count; /**< This counts incoming buffer */
+} pt_data;
+
+/**
+ * @brief nnstreamer custom filter standard vmethod
+ * Refer tensor_filter_custom.h
+ */
+static void *
+pt_init (const GstTensorFilterProperties * prop)
+{
+ pt_data *data = (pt_data *) malloc (sizeof (pt_data));
+
+ assert (data);
+ data->count = 0;
+
+ return data;
+}
+
+/**
+ * @brief nnstreamer custom filter standard vmethod
+ * Refer tensor_filter_custom.h
+ */
+static void
+pt_exit (void *_data, const GstTensorFilterProperties * prop)
+{
+ pt_data *data = _data;
+
+ assert (data);
+ free (data);
+}
+
+/**
+ * @brief nnstreamer custom filter standard vmethod
+ * Refer tensor_filter_custom.h
+ */
+static int
+set_inputDim (void *_data, const GstTensorFilterProperties * prop,
+ const GstTensorsInfo * in_info, GstTensorsInfo * out_info)
+{
+ int i, t;
+
+ assert (in_info);
+ assert (out_info);
+
+ /** @todo use common function to copy tensor info */
+ out_info->num_tensors = in_info->num_tensors;
+
+ for (t = 0; t < in_info->num_tensors; t++) {
+ out_info->info[t].name = NULL;
+ out_info->info[t].type = in_info->info[t].type;
+
+ for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
+ out_info->info[t].dimension[i] = in_info->info[t].dimension[i];
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * @brief nnstreamer custom filter standard vmethod
+ * Refer tensor_filter_custom.h
+ */
+static int
+invoke (void *_data, const GstTensorFilterProperties * prop,
+ const GstTensorMemory * input, GstTensorMemory * output)
+{
+ pt_data *data = _data;
+ int t;
+
+ assert (data);
+
+ data->count++;
+ if (data->count % 10) {
+ /* drop this buffer */
+ /** @todo define enum to indicate status code */
+ return 2;
+ }
+
+ for (t = 0; t < prop->output_meta.num_tensors; t++) {
+ memcpy (output[t].data, input[t].data, input[t].size);
+ }
+
+ return 0;
+}
+
+static NNStreamer_custom_class NNStreamer_custom_body = {
+ .initfunc = pt_init,
+ .exitfunc = pt_exit,
+ .setInputDim = set_inputDim,
+ .invoke = invoke,
+};
+
+/* The dyn-loaded object */
+NNStreamer_custom_class *NNStreamer_custom = &NNStreamer_custom_body;
TEST_TYPE_TENSORS_MIX, /**< pipeline for tensors with tensor_mux, tensor_demux */
TEST_TYPE_CUSTOM_TENSOR, /**< pipeline for single tensor with passthrough custom filter */
TEST_TYPE_CUSTOM_TENSORS, /**< pipeline for tensors with passthrough custom filter */
+ TEST_TYPE_CUSTOM_BUF_DROP, /**< pipeline to test buffer-drop in tensor_filter using custom filter */
TEST_TYPE_NEGO_FAILED, /**< pipeline to test caps negotiation */
TEST_TYPE_VIDEO_RGB_SPLIT, /**< pipeline to test tensor_split */
TEST_TYPE_VIDEO_RGB_AGGR_1, /**< pipeline to test tensor_aggregator (change dimension index 3 : 1 > 10)*/
"videotestsrc num-buffers=%d ! video/x-raw,width=64,height=48,format=RGB,framerate=(fraction)30/1 ! tensor_converter ! mux.sink_2",
option.num_buffers, option.num_buffers, option.num_buffers);
break;
+ case TEST_TYPE_CUSTOM_BUF_DROP:
+ /* audio stream to test buffer-drop using custom filter */
+ str_pipeline =
+ g_strdup_printf
+ ("audiotestsrc num-buffers=%d samplesperbuffer=200 ! audioconvert ! audio/x-raw,format=S16LE,rate=16000,channels=1 ! "
+ "tensor_converter frames-per-tensor=200 ! tensor_filter framework=custom model=./tests/libnnscustom_drop_buffer.so ! tensor_sink name=test_sink",
+ option.num_buffers);
+ break;
case TEST_TYPE_NEGO_FAILED:
/** caps negotiation failed */
str_pipeline =
}
/**
+ * @brief Test to drop incoming buffer in tensor_filter using custom filter.
+ */
+TEST (tensor_stream_test, custom_filter_drop_buffer)
+{
+ const guint num_buffers = 22;
+ TestOption option = { num_buffers, TEST_TYPE_CUSTOM_BUF_DROP };
+
+ ASSERT_TRUE (_setup_pipeline (option));
+
+ gst_element_set_state (g_test_data.pipeline, GST_STATE_PLAYING);
+ g_main_loop_run (g_test_data.loop);
+ gst_element_set_state (g_test_data.pipeline, GST_STATE_NULL);
+
+ /** check eos message */
+ EXPECT_EQ (g_test_data.status, TEST_EOS);
+
+ /** check received buffers */
+ EXPECT_EQ (g_test_data.received, 2);
+ EXPECT_EQ (g_test_data.mem_blocks, 1);
+ EXPECT_EQ (g_test_data.received_size, 200 * 2);
+
+ /** check caps name */
+ EXPECT_TRUE (g_str_equal (g_test_data.caps_name, "other/tensor"));
+
+ /** check timestamp */
+ EXPECT_FALSE (g_test_data.invalid_timestamp);
+
+ /** check tensor config for audio */
+ EXPECT_TRUE (gst_tensor_config_validate (&g_test_data.tensor_config));
+ EXPECT_EQ (g_test_data.tensor_config.info.type, _NNS_INT16);
+ EXPECT_EQ (g_test_data.tensor_config.info.dimension[0], 1);
+ EXPECT_EQ (g_test_data.tensor_config.info.dimension[1], 200);
+ EXPECT_EQ (g_test_data.tensor_config.info.dimension[2], 1);
+ EXPECT_EQ (g_test_data.tensor_config.info.dimension[3], 1);
+ EXPECT_EQ (g_test_data.tensor_config.rate_n, 16000);
+ EXPECT_EQ (g_test_data.tensor_config.rate_d, 1);
+
+ EXPECT_FALSE (g_test_data.test_failed);
+ _free_test_data ();
+}
+
+/**
* @brief Test for tensors (mixed, video and audio).
*/
TEST (tensor_stream_test, tensors_mix)