From 75ab8729d5238c16917d14242a278ddad8d4b332 Mon Sep 17 00:00:00 2001 From: Jaeyun Date: Wed, 2 Jun 2021 20:34:46 +0900 Subject: [PATCH] [Test/Crop] testcases for tensor-crop add new testcases for tensor-crop (default crop region) Signed-off-by: Jaeyun --- tests/nnstreamer_plugins/unittest_plugins.cc | 552 ++++++++++++++++++++++++++- 1 file changed, 544 insertions(+), 8 deletions(-) diff --git a/tests/nnstreamer_plugins/unittest_plugins.cc b/tests/nnstreamer_plugins/unittest_plugins.cc index c3f755d..cba8957 100644 --- a/tests/nnstreamer_plugins/unittest_plugins.cc +++ b/tests/nnstreamer_plugins/unittest_plugins.cc @@ -197,6 +197,24 @@ } while (0) /** + * @brief wait for output buffer on GstHarness sinkpad. + */ +static guint +_harness_wait_for_output_buffer (GstHarness * h, guint expected) +{ + guint received, count; + + received = count = 0; + do { + g_usleep (100000); + received = gst_harness_buffers_received (h); + count++; + } while (received < expected && count < 30); + + return received; +} + +/** * @brief Test for setting/getting properties of tensor_transform */ TEST (testTensorTransform, properties01) @@ -5873,7 +5891,7 @@ TEST_REQUIRE_TFLITE (testTensorFilter, flexToFlex) gsize data_size; gchar *pipeline; gchar *test_model; - guint received, count; + guint received; GET_MODEL_PATH ("mobilenet_v1_1.0_224_quant.tflite"); @@ -5914,13 +5932,7 @@ TEST_REQUIRE_TFLITE (testTensorFilter, flexToFlex) EXPECT_EQ (gst_harness_push (h, in_buf), GST_FLOW_OK); /* wait for output buffer */ - received = count = 0; - do { - g_usleep (100000); - received = gst_harness_buffers_received (h); - count++; - } while (received < 1 && count < 100); - + received = _harness_wait_for_output_buffer (h, 1U); EXPECT_EQ (received, 1U); /* get output buffer (uint8, 1001:1) */ @@ -6337,6 +6349,530 @@ TEST (testConverterSubplugins, flexbufInvalidParam1_n) } /** + * @brief Data structure for tensor-crop test. + */ +typedef struct +{ + GstHarness *crop; + GstHarness *raw; + GstHarness *info; + GstHarness *raw_q; + GstHarness *info_q; + + GstTensorConfig config; + guint received; + gpointer raw_data; + gsize raw_size; + GstClockTime ts_raw; + tensor_type info_type; + gpointer info_data; + gsize info_size; + GstClockTime ts_info; +} crop_test_data_s; + +/** + * @brief Initialize tensor-crop test data. + * After calling this function, you should set raw-pad caps. + */ +static void +_crop_test_init (crop_test_data_s * crop_test) +{ + GstPad *raw_sink, *info_sink, *raw_src, *info_src; + + crop_test->crop = gst_harness_new_with_padnames ("tensor_crop", NULL, "src"); + crop_test->raw = gst_harness_new_with_element (crop_test->crop->element, "raw", NULL); + crop_test->info = gst_harness_new_with_element (crop_test->crop->element, "info", NULL); + crop_test->raw_q = gst_harness_new ("queue"); + crop_test->info_q = gst_harness_new ("queue"); + + raw_sink = GST_PAD_PEER (crop_test->raw->srcpad); + info_sink = GST_PAD_PEER (crop_test->info->srcpad); + raw_src = GST_PAD_PEER (crop_test->raw_q->sinkpad); + info_src = GST_PAD_PEER (crop_test->info_q->sinkpad); + + gst_pad_unlink (crop_test->raw->srcpad, raw_sink); + gst_pad_unlink (crop_test->info->srcpad, info_sink); + gst_pad_unlink (raw_src, crop_test->raw_q->sinkpad); + gst_pad_unlink (info_src, crop_test->info_q->sinkpad); + gst_pad_link (raw_src, raw_sink); + gst_pad_link (info_src, info_sink); + + /* caps for crop info (flex tensor) */ + gst_harness_set_src_caps (crop_test->info_q, + gst_caps_from_string (GST_TENSORS_FLEX_CAP_DEFAULT)); + + gst_tensor_config_init (&crop_test->config); + crop_test->config.rate_n = 0; + crop_test->config.rate_d = 1; + + crop_test->received = 0; + crop_test->raw_data = NULL; + crop_test->raw_size = 0; + crop_test->ts_raw = GST_CLOCK_TIME_NONE; + crop_test->info_type = _NNS_END; + crop_test->info_data = NULL; + crop_test->info_size = 0; + crop_test->ts_info = GST_CLOCK_TIME_NONE; +} + +/** + * @brief Free tensor-crop test data. + */ +static void +_crop_test_free (crop_test_data_s * crop_test) +{ + gst_harness_teardown (crop_test->raw); + gst_harness_teardown (crop_test->info); + gst_harness_teardown (crop_test->raw_q); + gst_harness_teardown (crop_test->info_q); + gst_harness_teardown (crop_test->crop); + + g_free (crop_test->raw_data); + g_free (crop_test->info_data); + gst_tensor_config_free (&crop_test->config); +} + +/** + * @brief Macro to push raw buffer to tensor_crop. + */ +#define _crop_test_push_raw_buffer(ctd,ts) \ + do { \ + GstBuffer *rb = gst_buffer_new (); \ + GstMemory *mem; \ + mem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, \ + (ctd)->raw_data, (ctd)->raw_size, 0, (ctd)->raw_size, NULL, NULL); \ + if ((ctd)->config.info.format == _NNS_TENSOR_FORMAT_FLEXIBLE) { \ + GstTensorMetaInfo meta; \ + gst_tensor_info_convert_to_meta (&(ctd)->config.info, &meta); \ + gst_buffer_append_memory (rb, gst_tensor_meta_info_append_header (&meta, mem)); \ + gst_memory_unref (mem); \ + } else { \ + gst_buffer_append_memory (rb, mem); \ + } \ + if ((ts) != GST_CLOCK_TIME_NONE) \ + GST_BUFFER_TIMESTAMP (rb) = (ts); \ + EXPECT_EQ (gst_harness_push ((ctd)->raw_q, rb), GST_FLOW_OK); \ + } while (0) + +/** + * @brief Macro to push info buffer to tensor_crop. + */ +#define _crop_test_push_info_buffer(ctd,ts) \ + do { \ + GstBuffer *ib = gst_buffer_new (); \ + GstMemory *mem; \ + GstTensorMetaInfo meta; \ + gst_tensor_meta_info_init (&meta); \ + meta.type = (ctd)->info_type; \ + meta.dimension[0] = 4U; \ + meta.dimension[1] = (ctd)->info_size / (4U * gst_tensor_get_element_size ((ctd)->info_type)); \ + meta.format = _NNS_TENSOR_FORMAT_FLEXIBLE; \ + mem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, \ + (ctd)->info_data, (ctd)->info_size, 0, (ctd)->info_size, NULL, NULL); \ + gst_buffer_append_memory (ib, gst_tensor_meta_info_append_header (&meta, mem)); \ + gst_memory_unref (mem); \ + if ((ts) != GST_CLOCK_TIME_NONE) \ + GST_BUFFER_TIMESTAMP (ib) = (ts); \ + EXPECT_EQ (gst_harness_push ((ctd)->info_q, ib), GST_FLOW_OK); \ + } while (0) + +/** + * @brief Push raw and info buffer to tensor_crop. + */ +static void +_crop_test_push_buffer (crop_test_data_s * crop_test) +{ + /* caps for raw data */ + gst_harness_set_src_caps (crop_test->raw_q, + gst_tensor_caps_from_config (&crop_test->config)); + + /* push raw buffer */ + _crop_test_push_raw_buffer (crop_test, crop_test->ts_raw); + + /* push info buffer (default mode region [x, y, w, h] * num) */ + _crop_test_push_info_buffer (crop_test, crop_test->ts_info); + + /* wait for output buffer */ + crop_test->received = _harness_wait_for_output_buffer (crop_test->crop, (crop_test->received + 1)); +} + +/** + * @brief Internal function to check cropped buffer. + * raw buffer uint32 [1, 2, ..., 40] dimension 1:10:4:1 + * info buffer uint32 [3, 0, 3, 1] [2, 1, 7, 2] + */ +static void +_crop_test_compare_res1 (crop_test_data_s * crop_test) +{ + GstBuffer *out_buf; + GstMemory *mem; + GstMapInfo map; + GstTensorMetaInfo meta; + gsize hsize; + guint i; + guint *cropped; + + out_buf = gst_harness_pull (crop_test->crop); + ASSERT_EQ (gst_buffer_n_memory (out_buf), 2U); + + /* 1st cropped data [3, 0, 3, 1] */ + mem = gst_buffer_peek_memory (out_buf, 0); + ASSERT_TRUE (gst_memory_map (mem, &map, GST_MAP_READ)); + + gst_tensor_meta_info_parse_header (&meta, map.data); + EXPECT_EQ (meta.type, _NNS_UINT32); + EXPECT_EQ (meta.dimension[0], 1U); + EXPECT_EQ (meta.dimension[1], 3U); + EXPECT_EQ (meta.dimension[2], 1U); + + hsize = gst_tensor_meta_info_get_header_size (&meta); + cropped = (guint *) (map.data + hsize); + /* expected [4, 5, 6] */ + EXPECT_EQ (map.size - hsize, sizeof (guint) * 3U); + EXPECT_EQ (cropped[0], 4U); + EXPECT_EQ (cropped[1], 5U); + EXPECT_EQ (cropped[2], 6U); + + gst_memory_unmap (mem, &map); + + /* 2nd cropped data [2, 1, 7, 2] */ + mem = gst_buffer_peek_memory (out_buf, 1); + ASSERT_TRUE (gst_memory_map (mem, &map, GST_MAP_READ)); + + gst_tensor_meta_info_parse_header (&meta, map.data); + EXPECT_EQ (meta.dimension[0], 1U); + EXPECT_EQ (meta.dimension[1], 7U); + EXPECT_EQ (meta.dimension[2], 2U); + + hsize = gst_tensor_meta_info_get_header_size (&meta); + cropped = (guint *) (map.data + hsize); + /* expected [13, 14, ..., 19, 23, 24, ..., 29] */ + EXPECT_EQ (map.size - hsize, sizeof (guint) * 14U); + for (i = 0; i < 2; i++) { + EXPECT_EQ (cropped[0 + 7 * i], 3U + (10U * (i + 1))); + EXPECT_EQ (cropped[1 + 7 * i], 4U + (10U * (i + 1))); + EXPECT_EQ (cropped[2 + 7 * i], 5U + (10U * (i + 1))); + EXPECT_EQ (cropped[3 + 7 * i], 6U + (10U * (i + 1))); + EXPECT_EQ (cropped[4 + 7 * i], 7U + (10U * (i + 1))); + EXPECT_EQ (cropped[5 + 7 * i], 8U + (10U * (i + 1))); + EXPECT_EQ (cropped[6 + 7 * i], 9U + (10U * (i + 1))); + } + + gst_memory_unmap (mem, &map); + gst_buffer_unref (out_buf); +} + +/** + * @brief Internal function to check cropped buffer. + * raw buffer uint32 [1, 2, ..., 40] dimension 2:5:4:1 + * info buffer uint32 [2, 0, 3, 1] [1, 1, 5, 2] + */ +static void +_crop_test_compare_res2 (crop_test_data_s * crop_test) +{ + GstBuffer *out_buf; + GstMemory *mem; + GstMapInfo map; + GstTensorMetaInfo meta; + gsize hsize; + guint i; + guint *cropped; + + out_buf = gst_harness_pull (crop_test->crop); + ASSERT_EQ (gst_buffer_n_memory (out_buf), 2U); + + /* 1st cropped data [2, 0, 3, 1] */ + mem = gst_buffer_peek_memory (out_buf, 0); + ASSERT_TRUE (gst_memory_map (mem, &map, GST_MAP_READ)); + + gst_tensor_meta_info_parse_header (&meta, map.data); + EXPECT_EQ (meta.type, _NNS_UINT32); + EXPECT_EQ (meta.dimension[0], 2U); + EXPECT_EQ (meta.dimension[1], 3U); + EXPECT_EQ (meta.dimension[2], 1U); + + hsize = gst_tensor_meta_info_get_header_size (&meta); + cropped = (guint *) (map.data + hsize); + /* expected [5, 6, 7, ..., 10] */ + EXPECT_EQ (map.size - hsize, sizeof (guint) * 6U); + EXPECT_EQ (cropped[0], 5U); + EXPECT_EQ (cropped[1], 6U); + EXPECT_EQ (cropped[2], 7U); + EXPECT_EQ (cropped[3], 8U); + EXPECT_EQ (cropped[4], 9U); + EXPECT_EQ (cropped[5], 10U); + + gst_memory_unmap (mem, &map); + + /* 2nd cropped data [1, 1, 5, 2] -> [1, 1, 4, 2] */ + mem = gst_buffer_peek_memory (out_buf, 1); + ASSERT_TRUE (gst_memory_map (mem, &map, GST_MAP_READ)); + + gst_tensor_meta_info_parse_header (&meta, map.data); + EXPECT_EQ (meta.dimension[0], 2U); + EXPECT_EQ (meta.dimension[1], 4U); + EXPECT_EQ (meta.dimension[2], 2U); + + hsize = gst_tensor_meta_info_get_header_size (&meta); + cropped = (guint *) (map.data + hsize); + /* expected [13, 14, ..., 20, 23, 24, ..., 30] */ + EXPECT_EQ (map.size - hsize, sizeof (guint) * 16U); + for (i = 0; i < 2; i++) { + EXPECT_EQ (cropped[0 + 8 * i], 3U + (10U * (i + 1))); + EXPECT_EQ (cropped[1 + 8 * i], 4U + (10U * (i + 1))); + EXPECT_EQ (cropped[2 + 8 * i], 5U + (10U * (i + 1))); + EXPECT_EQ (cropped[3 + 8 * i], 6U + (10U * (i + 1))); + EXPECT_EQ (cropped[4 + 8 * i], 7U + (10U * (i + 1))); + EXPECT_EQ (cropped[5 + 8 * i], 8U + (10U * (i + 1))); + EXPECT_EQ (cropped[6 + 8 * i], 9U + (10U * (i + 1))); + EXPECT_EQ (cropped[7 + 8 * i], 10U + (10U * (i + 1))); + } + + gst_memory_unmap (mem, &map); + gst_buffer_unref (out_buf); +} + +/** + * @brief Test for tensor_crop, cropping raw data with crop info. + */ +TEST (testTensorCrop, cropTensor) +{ + crop_test_data_s crop_test; + guint i; + guint *_data, *_info; + + _crop_test_init (&crop_test); + + /* prepare test data */ + crop_test.config.info.type = _NNS_UINT32; + + crop_test.raw_size = sizeof (guint) * 40U; + crop_test.raw_data = g_malloc0 (crop_test.raw_size); + _data = (guint *) crop_test.raw_data; + + for (i = 0; i < 40; i++) + _data[i] = i + 1; + + crop_test.info_type = _NNS_UINT32; + crop_test.info_size = sizeof (guint) * 8U; + crop_test.info_data = g_malloc0 (crop_test.info_size); + _info = (guint *) crop_test.info_data; + + /* crop info (1 ch / [3, 0, 3, 1] [2, 1, 7, 2]) */ + _info[0] = 3U; + _info[1] = 0U; + _info[2] = 3U; + _info[3] = 1U; + _info[4] = 2U; + _info[5] = 1U; + _info[6] = 7U; + _info[7] = 2U; + + gst_tensor_parse_dimension ("1:10:4:1", crop_test.config.info.dimension); + _crop_test_push_buffer (&crop_test); + EXPECT_EQ (crop_test.received, 1U); + + if (crop_test.received > 0) + _crop_test_compare_res1 (&crop_test); + + /* crop info (2 ch / [2, 0, 3, 1] [1, 1, 5, 2]) */ + _info[0] = 2U; + _info[1] = 0U; + _info[2] = 3U; + _info[3] = 1U; + _info[4] = 1U; + _info[5] = 1U; + _info[6] = 5U; + _info[7] = 2U; + + gst_tensor_parse_dimension ("2:5:4:1", crop_test.config.info.dimension); + _crop_test_push_buffer (&crop_test); + EXPECT_EQ (crop_test.received, 2U); + + if (crop_test.received > 1) + _crop_test_compare_res2 (&crop_test); + + _crop_test_free (&crop_test); +} + +/** + * @brief Test for tensor_crop, push invalid raw buffer. + */ +TEST (testTensorCrop, rawInvalidSize_n) +{ + crop_test_data_s crop_test; + + _crop_test_init (&crop_test); + + crop_test.config.info.type = _NNS_UINT32; + gst_tensor_parse_dimension ("20:1:1:1", crop_test.config.info.dimension); + + crop_test.raw_size = sizeof (guint) * 10U; + crop_test.raw_data = g_malloc0 (crop_test.raw_size); + + crop_test.info_type = _NNS_UINT16; + crop_test.info_size = gst_tensor_get_element_size (crop_test.info_type) * 8U; + crop_test.info_data = g_malloc0 (crop_test.info_size); + + /* raw buffer has invalid size */ + _crop_test_push_buffer (&crop_test); + EXPECT_EQ (crop_test.received, 0U); + + _crop_test_free (&crop_test); +} + +/** + * @brief Test for tensor_crop, push invalid info buffer. + */ +TEST (testTensorCrop, infoInvalidSize_n) +{ + crop_test_data_s crop_test; + + _crop_test_init (&crop_test); + + crop_test.config.info.type = _NNS_UINT32; + gst_tensor_parse_dimension ("10:1:1:1", crop_test.config.info.dimension); + + crop_test.raw_size = sizeof (guint) * 10U; + crop_test.raw_data = g_malloc0 (crop_test.raw_size); + + crop_test.info_type = _NNS_INT8; + crop_test.info_size = gst_tensor_get_element_size (crop_test.info_type) * 7U; + crop_test.info_data = g_malloc0 (crop_test.info_size); + + /* info buffer has invalid size */ + _crop_test_push_buffer (&crop_test); + EXPECT_EQ (crop_test.received, 0U); + + _crop_test_free (&crop_test); +} + +/** + * @brief Test for tensor_crop, push delayed raw buffer. + */ +TEST (testTensorCrop, rawDelayed_n) +{ + crop_test_data_s crop_test; + gint lateness; + guint i; + guint *_data; + guint8 *_info; + + _crop_test_init (&crop_test); + + /* set lateness 300ms */ + g_object_set (crop_test.crop->element, "lateness", 300, NULL); + g_object_get (crop_test.crop->element, "lateness", &lateness, NULL); + EXPECT_EQ (lateness, 300); + + crop_test.config.info.type = _NNS_UINT32; + gst_tensor_parse_dimension ("1:10:4:1", crop_test.config.info.dimension); + + crop_test.raw_size = sizeof (guint) * 40U; + crop_test.raw_data = g_malloc0 (crop_test.raw_size); + _data = (guint *) crop_test.raw_data; + + crop_test.info_type = _NNS_UINT8; + crop_test.info_size = gst_tensor_get_element_size (crop_test.info_type) * 8U; + crop_test.info_data = g_malloc0 (crop_test.info_size); + _info = (guint8 *) crop_test.info_data; + + /* crop info (1 ch / [3, 0, 3, 1] [2, 1, 7, 2]) */ + _info[0] = 3U; + _info[1] = 0U; + _info[2] = 3U; + _info[3] = 1U; + _info[4] = 2U; + _info[5] = 1U; + _info[6] = 7U; + _info[7] = 2U; + + /* delayed raw buffer */ + crop_test.ts_raw = 10U * GST_MSECOND; + crop_test.ts_info = 400U * GST_MSECOND; + + /* raw buffer is dropped, no result buffer. */ + _crop_test_push_buffer (&crop_test); + EXPECT_EQ (crop_test.received, 0U); + + /* fill raw buffer and push valid buffer */ + for (i = 0; i < 40; i++) + _data[i] = i + 1; + + _crop_test_push_raw_buffer (&crop_test, 300U * GST_MSECOND); + + crop_test.received = _harness_wait_for_output_buffer (crop_test.crop, 1U); + EXPECT_EQ (crop_test.received, 1U); + + if (crop_test.received > 0) + _crop_test_compare_res1 (&crop_test); + + _crop_test_free (&crop_test); +} + +/** + * @brief Test for tensor_crop, push delayed info buffer. + */ +TEST (testTensorCrop, infoDelayed_n) +{ + crop_test_data_s crop_test; + gint lateness; + guint i; + guint *_data; + guint8 *_info; + + _crop_test_init (&crop_test); + + /* set lateness 100ms */ + g_object_set (crop_test.crop->element, "lateness", 100, NULL); + g_object_get (crop_test.crop->element, "lateness", &lateness, NULL); + EXPECT_EQ (lateness, 100); + + crop_test.config.info.type = _NNS_UINT32; + gst_tensor_parse_dimension ("2:5:4:1", crop_test.config.info.dimension); + + crop_test.raw_size = sizeof (guint) * 40U; + crop_test.raw_data = g_malloc0 (crop_test.raw_size); + _data = (guint *) crop_test.raw_data; + + for (i = 0; i < 40; i++) + _data[i] = i + 1; + + crop_test.info_type = _NNS_UINT8; + crop_test.info_size = gst_tensor_get_element_size (crop_test.info_type) * 8U; + crop_test.info_data = g_malloc0 (crop_test.info_size); + _info = (guint8 *) crop_test.info_data; + + /* delayed info buffer */ + crop_test.ts_raw = 200U * GST_MSECOND; + crop_test.ts_info = 10U * GST_MSECOND; + + /* info buffer is dropped, no result buffer. */ + _crop_test_push_buffer (&crop_test); + EXPECT_EQ (crop_test.received, 0U); + + /* crop info (2 ch / [2, 0, 3, 1] [1, 1, 5, 2]) */ + _info[0] = 2U; + _info[1] = 0U; + _info[2] = 3U; + _info[3] = 1U; + _info[4] = 1U; + _info[5] = 1U; + _info[6] = 5U; + _info[7] = 2U; + + _crop_test_push_info_buffer (&crop_test, 220U * GST_MSECOND); + + crop_test.received = _harness_wait_for_output_buffer (crop_test.crop, 1U); + EXPECT_EQ (crop_test.received, 1U); + + if (crop_test.received > 0) + _crop_test_compare_res2 (&crop_test); + + _crop_test_free (&crop_test); +} + +/** * @brief Main function for unit test. */ int -- 2.7.4