/* * vaapipostproc.c - GStreamer unit test for the vaapipostproc element * * Copyright (C) 2019 Intel Corporation * Author: U. Artie Eoff * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include typedef struct { GstElement *pipeline; GstElement *source; GstElement *filter; GstElement *vpp; GstElement *sink; } VppTestContext; typedef struct { gdouble x; gdouble y; } VppTestCoordinate; typedef struct { VppTestCoordinate send; VppTestCoordinate expect; } VppTestCoordinateParams; static void vpp_test_init_context (VppTestContext * ctx) { GST_INFO ("initing context"); ctx->pipeline = gst_pipeline_new ("pipeline"); fail_unless (ctx->pipeline != NULL); ctx->source = gst_element_factory_make ("videotestsrc", "src"); fail_unless (ctx->source != NULL, "Failed to create videotestsrc element"); ctx->filter = gst_element_factory_make ("capsfilter", "filter"); fail_unless (ctx->filter != NULL, "Failed to create caps filter element"); ctx->vpp = gst_element_factory_make ("vaapipostproc", "vpp"); fail_unless (ctx->vpp != NULL, "Failed to create vaapipostproc element"); ctx->sink = gst_element_factory_make ("fakesink", "sink"); fail_unless (ctx->sink != NULL, "Failed to create fakesink element"); gst_bin_add_many (GST_BIN (ctx->pipeline), ctx->source, ctx->filter, ctx->vpp, ctx->sink, NULL); gst_element_link_many (ctx->source, ctx->filter, ctx->vpp, ctx->sink, NULL); } static void vpp_test_deinit_context (VppTestContext * ctx) { GST_INFO ("deiniting context"); gst_element_set_state (ctx->pipeline, GST_STATE_NULL); gst_object_unref (ctx->pipeline); memset (ctx, 0x00, sizeof (VppTestContext)); } static void vpp_test_set_crop (VppTestContext * ctx, gint l, gint r, gint t, gint b) { GST_LOG ("%d %d %d %0d", l, r, t, b); g_object_set (ctx->vpp, "crop-left", l, "crop-right", r, "crop-top", t, "crop-bottom", b, NULL); } static void vpp_test_set_orientation (VppTestContext * ctx, GstVideoOrientationMethod m) { GST_LOG ("%u", m); g_object_set (ctx->vpp, "video-direction", m, NULL); } static void vpp_test_set_dimensions (VppTestContext * ctx, gint w, gint h) { GstCaps *caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, w, "height", G_TYPE_INT, h, NULL); GST_LOG ("%dx%d", w, h); g_object_set (ctx->filter, "caps", caps, NULL); gst_caps_unref (caps); } static GstPadProbeReturn cb_mouse_event (GstPad * pad, GstPadProbeInfo * info, gpointer data) { VppTestCoordinate *coord = data; gdouble x = 0, y = 0; GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); if (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION) { switch (gst_navigation_event_get_type (event)) { case GST_NAVIGATION_EVENT_MOUSE_MOVE: if (gst_navigation_event_parse_mouse_move_event (event, &x, &y)) { coord->x = x; coord->y = y; } break; case GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS: case GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE: if (gst_navigation_event_parse_mouse_button_event (event, NULL, &x, &y)) { coord->x = x; coord->y = y; } break; default: break; } } return GST_PAD_PROBE_OK; } static void vpp_test_mouse_events (VppTestContext * ctx, const VppTestCoordinateParams * const params, const size_t nparams) { GstEvent *event = NULL; VppTestCoordinate probed = { 0, }; guint i, j; /* probe mouse events propagated up from vaapipostproc */ GstPad *pad = gst_element_get_static_pad (ctx->source, "src"); gulong id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, (GstPadProbeCallback) cb_mouse_event, &probed, NULL); const char *mouse_events[] = { "mouse-move", "mouse-button-press", "mouse-button-release", }; fail_unless (gst_element_set_state (ctx->pipeline, GST_STATE_PAUSED) != GST_STATE_CHANGE_FAILURE); fail_unless (gst_element_get_state (ctx->pipeline, NULL, NULL, -1) == GST_STATE_CHANGE_SUCCESS); for (i = 0; i < nparams; ++i) { for (j = 0; j < G_N_ELEMENTS (mouse_events); ++j) { probed.x = probed.y = -1; switch (j) { case 0: event = gst_navigation_event_new_mouse_move (params[i].send.x, params[i].send.y, GST_NAVIGATION_MODIFIER_NONE); break; case 1: event = gst_navigation_event_new_mouse_button_press (0, params[i].send.x, params[i].send.y, GST_NAVIGATION_MODIFIER_NONE); break; case 2: event = gst_navigation_event_new_mouse_button_release (0, params[i].send.x, params[i].send.y, GST_NAVIGATION_MODIFIER_NONE); break; } GST_LOG ("sending %s event %fx%f", mouse_events[j], params[i].send.x, params[i].send.y); gst_element_send_event (ctx->pipeline, event); GST_LOG ("probed %s event %fx%f", mouse_events[j], probed.x, probed.y); GST_LOG ("expect %s event %fx%f", mouse_events[j], params[i].expect.x, params[i].expect.y); fail_unless (params[i].expect.x == probed.x); fail_unless (params[i].expect.y == probed.y); } } gst_element_set_state (ctx->pipeline, GST_STATE_NULL); gst_pad_remove_probe (pad, id); gst_object_unref (pad); } static void vpp_test_crop_mouse_events (VppTestContext * ctx, gint w, gint h, gint l, gint r, gint t, gint b) { const gdouble xmin = 0.0; const gdouble ymin = 0.0; const gdouble xmax = w - (l + r) - 1; const gdouble ymax = h - (t + b) - 1; const gdouble xctr = xmax / 2; const gdouble yctr = ymax / 2; const gdouble xrand = g_random_double_range (xmin, xmax); const gdouble yrand = g_random_double_range (ymin, ymax); const gdouble e_xmin = xmin + l; const gdouble e_ymin = ymin + t; const gdouble e_xmax = xmax + l; const gdouble e_ymax = ymax + t; const gdouble e_xctr = xctr + l; const gdouble e_yctr = yctr + t; const gdouble e_xrand = xrand + l; const gdouble e_yrand = yrand + t; const VppTestCoordinateParams params[] = { {{xmin, ymin}, {e_xmin, e_ymin}}, /* left-top */ {{xmin, yctr}, {e_xmin, e_yctr}}, /* left-center */ {{xmin, ymax}, {e_xmin, e_ymax}}, /* left-bottom */ {{xmax, ymin}, {e_xmax, e_ymin}}, /* right-top */ {{xmax, yctr}, {e_xmax, e_yctr}}, /* right-center */ {{xmax, ymax}, {e_xmax, e_ymax}}, /* right-bottom */ {{xctr, ymin}, {e_xctr, e_ymin}}, /* center-top */ {{xctr, yctr}, {e_xctr, e_yctr}}, /* center */ {{xctr, ymax}, {e_xctr, e_ymax}}, /* center-bottom */ {{xrand, yrand}, {e_xrand, e_yrand}}, /* random */ }; vpp_test_set_dimensions (ctx, w, h); vpp_test_set_crop (ctx, l, r, t, b); vpp_test_mouse_events (ctx, params, G_N_ELEMENTS (params)); } GST_START_TEST (test_crop_mouse_events) { VppTestContext ctx; vpp_test_init_context (&ctx); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 1, 0, 0, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 1, 0, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 1, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 1); vpp_test_crop_mouse_events (&ctx, 160, 160, 63, 0, 0, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 63, 0, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 63, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 63); vpp_test_crop_mouse_events (&ctx, 160, 160, 63, 0, 0, 1); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 63, 1, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 1, 63, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 1, 0, 0, 63); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 32, 0, 0, 128); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 32, 128, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 128, 32, 0); vpp_test_crop_mouse_events (&ctx, 160, 160, 128, 0, 0, 32); vpp_test_crop_mouse_events (&ctx, 160, 160, 1, 1, 1, 1); vpp_test_crop_mouse_events (&ctx, 160, 160, 63, 63, 63, 63); vpp_test_crop_mouse_events (&ctx, 160, 160, 64, 64, 64, 64); vpp_test_deinit_context (&ctx); } GST_END_TEST; static void vpp_test_orientation_mouse_events (VppTestContext * ctx, gint w, gint h) { size_t i; const gdouble xmin = 0.0; const gdouble ymin = 0.0; const gdouble xmax = w - 1; const gdouble ymax = h - 1; const VppTestCoordinateParams params[8][4] = { /* (0) identity */ { {{xmin, ymin}, {xmin, ymin}}, {{xmax, ymin}, {xmax, ymin}}, {{xmin, ymax}, {xmin, ymax}}, {{xmax, ymax}, {xmax, ymax}}, }, /* (1) 90 Rotation */ { {{ymin, xmin}, {xmin, ymax}}, {{ymax, xmin}, {xmin, ymin}}, {{ymin, xmax}, {xmax, ymax}}, {{ymax, xmax}, {xmax, ymin}}, }, /* (2) 180 Rotation */ { {{xmin, ymin}, {xmax, ymax}}, {{xmax, ymin}, {xmin, ymax}}, {{xmin, ymax}, {xmax, ymin}}, {{xmax, ymax}, {xmin, ymin}}, }, /* (3) 270 Rotation */ { {{ymin, xmin}, {xmax, ymin}}, {{ymax, xmin}, {xmax, ymax}}, {{ymin, xmax}, {xmin, ymin}}, {{ymax, xmax}, {xmin, ymax}}, }, /* (4) Horizontal Flip */ { {{xmin, ymin}, {xmax, ymin}}, {{xmax, ymin}, {xmin, ymin}}, {{xmin, ymax}, {xmax, ymax}}, {{xmax, ymax}, {xmin, ymax}}, }, /* (5) Vertical Flip */ { {{xmin, ymin}, {xmin, ymax}}, {{xmax, ymin}, {xmax, ymax}}, {{xmin, ymax}, {xmin, ymin}}, {{xmax, ymax}, {xmax, ymin}}, }, /* (6) Vertical Flip + 90 Rotation */ { {{ymin, xmin}, {xmin, ymin}}, {{ymax, xmin}, {xmin, ymax}}, {{ymin, xmax}, {xmax, ymin}}, {{ymax, xmax}, {xmax, ymax}}, }, /* (7) Horizontal Flip + 90 Rotation */ { {{ymin, xmin}, {xmax, ymax}}, {{ymax, xmin}, {xmax, ymin}}, {{ymin, xmax}, {xmin, ymax}}, {{ymax, xmax}, {xmin, ymin}}, }, }; vpp_test_set_dimensions (ctx, w, h); for (i = 0; i < 8; ++i) { vpp_test_set_orientation (ctx, i); vpp_test_mouse_events (ctx, params[i], 4); } } GST_START_TEST (test_orientation_mouse_events) { VppTestContext ctx; vpp_test_init_context (&ctx); vpp_test_orientation_mouse_events (&ctx, 160, 320); vpp_test_orientation_mouse_events (&ctx, 161, 320); vpp_test_orientation_mouse_events (&ctx, 160, 321); vpp_test_orientation_mouse_events (&ctx, 161, 321); vpp_test_orientation_mouse_events (&ctx, 320, 160); vpp_test_orientation_mouse_events (&ctx, 320, 161); vpp_test_orientation_mouse_events (&ctx, 321, 160); vpp_test_orientation_mouse_events (&ctx, 321, 161); vpp_test_deinit_context (&ctx); } GST_END_TEST; static Suite * vaapipostproc_suite (void) { Suite *s = suite_create ("vaapipostproc"); TCase *tc_chain = tcase_create ("general"); gboolean has_vaapipostproc = FALSE; { GstElement *vaapipostproc; vaapipostproc = gst_element_factory_make ("vaapipostproc", NULL); if (vaapipostproc) { has_vaapipostproc = TRUE; gst_object_unref (vaapipostproc); } } suite_add_tcase (s, tc_chain); if (has_vaapipostproc) { tcase_add_test (tc_chain, test_crop_mouse_events); tcase_add_test (tc_chain, test_orientation_mouse_events); } return s; } GST_CHECK_MAIN (vaapipostproc);