diff --git a/ChangeLog b/ChangeLog index e9512c5c09..f9dd03fa1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-06-24 Stefan Kost + + * tests/examples/seek/Makefile.am: + * tests/examples/seek/seek.c: + Embedd the xwindow. + 2008-06-24 Jan Schmidt * sys/ximage/ximagesink.c (gst_ximagesink_ximage_put), diff --git a/tests/examples/seek/Makefile.am b/tests/examples/seek/Makefile.am index 50483e7633..88d17c8d3e 100644 --- a/tests/examples/seek/Makefile.am +++ b/tests/examples/seek/Makefile.am @@ -6,5 +6,7 @@ examples = $(GTK_EXAMPLES) noinst_PROGRAMS = $(examples) -LIBS = $(GST_LIBS) $(GTK_LIBS) -AM_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) +LDADD = $(GST_LIBS) $(GTK_LIBS) \ + $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-@GST_MAJORMINOR@.la \ + $(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_MAJORMINOR@.la +AM_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) -I$(top_builddir)/gst-libs diff --git a/tests/examples/seek/seek.c b/tests/examples/seek/seek.c index 544efeced4..a966402465 100644 --- a/tests/examples/seek/seek.c +++ b/tests/examples/seek/seek.c @@ -26,6 +26,11 @@ #include #include +#include +#include +#include +#include + GST_DEBUG_CATEGORY_STATIC (seek_debug); #define GST_CAT_DEFAULT (seek_debug) @@ -54,6 +59,8 @@ GST_DEBUG_CATEGORY_STATIC (seek_debug); /* timeout for gst_element_get_state() after a seek */ #define SEEK_TIMEOUT 40 * GST_MSECOND +#define DEFAULT_VIDEO_HEIGHT 300 + static GList *seekable_pads = NULL; static GList *rate_pads = NULL; @@ -94,6 +101,10 @@ static gboolean need_streams = TRUE; static GtkWidget *video_combo, *audio_combo, *text_combo, *vis_combo; static GtkWidget *vis_checkbox, *video_checkbox, *audio_checkbox; static GtkWidget *text_checkbox, *mute_checkbox, *volume_spinbutton; +static GtkWidget *video_window; +static guint embed_xid = 0; + +GList *paths = NULL, *l = NULL; /* we keep an array of the visualisation entries so that we can easily switch * with the combo box index. */ @@ -863,15 +874,30 @@ make_mpegnt_pipeline (const gchar * location) return pipeline; } +static void +playerbin_set_uri (GstElement * player, const gchar * location) +{ + gchar *uri; + + /* Add "file://" prefix for convenience */ + if (g_str_has_prefix (location, "/")) { + uri = g_strconcat ("file://", location, NULL); + g_object_set (G_OBJECT (player), "uri", uri, NULL); + g_free (uri); + } else { + g_object_set (G_OBJECT (player), "uri", location, NULL); + } +} + static GstElement * -make_playerbin_pipeline (const gchar * location) +construct_playerbin (const gchar * name, const gchar * location) { GstElement *player; - player = gst_element_factory_make ("playbin", "player"); + player = gst_element_factory_make (name, "player"); g_assert (player); - g_object_set (G_OBJECT (player), "uri", location, NULL); + playerbin_set_uri (player, location); seekable_elements = g_list_prepend (seekable_elements, player); @@ -881,22 +907,16 @@ make_playerbin_pipeline (const gchar * location) return player; } +static GstElement * +make_playerbin_pipeline (const gchar * location) +{ + return construct_playerbin ("playbin", location); +} + static GstElement * make_playerbin2_pipeline (const gchar * location) { - GstElement *player; - - player = gst_element_factory_make ("playbin2", "player"); - g_assert (player); - - g_object_set (G_OBJECT (player), "uri", location, NULL); - - seekable_elements = g_list_prepend (seekable_elements, player); - - /* force element seeking on this pipeline */ - elem_seek = TRUE; - - return player; + return construct_playerbin ("playbin2", location); } #ifndef GST_DISABLE_PARSE @@ -2071,11 +2091,54 @@ msg_buffering (GstBus * bus, GstMessage * message, GstPipeline * data) } } +static GstBusSyncReply +bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data) +{ + if ((GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) && + gst_structure_has_name (message->structure, "prepare-xwindow-id")) { + GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message)); + + g_print ("got prepare-xwindow-id\n"); + if (!embed_xid) { + embed_xid = GDK_WINDOW_XID (GDK_WINDOW (video_window->window)); + } + + if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), + "force-aspect-ratio")) { + g_object_set (element, "force-aspect-ratio", TRUE, NULL); + } + + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), + embed_xid); + } + return GST_BUS_PASS; +} + +static void +msg_eos (GstBus * bus, GstMessage * message, GstPipeline * data) +{ + message_received (bus, message, data); + + /* Set new uri for playerbins and continue playback */ + if (l && (pipeline_type == 14 || pipeline_type == 16)) { + stop_cb (NULL, NULL); + l = g_list_next (l); + if (l) { + playerbin_set_uri (GST_ELEMENT (data), l->data); + play_cb (NULL, NULL); + } + } +} + static void connect_bus_signals (GstElement * pipeline) { GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + /* handle prepare-xwindow-id element message synchronously */ + gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, + pipeline); + gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH); g_signal_connect (bus, "message::state-changed", @@ -2091,8 +2154,7 @@ connect_bus_signals (GstElement * pipeline) pipeline); g_signal_connect (bus, "message::warning", (GCallback) message_received, pipeline); - g_signal_connect (bus, "message::eos", (GCallback) message_received, - pipeline); + g_signal_connect (bus, "message::eos", (GCallback) msg_eos, pipeline); g_signal_connect (bus, "message::tag", (GCallback) message_received, pipeline); g_signal_connect (bus, "message::element", (GCallback) message_received, @@ -2105,6 +2167,47 @@ connect_bus_signals (GstElement * pipeline) gst_object_unref (bus); } +/* Return GList of paths described in location string */ +static GList * +handle_wildcards (const gchar * location) +{ + GList *res = NULL; + gchar *path = g_path_get_dirname (location); + gchar *pattern = g_path_get_basename (location); + GPatternSpec *pspec = g_pattern_spec_new (pattern); + GDir *dir = g_dir_open (path, 0, NULL); + const gchar *name; + + g_print ("matching %s from %s\n", pattern, path); + + if (!dir) { + g_print ("opening directory %s failed\n", path); + goto out; + } + + while ((name = g_dir_read_name (dir)) != NULL) { + if (g_pattern_match_string (pspec, name)) { + res = g_list_append (res, g_strjoin ("/", path, name, NULL)); + g_print (" found clip %s\n", name); + } + } + + g_dir_close (dir); +out: + g_pattern_spec_free (pspec); + g_free (pattern); + g_free (path); + + return res; +} + +static void +delete_event_cb (void) +{ + stop_cb (NULL, NULL); + gtk_main_quit (); +} + static void print_usage (int argc, char **argv) { @@ -2142,6 +2245,11 @@ main (int argc, char **argv) if (!g_thread_supported ()) g_thread_init (NULL); + if (!XInitThreads ()) { + g_print ("XInitThreads failed\n"); + exit (-1); + } + ctx = g_option_context_new ("- test seeking in gsteamer"); g_option_context_add_main_entries (ctx, options, NULL); g_option_context_add_group (ctx, gst_init_get_option_group ()); @@ -2169,12 +2277,28 @@ main (int argc, char **argv) pipeline_spec = argv[2]; - pipeline = pipelines[pipeline_type].func (pipeline_spec); + if (g_strrstr (pipeline_spec, "*") != NULL || + g_strrstr (pipeline_spec, "?") != NULL) { + paths = handle_wildcards (pipeline_spec); + } else { + paths = g_list_prepend (paths, g_strdup (pipeline_spec)); + } + + if (!paths) { + g_print ("opening %s failed\n", pipeline_spec); + exit (-1); + } + + l = paths; + + pipeline = pipelines[pipeline_type].func ((gchar *) l->data); g_assert (pipeline); /* initialize gui elements ... */ tips = gtk_tooltips_new (); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + video_window = gtk_drawing_area_new (); + gtk_widget_set_double_buffered (video_window, FALSE); statusbar = gtk_statusbar_new (); status_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), "seek"); gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stopped"); @@ -2310,8 +2434,12 @@ main (int argc, char **argv) /* do the packing stuff ... */ gtk_window_set_default_size (GTK_WINDOW (window), 250, 96); + /* FIXME: can we avoid this for audio only? */ + gtk_widget_set_size_request (GTK_WIDGET (video_window), -1, + DEFAULT_VIDEO_HEIGHT); gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_container_add (GTK_CONTAINER (vbox), hbox); + gtk_box_pack_start (GTK_BOX (vbox), video_window, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2); @@ -2328,12 +2456,12 @@ main (int argc, char **argv) gtk_table_attach_defaults (GTK_TABLE (flagtable), rate_spinbutton, 3, 4, 1, 2); if (panel && boxes && boxes2) { - gtk_box_pack_start (GTK_BOX (vbox), panel, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (vbox), boxes, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (vbox), boxes2, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (vbox), panel, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), boxes, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), boxes2, FALSE, FALSE, 2); } - gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (vbox), statusbar, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (vbox), hscale, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), statusbar, FALSE, FALSE, 2); /* connect things ... */ g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb), @@ -2357,7 +2485,7 @@ main (int argc, char **argv) g_signal_connect (G_OBJECT (rate_spinbutton), "value_changed", G_CALLBACK (rate_spinbutton_changed_cb), pipeline); - g_signal_connect (G_OBJECT (window), "delete-event", gtk_main_quit, NULL); + g_signal_connect (G_OBJECT (window), "delete-event", delete_event_cb, NULL); /* show the gui. */ gtk_widget_show_all (window); @@ -2376,5 +2504,8 @@ main (int argc, char **argv) g_print ("free pipeline\n"); gst_object_unref (pipeline); + g_list_foreach (paths, (GFunc) g_free, NULL); + g_list_free (paths); + return 0; }