tests/examples/seek/seek.c: Allow to toggle looping while it plays. Fix callback prototype. Clean up code a bit more....

Original commit message from CVS:
* tests/examples/seek/seek.c: (set_scale), (update_scale),
(do_seek), (stop_seek), (pause_cb), (stop_cb), (loop_toggle_cb),
(rate_spinbutton_changed_cb), (msg_eos), (msg_segment_done),
(main):
Allow to toggle looping while it plays. Fix callback prototype. Clean
up code a bit more. Add copyright header.
This commit is contained in:
Stefan Kost 2007-01-16 12:17:06 +00:00
parent bc62bb15e5
commit 268dcb0ab1
2 changed files with 145 additions and 44 deletions

View file

@ -1,3 +1,12 @@
2007-01-16 Stefan Kost <ensonic@users.sf.net>
* tests/examples/seek/seek.c: (set_scale), (update_scale),
(do_seek), (stop_seek), (pause_cb), (stop_cb), (loop_toggle_cb),
(rate_spinbutton_changed_cb), (msg_eos), (msg_segment_done),
(main):
Allow to toggle looping while it plays. Fix callback prototype. Clean
up code a bit more. Add copyright header.
2007-01-16 Stefan Kost <ensonic@users.sf.net> 2007-01-16 Stefan Kost <ensonic@users.sf.net>
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support): * sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support):

View file

