From 899330d90443a9ba411ddacf1c389bae3c11721e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 1 Feb 2008 16:44:21 +0000 Subject: [PATCH] gst/playback/gstplaybin2.c: Remove stream-info, we going for something easier. Original commit message from CVS: * 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. --- ChangeLog | 26 +++++++ gst/playback/gstplaybin2.c | 90 +++++++++++++++++------- gst/playback/gststreamselector.c | 27 ++++++-- gst/playback/gststreamselector.h | 4 +- tests/examples/seek/seek.c | 114 ++++++++++++++++++++++++++++++- 5 files changed, 228 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index a36e7f8096..f55edcee37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2008-02-01 Wim Taymans + + * 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 * docs/plugins/Makefile.am: diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index 97987e5c16..edc8d4e1fa 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -336,7 +336,6 @@ struct _GstPlayBinClass /* 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 @@ -360,7 +359,6 @@ enum PROP_0, PROP_URI, PROP_SUBURI, - PROP_STREAMINFO, PROP_SOURCE, PROP_FLAGS, PROP_N_VIDEO, @@ -476,12 +474,6 @@ gst_play_bin_class_init (GstPlayBinClass * klass) 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)); @@ -753,6 +745,32 @@ gst_play_bin_set_property (GObject * object, guint prop_id, } } +/* 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) @@ -763,36 +781,58 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value, 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; @@ -878,7 +918,7 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) 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; @@ -1011,7 +1051,7 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group) 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) { @@ -1035,7 +1075,7 @@ perform_eos (GstPlayBin * playbin, GstSourceGroup * group) 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) { @@ -1231,7 +1271,7 @@ deactivate_group (GstPlayBin * playbin, GstSourceGroup * group) 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) diff --git a/gst/playback/gststreamselector.c b/gst/playback/gststreamselector.c index 86ced9f825..9681f01a43 100644 --- a/gst/playback/gststreamselector.c +++ b/gst/playback/gststreamselector.c @@ -54,7 +54,10 @@ GST_STATIC_PAD_TEMPLATE ("src", 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, @@ -422,14 +425,20 @@ gst_stream_selector_class_init (GstStreamSelectorClass * klass) 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; } @@ -445,7 +454,8 @@ gst_stream_selector_init (GstStreamSelector * sel) 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); } @@ -511,6 +521,11 @@ gst_stream_selector_get_property (GObject * object, guint prop_id, 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) { @@ -635,9 +650,10 @@ gst_stream_selector_request_new_pad (GstElement * element, 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); @@ -673,6 +689,7 @@ gst_stream_selector_release_pad (GstElement * element, GstPad * pad) 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); diff --git a/gst/playback/gststreamselector.h b/gst/playback/gststreamselector.h index a7c4b22fc1..d64da770ce 100644 --- a/gst/playback/gststreamselector.h +++ b/gst/playback/gststreamselector.h @@ -44,8 +44,10 @@ struct _GstStreamSelector { GstPad *srcpad; + guint padcount; + GstPad *active_sinkpad; - guint nb_sinkpads; + guint n_pads; GstSegment segment; }; diff --git a/tests/examples/seek/seek.c b/tests/examples/seek/seek.c index fb6dddeba4..4c4b17ce7f 100644 --- a/tests/examples/seek/seek.c +++ b/tests/examples/seek/seek.c @@ -86,6 +86,9 @@ static guint update_id = 0; 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 */ @@ -1047,6 +1050,7 @@ static gboolean start_seek (GtkWidget * widget, GdkEventButton * event, 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) @@ -1055,11 +1059,14 @@ 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); } @@ -1454,6 +1461,57 @@ rate_spinbutton_changed_cb (GtkSpinButton * button, GstPipeline * pipeline) 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) { @@ -1474,6 +1532,18 @@ 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) { @@ -1487,7 +1557,7 @@ 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 { @@ -1542,7 +1612,7 @@ print_usage (int argc, char **argv) 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; @@ -1655,6 +1725,40 @@ main (int argc, char **argv) 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); @@ -1674,6 +1778,10 @@ main (int argc, char **argv) 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 ... */ @@ -1717,6 +1825,8 @@ main (int argc, char **argv) (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); -- 2.34.1