add framestepping to playbin2 and seek
authorWim Taymans <wim.taymans@collabora.co.uk>
Mon, 1 Jun 2009 09:31:49 +0000 (11:31 +0200)
committerWim Taymans <wim@metal.(none)>
Mon, 1 Jun 2009 09:31:49 +0000 (11:31 +0200)
gst/playback/gstplaysink.c
tests/examples/seek/seek.c

index 8796346..5156dd8 100644 (file)
@@ -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,
index 9ec4da6..d9eb8d7 100644 (file)
@@ -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)
 {
@@ -2241,6 +2282,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)
 {
   GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (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);