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 =
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");
}
}
}
+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)
*/
{
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,
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. */
}
query_rates ();
}
+
if (position >= duration)
duration = position;
}
}
+/* 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)
{
}
static void
+msg_step_done (GstBus * bus, GstMessage * message, GstPipeline * data)
+{
+ message_received (bus, message, data);
+}
+
+static void
connect_bus_signals (GstElement * pipeline)
{
GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (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);
}
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;
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));
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);