From f62ecc1625aa3dd81a963fdeb4019e14437ffa61 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sun, 11 Aug 2019 15:02:04 +0900 Subject: [PATCH] tests: Add CUDA filter unit tests Adding a test for buffer meta and colorspace conversion Part-of: --- tests/check/elements/cudaconvert.c | 216 +++++++++++++++++++++++++++++++++++++ tests/check/elements/cudafilter.c | 168 +++++++++++++++++++++++++++++ tests/check/meson.build | 2 + 3 files changed, 386 insertions(+) create mode 100644 tests/check/elements/cudaconvert.c create mode 100644 tests/check/elements/cudafilter.c diff --git a/tests/check/elements/cudaconvert.c b/tests/check/elements/cudaconvert.c new file mode 100644 index 0000000..67713d2 --- /dev/null +++ b/tests/check/elements/cudaconvert.c @@ -0,0 +1,216 @@ +/* GStreamer + * Copyright (C) 2019 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +static gboolean +bus_cb (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_error (message, &err, &debug); + + GST_ERROR ("Error: %s : %s", err->message, debug); + g_error_free (err); + g_free (debug); + + fail_if (TRUE, "failed"); + g_main_loop_quit (loop); + } + break; + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + break; + default: + break; + } + return TRUE; +} + +static void +run_convert_pipelne (const gchar * in_format, const gchar * out_format) +{ + GstBus *bus; + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + gchar *pipeline_str = + g_strdup_printf ("videotestsrc num-buffers=1 is-live=true ! " + "video/x-raw,format=%s,framerate=3/1 ! cudaupload ! " + "cudaconvert ! cudadownload ! video/x-raw,format=%s ! " + "videoconvert ! autovideosink", in_format, out_format); + GstElement *pipeline; + + pipeline = gst_parse_launch (pipeline_str, NULL); + fail_unless (pipeline != NULL); + g_free (pipeline_str); + + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + gst_bus_add_watch (bus, (GstBusFunc) bus_cb, loop); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + gst_element_set_state (pipeline, GST_STATE_NULL); + + gst_bus_remove_watch (bus); + gst_object_unref (bus); + gst_object_unref (pipeline); + g_main_loop_unref (loop); +} + +GST_START_TEST (test_convert_yuv_yuv) +{ + const gchar *format_list[] = { + "I420", "YV12", "NV12", "NV21", "P010_10LE", "I420_10LE", + "Y444", "Y444_16LE", + }; + + gint i, j; + + for (i = 0; i < G_N_ELEMENTS (format_list); i++) { + for (j = 0; j < G_N_ELEMENTS (format_list); j++) { + if (i == j) + continue; + + GST_DEBUG ("run conversion %s to %s", format_list[i], format_list[j]); + run_convert_pipelne (format_list[i], format_list[j]); + } + } +} + +GST_END_TEST; + +GST_START_TEST (test_convert_yuv_rgb) +{ + const gchar *in_format_list[] = { + "I420", "YV12", "NV12", "NV21", "P010_10LE", "I420_10LE", + "Y444", "Y444_16LE", + }; + const gchar *out_format_list[] = { + "BGRA", "RGBA", "RGBx", "BGRx", "ARGB", "ABGR", "RGB", "BGR", "BGR10A2_LE", + "RGB10A2_LE", + }; + + gint i, j; + + for (i = 0; i < G_N_ELEMENTS (in_format_list); i++) { + for (j = 0; j < G_N_ELEMENTS (out_format_list); j++) { + GST_DEBUG ("run conversion %s to %s", in_format_list[i], + out_format_list[j]); + run_convert_pipelne (in_format_list[i], out_format_list[j]); + } + } +} + +GST_END_TEST; + +GST_START_TEST (test_convert_rgb_yuv) +{ + const gchar *in_format_list[] = { + "BGRA", "RGBA", "RGBx", "BGRx", "ARGB", "ABGR", "RGB", "BGR", "BGR10A2_LE", + "RGB10A2_LE", + }; + const gchar *out_format_list[] = { + "I420", "YV12", "NV12", "NV21", "P010_10LE", "I420_10LE", + "Y444", "Y444_16LE", + }; + + gint i, j; + + for (i = 0; i < G_N_ELEMENTS (in_format_list); i++) { + for (j = 0; j < G_N_ELEMENTS (out_format_list); j++) { + GST_DEBUG ("run conversion %s to %s", in_format_list[i], + out_format_list[j]); + run_convert_pipelne (in_format_list[i], out_format_list[j]); + } + } +} + +GST_END_TEST; + +GST_START_TEST (test_convert_rgb_rgb) +{ + const gchar *format_list[] = { + "BGRA", "RGBA", "RGBx", "BGRx", "ARGB", "ABGR", "RGB", "BGR", "BGR10A2_LE", + "RGB10A2_LE", + }; + + gint i, j; + + for (i = 0; i < G_N_ELEMENTS (format_list); i++) { + for (j = 0; j < G_N_ELEMENTS (format_list); j++) { + if (i == j) + continue; + + GST_DEBUG ("run conversion %s to %s", format_list[i], format_list[j]); + run_convert_pipelne (format_list[i], format_list[j]); + } + } +} + +GST_END_TEST; + +static gboolean +check_cuda_convert_available (void) +{ + gboolean ret = TRUE; + GstElement *upload; + + upload = gst_element_factory_make ("cudaconvert", NULL); + if (!upload) { + GST_WARNING ("cudaconvert is not available, possibly driver load failure"); + return FALSE; + } + + gst_object_unref (upload); + + return ret; +} + +static Suite * +cudaconvert_suite (void) +{ + Suite *s; + TCase *tc_chain; + + /* HACK: cuda device init/deinit with fork seems to problematic */ + g_setenv ("CK_FORK", "no", TRUE); + + s = suite_create ("cudaconvert"); + tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + if (!check_cuda_convert_available ()) { + GST_DEBUG ("Skip cudaconvert test since cannot open device"); + goto end; + } + + tcase_add_test (tc_chain, test_convert_yuv_yuv); + tcase_add_test (tc_chain, test_convert_yuv_rgb); + tcase_add_test (tc_chain, test_convert_rgb_yuv); + tcase_add_test (tc_chain, test_convert_rgb_rgb); + +end: + return s; +} + +GST_CHECK_MAIN (cudaconvert); diff --git a/tests/check/elements/cudafilter.c b/tests/check/elements/cudafilter.c new file mode 100644 index 0000000..8c3fd50 --- /dev/null +++ b/tests/check/elements/cudafilter.c @@ -0,0 +1,168 @@ +/* GStreamer + * Copyright (C) 2019 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + + +static void +test_buffer_meta_common (const gchar * in_caps, const gchar * out_caps, + const gchar * pipeline) +{ + GstHarness *h; + GstElement *capsfilter; + GstCaps *caps, *srccaps; + GstBuffer *in_buf, *out_buf = NULL; + GstFlowReturn ret; + GstVideoInfo info; + GstVideoTimeCodeMeta *meta = NULL; + + h = gst_harness_new_parse (pipeline); + fail_unless (h != NULL); + + capsfilter = gst_harness_find_element (h, "capsfilter"); + + gst_harness_play (h); + + srccaps = gst_caps_from_string (in_caps); + fail_unless (srccaps != NULL); + fail_unless (gst_video_info_from_caps (&info, srccaps)); + + gst_harness_set_src_caps (h, srccaps); + + /* enforce cuda memory */ + caps = gst_caps_from_string (out_caps); + g_object_set (capsfilter, "caps", caps, NULL); + gst_caps_unref (caps); + gst_object_unref (capsfilter); + + in_buf = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (&info)); + gst_buffer_memset (in_buf, 0, 0, GST_VIDEO_INFO_SIZE (&info)); + + GST_BUFFER_DURATION (in_buf) = GST_SECOND; + GST_BUFFER_PTS (in_buf) = 0; + GST_BUFFER_DTS (in_buf) = GST_CLOCK_TIME_NONE; + + gst_buffer_add_video_time_code_meta_full (in_buf, 30, 1, + NULL, GST_VIDEO_TIME_CODE_FLAGS_NONE, 0, 0, 1, 1, 0); + + ret = gst_harness_push (h, gst_buffer_ref (in_buf)); + fail_unless (ret == GST_FLOW_OK, "GstFlowReturn was %s", + gst_flow_get_name (ret)); + + out_buf = gst_harness_try_pull (h); + fail_unless (out_buf != NULL, "No output buffer"); + + meta = gst_buffer_get_video_time_code_meta (out_buf); + fail_unless (meta != NULL, "output buffer has no meta"); + fail_unless_equals_int (meta->tc.config.fps_n, 30); + fail_unless_equals_int (meta->tc.config.fps_d, 1); + fail_unless_equals_int (meta->tc.seconds, 1); + + gst_buffer_unref (in_buf); + gst_buffer_unref (out_buf); + + gst_harness_teardown (h); +} + +GST_START_TEST (test_buffer_meta) +{ + /* test whether buffer meta would be preserved or not */ + + test_buffer_meta_common + ("video/x-raw,format=(string)NV12,width=340,height=240", + "video/x-raw(memory:CUDAMemory)", "cudaupload ! capsfilter"); + test_buffer_meta_common + ("video/x-raw,format=(string)NV12,width=340,height=240", "video/x-raw", + "cudaupload ! cudadownload ! capsfilter"); + test_buffer_meta_common + ("video/x-raw,format=(string)NV12,width=340,height=240", + "video/x-raw,format=(string)I420,width=340,height=240", + "cudaupload ! cudaconvert ! cudadownload ! capsfilter"); + test_buffer_meta_common + ("video/x-raw,format=(string)NV12,width=340,height=240", + "video/x-raw,format=(string)NV12,width=640,height=480", + "cudaupload ! cudaconvert ! cudascale ! cudaconvert ! cudadownload ! capsfilter"); +} + +GST_END_TEST; + +static gboolean +check_cuda_available (void) +{ + GstElement *elem; + + elem = gst_element_factory_make ("cudaupload", NULL); + if (!elem) { + GST_WARNING ("cudaupload is not available, possibly driver load failure"); + return FALSE; + } + gst_object_unref (elem); + + elem = gst_element_factory_make ("cudadownload", NULL); + if (!elem) { + GST_WARNING ("cudadownload is not available, possibly driver load failure"); + return FALSE; + } + gst_object_unref (elem); + + elem = gst_element_factory_make ("cudaconvert", NULL); + if (!elem) { + GST_WARNING ("cudaconvert is not available, possibly driver load failure"); + return FALSE; + } + gst_object_unref (elem); + + elem = gst_element_factory_make ("cudadownload", NULL); + if (!elem) { + GST_WARNING ("cudascale is not available, possibly driver load failure"); + return FALSE; + } + gst_object_unref (elem); + + return TRUE; +} + +static Suite * +cudafilter_suite (void) +{ + Suite *s; + TCase *tc_chain; + + /* HACK: cuda device init/deinit with fork seems to problematic */ + g_setenv ("CK_FORK", "no", TRUE); + + s = suite_create ("cudafilter"); + tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + if (!check_cuda_available ()) { + GST_DEBUG ("Skip cuda filter test since cannot open device"); + goto end; + } + + tcase_add_test (tc_chain, test_buffer_meta); + +end: + return s; +} + +GST_CHECK_MAIN (cudafilter); diff --git a/tests/check/meson.build b/tests/check/meson.build index bbcf689..8934c43 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -26,6 +26,8 @@ base_tests = [ [['elements/avwait.c']], [['elements/camerabin.c']], [['elements/d3d11colorconvert.c'], host_machine.system() != 'windows', ], + [['elements/cudaconvert.c'], false, [gmodule_dep, gstgl_dep]], + [['elements/cudafilter.c'], false, [gmodule_dep, gstgl_dep]], [['elements/gdpdepay.c']], [['elements/gdppay.c']], [['elements/h263parse.c'], false, [libparser_dep, gstcodecparsers_dep]], -- 2.7.4