diff options
author | U. Artie Eoff <ullysses.a.eoff@intel.com> | 2019-10-08 12:19:06 -0700 |
---|---|---|
committer | U. Artie Eoff <ullysses.a.eoff@intel.com> | 2019-10-16 12:48:24 -0700 |
commit | 97aabe8784c057a4bee33d6f541ab7d75ca3708e (patch) | |
tree | ba1cf34ee77bd61bc9bf8844379302fb0d609ebe /tests/examples | |
parent | 8af5ef8a0be0e5a6d97b6f8e9c942331d065e30a (diff) |
tests: move examples and tests to subfolders
This makes way for adding unit (check) tests.
Diffstat (limited to 'tests/examples')
-rw-r--r-- | tests/examples/meson.build | 28 | ||||
-rw-r--r-- | tests/examples/test-roi.c | 261 | ||||
-rw-r--r-- | tests/examples/test-vaapicontext.c | 354 | ||||
-rw-r--r-- | tests/examples/test-vaapipostproc.c | 157 | ||||
-rw-r--r-- | tests/examples/test-vaapisink.c | 189 |
5 files changed, 989 insertions, 0 deletions
diff --git a/tests/examples/meson.build b/tests/examples/meson.build new file mode 100644 index 00000000..0a61f7d0 --- /dev/null +++ b/tests/examples/meson.build @@ -0,0 +1,28 @@ +examples = [ + 'test-vaapisink', + 'test-vaapipostproc', + 'test-roi', +] + +foreach example : examples + executable(example, '@0@.c'.format(example), + c_args : gstreamer_vaapi_args, + include_directories: [configinc, libsinc], + dependencies : [gst_dep, gstvideo_dep], + install: false) +endforeach + +if USE_X11 +if gtk_dep.found() + executable('test-vaapicontext', 'test-vaapicontext.c', + c_args : gstreamer_vaapi_args, + include_directories: [configinc, libsinc], + dependencies : [ gst_dep, + gstvideo_dep, + libva_dep, + x11_dep, + gtk_dep, + libva_x11_dep ], + install: false) +endif +endif diff --git a/tests/examples/test-roi.c b/tests/examples/test-roi.c new file mode 100644 index 00000000..2ce614ef --- /dev/null +++ b/tests/examples/test-roi.c @@ -0,0 +1,261 @@ +/* + * test-roi.c - Testsuite for Region of Interest + * + * 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 <stdio.h> +#include <gst/gst.h> +#include <gst/video/navigation.h> +#include <gst/video/gstvideometa.h> + +typedef struct _CustomData +{ + GstElement *pipeline; + GMainLoop *loop; + gboolean roi_enabled; +} AppData; + +static void +send_eos_event (AppData * data) +{ + gst_element_send_event (data->pipeline, gst_event_new_eos ()); +} + +static void +dispatch_keystroke (AppData * app, const gchar * str) +{ + switch (g_ascii_tolower (str[0])) { + case 'r': + app->roi_enabled = !app->roi_enabled; + gst_println ("ROI %s", app->roi_enabled ? "enabled" : "disabled"); + break; + case 'q': + send_eos_event (app); + break; + default: + break; + } + + return; +} + +static void +cb_msg (GstBus * bus, GstMessage * msg, gpointer data) +{ + AppData *app = data; + GstNavigationMessageType mtype = gst_navigation_message_get_type (msg); + GstEvent *ev = NULL; + GstNavigationEventType type; + const gchar *key; + + if (mtype != GST_NAVIGATION_MESSAGE_EVENT) + return; + if (!gst_navigation_message_parse_event (msg, &ev)) + goto bail; + + type = gst_navigation_event_get_type (ev); + if (type != GST_NAVIGATION_EVENT_KEY_PRESS) + goto bail; + if (!gst_navigation_event_parse_key_event (ev, &key)) + goto bail; + + dispatch_keystroke (app, key); + +bail: + if (ev) + gst_event_unref (ev); +} + +static void +cb_msg_eos (GstBus * bus, GstMessage * msg, gpointer data) +{ + AppData *app = data; + g_main_loop_quit (app->loop); +} + + +static void +cb_msg_error (GstBus * bus, GstMessage * msg, gpointer data) +{ + AppData *app = data; + gchar *debug = NULL; + GError *err = NULL; + + gst_message_parse_error (msg, &err, &debug); + + g_print ("Error: %s\n", err->message); + g_error_free (err); + + if (debug) { + g_print ("Debug details: %s\n", debug); + g_free (debug); + } + + g_main_loop_quit (app->loop); +} + +static GstPadProbeReturn +cb_add_roi (GstPad * pad, GstPadProbeInfo * info, gpointer data) +{ + AppData *app = data; + GstVideoRegionOfInterestMeta *rmeta; + GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info); + GstStructure *s; + + if (!app->roi_enabled) + return GST_PAD_PROBE_OK; + + buf = gst_buffer_make_writable (buf); + if (!buf) + return GST_PAD_PROBE_OK; + + rmeta = + gst_buffer_add_video_region_of_interest_meta (buf, "test", 0, 0, 320, + 240); + if (!rmeta) + return GST_PAD_PROBE_OK; + + s = gst_structure_new ("roi/vaapi", "delta-qp", G_TYPE_INT, -10, NULL); + gst_video_region_of_interest_meta_add_param (rmeta, s); + + GST_PAD_PROBE_INFO_DATA (info) = buf; + return GST_PAD_PROBE_OK; +} + +/* Process keyboard input */ +static gboolean +handle_keyboard (GIOChannel * source, GIOCondition cond, gpointer data) +{ + AppData *app = data; + gchar *str = NULL; + + if (g_io_channel_read_line (source, &str, NULL, NULL, + NULL) != G_IO_STATUS_NORMAL) { + return TRUE; + } + + dispatch_keystroke (app, str); + + g_free (str); + return TRUE; +} + +/* + * This is an example pipeline to recognize difference between ROI and non-ROI. + * 1. Produce snow pattern with 320p + * 2. Encode and decode the raw data with 2 pipelines at same time. + * 2.1. Insert GstVideoRegionOfInterestMeta to the 2nd pipeline buffers to enable ROI. + * 3. Mix both streams in videomixer. + * 5. Output the result in one window. + * + * Note that the higher definition of original raw data, the easier we + * recognize. So you can replace videotestsrc with your + * high-definition camera or other src elements. + */ + +/* +.----------. .---. .--------. .---. .---. .---. .--------. .----------. .-----. +| videosrc |->|tee|->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->|videomixer|->|vsink| +'----------' '---' '--------' '---' '---' '---' '--------' '----------' '-----' + ^ ^ + | | + | .--------. .---. .---. .---. .--------. | + '--->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->' + ^ '--------' '---' '---' '---' '--------' + | + '-- Insert GstVideoRegionOfInterestMeta width roit/vaapi params on buffers +*/ + +int +main (int argc, char *argv[]) +{ + AppData data = { 0, }; + GstStateChangeReturn ret; + GstElement *el; + GstPad *pad; + GError *err = NULL; + GIOChannel *io_stdin; + GstBus *bus; + + data.roi_enabled = TRUE; + + /* Initialize GStreamer */ + gst_init (&argc, &argv); + + /* Print usage map */ + g_print ("USAGE: 'r' to enable/disable ROI && 'q' to quit\n"); + +#define SRC "videotestsrc pattern=snow ! " \ + "video/x-raw, format=NV12, width=320, framerate=5/1" +#define ENCDEC "vaapih265enc rate-control=cbr bitrate=2000 ! vaapih265dec ! " \ + "vaapipostproc ! video/x-raw, width=640" +#define TEXT "textoverlay font-desc=\"Arial Bold 48\" " + + data.pipeline = + gst_parse_launch + ("videomixer name=mix ! vaapipostproc ! vaapisink sync=false " + SRC " ! tee name=t ! queue ! " TEXT " text=\"non-ROI\" ! " ENCDEC + " ! videobox left=-640 ! mix. " + " t. ! queue name=roi ! " TEXT " text=\"ROI\" ! " ENCDEC + " ! videobox ! mix.", &err); + + if (err) { + g_printerr ("failed to parse pipeline: %s\n", err->message); + g_error_free (err); + return -1; + } + + bus = gst_pipeline_get_bus (GST_PIPELINE (data.pipeline)); + gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH); + gst_bus_enable_sync_message_emission (bus); + g_signal_connect (bus, "message::error", G_CALLBACK (cb_msg_error), &data); + g_signal_connect (bus, "message::eos", G_CALLBACK (cb_msg_eos), &data); + g_signal_connect (bus, "message::element", G_CALLBACK (cb_msg), &data); + gst_object_unref (bus); + + el = gst_bin_get_by_name (GST_BIN (data.pipeline), "roi"); + pad = gst_element_get_static_pad (el, "src"); + gst_object_unref (el); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, cb_add_roi, &data, NULL); + gst_object_unref (pad); + + /* Add a keyboard watch so we get notified of keystrokes */ + io_stdin = g_io_channel_unix_new (fileno (stdin)); + g_io_add_watch (io_stdin, G_IO_IN, handle_keyboard, &data); + + /* Start playing */ + ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_printerr ("Unable to set the pipeline to the playing state.\n"); + gst_object_unref (data.pipeline); + return -1; + } + + /* Create a GLib Main Loop and set it to run */ + data.loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (data.loop); + + /* Free resources */ + g_main_loop_unref (data.loop); + gst_element_set_state (data.pipeline, GST_STATE_NULL); + gst_object_unref (data.pipeline); + g_io_channel_unref (io_stdin); + + return 0; +} diff --git a/tests/examples/test-vaapicontext.c b/tests/examples/test-vaapicontext.c new file mode 100644 index 00000000..0085ca96 --- /dev/null +++ b/tests/examples/test-vaapicontext.c @@ -0,0 +1,354 @@ +/* + * 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]; + GstObject *gstvaapidisplay; +} 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", FALSE); + 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.Display") == 0) { + if (app->gstvaapidisplay) { + GstStructure *s; + + context = gst_context_new ("gst.vaapi.Display", FALSE); + s = gst_context_writable_structure (context); + gst_structure_set (s, "gst.vaapi.Display", + GST_TYPE_OBJECT, app->gstvaapidisplay, NULL); + } + break; + } + + 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_HAVE_CONTEXT:{ + const gchar *context_type; + const GstStructure *s; + GstContext *context = NULL; + const GValue *value; + + gst_message_parse_have_context (msg, &context); + if (!context) + break; + + context_type = gst_context_get_context_type (context); + gst_println ("Got have context %s from %s", context_type, + GST_MESSAGE_SRC_NAME (msg)); + + if (g_strcmp0 (context_type, "gst.vaapi.Display") != 0) + break; + s = gst_context_get_structure (context); + if (!s) + break; + value = gst_structure_get_value (s, "gst.vaapi.Display"); + if (!value) + break; + app->gstvaapidisplay = g_value_dup_object (value); + gst_println ("found display %s", GST_OBJECT_NAME (app->gstvaapidisplay)); + 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); + gst_object_unref (app.gstvaapidisplay); + /* there is no need to call vaTerminate() because it is done by the + * vaapi elements */ + return 0; +} diff --git a/tests/examples/test-vaapipostproc.c b/tests/examples/test-vaapipostproc.c new file mode 100644 index 00000000..87d13539 --- /dev/null +++ b/tests/examples/test-vaapipostproc.c @@ -0,0 +1,157 @@ +/* + * test-vaapipostproc.c - Testsuite for VAAPI Postprocessor + * + * 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 <stdio.h> +#include <gst/gst.h> +#include <gst/base/gstbasetransform.h> + +typedef struct _CustomData +{ + GstElement *pipeline; + GstElement *postproc; + GMainLoop *loop; +} AppData; + +static gboolean +_check_passthrough_mode (gpointer user_data) +{ + gboolean ret; + AppData *data = (AppData *) user_data; + + ret = gst_base_transform_is_passthrough (GST_BASE_TRANSFORM (data->postproc)); + + if (ret) + gst_println ("Now this pipeline is on passthrough mode"); + else + gst_println ("Now this pipeline is NOT on passthrough mode"); + + return FALSE; +} + +static void +set_contrast (AppData * data) +{ + static gfloat value = 1.0; + + value = value == 1.0 ? 0.5 : 1.0; + g_object_set (data->postproc, "contrast", value, NULL); + gst_println ("contrast value is changed to %f", value); + + g_timeout_add (300, _check_passthrough_mode, data); +} + +static void +change_size (AppData * data) +{ + static gint i = 0; + if (i == 0) { + g_object_set (data->postproc, "width", 1280, "height", 720, NULL); + gst_println ("frame size is changed to 1280x720"); + i++; + } else { + g_object_set (data->postproc, "width", 0, "height", 0, NULL); + gst_println ("frame size is changed to default"); + i = 0; + } + + g_timeout_add (300, _check_passthrough_mode, data); +} + +/* Process keyboard input */ +static gboolean +handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data) +{ + gchar *str = NULL; + + if (g_io_channel_read_line (source, &str, NULL, NULL, + NULL) != G_IO_STATUS_NORMAL) { + return TRUE; + } + + switch (g_ascii_tolower (str[0])) { + case 's':{ + set_contrast (data); + break; + } + case 'c':{ + change_size (data); + break; + } + case 'q': + g_main_loop_quit (data->loop); + break; + default: + break; + } + + g_free (str); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + AppData data = { 0, }; + GstStateChangeReturn ret; + GIOChannel *io_stdin; + + /* Initialize GStreamer */ + gst_init (&argc, &argv); + + /* Print usage map */ + gst_println ("USAGE: Choose one of the following options, then press enter:\n" + " 's' to set contrast\n" " 'c' to change size\n" " 'q' to quit\n"); + + data.pipeline = + gst_parse_launch + ("videotestsrc name=src ! vaapih264enc ! vaapih264dec ! vaapipostproc name=postproc ! vaapisink", + NULL); + data.postproc = gst_bin_get_by_name (GST_BIN (data.pipeline), "postproc"); + + /* Add a keyboard watch so we get notified of keystrokes */ + io_stdin = g_io_channel_unix_new (fileno (stdin)); + g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc) handle_keyboard, &data); + + /* Start playing */ + ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_printerr ("Unable to set the pipeline to the playing state.\n"); + gst_object_unref (data.pipeline); + return -1; + } + + g_timeout_add (300, _check_passthrough_mode, &data); + + /* Create a GLib Main Loop and set it to run */ + data.loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (data.loop); + + /* Free resources */ + g_main_loop_unref (data.loop); + g_io_channel_unref (io_stdin); + gst_element_set_state (data.pipeline, GST_STATE_NULL); + + gst_object_unref (data.postproc); + gst_object_unref (data.pipeline); + + return 0; +} diff --git a/tests/examples/test-vaapisink.c b/tests/examples/test-vaapisink.c new file mode 100644 index 00000000..41f3fc3e --- /dev/null +++ b/tests/examples/test-vaapisink.c @@ -0,0 +1,189 @@ +#include <stdio.h> +#include <string.h> +#include <gst/gst.h> +#include <gst/video/video.h> + +static gboolean use_postproc; +static GOptionEntry g_options[] = { + {"postproc", 'p', 0, G_OPTION_ARG_NONE, &use_postproc, + "use vaapipostproc to rotate rather than vaapisink", NULL}, + {NULL,} +}; + +typedef struct _CustomData +{ + GstElement *pipeline; + GstElement *rotator; + GMainLoop *loop; + gboolean orient_automatic; +} AppData; + +static void +send_rotate_event (AppData * data) +{ + gboolean res = FALSE; + GstEvent *event; + static gint counter = 0; + const static gchar *tags[] = { "rotate-90", "rotate-180", "rotate-270", + "rotate-0", "flip-rotate-0", "flip-rotate-90", "flip-rotate-180", + "flip-rotate-270", + }; + + event = gst_event_new_tag (gst_tag_list_new (GST_TAG_IMAGE_ORIENTATION, + tags[counter++ % G_N_ELEMENTS (tags)], NULL)); + + /* Send the event */ + g_print ("Sending event %" GST_PTR_FORMAT ": ", event); + res = gst_element_send_event (data->pipeline, event); + g_print ("%s\n", res ? "ok" : "failed"); + +} + +static void +keyboard_cb (const gchar * key, AppData * data) +{ + switch (g_ascii_tolower (key[0])) { + case 'r': + send_rotate_event (data); + break; + case 's':{ + if (use_postproc) { + g_object_set (G_OBJECT (data->rotator), "video-direction", + GST_VIDEO_ORIENTATION_AUTO, NULL); + } else { + /* rotation=360 means auto for vaapisnk */ + g_object_set (G_OBJECT (data->rotator), "rotation", 360, NULL); + } + break; + } + case 'q': + g_main_loop_quit (data->loop); + break; + default: + break; + } +} + +static gboolean +bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data) +{ + AppData *data = user_data; + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_ELEMENT: + { + GstNavigationMessageType mtype = gst_navigation_message_get_type (msg); + if (mtype == GST_NAVIGATION_MESSAGE_EVENT) { + GstEvent *ev = NULL; + + if (gst_navigation_message_parse_event (msg, &ev)) { + GstNavigationEventType type = gst_navigation_event_get_type (ev); + if (type == GST_NAVIGATION_EVENT_KEY_PRESS) { + const gchar *key; + + if (gst_navigation_event_parse_key_event (ev, &key)) + keyboard_cb (key, data); + } + } + if (ev) + gst_event_unref (ev); + } + break; + } + default: + break; + } + + return TRUE; +} + +/* Process keyboard input */ +static gboolean +handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data) +{ + gchar *str = NULL; + + if (g_io_channel_read_line (source, &str, NULL, NULL, + NULL) != G_IO_STATUS_NORMAL) { + return TRUE; + } + + keyboard_cb (str, data); + g_free (str); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + AppData data; + GstStateChangeReturn ret; + GIOChannel *io_stdin; + GOptionContext *ctx; + GError *err = NULL; + guint srcid; + + /* Initialize GStreamer */ + ctx = g_option_context_new ("- test options"); + if (!ctx) + return -1; + 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); + + /* Print usage map */ + g_print ("USAGE: Choose one of the following options, then press enter:\n" + " 'r' to send image-orientation tag event\n" + " 's' to set orient-automatic\n" " 'Q' to quit\n"); + + if (use_postproc) { + data.pipeline = + gst_parse_launch ("videotestsrc ! vaapipostproc name=pp ! xvimagesink", + &err); + } else { + data.pipeline = + gst_parse_launch ("videotestsrc ! vaapisink name=sink", &err); + } + if (err) { + g_printerr ("failed to create pipeline: %s\n", err->message); + g_error_free (err); + return -1; + } + + if (use_postproc) + data.rotator = gst_bin_get_by_name (GST_BIN (data.pipeline), "pp"); + else + data.rotator = gst_bin_get_by_name (GST_BIN (data.pipeline), "sink"); + srcid = gst_bus_add_watch (GST_ELEMENT_BUS (data.pipeline), bus_msg, &data); + + /* Add a keyboard watch so we get notified of keystrokes */ + io_stdin = g_io_channel_unix_new (fileno (stdin)); + g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc) handle_keyboard, &data); + + /* Start playing */ + ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_printerr ("Unable to set the pipeline to the playing state.\n"); + goto bail; + } + + /* Create a GLib Main Loop and set it to run */ + data.loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (data.loop); + + gst_element_set_state (data.pipeline, GST_STATE_NULL); + +bail: + /* Free resources */ + g_source_remove (srcid); + g_main_loop_unref (data.loop); + g_io_channel_unref (io_stdin); + + gst_object_unref (data.rotator); + gst_object_unref (data.pipeline); + + return 0; +} |