+2008-02-01 Wim Taymans <wim.taymans@collabora.co.uk>
+
+ * gst/playback/gstplaybin2.c: (gst_play_bin_class_init),
+ (get_group), (get_n_pads), (gst_play_bin_get_property),
+ (pad_added_cb), (no_more_pads_cb), (perform_eos),
+ (autoplug_select_cb), (deactivate_group):
+ Remove stream-info, we going for something easier.
+ Refactor getting the current group.
+ Implement getting the number of audio/video/text streams.
+
+ * gst/playback/gststreamselector.c:
+ (gst_stream_selector_class_init), (gst_stream_selector_init),
+ (gst_stream_selector_get_property),
+ (gst_stream_selector_request_new_pad),
+ (gst_stream_selector_release_pad):
+ * gst/playback/gststreamselector.h:
+ Add property for number of pads.
+
+ * tests/examples/seek/seek.c: (set_scale), (update_flag),
+ (vis_toggle_cb), (audio_toggle_cb), (video_toggle_cb),
+ (text_toggle_cb), (update_streams), (msg_async_done),
+ (msg_state_changed), (main):
+ Block slider callback when updating the slider position.
+ Add gui elements for controlling playbin2.
+ Add callback for async_done that updates position/duration.
+
2008-02-01 Stefan Kost <ensonic@users.sf.net>
* docs/plugins/Makefile.am:
/* props */
#define DEFAULT_URI NULL
#define DEFAULT_SUBURI NULL
-#define DEFAULT_STREAMINFO NULL
#define DEFAULT_SOURCE NULL
#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
GST_PLAY_FLAG_SOFT_VOLUME
PROP_0,
PROP_URI,
PROP_SUBURI,
- PROP_STREAMINFO,
PROP_SOURCE,
PROP_FLAGS,
PROP_N_VIDEO,
g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
NULL, G_PARAM_READWRITE));
- g_object_class_install_property (gobject_klass, PROP_STREAMINFO,
- g_param_spec_value_array ("stream-info",
- "StreamInfo GValueArray", "value array of streaminfo",
- g_param_spec_object ("streaminfo", "StreamInfo", "Streaminfo object",
- GST_TYPE_STREAM_INFO, G_PARAM_READABLE), G_PARAM_READABLE));
-
g_object_class_install_property (gobject_klass, PROP_SOURCE,
g_param_spec_object ("source", "Source", "Source element",
GST_TYPE_ELEMENT, G_PARAM_READABLE));
}
}
+/* get the currently playing group or if nothing is playing, the next
+ * group. Must be called with the LOCK. */
+static GstSourceGroup *
+get_group (GstPlayBin * playbin)
+{
+ GstSourceGroup *result;
+
+ if (!(result = playbin->curr_group))
+ result = playbin->next_group;
+
+ return result;
+}
+
+static gint
+get_n_pads (GstSourceSelect * select)
+{
+ gint res;
+
+ if (select->selector == NULL)
+ return 0;
+
+ g_object_get (select->selector, "n-pads", &res, NULL);
+
+ return res;
+}
+
static void
gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
switch (prop_id) {
case PROP_URI:
+ {
+ GstSourceGroup *group;
+
GST_OBJECT_LOCK (playbin);
- /* get the currently playing group first, then the queued one, just in
- * case we did not yet start playback. */
- if (playbin->curr_group)
- g_value_set_string (value, playbin->curr_group->uri);
- else
- g_value_set_string (value, playbin->next_group->uri);
+ group = get_group (playbin);
+ g_value_set_string (value, group->uri);
GST_OBJECT_UNLOCK (playbin);
break;
+ }
case PROP_SUBURI:
+ {
+ GstSourceGroup *group;
+
GST_OBJECT_LOCK (playbin);
- /* get the currently playing group first, then the queued one */
- if (playbin->curr_group)
- g_value_set_string (value, playbin->curr_group->suburi);
- else
- g_value_set_string (value, playbin->next_group->suburi);
+ group = get_group (playbin);
+ g_value_set_string (value, group->suburi);
GST_OBJECT_UNLOCK (playbin);
break;
- case PROP_STREAMINFO:
- break;
+ }
case PROP_SOURCE:
break;
case PROP_FLAGS:
g_value_set_flags (value, gst_play_sink_get_flags (playbin->playsink));
break;
case PROP_N_VIDEO:
+ {
+ GstSourceGroup *group;
+ gint n_rawvideo, n_video;
+
+ GST_OBJECT_LOCK (playbin);
+ group = get_group (playbin);
+ n_rawvideo = get_n_pads (&group->selector[2]);
+ n_video = get_n_pads (&group->selector[3]);
+ g_value_set_int (value, n_rawvideo + n_video);
+ GST_OBJECT_UNLOCK (playbin);
break;
+ }
case PROP_CURRENT_VIDEO:
break;
case PROP_N_AUDIO:
+ {
+ GstSourceGroup *group;
+ gint n_rawaudio, n_audio;
+
+ GST_OBJECT_LOCK (playbin);
+ group = get_group (playbin);
+ n_rawaudio = get_n_pads (&group->selector[0]);
+ n_audio = get_n_pads (&group->selector[1]);
+ g_value_set_int (value, n_rawaudio + n_audio);
+ GST_OBJECT_UNLOCK (playbin);
+ break;
+ }
break;
case PROP_CURRENT_AUDIO:
break;
GST_DEBUG_PAD_NAME (pad), caps, group);
/* major type of the pad, this determines the selector to use */
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
if (g_str_has_prefix (name, group->selector[i].media)) {
select = &group->selector[i];
break;
GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
if (select->selector) {
GST_DEBUG_OBJECT (playbin, "doing EOS in group %p", group);
event = gst_event_new_eos ();
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
if (select->selector) {
GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
if (!select->selector)
enum
{
- PROP_ACTIVE_PAD = 1
+ PROP_0,
+ PROP_N_PADS,
+ PROP_ACTIVE_PAD,
+ PROP_LAST
};
static gboolean gst_stream_selector_is_active_sinkpad (GstStreamSelector * sel,
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->dispose = gst_stream_selector_dispose;
gobject_class->set_property =
GST_DEBUG_FUNCPTR (gst_stream_selector_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_stream_selector_get_property);
+
+ g_object_class_install_property (gobject_class, PROP_N_PADS,
+ g_param_spec_int ("n-pads", "Number of Pads",
+ "The number of sink pads", 0, G_MAXINT, 0, G_PARAM_READABLE));
g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
g_param_spec_string ("active-pad", "Active pad",
"Name of the currently" " active sink pad", NULL, G_PARAM_READWRITE));
- gobject_class->dispose = gst_stream_selector_dispose;
+
gstelement_class->request_new_pad = gst_stream_selector_request_new_pad;
gstelement_class->release_pad = gst_stream_selector_release_pad;
}
gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
/* sinkpad management */
sel->active_sinkpad = NULL;
- sel->nb_sinkpads = 0;
+ sel->padcount = 0;
+ sel->n_pads = 0;
gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
}
GstStreamSelector *sel = GST_STREAM_SELECTOR (object);
switch (prop_id) {
+ case PROP_N_PADS:
+ GST_OBJECT_LOCK (object);
+ g_value_set_int (value, sel->n_pads);
+ GST_OBJECT_UNLOCK (object);
+ break;
case PROP_ACTIVE_PAD:{
GST_OBJECT_LOCK (object);
if (sel->active_sinkpad != NULL) {
sel = GST_STREAM_SELECTOR (element);
g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
- GST_LOG_OBJECT (sel, "Creating new pad %d", sel->nb_sinkpads);
+ GST_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount);
GST_OBJECT_LOCK (sel);
- name = g_strdup_printf ("sink%d", sel->nb_sinkpads++);
+ name = g_strdup_printf ("sink%d", sel->padcount++);
+ sel->n_pads++;
sinkpad = g_object_new (GST_TYPE_SELECTOR_PAD,
"name", name, "direction", templ->direction, "template", templ, NULL);
g_free (name);
GST_DEBUG_OBJECT (sel, "Deactivating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
sel->active_sinkpad = NULL;
}
+ sel->n_pads--;
GST_OBJECT_UNLOCK (sel);
gst_pad_set_active (pad, FALSE);
GstPad *srcpad;
+ guint padcount;
+
GstPad *active_sinkpad;
- guint nb_sinkpads;
+ guint n_pads;
GstSegment segment;
};
static guint seek_timeout_id = 0;
static gulong changed_id;
+static GtkWidget *video_combo, *audio_combo, *text_combo;
+static GtkWidget *vis_checkbox, *video_checkbox, *audio_checkbox;
+static GtkWidget *text_checkbox;
/* pipeline construction */
gpointer user_data);
static gboolean stop_seek (GtkWidget * widget, GdkEventButton * event,
gpointer user_data);
+static void seek_cb (GtkWidget * widget);
static void
set_scale (gdouble value)
(void *) pipeline);
g_signal_handlers_block_by_func (hscale, (void *) stop_seek,
(void *) pipeline);
+ g_signal_handlers_block_by_func (hscale, (void *) seek_cb, (void *) pipeline);
gtk_adjustment_set_value (adjustment, value);
g_signal_handlers_unblock_by_func (hscale, (void *) start_seek,
(void *) pipeline);
g_signal_handlers_unblock_by_func (hscale, (void *) stop_seek,
(void *) pipeline);
+ g_signal_handlers_unblock_by_func (hscale, (void *) seek_cb,
+ (void *) pipeline);
gtk_widget_queue_draw (hscale);
}
g_print ("seek failed\n");
}
+static void
+update_flag (GstPipeline * pipeline, gint num, gboolean state)
+{
+ gint flags;
+
+ g_object_get (pipeline, "flags", &flags, NULL);
+ if (state)
+ flags |= (1 << num);
+ else
+ flags &= ~(1 << num);
+ g_object_set (pipeline, "flags", flags, NULL);
+}
+
+static void
+vis_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
+{
+ update_flag (pipeline, 3, gtk_toggle_button_get_active (button));
+}
+
+static void
+audio_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
+{
+ update_flag (pipeline, 1, gtk_toggle_button_get_active (button));
+}
+
+static void
+video_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
+{
+ update_flag (pipeline, 0, gtk_toggle_button_get_active (button));
+}
+
+static void
+text_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
+{
+ update_flag (pipeline, 2, gtk_toggle_button_get_active (button));
+}
+
+static void
+update_streams (GstPipeline * pipeline)
+{
+ gint n_video, n_audio, n_text;
+
+ /* here we get and update the different streams detected by playbin2 */
+ g_object_get (pipeline, "n-video", &n_video, NULL);
+ g_object_get (pipeline, "n-audio", &n_audio, NULL);
+ g_object_get (pipeline, "n-text", &n_text, NULL);
+
+ g_print ("video %d, audio %d, text %d\n", n_video, n_audio, n_text);
+
+}
+
static void
message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{
}
}
+static void
+msg_async_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
+{
+ GST_DEBUG ("async done");
+ /* when we get ASYNC_DONE we can query position, duration and other
+ * properties */
+ update_scale (pipeline);
+
+ /* update the available streams */
+ update_streams (pipeline);
+}
+
static void
msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{
gst_message_parse_state_changed (message, &old, &new, &pending);
- /* When state of the pipeline changes to playing we start updating scale */
+ /* When state of the pipeline changes to paused or playing we start updating scale */
if (new == GST_STATE_PLAYING) {
set_update_scale (TRUE);
} else {
int
main (int argc, char **argv)
{
- GtkWidget *window, *hbox, *vbox, *flagtable;
+ GtkWidget *window, *hbox, *vbox, *panel, *boxes, *flagtable;
GtkWidget *play_button, *pause_button, *stop_button;
GtkWidget *accurate_checkbox, *key_checkbox, *loop_checkbox, *flush_checkbox;
GtkWidget *scrub_checkbox, *play_scrub_checkbox, *rate_spinbutton;
gtk_signal_connect (GTK_OBJECT (hscale),
"format_value", G_CALLBACK (format_value), pipeline);
+ if (pipeline_type == 16) {
+ /* the playbin2 panel controls for the video/audio/subtitle tracks */
+ panel = gtk_hbox_new (FALSE, 0);
+ boxes = gtk_hbox_new (FALSE, 0);
+ video_combo = gtk_combo_box_new_text ();
+ audio_combo = gtk_combo_box_new_text ();
+ text_combo = gtk_combo_box_new_text ();
+ gtk_box_pack_start (GTK_BOX (panel), video_combo, TRUE, TRUE, 2);
+ gtk_box_pack_start (GTK_BOX (panel), audio_combo, TRUE, TRUE, 2);
+ gtk_box_pack_start (GTK_BOX (panel), text_combo, TRUE, TRUE, 2);
+ vis_checkbox = gtk_check_button_new_with_label ("Vis");
+ video_checkbox = gtk_check_button_new_with_label ("Video");
+ audio_checkbox = gtk_check_button_new_with_label ("Audio");
+ text_checkbox = gtk_check_button_new_with_label ("Text");
+ gtk_box_pack_start (GTK_BOX (boxes), vis_checkbox, TRUE, TRUE, 2);
+ gtk_box_pack_start (GTK_BOX (boxes), audio_checkbox, TRUE, TRUE, 2);
+ gtk_box_pack_start (GTK_BOX (boxes), video_checkbox, TRUE, TRUE, 2);
+ gtk_box_pack_start (GTK_BOX (boxes), text_checkbox, TRUE, TRUE, 2);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (vis_checkbox), TRUE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (audio_checkbox), TRUE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (video_checkbox), TRUE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_checkbox), TRUE);
+ g_signal_connect (G_OBJECT (vis_checkbox), "toggled",
+ G_CALLBACK (vis_toggle_cb), pipeline);
+ g_signal_connect (G_OBJECT (audio_checkbox), "toggled",
+ G_CALLBACK (audio_toggle_cb), pipeline);
+ g_signal_connect (G_OBJECT (video_checkbox), "toggled",
+ G_CALLBACK (video_toggle_cb), pipeline);
+ g_signal_connect (G_OBJECT (text_checkbox), "toggled",
+ G_CALLBACK (text_toggle_cb), pipeline);
+ } else {
+ panel = boxes = NULL;
+ }
+
/* do the packing stuff ... */
gtk_window_set_default_size (GTK_WINDOW (window), 250, 96);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_table_attach_defaults (GTK_TABLE (flagtable), rate_label, 3, 4, 0, 1);
gtk_table_attach_defaults (GTK_TABLE (flagtable), rate_spinbutton, 3, 4, 1,
2);
+ if (panel && boxes) {
+ gtk_box_pack_start (GTK_BOX (vbox), panel, TRUE, TRUE, 2);
+ gtk_box_pack_start (GTK_BOX (vbox), boxes, TRUE, TRUE, 2);
+ }
gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
/* connect things ... */
(GCallback) msg_state_changed, pipeline);
g_signal_connect (bus, "message::segment-done",
(GCallback) msg_segment_done, pipeline);
+ g_signal_connect (bus, "message::async-done",
+ (GCallback) msg_async_done, pipeline);
g_signal_connect (bus, "message::new-clock", (GCallback) message_received,
pipeline);