@ -1,3 +1,29 @@
/* GStreamer
*
* seek.c: seeking sample application
*
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
* 2006 Stefan Kost <ensonic@users.sf.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* FIXME: remove #if 0 code
* FIXME: is the flush_seek part after sending the seek still needed?
*
*/
#include <stdlib.h> #include <stdlib.h>
#include <glib.h> #include <glib.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
@ -20,15 +46,15 @@ static gboolean play_scrub = FALSE;
static gdouble rate = 1.0; static gdouble rate = 1.0;
static GstElement *pipeline; static GstElement *pipeline;
static gint64 position; static gint64 position = -1;
static gint64 duration; static gint64 duration = -1;
static GtkAdjustment *adjustment; static GtkAdjustment *adjustment;
static GtkWidget *hscale; static GtkWidget *hscale;
static gboolean stats = FALSE; static gboolean stats = FALSE;
static gboolean elem_seek = FALSE; static gboolean elem_seek = FALSE;
static gboolean verbose = FALSE; static gboolean verbose = FALSE;
static GstState state; static GstState state = GST_STATE_NULL;
static guint update_id = 0; static guint update_id = 0;
static guint seek_timeout_id = 0; static guint seek_timeout_id = 0;
static gulong changed_id; static gulong changed_id;
@ -958,16 +984,30 @@ query_positions_pads ()
} }
} }
static gboolean start_seek (GtkWidget * widget, GdkEventButton * event,
gpointer user_data);
static gboolean stop_seek (GtkWidget * widget, GdkEventButton * event,
gpointer user_data);
static void
set_scale (gdouble value)
{
g_signal_handlers_block_by_func (hscale, start_seek, pipeline);
g_signal_handlers_block_by_func (hscale, stop_seek, pipeline);
gtk_adjustment_set_value (adjustment, value);
g_signal_handlers_unblock_by_func (hscale, start_seek, pipeline);
g_signal_handlers_unblock_by_func (hscale, stop_seek, pipeline);
gtk_widget_queue_draw (hscale);
}
static gboolean static gboolean
update_scale (gpointer data) update_scale (gpointer data)
{ {
GstFormat format; GstFormat format = GST_FORMAT_TIME;
position = 0; position = 0;
duration = 0; duration = 0;
format = GST_FORMAT_TIME;
if (elem_seek) { if (elem_seek) {
if (seekable_elements) { if (seekable_elements) {
GstElement *element = GST_ELEMENT (seekable_elements->data); GstElement *element = GST_ELEMENT (seekable_elements->data);
@ -996,8 +1036,7 @@ update_scale (gpointer data)
duration = position; duration = position;
if (duration > 0) { if (duration > 0) {
gtk_adjustment_set_value (adjustment, position * 100.0 / duration); set_scale (position * 100.0 / duration);
gtk_widget_queue_draw (hscale);
} }
return TRUE; return TRUE;
@ -1076,10 +1115,12 @@ do_seek (GtkWidget * widget)
GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, real, GST_SEEK_TYPE_SET, -1); GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, real, GST_SEEK_TYPE_SET, -1);
} else { } else {
s_event = gst_event_new_seek (rate, s_event = gst_event_new_seek (rate,
GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, real); GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
GST_SEEK_TYPE_SET, real);
} }
GST_DEBUG ("seek to %" GST_TIME_FORMAT, GST_TIME_ARGS (real)); GST_DEBUG ("seek with rate %lf to %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT,
rate, GST_TIME_ARGS (real), GST_TIME_ARGS (duration));
res = send_event (s_event); res = send_event (s_event);
@ -1153,7 +1194,7 @@ start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
} }
static gboolean static gboolean
stop_seek (GtkWidget * widget, gpointer user_data) stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
{ {
if (changed_id) { if (changed_id) {
g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id); g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id);
@ -1203,9 +1244,9 @@ failed:
static void static void
pause_cb (GtkButton * button, gpointer data) pause_cb (GtkButton * button, gpointer data)
{ {
GstStateChangeReturn ret;
if (state != GST_STATE_PAUSED) { if (state != GST_STATE_PAUSED) {
GstStateChangeReturn ret;
g_print ("PAUSE pipeline\n"); g_print ("PAUSE pipeline\n");
ret = gst_element_set_state (pipeline, GST_STATE_PAUSED); ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
if (ret == GST_STATE_CHANGE_FAILURE) if (ret == GST_STATE_CHANGE_FAILURE)
@ -1224,15 +1265,15 @@ failed:
static void static void
stop_cb (GtkButton * button, gpointer data) stop_cb (GtkButton * button, gpointer data)
{ {
GstStateChangeReturn ret;
if (state != GST_STATE_READY) { if (state != GST_STATE_READY) {
GstStateChangeReturn ret;
g_print ("READY pipeline\n"); g_print ("READY pipeline\n");
ret = gst_element_set_state (pipeline, GST_STATE_READY); ret = gst_element_set_state (pipeline, GST_STATE_READY);
if (ret == GST_STATE_CHANGE_FAILURE) if (ret == GST_STATE_CHANGE_FAILURE)
goto failed; goto failed;
gtk_adjustment_set_value (adjustment, 0.0); set_scale (0.0);
state = GST_STATE_READY; state = GST_STATE_READY;
} }
@ -1260,6 +1301,9 @@ static void
loop_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline) loop_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
{ {
loop_seek = gtk_toggle_button_get_active (button); loop_seek = gtk_toggle_button_get_active (button);
if (state == GST_STATE_PLAYING) {
do_seek (hscale);
}
} }
static void static void
@ -1301,10 +1345,12 @@ rate_spinbutton_changed_cb (GtkSpinButton * button, GstPipeline * pipeline)
GST_SEEK_TYPE_SET, -1); GST_SEEK_TYPE_SET, -1);
} else { } else {
s_event = gst_event_new_seek (rate, s_event = gst_event_new_seek (rate,
GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
position); GST_SEEK_TYPE_SET, position);
} }
GST_DEBUG ("rate changed to %lf", rate);
res = send_event (s_event); res = send_event (s_event);
if (res) { if (res) {
@ -1316,26 +1362,6 @@ rate_spinbutton_changed_cb (GtkSpinButton * button, GstPipeline * pipeline)
g_print ("seek failed\n"); g_print ("seek failed\n");
} }
static void
segment_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{
GstEvent *event;
GstSeekFlags flags;
gboolean res;
flags = 0;
if (loop_seek)
flags |= GST_SEEK_FLAG_SEGMENT;
event = gst_event_new_seek (rate,
GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1);
res = send_event (event);
if (!res) {
g_print ("segment seek failed\n");
}
}
static void static void
message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline) message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{ {
@ -1356,6 +1382,23 @@ message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
} }
} }
static void
msg_eos (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{
GstStateChangeReturn ret;
GST_DEBUG ("position is %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
g_print ("READY pipeline\n");
ret = gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_READY);
if (ret == GST_STATE_CHANGE_FAILURE)
g_print ("READY failed\n");
set_scale (0.0);
state = GST_STATE_READY;
}
static void static void
msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline) msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{ {
@ -1378,6 +1421,51 @@ msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
} }
} }
static void
msg_segment_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{
GstEvent *s_event;
GstSeekFlags flags;
gboolean res;
GstFormat format;
GST_DEBUG ("position is %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
format = GST_FORMAT_TIME;
gst_message_parse_segment_done (message, &format, &position);
GST_DEBUG ("end of segment at %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
set_update_scale (FALSE);
flags = GST_SEEK_FLAG_SEGMENT;
if (flush_seek)
flags |= GST_SEEK_FLAG_FLUSH;
if (rate >= 0) {
s_event = gst_event_new_seek (rate,
GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
GST_SEEK_TYPE_SET, duration);
} else {
s_event = gst_event_new_seek (rate,
GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, duration,
GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0));
}
GST_DEBUG ("restart loop with rate %lf to 0 / %" GST_TIME_FORMAT,
rate, GST_TIME_ARGS (duration));
res = send_event (s_event);
if (res) {
if (flush_seek) {
gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline), 0);
gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
}
} else
g_print ("segment seek failed\n");
position = 0;
set_update_scale (TRUE);
}
typedef struct typedef struct
{ {
gchar *name; gchar *name;
@ -1509,7 +1597,6 @@ main (int argc, char **argv)
NULL); NULL);
gtk_tooltips_set_tip (tips, rate_spinbutton, "define the playback rate, " gtk_tooltips_set_tip (tips, rate_spinbutton, "define the playback rate, "
"negative value trigger reverse playback", NULL); "negative value trigger reverse playback", NULL);
/* FIXME: describe these */
gtk_tooltips_set_tip (tips, scrub_checkbox, "show images while seeking", gtk_tooltips_set_tip (tips, scrub_checkbox, "show images while seeking",
NULL); NULL);
gtk_tooltips_set_tip (tips, play_scrub_checkbox, "play video while seeking", gtk_tooltips_set_tip (tips, play_scrub_checkbox, "play video while seeking",
@ -1592,7 +1679,12 @@ main (int argc, char **argv)
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH); gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
// g_signal_connect (bus, "message::state-changed", (GCallback) message_received, pipeline); g_signal_connect (bus, "message::eos", (GCallback) msg_eos, pipeline);
g_signal_connect (bus, "message::state-changed",
(GCallback) msg_state_changed, pipeline);
g_signal_connect (bus, "message::segment-done",
(GCallback) msg_segment_done, pipeline);
g_signal_connect (bus, "message::new-clock", (GCallback) message_received, g_signal_connect (bus, "message::new-clock", (GCallback) message_received,
pipeline); pipeline);
g_signal_connect (bus, "message::error", (GCallback) message_received, g_signal_connect (bus, "message::error", (GCallback) message_received,
@ -1607,10 +1699,10 @@ main (int argc, char **argv)
pipeline); pipeline);
g_signal_connect (bus, "message::segment-done", g_signal_connect (bus, "message::segment-done",
(GCallback) message_received, pipeline); (GCallback) message_received, pipeline);
g_signal_connect (bus, "message::state-changed", /*g_signal_connect (bus, "message::state-changed",
(GCallback) msg_state_changed, pipeline); (GCallback) message_received, pipeline);
g_signal_connect (bus, "message::segment-done", (GCallback) segment_done, */
pipeline);
} }
gtk_main (); gtk_main ();