Created
November 10, 2014 08:49
-
-
Save fourdollars/a6799f803c7a3d63a79f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Refer 1. http://docs.gstreamer.com/display/GstSDK/Basic+tutorial+5%3A+GUI+toolkit+integration | |
// Refer 2. http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideooverlay.html | |
// gcc playback.c -o playback `pkg-config --cflags --libs gtk+-3.0 gstreamer-1.0 gstreamer-video-1.0` | |
#include <gst/video/videooverlay.h> | |
#include <gtk/gtk.h> | |
#ifdef GDK_WINDOWING_X11 | |
#include <gdk/gdkx.h> // for GDK_WINDOW_XID | |
#endif | |
#ifdef GDK_WINDOWING_WIN32 | |
#include <gdk/gdkwin32.h> // for GDK_WINDOW_HWND | |
#endif | |
static guintptr video_window_handle = 0; | |
static GstBusSyncReply | |
bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data) | |
{ | |
// ignore anything but 'prepare-window-handle' element messages | |
if (!gst_is_video_overlay_prepare_window_handle_message (message)) | |
return GST_BUS_PASS; | |
if (video_window_handle != 0) { | |
GstVideoOverlay *overlay; | |
// GST_MESSAGE_SRC (message) will be the video sink element | |
overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message)); | |
gst_video_overlay_set_window_handle (overlay, video_window_handle); | |
} else { | |
g_warning ("Should have obtained video_window_handle by now!"); | |
} | |
gst_message_unref (message); | |
return GST_BUS_DROP; | |
} | |
static const char* get_uri() | |
{ | |
static int index = 0; | |
static const char *playlist[] = { | |
"http://video.blendertestbuilds.de/download.blender.org/peach/trailer_480p.mov", | |
"http://video.webmfiles.org/big-buck-bunny_trailer.webm", | |
"http://video.webmfiles.org/elephants-dream.webm", | |
"http://docs.gstreamer.com/media/sintel_trailer-480p.webm" | |
}; | |
if (index >= sizeof(playlist)/sizeof(playlist[0])) { | |
index = 0; | |
} | |
g_printf("%d %d\n", sizeof(playlist), sizeof(playlist[0])); | |
return playlist[index++]; | |
} | |
static void | |
video_widget_realize_cb (GtkWidget * video_window, gpointer data) | |
{ | |
#if GTK_CHECK_VERSION(2,18,0) | |
// Tell Gtk+/Gdk to create a native window for this widget instead of | |
// drawing onto the parent widget. | |
// This is here just for pedagogical purposes, GDK_WINDOW_XID will call | |
// it as well in newer Gtk versions | |
if (!gdk_window_ensure_native (gtk_widget_get_window (video_window))) | |
g_error ("Couldn't create native window needed for GstVideoOverlay!"); | |
#endif | |
#ifdef GDK_WINDOWING_X11 | |
{ | |
gulong xid = GDK_WINDOW_XID (gtk_widget_get_window (video_window)); | |
video_window_handle = xid; | |
} | |
#endif | |
#ifdef GDK_WINDOWING_WIN32 | |
{ | |
HWND wnd = GDK_WINDOW_HWND (gtk_widget_get_window (video_window)); | |
video_window_handle = (guintptr) wnd; | |
} | |
#endif | |
} | |
static const char *stream_status[] = { "CREATE", "ENTER", "LEAVE", "DESTROY", "START", "PAUSE", "STOP" }; | |
gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data) | |
{ | |
GstElement *play = GST_ELEMENT(data); | |
switch (GST_MESSAGE_TYPE(msg)) | |
{ | |
case GST_MESSAGE_EOS: | |
g_print("%s\n", gst_message_type_get_name (GST_MESSAGE_TYPE(msg))); | |
gst_element_set_state (play, GST_STATE_READY); | |
g_object_set (play, "uri", get_uri(), NULL); | |
gst_element_set_state (play, GST_STATE_PLAYING); | |
break; | |
case GST_MESSAGE_BUFFERING: | |
{ | |
gint percentage; | |
gst_message_parse_buffering (msg, &percentage); | |
g_print("buffering %d%%\n", percentage); | |
} | |
break; | |
case GST_MESSAGE_TAG: | |
{ | |
GstTagList *tags = NULL; | |
gst_message_parse_tag (msg, &tags); | |
g_print ("Got tags from element %s\n", GST_OBJECT_NAME (msg->src)); | |
//handle_tags (tags); | |
gst_tag_list_unref (tags); | |
} | |
break; | |
case GST_MESSAGE_STATE_CHANGED: | |
{ | |
GstState old_state, new_state; | |
gst_message_parse_state_changed (msg, &old_state, &new_state, NULL); | |
g_print ("Element %s state %s -> %s.\n", | |
GST_OBJECT_NAME (msg->src), | |
gst_element_state_get_name (old_state), | |
gst_element_state_get_name (new_state)); | |
} | |
break; | |
case GST_MESSAGE_STREAM_STATUS: | |
{ | |
GstElement *elem; | |
GstStreamStatusType type; | |
gst_message_parse_stream_status (msg, &type, &elem); | |
g_print ("Stream %s status %s.\n", | |
GST_OBJECT_NAME (elem), | |
stream_status[type]); | |
} | |
break; | |
default: | |
g_print("%s\n", gst_message_type_get_name (GST_MESSAGE_TYPE(msg))); | |
break; | |
} | |
return TRUE; | |
} | |
int | |
main (int argc, char **argv) | |
{ | |
GtkWidget *video_window; | |
GtkWidget *app_window; | |
GtkWidget *box; | |
GstElement *pipeline; | |
GstBus *bus; | |
/* Initialize GTK */ | |
gtk_init (&argc, &argv); | |
/* Initialize GStreamer */ | |
gst_init (&argc, &argv); | |
app_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); | |
gtk_window_set_title (GTK_WINDOW (app_window), "Media Player"); | |
gtk_window_set_default_size (GTK_WINDOW (app_window), 800, 600); | |
g_signal_connect (app_window, "delete_event", G_CALLBACK (gtk_main_quit), NULL); | |
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); | |
printf("scale factor %d\n", gtk_widget_get_scale_factor (box)); | |
video_window = gtk_drawing_area_new (); | |
g_signal_connect (video_window, "realize", | |
G_CALLBACK (video_widget_realize_cb), NULL); | |
gtk_widget_set_double_buffered (video_window, FALSE); | |
gtk_box_pack_start (GTK_BOX (box), video_window, TRUE, TRUE, 0); | |
// usually the video_window will not be directly embedded into the | |
// application window like this, but there will be many other widgets | |
// and the video window will be embedded in one of them instead | |
gtk_container_add (GTK_CONTAINER (app_window), box); | |
// show the GUI | |
gtk_widget_show_all (app_window); | |
// realize window now so that the video window gets created and we can | |
// obtain its XID/HWND before the pipeline is started up and the videosink | |
// asks for the XID/HWND of the window to render onto | |
gtk_widget_realize (video_window); | |
// we should have the XID/HWND now | |
g_assert (video_window_handle != 0); | |
pipeline = gst_element_factory_make ("playbin", "playbin"); | |
g_object_set (pipeline, "uri", get_uri(), NULL); | |
// set up sync handler for setting the xid once the pipeline is started | |
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); | |
gst_bus_add_watch (bus, bus_callback, pipeline); | |
gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, NULL, | |
NULL); | |
gst_object_unref (bus); | |
gst_element_set_state (pipeline, GST_STATE_PLAYING); | |
gtk_main (); | |
gst_element_set_state (pipeline, GST_STATE_NULL); | |
gst_object_unref (pipeline); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment