Skip to content

Instantly share code, notes, and snippets.

@fourdollars
Created November 10, 2014 08:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fourdollars/a6799f803c7a3d63a79f to your computer and use it in GitHub Desktop.
Save fourdollars/a6799f803c7a3d63a79f to your computer and use it in GitHub Desktop.
// 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