From 5277b320d9c1d68ab96add78779c294096ed48c6 Mon Sep 17 00:00:00 2001 From: Jaeyun Date: Fri, 25 Jan 2019 13:58:55 +0900 Subject: [PATCH] [Filter/Test] flow-return to drop incoming buffer 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 --- gst/nnstreamer/tensor_filter/tensor_filter.c | 9 +- tests/meson.build | 8 +- tests/nnstreamer_sink/nnscustom_drop_buffer.c | 119 ++++++++++++++++++++++++++ tests/nnstreamer_sink/unittest_sink.cpp | 51 +++++++++++ 4 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 tests/nnstreamer_sink/nnscustom_drop_buffer.c diff --git a/gst/nnstreamer/tensor_filter/tensor_filter.c b/gst/nnstreamer/tensor_filter/tensor_filter.c index ddf3787..3c54766 100644 --- a/gst/nnstreamer/tensor_filter/tensor_filter.c +++ b/gst/nnstreamer/tensor_filter/tensor_filter.c @@ -904,7 +904,8 @@ gst_tensor_filter_transform (GstBaseTransform * trans, /* 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++) { @@ -927,6 +928,12 @@ gst_tensor_filter_transform (GstBaseTransform * trans, } /* 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")); diff --git a/tests/meson.build b/tests/meson.build index b9d1ac9..e780fb5 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -11,13 +11,19 @@ library('tensorscheck', 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() diff --git a/tests/nnstreamer_sink/nnscustom_drop_buffer.c b/tests/nnstreamer_sink/nnscustom_drop_buffer.c new file mode 100644 index 0000000..08d43bd --- /dev/null +++ b/tests/nnstreamer_sink/nnscustom_drop_buffer.c @@ -0,0 +1,119 @@ +/** + * NNStreamer custom filter to test buffer-drop + * Copyright (C) 2018 Jaeyun Jung + * + * LICENSE: LGPL-2.1 + * + * @file nnscustom_drop_buffer.c + * @date 25 Jan 2019 + * @author Jaeyun Jung + * @brief Custom filter to drop incoming buffer (skip 9 buffers, then pass 1 buffer) + * @bug No known bugs + */ + +#include +#include +#include +#include +#include + +/** + * @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; diff --git a/tests/nnstreamer_sink/unittest_sink.cpp b/tests/nnstreamer_sink/unittest_sink.cpp index 27221d3..6ef77fe 100644 --- a/tests/nnstreamer_sink/unittest_sink.cpp +++ b/tests/nnstreamer_sink/unittest_sink.cpp @@ -89,6 +89,7 @@ typedef enum 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)*/ @@ -670,6 +671,14 @@ _setup_pipeline (TestOption & option) "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 = @@ -2705,6 +2714,48 @@ TEST (tensor_stream_test, custom_filter_tensors) } /** + * @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) -- 2.7.4