mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 12:49:40 +00:00
tests: elements: add testsuite of vaapi context
Signed-off-by: Víctor Manuel Jáquez Leal <vjaquez@igalia.com> https://bugzilla.gnome.org/show_bug.cgi?id=766704
This commit is contained in:
parent
736478d2a7
commit
85856c29a7
3 changed files with 355 additions and 0 deletions
21
configure.ac
21
configure.ac
|
@ -155,6 +155,11 @@ AC_ARG_WITH([glapi],
|
|||
[build with the specified OpenGL APIs @<:@default=default_glapi@:>@]),
|
||||
[GLAPI="$with_glapi"], [GLAPI=default_glapi])
|
||||
|
||||
AC_ARG_WITH([gtk],
|
||||
[AS_HELP_STRING([--with-gtk],
|
||||
[compile GTK3 based test apps @<:@default=check@:>@])],
|
||||
[], [with_gtk="check"])
|
||||
|
||||
dnl *** checks for platform ***
|
||||
|
||||
dnl * hardware/architecture *
|
||||
|
@ -479,6 +484,22 @@ if test "x$enable_wayland" = "xyes"; then
|
|||
], [:])
|
||||
fi
|
||||
|
||||
dnl Check for GTK for tests
|
||||
USE_GTK=0
|
||||
AS_IF([test "x$BUILD_EXAMPLES" = "xyes" -a $USE_X11 -eq 1],
|
||||
[AS_CASE([$with_gtk],
|
||||
[yes], [PKG_CHECK_MODULES([GTK3], [gtk+-3.0], [USE_GTK=1])],
|
||||
[no], [],
|
||||
[PKG_CHECK_MODULES([GTK3], [gtk+-3.0], [USE_GTK=1])])])
|
||||
AS_IF([test $USE_GTK -eq 1],
|
||||
[
|
||||
saved_CPPFLAGS="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $GTK3_CFLAGS"
|
||||
AC_CHECK_HEADERS([gtk/gtk.h], [], [USE_GTK=0])
|
||||
CPPFLAGS="$saved_CPPFLAGS"
|
||||
])
|
||||
AM_CONDITIONAL([USE_GTK], [test $USE_GTK -eq 1])
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl -- VA-API --
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
|
|
@ -27,4 +27,24 @@ test_roi_SOURCES = test-roi.c
|
|||
test_roi_CFLAGS = $(TEST_CFLAGS)
|
||||
test_roi_LDADD = $(TEST_LIBS)
|
||||
|
||||
if USE_GTK
|
||||
noinst_PROGRAMS += test-vaapicontext
|
||||
|
||||
test_vaapicontext_SOURCES = test-vaapicontext.c
|
||||
test_vaapicontext_CFLAGS = \
|
||||
$(TEST_CFLAGS) \
|
||||
$(GTK3_CFLAGS) \
|
||||
$(X11_CFLAGS) \
|
||||
$(LIBVA_CFLAGS) \
|
||||
$(LIBVA_X11_CFLAGS) \
|
||||
$(NULL)
|
||||
test_vaapicontext_LDADD = \
|
||||
$(TEST_LIBS) \
|
||||
$(GTK3_LIBS) \
|
||||
$(X11_LIBS) \
|
||||
$(LIBVA_LIBS) \
|
||||
$(LIBVA_X11_LIBS) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
|
|
314
tests/elements/test-vaapicontext.c
Normal file
314
tests/elements/test-vaapicontext.c
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* test-vaapicontext.c - Testsuite for VAAPI app context
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/videooverlay.h>
|
||||
|
||||
#include <va/va.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <va/va_x11.h>
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#else
|
||||
#error "X11 is not supported in GTK+"
|
||||
#endif
|
||||
|
||||
static gboolean g_multisink;
|
||||
static gchar *g_filepath;
|
||||
|
||||
static GOptionEntry g_options[] = {
|
||||
{"multi", 'm', 0, G_OPTION_ARG_NONE, &g_multisink, "test multiple vaapisink",
|
||||
NULL},
|
||||
{"file", 'f', 0, G_OPTION_ARG_STRING, &g_filepath,
|
||||
"file path to play (only mp4/h264)", NULL},
|
||||
{NULL,}
|
||||
};
|
||||
|
||||
typedef struct _CustomData
|
||||
{
|
||||
GtkWidget *main_window;
|
||||
VADisplay va_display;
|
||||
GstElement *pipeline;
|
||||
guintptr videoarea_handle[2];
|
||||
} AppData;
|
||||
|
||||
static void
|
||||
delete_event_cb (GtkWidget * widget, GdkEvent * event, gpointer data)
|
||||
{
|
||||
AppData *app = data;
|
||||
|
||||
gst_element_set_state (app->pipeline, GST_STATE_NULL);
|
||||
gtk_main_quit ();
|
||||
}
|
||||
|
||||
static void
|
||||
button_rotate_cb (GtkWidget * widget, GstElement * elem)
|
||||
{
|
||||
static gint counter = 0;
|
||||
const static gint tags[] = { 90, 180, 270, 0 };
|
||||
|
||||
g_object_set (elem, "rotation", tags[counter++ % G_N_ELEMENTS (tags)], NULL);
|
||||
}
|
||||
|
||||
static Display *
|
||||
get_x11_window_display (AppData * app)
|
||||
{
|
||||
#if defined(GDK_WINDOWING_X11)
|
||||
GdkDisplay *gdk_display;
|
||||
Display *x11_display;
|
||||
|
||||
gdk_display = gtk_widget_get_display (app->main_window);
|
||||
x11_display = gdk_x11_display_get_xdisplay (gdk_display);
|
||||
return x11_display;
|
||||
#endif
|
||||
g_error ("Running in a non-X11 environment");
|
||||
}
|
||||
|
||||
static VADisplay
|
||||
ensure_va_display (AppData * app)
|
||||
{
|
||||
if (app->va_display)
|
||||
return app->va_display;
|
||||
app->va_display = vaGetDisplay (get_x11_window_display (app));
|
||||
/* There's no need to call vaInitialize() since element does it
|
||||
* internally */
|
||||
return app->va_display;
|
||||
}
|
||||
|
||||
static GstContext *
|
||||
create_vaapi_app_display_context (AppData * app, gboolean new_va_display)
|
||||
{
|
||||
GstContext *context;
|
||||
GstStructure *s;
|
||||
VADisplay va_display;
|
||||
Display *x11_display;
|
||||
|
||||
x11_display = get_x11_window_display (app);
|
||||
|
||||
if (new_va_display)
|
||||
va_display = vaGetDisplay (x11_display);
|
||||
else
|
||||
va_display = ensure_va_display (app);
|
||||
|
||||
context = gst_context_new ("gst.vaapi.app.Display", TRUE);
|
||||
s = gst_context_writable_structure (context);
|
||||
gst_structure_set (s, "va-display", G_TYPE_POINTER, va_display, NULL);
|
||||
gst_structure_set (s, "x11-display", G_TYPE_POINTER, x11_display, NULL);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static GstBusSyncReply
|
||||
bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer data)
|
||||
{
|
||||
AppData *app = data;
|
||||
|
||||
switch (GST_MESSAGE_TYPE (msg)) {
|
||||
case GST_MESSAGE_NEED_CONTEXT:{
|
||||
const gchar *context_type;
|
||||
gboolean new_va_disp;
|
||||
GstContext *context;
|
||||
|
||||
gst_message_parse_context_type (msg, &context_type);
|
||||
gst_println ("Got need context %s from %s", context_type,
|
||||
GST_MESSAGE_SRC_NAME (msg));
|
||||
|
||||
if (g_strcmp0 (context_type, "gst.vaapi.app.Display") != 0)
|
||||
break;
|
||||
|
||||
/* create a new VA display *only* for the second video sink */
|
||||
new_va_disp = (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0);
|
||||
|
||||
context = create_vaapi_app_display_context (app, new_va_disp);
|
||||
gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (msg)), context);
|
||||
gst_context_unref (context);
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_ELEMENT:{
|
||||
if (!gst_is_video_overlay_prepare_window_handle_message (msg))
|
||||
break;
|
||||
|
||||
if (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0)
|
||||
gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY
|
||||
(GST_MESSAGE_SRC (msg)), app->videoarea_handle[1]);
|
||||
else
|
||||
gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY
|
||||
(GST_MESSAGE_SRC (msg)), app->videoarea_handle[0]);
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_EOS:
|
||||
gtk_main_quit ();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return GST_BUS_PASS;
|
||||
}
|
||||
|
||||
static void
|
||||
realize_cb (GtkWidget * widget, gpointer data)
|
||||
{
|
||||
AppData *app = data;
|
||||
GdkWindow *window;
|
||||
static guint counter = 0;
|
||||
|
||||
#if defined(GDK_WINDOWING_X11)
|
||||
window = gtk_widget_get_window (widget);
|
||||
|
||||
if (!gdk_window_ensure_native (window))
|
||||
g_error ("Couldn't create native window needed for GstXOverlay!");
|
||||
|
||||
app->videoarea_handle[counter++ % 2] = GDK_WINDOW_XID (window);
|
||||
#endif
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_video_box (AppData * app)
|
||||
{
|
||||
GtkWidget *video_area;
|
||||
|
||||
video_area = gtk_drawing_area_new ();
|
||||
gtk_widget_set_size_request (video_area, 640, 480);
|
||||
g_signal_connect (video_area, "realize", G_CALLBACK (realize_cb), app);
|
||||
return video_area;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_rotate_button (AppData * app, const gchar * name)
|
||||
{
|
||||
GtkWidget *rotate;
|
||||
GstElement *sink;
|
||||
|
||||
sink = gst_bin_get_by_name (GST_BIN (app->pipeline), name);
|
||||
g_assert (sink);
|
||||
|
||||
rotate = gtk_button_new_with_label ("Rotate");
|
||||
g_signal_connect (rotate, "clicked", G_CALLBACK (button_rotate_cb), sink);
|
||||
gst_object_unref (sink);
|
||||
|
||||
return rotate;
|
||||
}
|
||||
|
||||
static void
|
||||
build_ui (AppData * app)
|
||||
{
|
||||
GtkWidget *mainwin, *vbox, *pane, *bbox;
|
||||
|
||||
mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (mainwin), "VAAPI display context test");
|
||||
gtk_window_set_resizable (GTK_WINDOW (mainwin), FALSE);
|
||||
g_signal_connect (mainwin, "delete-event", G_CALLBACK (delete_event_cb), app);
|
||||
app->main_window = mainwin;
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (mainwin), vbox);
|
||||
|
||||
pane = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0);
|
||||
|
||||
/* first video box */
|
||||
gtk_paned_pack1 (GTK_PANED (pane), create_video_box (app), TRUE, TRUE);
|
||||
|
||||
/* rotate buttons */
|
||||
bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
|
||||
gtk_box_pack_end (GTK_BOX (vbox), bbox, TRUE, TRUE, 0);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (bbox), create_rotate_button (app, "sink1"), TRUE,
|
||||
TRUE, 0);
|
||||
|
||||
if (g_multisink) {
|
||||
/* second video box */
|
||||
gtk_paned_pack2 (GTK_PANED (pane), create_video_box (app), TRUE, TRUE);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (bbox), create_rotate_button (app, "sink2"),
|
||||
TRUE, TRUE, 0);
|
||||
}
|
||||
|
||||
gtk_widget_show_all (mainwin);
|
||||
}
|
||||
|
||||
int
|
||||
main (gint argc, gchar ** argv)
|
||||
{
|
||||
AppData app = { 0, };
|
||||
GstBus *bus;
|
||||
GOptionContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
XInitThreads ();
|
||||
|
||||
ctx = g_option_context_new ("- test options");
|
||||
if (!ctx)
|
||||
return -1;
|
||||
|
||||
g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
|
||||
g_option_context_add_group (ctx, gst_init_get_option_group ());
|
||||
g_option_context_add_main_entries (ctx, g_options, NULL);
|
||||
if (!g_option_context_parse (ctx, &argc, &argv, NULL))
|
||||
return -1;
|
||||
g_option_context_free (ctx);
|
||||
|
||||
if (g_multisink) {
|
||||
app.pipeline = gst_parse_launch ("videotestsrc ! tee name=t ! queue ! "
|
||||
"vaapisink name=sink1 t. ! queue ! vaapisink name=sink2", &error);
|
||||
} else if (!g_filepath) {
|
||||
app.pipeline = gst_parse_launch ("videotestsrc ! vaapih264enc ! "
|
||||
"vaapidecodebin ! vaapisink name=sink1", &error);
|
||||
} else {
|
||||
app.pipeline = gst_parse_launch ("filesrc name=src ! qtdemux ! h264parse ! "
|
||||
"vaapidecodebin ! vaapisink name=sink1", &error);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
gst_printerrln ("failed to parse pipeline: %s", error->message);
|
||||
g_error_free (error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_multisink && g_filepath) {
|
||||
GstElement *src;
|
||||
|
||||
src = gst_bin_get_by_name (GST_BIN (app.pipeline), "src");
|
||||
g_assert (src);
|
||||
g_object_set (src, "location", g_filepath, NULL);
|
||||
gst_object_unref (src);
|
||||
}
|
||||
|
||||
build_ui (&app);
|
||||
|
||||
bus = gst_element_get_bus (app.pipeline);
|
||||
gst_bus_set_sync_handler (bus, bus_sync_handler, (gpointer) & app, NULL);
|
||||
gst_object_unref (bus);
|
||||
|
||||
gst_element_set_state (app.pipeline, GST_STATE_PLAYING);
|
||||
gst_println ("Now playing…");
|
||||
|
||||
gtk_main ();
|
||||
|
||||
gst_object_unref (app.pipeline);
|
||||
/* there is no need to call vaTerminate() because it is done by the
|
||||
* vaapi elements */
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue