From: gichan Date: Wed, 12 Apr 2023 05:00:36 +0000 (+0900) Subject: [TEST] Add testcase for flexible tensor_filter X-Git-Tag: accepted/tizen/7.0/unified/20230621.051151~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=65f2649f7cbc8ebc4a45d0c610644f5faad9bd6e;p=platform%2Fupstream%2Fnnstreamer.git [TEST] Add testcase for flexible tensor_filter - Testcase for flexible tensor filter is disabled and activate after development is done. - In order to invoke tensor_filter with flexible input/output, you need to specify custom option. ex) ... ! tensor_filter framework=... invoke-dynamic=TRUE model=... ! ... Signed-off-by: gichan --- diff --git a/tests/meson.build b/tests/meson.build index a4a3e1b..21df1fc 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -198,6 +198,15 @@ if gtest_dep.found() test('unittest_converter', unittest_converter, env: testenv) endif + + unittest_filter_custom = executable('unittest_filter_custom', + join_paths('nnstreamer_filter_custom', 'unittest_filter_custom.cc'), + dependencies: [nnstreamer_unittest_deps], + install: get_option('install-test'), + install_dir: unittest_install_dir + ) + + test('unittest_filter_custom', unittest_filter_custom, timeout: 120, env: testenv) endif # Armnn unittest diff --git a/tests/nnstreamer_filter_custom/unittest_filter_custom.cc b/tests/nnstreamer_filter_custom/unittest_filter_custom.cc new file mode 100644 index 0000000..ec7f009 --- /dev/null +++ b/tests/nnstreamer_filter_custom/unittest_filter_custom.cc @@ -0,0 +1,409 @@ +/** + * @file unittest_filter_custom.cc + * @date 11 Apr 2023 + * @brief Unit test for tensor filter custom-easy plugin + * @see https://github.com/nnstreamer/nnstreamer + * @author Gichan Jang + * @bug No known bugs. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static guint filter_received; +static guint sink_received; + +#define NNS_custom_easy_dynamic_register(...) 0 +/** + * @brief In-Code Test Function for custom-easy filter + */ +// static int +// _custom_easy_filter_dynamic (void *data, const GstTensorsInfo * in_info, +// GstTensorsInfo * out_info, const GstTensorMemory * input, +// GstTensorMemory * output) +// { +// gchar *dim_str; +// guint i; + +// /* Fill output tensors info */ +// gst_tensors_info_init (out_info); +// out_info->info[0].type = _NNS_UINT32; +// dim_str = g_strdup_printf ("%u:1:1:1", ++filter_received); +// gst_tensor_parse_dimension (dim_str, out_info->info[0].dimension); +// out_info->num_tensors = 1; +// out_info->format = _NNS_TENSOR_FORMAT_FLEXIBLE; + +// /* Allocate and fill output memory */ +// output[0].size = sizeof (guint) * filter_received; +// output[0].data = g_malloc0 (output[0].size); + +// for (i = 0; i < filter_received; i++) { +// ((guint *) output[0].data)[i] = i; +// } + +// return 0; +// } + +/** + * @brief Callback for tensor sink signal. + */ +static void +new_data_cb (GstElement *element, GstBuffer *buffer, gpointer user_data) +{ + gsize mem_size, header_size, expected_size; + GstTensorMetaInfo meta; + GstMemory *mem; + GstMapInfo map; + guint *data; + guint i; + + expected_size = sizeof (guint) * ++sink_received; + + EXPECT_EQ (1U, gst_buffer_n_memory (buffer)); + + mem = gst_buffer_peek_memory (buffer, 0); + if (!gst_memory_map (mem, &map, GST_MAP_READ)) { + g_message ("Failed to map the info buffer."); + return; + } + + gst_tensor_meta_info_parse_header (&meta, map.data); + EXPECT_EQ (_NNS_TENSOR_FORMAT_FLEXIBLE, meta.format); + EXPECT_EQ (sink_received, meta.dimension[0]); + + mem_size = gst_memory_get_sizes (mem, NULL, NULL); + header_size = gst_tensor_meta_info_get_header_size (&meta); + EXPECT_EQ (expected_size, mem_size - header_size); + + data = (guint *) (map.data + header_size); + for (i = 0; i < filter_received; i++) { + EXPECT_EQ (i, data[i]); + } + + gst_memory_unmap (mem, &map); +} + +/** + * @brief Test custom-easy filter with flexible tensor input/output. + * @todo Enable the test after development is done. + */ +TEST (tensorFilterCustom, DISABLED_flexibleInvoke_p) +{ + gchar *pipeline; + GstElement *gstpipe; + GError *err = NULL; + GstTensorsInfo info_in; + GstElement *sink_handle; + int ret; + + gst_tensors_info_init (&info_in); + info_in.num_tensors = 1U; + info_in.info[0].name = NULL; + info_in.format = _NNS_TENSOR_FORMAT_FLEXIBLE; + + ret = NNS_custom_easy_dynamic_register ( + "flexbible_filter", _custom_easy_filter_dynamic, NULL, &info_in); + ASSERT_EQ (ret, 0); + + /* create a nnstreamer pipeline */ + pipeline = g_strdup_printf ( + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=224,height=224,framerate=10/1 ! tensor_converter ! other/tensors,format=flexible ! j.sink_0 " + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=320,height=240,framerate=10/1 ! tensor_converter ! other/tensors,format=flexible ! j.sink_1 " + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=640,height=480,framerate=10/1 ! tensor_converter ! other/tensors,format=flexible ! j.sink_2 " + "join name=j ! other/tensors,format=flexible ! tensor_filter framework=custom-easy invoke-dynamic=TRUE model=flexbible_filter ! other/tensors,format=flexible ! tensor_sink name=sinkx sync=true"); + + gstpipe = gst_parse_launch (pipeline, &err); + ASSERT_TRUE (gstpipe != nullptr); + + sink_handle = gst_bin_get_by_name (GST_BIN (gstpipe), "sinkx"); + EXPECT_NE (sink_handle, nullptr); + + g_signal_connect (sink_handle, "new-data", (GCallback) new_data_cb, NULL); + + filter_received = 0; + sink_received = 0; + EXPECT_EQ (setPipelineStateSync (gstpipe, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + + EXPECT_TRUE (wait_pipeline_process_buffers (&sink_received, 6, TEST_TIMEOUT_LIMIT)); + g_usleep (1000000); + + /** cleanup registered custom_easy filter */ + ret = NNS_custom_easy_unregister ("flexbible_filter"); + ASSERT_EQ (0, ret); + + gst_object_unref (sink_handle); + gst_object_unref (gstpipe); + g_free (pipeline); +} + + +/** + * @brief Test custom-easy filter with static input, flexible output. + * @todo Enable the test after development is done. + */ +TEST (tensorFilterCustom, DISABLED_staticFlexibleInvoke_p) +{ + gchar *pipeline; + GstElement *gstpipe; + GError *err = NULL; + GstTensorsInfo info_in; + GstElement *sink_handle; + int ret; + + gst_tensors_info_init (&info_in); + info_in.num_tensors = 1U; + info_in.info[0].name = NULL; + info_in.format = _NNS_TENSOR_FORMAT_FLEXIBLE; + + ret = NNS_custom_easy_dynamic_register ( + "flexbible_filter", _custom_easy_filter_dynamic, NULL, &info_in); + ASSERT_EQ (ret, 0); + + /* create a nnstreamer pipeline */ + pipeline = g_strdup_printf ( + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=224,height=224,framerate=10/1 ! tensor_converter ! j.sink_0 " + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=320,height=240,framerate=10/1 ! tensor_converter ! j.sink_1 " + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=640,height=480,framerate=10/1 ! tensor_converter ! j.sink_2 " + "join name=j ! other/tensors,format=flexible ! tensor_filter framework=custom-easy invoke-dynamic=TRUE model=flexbible_filter ! other/tensors,format=flexible ! tensor_sink name=sinkx sync=true"); + + gstpipe = gst_parse_launch (pipeline, &err); + ASSERT_TRUE (gstpipe != nullptr); + + sink_handle = gst_bin_get_by_name (GST_BIN (gstpipe), "sinkx"); + EXPECT_NE (sink_handle, nullptr); + + g_signal_connect (sink_handle, "new-data", (GCallback) new_data_cb, NULL); + + filter_received = 0; + sink_received = 0; + EXPECT_EQ (setPipelineStateSync (gstpipe, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + + EXPECT_TRUE (wait_pipeline_process_buffers (&sink_received, 6, TEST_TIMEOUT_LIMIT)); + g_usleep (1000000); + + /** cleanup registered custom_easy filter */ + ret = NNS_custom_easy_unregister ("flexbible_filter"); + ASSERT_EQ (0, ret); + + gst_object_unref (sink_handle); + gst_object_unref (gstpipe); + g_free (pipeline); +} + + +/** + * @brief Test dynamic invoke with invalid prop.. + * @todo Enable the test after development is done. + */ +TEST (tensorFilterCustom, DISABLED_flexibleInvokeInvalidProp_n) +{ + gchar *pipeline; + GstElement *gstpipe; + GError *err = NULL; + GstTensorsInfo info_in; + GstElement *sink_handle; + int ret; + + gst_tensors_info_init (&info_in); + info_in.num_tensors = 1U; + info_in.info[0].name = NULL; + info_in.format = _NNS_TENSOR_FORMAT_FLEXIBLE; + + ret = NNS_custom_easy_dynamic_register ( + "flexbible_filter", _custom_easy_filter_dynamic, NULL, &info_in); + ASSERT_EQ (ret, 0); + + /* create a nnstreamer pipeline */ + pipeline = g_strdup_printf ( + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=224,height=224,framerate=10/1 ! tensor_converter ! other/tensors,format=flexible ! j.sink_0 " + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=320,height=240,framerate=10/1 ! tensor_converter ! other/tensors,format=flexible ! j.sink_1 " + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=640,height=480,framerate=10/1 ! tensor_converter ! other/tensors,format=flexible ! j.sink_2 " + "join name=j ! other/tensors,format=flexible ! tensor_filter framework=custom-easy invoke-dynamic=FALSE model=flexbible_filter ! other/tensors,format=flexible ! tensor_sink name=sinkx sync=true"); + + gstpipe = gst_parse_launch (pipeline, &err); + ASSERT_TRUE (gstpipe != nullptr); + + sink_handle = gst_bin_get_by_name (GST_BIN (gstpipe), "sinkx"); + EXPECT_NE (sink_handle, nullptr); + + g_signal_connect (sink_handle, "new-data", (GCallback) new_data_cb, NULL); + + filter_received = 0; + sink_received = 0; + EXPECT_NE (setPipelineStateSync (gstpipe, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + + /** cleanup registered custom_easy filter */ + ret = NNS_custom_easy_unregister ("flexbible_filter"); + ASSERT_EQ (0, ret); + + gst_object_unref (sink_handle); + gst_object_unref (gstpipe); + g_free (pipeline); +} + +/** + * @brief In-Code Test Function for custom-easy filter + */ +static int +_custom_easy_filter (void *data, const GstTensorFilterProperties *prop, + const GstTensorMemory *input, GstTensorMemory *output) +{ + guint i; + + /* Allocate and fill output memory */ + output[0].size = sizeof (guint) * ++filter_received; + output[0].data = g_malloc0 (output[0].size); + + for (i = 0; i < filter_received; i++) { + ((guint *) output[0].data)[i] = i; + } + + return 0; +} + +/** + * @brief Test custom-easy statc invoke with flexible tensor input/output. + * @todo Enable the test after development is done. + */ +TEST (tensorFilterCustom, DISABLED_staticInvoke_n) +{ + gchar *pipeline; + GstElement *gstpipe; + GError *err = NULL; + GstTensorsInfo info_in; + GstTensorsInfo info_out; + GstElement *sink_handle; + int ret; + + gst_tensors_info_init (&info_in); + info_in.num_tensors = 1U; + info_in.info[0].name = NULL; + info_in.format = _NNS_TENSOR_FORMAT_FLEXIBLE; + + gst_tensors_info_init (&info_out); + info_out.num_tensors = 1U; + info_out.info[0].name = NULL; + info_out.format = _NNS_TENSOR_FORMAT_FLEXIBLE; + + ret = NNS_custom_easy_register ( + "normal_filter", _custom_easy_filter, NULL, &info_in, &info_out); + ASSERT_EQ (ret, 0); + + /* create a nnstreamer pipeline */ + pipeline = g_strdup_printf ( + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=224,height=224,framerate=10/1 ! tensor_converter ! other/tensors,format=flexible ! j.sink_0 " + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=320,height=240,framerate=10/1 ! tensor_converter ! other/tensors,format=flexible ! j.sink_1 " + "videotestsrc num-buffers=3 ! videoconvert ! videoscale ! video/x-raw,format=RGB,width=640,height=480,framerate=10/1 ! tensor_converter ! other/tensors,format=flexible ! j.sink_2 " + "join name=j ! other/tensors,format=flexible ! tensor_filter framework=custom-easy model=normal_filter ! other/tensors,format=flexible ! tensor_sink name=sinkx sync=true"); + + gstpipe = gst_parse_launch (pipeline, &err); + ASSERT_TRUE (gstpipe != nullptr); + + sink_handle = gst_bin_get_by_name (GST_BIN (gstpipe), "sinkx"); + EXPECT_NE (sink_handle, nullptr); + + g_signal_connect (sink_handle, "new-data", (GCallback) new_data_cb, NULL); + + filter_received = 0; + sink_received = 0; + EXPECT_NE (setPipelineStateSync (gstpipe, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + + /** cleanup registered custom_easy filter */ + ret = NNS_custom_easy_unregister ("normal_filter"); + ASSERT_EQ (0, ret); + + gst_object_unref (sink_handle); + gst_object_unref (gstpipe); + g_free (pipeline); +} + +/** + * @brief Test custom-easy filter with flexible tensor input/output without register custom easy model. + */ +TEST (tensorFilterCustom, DISABLED_notRegisterFlexibleInvoke_n) +{ + gchar *pipeline; + GstElement *gstpipe; + GError *err = NULL; + const gchar *root_path = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH"); + if (root_path == NULL) + root_path = ".."; + + gchar *model_file = g_build_filename (root_path, "build", "tests", + "nnstreamer_example", "libnnstreamer_customfilter_passthrough.so", NULL); + ASSERT_TRUE (g_file_test (model_file, G_FILE_TEST_EXISTS)); + + /* create a nnstreamer pipeline */ + pipeline = g_strdup_printf ( + "videotestsrc num-buffers=3 ! videoconvert ! video/x-raw,width=160,height=120,format=RGB,framerate=10/1 ! " + "tensor_converter ! tensor_filter name=test_filter framework=custom invoke-dynamic=TRUE model=%s ! tensor_sink sync=true", model_file); + + gstpipe = gst_parse_launch (pipeline, &err); + ASSERT_TRUE (gstpipe != nullptr); + + filter_received = 0; + EXPECT_NE (setPipelineStateSync (gstpipe, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + g_usleep (100000); + + gst_object_unref (gstpipe); + g_free (pipeline); +} + +/** + * @brief Test dynamic invoke with invalid param. + * @todo Enable the test after development is done. + */ +TEST (tensorFilterCustom, DISABLED_dynamicRegisterInvalidParam_n) +{ + GstTensorsInfo info_in; + int ret; + + gst_tensors_info_init (&info_in); + info_in.num_tensors = 1U; + info_in.info[0].name = NULL; + info_in.format = _NNS_TENSOR_FORMAT_FLEXIBLE; + + ret = NNS_custom_easy_dynamic_register ( + NULL, _custom_easy_filter_dynamic, NULL, &info_in); + EXPECT_NE (0, ret); + + ret = NNS_custom_easy_dynamic_register ( + "temp_name", NULL, NULL, &info_in); + EXPECT_NE (0, ret); + + ret = NNS_custom_easy_dynamic_register ( + "temp_name", _custom_easy_filter_dynamic, NULL, NULL); + EXPECT_NE (0, ret); +} + +/** + * @brief Main gtest + */ +int +main (int argc, char **argv) +{ + int result = -1; + + try { + testing::InitGoogleTest (&argc, argv); + } catch (...) { + g_warning ("catch 'testing::internal::::ClassUniqueToAlwaysTrue'"); + } + + gst_init (&argc, &argv); + + try { + result = RUN_ALL_TESTS (); + } catch (...) { + g_warning ("catch `testing::internal::GoogleTestFailureException`"); + } + + return result; +}