diff --git a/ChangeLog b/ChangeLog index 683be3b5e1..dbcc3f4895 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2004-10-25 Wim Taymans + + * examples/seeking/Makefile.am: + * examples/seeking/cdplayer.c: (update_scale): + * examples/seeking/chained.c: (unlinked), (new_pad), (main): + * examples/seeking/playbin.c: (make_playerbin_pipeline), + (format_value), (update_scale), (iterate), (start_seek), + (stop_seek), (print_media_info), (play_cb), (pause_cb), (stop_cb), + (print_usage), (main): + Added some more examples, update others. + 2004-10-25 Ronald S. Bultje * ext/flac/gstflacdec.c: (gst_flacdec_update_metadata): diff --git a/examples/seeking/Makefile.am b/examples/seeking/Makefile.am index 3d99ee2ecb..582306ac8a 100644 --- a/examples/seeking/Makefile.am +++ b/examples/seeking/Makefile.am @@ -1,4 +1,4 @@ -examples = seek spider_seek cdplayer cdparanoia vorbisfile +examples = seek spider_seek cdplayer cdparanoia vorbisfile playbin chained noinst_PROGRAMS = $(examples) diff --git a/examples/seeking/cdplayer.c b/examples/seeking/cdplayer.c index afccaa8469..73ab9cf857 100644 --- a/examples/seeking/cdplayer.c +++ b/examples/seeking/cdplayer.c @@ -131,9 +131,8 @@ update_scale (gpointer data) GstElement *element = GST_ELEMENT (seekable_elements->data); gst_element_query (element, GST_QUERY_TOTAL, &format, &duration); + gst_element_query (element, GST_QUERY_POSITION, &format, &position); } - if (clock) - position = gst_clock_get_time (clock); if (stats) { if (clock) diff --git a/examples/seeking/chained.c b/examples/seeking/chained.c new file mode 100644 index 0000000000..5bd0e12df3 --- /dev/null +++ b/examples/seeking/chained.c @@ -0,0 +1,104 @@ +#include +#include +#include + +static GstElement *bin; + +static void +unlinked (GstPad * pad, GstPad * peerpad, GstElement * pipeline) +{ + gst_element_set_state (pipeline, GST_STATE_PAUSED); + gst_bin_remove (GST_BIN (pipeline), bin); + gst_element_set_state (bin, GST_STATE_READY); + gst_element_set_state (pipeline, GST_STATE_PLAYING); +} + +static void +new_pad (GstElement * elem, GstPad * newpad, GstElement * pipeline) +{ + GstScheduler *sched; + GstClock *clock; + + g_print ("new pad %s\n", gst_pad_get_name (newpad)); + + gst_element_set_state (pipeline, GST_STATE_PAUSED); + gst_bin_add (GST_BIN (pipeline), bin); + + sched = gst_element_get_scheduler (GST_ELEMENT (pipeline)); + clock = gst_scheduler_get_clock (sched); + gst_scheduler_set_clock (sched, clock); + + gst_pad_link (newpad, gst_element_get_pad (bin, "sink")); + + g_signal_connect (G_OBJECT (newpad), "unlinked", G_CALLBACK (unlinked), + pipeline); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); +} + +int +main (int argc, char **argv) +{ + GstElement *pipeline; + GstElement *filesrc; + GstElement *oggdemux; + GstElement *vorbisdec; + GstElement *audioconvert; + GstElement *osssink; + + gst_init (&argc, &argv); + + if (argc < 2) { + g_print ("usage: %s \n", argv[0]); + return (-1); + } + + pipeline = gst_pipeline_new ("pipeline"); + + filesrc = gst_element_factory_make ("filesrc", "filesrc"); + g_assert (filesrc); + g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); + + oggdemux = gst_element_factory_make ("oggdemux", "oggdemux"); + g_assert (oggdemux); + + gst_bin_add (GST_BIN (pipeline), filesrc); + gst_bin_add (GST_BIN (pipeline), oggdemux); + + gst_element_link_pads (filesrc, "src", oggdemux, "sink"); + + g_signal_connect (G_OBJECT (oggdemux), "new_pad", G_CALLBACK (new_pad), + pipeline); + + bin = gst_bin_new ("bin"); + vorbisdec = gst_element_factory_make ("vorbisdec", "vorbisdec"); + g_assert (vorbisdec); + audioconvert = gst_element_factory_make ("audioconvert", "audioconvert"); + g_assert (audioconvert); + osssink = gst_element_factory_make ("osssink", "osssink"); + g_assert (osssink); + gst_bin_add (GST_BIN (bin), vorbisdec); + gst_bin_add (GST_BIN (bin), audioconvert); + gst_bin_add (GST_BIN (bin), osssink); + + gst_element_link_pads (vorbisdec, "src", audioconvert, "sink"); + gst_element_link_pads (audioconvert, "src", osssink, "sink"); + + gst_element_add_ghost_pad (bin, gst_element_get_pad (vorbisdec, "sink"), + "sink"); + + g_object_ref (G_OBJECT (bin)); + + g_signal_connect (pipeline, "deep_notify", + G_CALLBACK (gst_element_default_deep_notify), NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + while (gst_bin_iterate (GST_BIN (pipeline))) + /* nop */ ; + + /* stop probe */ + gst_element_set_state (pipeline, GST_STATE_NULL); + + return 0; +} diff --git a/examples/seeking/playbin.c b/examples/seeking/playbin.c new file mode 100644 index 0000000000..b6ff35b8e2 --- /dev/null +++ b/examples/seeking/playbin.c @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include + +static GstElement *playbin = NULL; +static GstElement *pipeline; +static guint64 duration; +static GtkAdjustment *adjustment; +static GtkWidget *hscale; +static gboolean verbose = FALSE; + +static guint update_id; + +#define UPDATE_INTERVAL 500 + +static GstElement * +make_playerbin_pipeline (const gchar * location) +{ + playbin = gst_element_factory_make ("playbin", "player"); + g_assert (playbin); + + g_object_set (G_OBJECT (playbin), "uri", location, NULL); + + return playbin; +} + +static gchar * +format_value (GtkScale * scale, gdouble value) +{ + gint64 real; + gint64 seconds; + gint64 subseconds; + + real = value * duration / 100; + seconds = (gint64) real / GST_SECOND; + subseconds = (gint64) real / (GST_SECOND / 100); + + return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02" + G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100); +} + +static gboolean +update_scale (gpointer data) +{ + GstClock *clock; + guint64 position; + GstFormat format = GST_FORMAT_TIME; + gboolean res; + + duration = 0; + clock = gst_bin_get_clock (GST_BIN (pipeline)); + + res = gst_element_query (playbin, GST_QUERY_TOTAL, &format, &duration); + if (!res) + duration = 0; + res = gst_element_query (playbin, GST_QUERY_POSITION, &format, &position); + if (!res) + position = 0; + + if (position >= duration) + duration = position; + + if (duration > 0) { + gtk_adjustment_set_value (adjustment, position * 100.0 / duration); + gtk_widget_queue_draw (hscale); + } + + return TRUE; +} + +static gboolean +iterate (gpointer data) +{ + gboolean res; + + if (!GST_FLAG_IS_SET (GST_OBJECT (data), GST_BIN_SELF_SCHEDULABLE)) { + res = gst_bin_iterate (GST_BIN (data)); + } else { + g_usleep (UPDATE_INTERVAL); + res = gst_element_get_state (GST_ELEMENT (data)) == GST_STATE_PLAYING; + } + + if (!res) { + gtk_timeout_remove (update_id); + g_print ("stopping iterations\n"); + } + return res; +} + +static gboolean +start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data) +{ + gst_element_set_state (pipeline, GST_STATE_PAUSED); + gtk_timeout_remove (update_id); + + return FALSE; +} + +static gboolean +stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data) +{ + gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100; + gboolean res; + GstEvent *s_event; + + g_print ("seek to %" G_GINT64_FORMAT " on element %s\n", real, + gst_element_get_name (playbin)); + s_event = + gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET | + GST_SEEK_FLAG_FLUSH, real); + + res = gst_element_send_event (playbin, s_event); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + gtk_idle_add ((GtkFunction) iterate, pipeline); + update_id = + gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline); + + return FALSE; +} + +static void +print_media_info (GstElement * playbin) +{ + GList *streaminfo; + GList *s; + + g_print ("have media info now\n"); + + /* get info about the stream */ + g_object_get (G_OBJECT (playbin), "stream-info", &streaminfo, NULL); + + for (s = streaminfo; s; s = g_list_next (s)) { + GObject *obj = G_OBJECT (s->data); + gint type; + gboolean mute; + + g_object_get (obj, "type", &type, NULL); + g_object_get (obj, "mute", &mute, NULL); + + g_print ("%d %d\n", type, mute); + } +} + +static void +play_cb (GtkButton * button, gpointer data) +{ + if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) { + GstElementStateReturn res; + + res = gst_element_set_state (pipeline, GST_STATE_PAUSED); + if (res == GST_STATE_SUCCESS) { + print_media_info (playbin); + + res = gst_element_set_state (pipeline, GST_STATE_PLAYING); + gtk_idle_add ((GtkFunction) iterate, pipeline); + update_id = + gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, + pipeline); + } else { + g_print ("failed playing\n"); + } + } +} + +static void +pause_cb (GtkButton * button, gpointer data) +{ + if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) { + gst_element_set_state (pipeline, GST_STATE_PAUSED); + gtk_timeout_remove (update_id); + } +} + +static void +stop_cb (GtkButton * button, gpointer data) +{ + if (gst_element_get_state (pipeline) != GST_STATE_READY) { + gst_element_set_state (pipeline, GST_STATE_READY); + gtk_adjustment_set_value (adjustment, 0.0); + gtk_timeout_remove (update_id); + } +} + +static void +print_usage (int argc, char **argv) +{ + g_print ("usage: %s \n", argv[0]); +} + +int +main (int argc, char **argv) +{ + GtkWidget *window, *hbox, *vbox, *play_button, *pause_button, *stop_button; + struct poptOption options[] = { + {"verbose", 'v', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &verbose, 0, + "Verbose properties", NULL}, + POPT_TABLEEND + }; + + gst_init_with_popt_table (&argc, &argv, options); + gtk_init (&argc, &argv); + + if (argc != 2) { + print_usage (argc, argv); + exit (-1); + } + + pipeline = make_playerbin_pipeline (argv[1]); + g_assert (pipeline); + + /* initialize gui elements ... */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + hbox = gtk_hbox_new (FALSE, 0); + vbox = gtk_vbox_new (FALSE, 0); + play_button = gtk_button_new_with_label ("play"); + pause_button = gtk_button_new_with_label ("pause"); + stop_button = gtk_button_new_with_label ("stop"); + + adjustment = + GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0)); + hscale = gtk_hscale_new (adjustment); + gtk_scale_set_digits (GTK_SCALE (hscale), 2); + gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS); + + gtk_signal_connect (GTK_OBJECT (hscale), + "button_press_event", G_CALLBACK (start_seek), pipeline); + gtk_signal_connect (GTK_OBJECT (hscale), + "button_release_event", G_CALLBACK (stop_seek), pipeline); + gtk_signal_connect (GTK_OBJECT (hscale), + "format_value", G_CALLBACK (format_value), pipeline); + + /* do the packing stuff ... */ + gtk_window_set_default_size (GTK_WINDOW (window), 96, 96); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_container_add (GTK_CONTAINER (vbox), hbox); + 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); + gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2); + + /* connect things ... */ + g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb), + pipeline); + g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb), + pipeline); + g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb), + pipeline); + g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL); + + /* show the gui. */ + gtk_widget_show_all (window); + + if (verbose) { + g_signal_connect (pipeline, "deep_notify", + G_CALLBACK (gst_element_default_deep_notify), NULL); + } + g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error), + NULL); + + gtk_main (); + + gst_element_set_state (pipeline, GST_STATE_NULL); + + gst_object_unref (GST_OBJECT (pipeline)); + + return 0; +}