#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; }