From ea97973efe0009b5aa382af2a468f38322f4b0f3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 1 Jun 2009 11:31:49 +0200 Subject: [PATCH] add framestepping to playbin2 and seek --- gst/playback/gstplaysink.c | 78 +++++++++++++++++++++++++++++++- tests/examples/seek/seek.c | 93 +++++++++++++++++++++++++++++++++++++- 2 files changed, 167 insertions(+), 4 deletions(-) diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index 8796346f89..5156dd83d0 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -201,6 +201,8 @@ static gboolean gst_play_sink_send_event (GstElement * element, static GstStateChangeReturn gst_play_sink_change_state (GstElement * element, GstStateChange transition); +static void gst_play_sink_handle_message (GstBin * bin, GstMessage * message); + /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */ static const GstElementDetails gst_play_sink_details = @@ -231,6 +233,9 @@ gst_play_sink_class_init (GstPlaySinkClass * klass) GST_DEBUG_FUNCPTR (gst_play_sink_change_state); gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_play_sink_send_event); + gstbin_klass->handle_message = + GST_DEBUG_FUNCPTR (gst_play_sink_handle_message); + GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin"); } @@ -2299,6 +2304,51 @@ gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad) } } +static void +gst_play_sink_handle_message (GstBin * bin, GstMessage * message) +{ + GstPlaySink *playsink; + + playsink = GST_PLAY_SINK_CAST (bin); + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_STEP_DONE: + { + GstFormat format; + guint64 amount; + gdouble rate; + gboolean flush, intermediate, res; + guint64 duration; + + GST_INFO_OBJECT (playsink, "Handling step-done message"); + gst_message_parse_step_done (message, &format, &amount, &rate, &flush, + &intermediate, &duration); + + if (format == GST_FORMAT_BUFFERS) { + /* for the buffer format, we align the other streams */ + if (playsink->audiochain) { + GstEvent *event; + + event = + gst_event_new_step (GST_FORMAT_TIME, duration, rate, flush, + intermediate); + + if (!(res = + gst_element_send_event (playsink->audiochain->chain.bin, + event))) { + GST_DEBUG_OBJECT (playsink, "Event failed when sent to audio sink"); + } + } + } + GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message); + break; + } + default: + GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message); + break; + } +} + /* Send an event to our sinks until one of them works; don't then send to the * remaining sinks (unlike GstBin) */ @@ -2336,12 +2386,36 @@ gst_play_sink_send_event (GstElement * element, GstEvent * event) { gboolean res = FALSE; GstEventType event_type = GST_EVENT_TYPE (event); + GstPlaySink *playsink; + + playsink = GST_PLAY_SINK_CAST (element); switch (event_type) { case GST_EVENT_SEEK: - GST_DEBUG_OBJECT (element, "Sending seek event to a sink"); - res = gst_play_sink_send_event_to_sink (GST_PLAY_SINK (element), event); + GST_DEBUG_OBJECT (element, "Sending event to a sink"); + res = gst_play_sink_send_event_to_sink (playsink, event); break; + case GST_EVENT_STEP: + { + GstFormat format; + guint64 amount; + gdouble rate; + gboolean flush, intermediate; + + gst_event_parse_step (event, &format, &amount, &rate, &flush, + &intermediate); + + if (format == GST_FORMAT_BUFFERS) { + /* for buffers, we will try to step video frames, for other formats we + * send the step to all sinks */ + res = gst_play_sink_send_event_to_sink (playsink, event); + } else { + res = + GST_ELEMENT_CLASS (gst_play_sink_parent_class)->send_event (element, + event); + } + break; + } default: res = GST_ELEMENT_CLASS (gst_play_sink_parent_class)->send_event (element, diff --git a/tests/examples/seek/seek.c b/tests/examples/seek/seek.c index 9ec4da66a4..d9eb8d7a23 100644 --- a/tests/examples/seek/seek.c +++ b/tests/examples/seek/seek.c @@ -110,7 +110,10 @@ static GtkWidget *vis_checkbox, *video_checkbox, *audio_checkbox; static GtkWidget *text_checkbox, *mute_checkbox, *volume_spinbutton; static GtkWidget *skip_checkbox, *video_window; -GList *paths = NULL, *l = NULL; +static GtkWidget *format_combo, *step_amount_spinbutton, *step_rate_spinbutton; +static GtkWidget *step_flush_checkbox, *step_button; + +static GList *paths = NULL, *l = NULL; /* we keep an array of the visualisation entries so that we can easily switch * with the combo box index. */ @@ -1217,6 +1220,7 @@ update_scale (gpointer data) } query_rates (); } + if (position >= duration) duration = position; @@ -2007,6 +2011,43 @@ shot_cb (GtkButton * button, gpointer data) } } +/* called when the Step button is pressed */ +static void +step_cb (GtkButton * button, gpointer data) +{ + GstEvent *event; + GstFormat format; + guint64 amount; + gdouble rate; + gboolean flush, res; + gint active; + + active = gtk_combo_box_get_active (GTK_COMBO_BOX (format_combo)); + amount = + gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON + (step_amount_spinbutton)); + rate = gtk_spin_button_get_value (GTK_SPIN_BUTTON (step_rate_spinbutton)); + flush = + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (step_flush_checkbox)); + + switch (active) { + case 0: + format = GST_FORMAT_BUFFERS; + break; + case 1: + format = GST_FORMAT_TIME; + amount *= GST_MSECOND; + break; + default: + format = GST_FORMAT_UNDEFINED; + break; + } + + event = gst_event_new_step (format, amount, rate, flush, FALSE); + + res = send_event (event); +} + static void message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline) { @@ -2240,6 +2281,12 @@ msg_eos (GstBus * bus, GstMessage * message, GstPipeline * data) } } +static void +msg_step_done (GstBus * bus, GstMessage * message, GstPipeline * data) +{ + message_received (bus, message, data); +} + static void connect_bus_signals (GstElement * pipeline) { @@ -2277,6 +2324,8 @@ connect_bus_signals (GstElement * pipeline) pipeline); g_signal_connect (bus, "message::buffering", (GCallback) msg_buffering, pipeline); + g_signal_connect (bus, "message::step-done", (GCallback) msg_step_done, + pipeline); gst_object_unref (bus); } @@ -2339,7 +2388,7 @@ int main (int argc, char **argv) { GtkWidget *window, *hbox, *vbox, *panel, *expander, *pb2vbox, *boxes, - *flagtable, *boxes2; + *flagtable, *boxes2, *step; GtkWidget *play_button, *pause_button, *stop_button, *shot_button; GtkWidget *accurate_checkbox, *key_checkbox, *loop_checkbox, *flush_checkbox; GtkWidget *scrub_checkbox, *play_scrub_checkbox, *rate_spinbutton; @@ -2458,6 +2507,45 @@ main (int argc, char **argv) gtk_spin_button_set_value (GTK_SPIN_BUTTON (rate_spinbutton), rate); + /* step expander */ + { + GtkWidget *hbox; + + step = gtk_expander_new ("step options"); + hbox = gtk_hbox_new (FALSE, 0); + + format_combo = gtk_combo_box_new_text (); + gtk_combo_box_append_text (GTK_COMBO_BOX (format_combo), "frames"); + gtk_combo_box_append_text (GTK_COMBO_BOX (format_combo), "time (ms)"); + gtk_combo_box_set_active (GTK_COMBO_BOX (format_combo), 0); + gtk_box_pack_start (GTK_BOX (hbox), format_combo, FALSE, FALSE, 2); + + step_amount_spinbutton = gtk_spin_button_new_with_range (1, 1000, 1); + gtk_spin_button_set_digits (GTK_SPIN_BUTTON (step_amount_spinbutton), 0); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (step_amount_spinbutton), 1.0); + gtk_box_pack_start (GTK_BOX (hbox), step_amount_spinbutton, FALSE, FALSE, + 2); + + step_rate_spinbutton = gtk_spin_button_new_with_range (0.0, 100, 0.1); + gtk_spin_button_set_digits (GTK_SPIN_BUTTON (step_rate_spinbutton), 3); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (step_rate_spinbutton), 1.0); + gtk_box_pack_start (GTK_BOX (hbox), step_rate_spinbutton, FALSE, FALSE, 2); + + step_flush_checkbox = gtk_check_button_new_with_label ("Flush"); + gtk_box_pack_start (GTK_BOX (hbox), step_flush_checkbox, FALSE, FALSE, 2); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (step_flush_checkbox), + TRUE); + + step_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_FORWARD); + gtk_button_set_label (GTK_BUTTON (step_button), "Step"); + gtk_box_pack_start (GTK_BOX (hbox), step_button, FALSE, FALSE, 2); + + g_signal_connect (G_OBJECT (step_button), "clicked", G_CALLBACK (step_cb), + pipeline); + + gtk_container_add (GTK_CONTAINER (step), hbox); + } + /* seek bar */ adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0)); @@ -2582,6 +2670,7 @@ main (int argc, char **argv) gtk_container_add (GTK_CONTAINER (expander), pb2vbox); gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 2); } + gtk_box_pack_start (GTK_BOX (vbox), step, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (vbox), hscale, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (vbox), statusbar, FALSE, FALSE, 2);