From c8bb67d0ca9b6cc4d7986b2781159bfbd05eacc5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 8 Feb 2008 17:47:37 +0000 Subject: [PATCH] gst/playback/gstplay-marshal.list: Added marshal for streamselector Tags. Original commit message from CVS: * gst/playback/gstplay-marshal.list: Added marshal for streamselector Tags. * gst/playback/gstplaybasebin.c: (set_active_source): Streamselector now selects pads based on the pad object instead of its name. * gst/playback/gstplaybin2.c: (gst_play_bin_class_init), (init_group), (gst_play_bin_init), (get_group), (get_tags), (gst_play_bin_get_video_tags), (gst_play_bin_get_audio_tags), (gst_play_bin_get_text_tags), (gst_play_bin_set_current_video_stream), (gst_play_bin_set_current_audio_stream), (gst_play_bin_set_current_text_stream), (gst_play_bin_set_property), (gst_play_bin_get_property), (pad_added_cb), (pad_removed_cb), (autoplug_select_cb): Remove option to mute streams with the current-a/v/t property, we have this functionality in the flags. Add signals to notify when the number of A/V/T channels changed. Add action signals to get tags for the A/V/T streams. Implement setting the current A/V/T stream. Rearrange some things to simplify stream selection. Implement volume. * gst/playback/gstplaysink.c: (gst_play_sink_set_volume), (gst_play_sink_get_volume), (gst_play_sink_set_property), (gst_play_sink_get_property), (gen_video_chain), (gen_audio_chain), (activate_vis), (gst_play_sink_reconfigure): * gst/playback/gstplaysink.h: Add and implement volume setting methods. * gst/playback/gststreamselector.c: (gst_selector_pad_class_init), (gst_selector_pad_finalize), (gst_selector_pad_get_property), (gst_selector_pad_event), (gst_stream_selector_class_init), (gst_stream_selector_init), (gst_stream_selector_finalize), (gst_stream_selector_set_property), (gst_stream_selector_get_property), (gst_stream_selector_get_linked_pad), (gst_stream_selector_request_new_pad): * gst/playback/gststreamselector.h: Add pad properties for tags and status of pads. Keep tags on pads. Make active pad selection based on pad object instead of name. --- ChangeLog | 46 ++++ common | 2 +- gst/playback/gstplay-marshal.list | 1 + gst/playback/gstplaybasebin.c | 5 +- gst/playback/gstplaybin2.c | 441 +++++++++++++++++++++++++++++++++----- gst/playback/gstplaysink.c | 45 +++- gst/playback/gstplaysink.h | 3 + gst/playback/gststreamselector.c | 120 +++++++++-- gst/playback/gststreamselector.h | 3 +- 9 files changed, 579 insertions(+), 87 deletions(-) diff --git a/ChangeLog b/ChangeLog index 07e832b..0a9cffe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,49 @@ +2008-02-08 Wim Taymans + + * gst/playback/gstplay-marshal.list: + Added marshal for streamselector Tags. + + * gst/playback/gstplaybasebin.c: (set_active_source): + Streamselector now selects pads based on the pad object instead of its + name. + + * gst/playback/gstplaybin2.c: (gst_play_bin_class_init), + (init_group), (gst_play_bin_init), (get_group), (get_tags), + (gst_play_bin_get_video_tags), (gst_play_bin_get_audio_tags), + (gst_play_bin_get_text_tags), + (gst_play_bin_set_current_video_stream), + (gst_play_bin_set_current_audio_stream), + (gst_play_bin_set_current_text_stream), + (gst_play_bin_set_property), (gst_play_bin_get_property), + (pad_added_cb), (pad_removed_cb), (autoplug_select_cb): + Remove option to mute streams with the current-a/v/t property, we have + this functionality in the flags. + Add signals to notify when the number of A/V/T channels changed. + Add action signals to get tags for the A/V/T streams. + Implement setting the current A/V/T stream. + Rearrange some things to simplify stream selection. + Implement volume. + + * gst/playback/gstplaysink.c: (gst_play_sink_set_volume), + (gst_play_sink_get_volume), (gst_play_sink_set_property), + (gst_play_sink_get_property), (gen_video_chain), (gen_audio_chain), + (activate_vis), (gst_play_sink_reconfigure): + * gst/playback/gstplaysink.h: + Add and implement volume setting methods. + + * gst/playback/gststreamselector.c: (gst_selector_pad_class_init), + (gst_selector_pad_finalize), (gst_selector_pad_get_property), + (gst_selector_pad_event), (gst_stream_selector_class_init), + (gst_stream_selector_init), (gst_stream_selector_finalize), + (gst_stream_selector_set_property), + (gst_stream_selector_get_property), + (gst_stream_selector_get_linked_pad), + (gst_stream_selector_request_new_pad): + * gst/playback/gststreamselector.h: + Add pad properties for tags and status of pads. + Keep tags on pads. + Make active pad selection based on pad object instead of name. + 2008-02-08 Stefan Kost * configure.ac: diff --git a/common b/common index aa24bcc..961bb6b 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit aa24bcc28323422b29ba41874a4a98b6b6ddf63a +Subproject commit 961bb6bd997d7c8da6058534e86b4a1361c0fcea diff --git a/gst/playback/gstplay-marshal.list b/gst/playback/gstplay-marshal.list index 300a5b4..c26a918 100644 --- a/gst/playback/gstplay-marshal.list +++ b/gst/playback/gstplay-marshal.list @@ -5,3 +5,4 @@ VOID:OBJECT,BOOLEAN ENUM:OBJECT,OBJECT,BOXED ENUM:OBJECT,OBJECT,OBJECT BOXED:OBJECT,OBJECT,BOXED +BOXED:INT diff --git a/gst/playback/gstplaybasebin.c b/gst/playback/gstplaybasebin.c index 150c0c4..4620feb 100644 --- a/gst/playback/gstplaybasebin.c +++ b/gst/playback/gstplaybasebin.c @@ -2443,8 +2443,7 @@ set_active_source (GstPlayBaseBin * play_base_bin, "pb_sel_pad")); if (sel && sel_pad != NULL) { - g_object_set (G_OBJECT (sel), "active-pad", GST_PAD_NAME (sel_pad), - NULL); + g_object_set (G_OBJECT (sel), "active-pad", sel_pad, NULL); } have_active = TRUE; @@ -2463,7 +2462,7 @@ set_active_source (GstPlayBaseBin * play_base_bin, if (!have_active) { GST_LOG ("Muting group type: %d", type); - g_object_set (sel, "active-pad", "", NULL); + g_object_set (sel, "active-pad", NULL, NULL); } else { GST_LOG ("Unmuting group type: %d", type); } diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index edc8d4e..51d3fa8 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -249,6 +249,7 @@ #include #include "gstplay-enum.h" +#include "gstplay-marshal.h" #include "gstplaysink.h" #include "gstfactorylists.h" #include "gststreaminfo.h" @@ -277,7 +278,7 @@ struct _GstSourceSelect GstPlaySinkType type; /* the sink pad type of the selector */ GstElement *selector; /* the selector */ - gint current; /* the currently selected stream */ + GPtrArray *channels; GstPad *srcpad; /* the source pad of the selector */ GstPad *sinkpad; /* the sinkpad of the sink when the selector is linked */ }; @@ -298,6 +299,10 @@ struct _GstSourceGroup GstElement *source; gchar *subencoding; /* encoding to propagate to the subtitle elements */ + GPtrArray *video_channels; /* links to selector pads */ + GPtrArray *audio_channels; /* links to selector pads */ + GPtrArray *text_channels; /* links to selector pads */ + /* uridecodebins for uri and subtitle uri */ GstElement *uridecodebin; GstElement *suburidecodebin; @@ -319,6 +324,9 @@ struct _GstPlayBin /* properties */ guint connection_speed; /* connection speed in bits/sec (0 = unknown) */ + gint current_video; /* the currently selected stream */ + gint current_audio; /* the currently selected stream */ + gint current_text; /* the currently selected stream */ /* our play sink */ GstPlaySink *playsink; @@ -330,7 +338,15 @@ struct _GstPlayBinClass { GstPipelineClass parent_class; - void (*about_to_finish) (void); + void (*about_to_finish) (GstPlayBin * playbin); + + void (*video_changed) (GstPlayBin * playbin); + void (*audio_changed) (GstPlayBin * playbin); + void (*text_changed) (GstPlayBin * playbin); + + GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream); + GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream); + GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream); }; /* props */ @@ -381,6 +397,12 @@ enum enum { SIGNAL_ABOUT_TO_FINISH, + SIGNAL_VIDEO_CHANGED, + SIGNAL_AUDIO_CHANGED, + SIGNAL_TEXT_CHANGED, + SIGNAL_GET_VIDEO_TAGS, + SIGNAL_GET_AUDIO_TAGS, + SIGNAL_GET_TEXT_TAGS, LAST_SIGNAL }; @@ -398,6 +420,13 @@ static GstStateChangeReturn gst_play_bin_change_state (GstElement * element, static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message); +static GstStructure *gst_play_bin_get_video_tags (GstPlayBin * playbin, + gint stream); +static GstStructure *gst_play_bin_get_audio_tags (GstPlayBin * playbin, + gint stream); +static GstStructure *gst_play_bin_get_text_tags (GstPlayBin * playbin, + gint stream); + static gboolean setup_next_source (GstPlayBin * playbin); static GstElementClass *parent_class; @@ -495,13 +524,11 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * * Get or set the currently playing video stream. By default the first video * stream with data is played. - * - * Setting this property to -2 will disable the video stream. */ g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO, g_param_spec_int ("current-video", "Current Video", - "Currently playing video stream (-1 = auto, -2 = none)", - -2, G_MAXINT, -1, G_PARAM_READWRITE)); + "Currently playing video stream (-1 = auto)", + -1, G_MAXINT, -1, G_PARAM_READWRITE)); /** * GstPlayBin:n-audio * @@ -515,13 +542,11 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * * Get or set the currently playing audio stream. By default the first audio * stream with data is played. - * - * Setting this property to -2 will disable the audio stream. */ g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO, g_param_spec_int ("current-audio", "Current audio", - "Currently playing audio stream (-1 = none, -2 = none)", - -2, G_MAXINT, -1, G_PARAM_READWRITE)); + "Currently playing audio stream (-1 = auto)", + -1, G_MAXINT, -1, G_PARAM_READWRITE)); /** * GstPlayBin:n-text * @@ -533,15 +558,13 @@ gst_play_bin_class_init (GstPlayBinClass * klass) /** * GstPlayBin:current-text * - * Get or set the currently playing subtitle stream. By default the first audio - * stream with data is played. - * - * Setting this property to -2 will disable the text stream. + * Get or set the currently playing subtitle stream. By default the first + * subtitle stream with data is played. */ g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT, g_param_spec_int ("current-text", "Current Text", - "Currently playing text stream (-1 = none, -2 = none)", - -2, G_MAXINT, -1, G_PARAM_READWRITE)); + "Currently playing text stream (-1 = auto)", + -1, G_MAXINT, -1, G_PARAM_READWRITE)); g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING, g_param_spec_string ("subtitle-encoding", "subtitle encoding", @@ -582,6 +605,7 @@ gst_play_bin_class_init (GstPlayBinClass * klass) 0, G_MAXUINT, DEFAULT_CONNECTION_SPEED, G_PARAM_READWRITE)); /** * GstPlayBin::about-to-finish: + * @playbin: a #GstPlayBin * * This signal is emitted when the current uri is about to finish. You can * set the next-uri and next-suburi to make sure that playback continues. @@ -592,6 +616,99 @@ gst_play_bin_class_init (GstPlayBinClass * klass) G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL, gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + /** + * GstPlayBin::video-changed + * @playbin: a #GstPlayBin + * + * This signal is emited whenever the number or order of the video + * streams has changed. The application will most likely want to select + * a new video stream. + */ + gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] = + g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL, + gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + /** + * GstPlayBin::audio-changed + * @playbin: a #GstPlayBin + * + * This signal is emited whenever the number or order of the audio + * streams has changed. The application will most likely want to select + * a new audio stream. + */ + gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] = + g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL, + gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + /** + * GstPlayBin::text-changed + * @playbin: a #GstPlayBin + * + * This signal is emited whenever the number or order of the text + * streams has changed. The application will most likely want to select + * a new text stream. + */ + gst_play_bin_signals[SIGNAL_TEXT_CHANGED] = + g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL, + gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + + /** + * GstPlayBin::get-video-tags + * @playbin: a #GstPlayBin + * @stream: a video stream number + * + * Action signal to retrieve the tags of a specific video stream number. + * This information can be used to select a stream. + * + * Returns: a GstTagList with tags or NULL when the stream number does not + * exist. + */ + gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] = + g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL, + gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT); + /** + * GstPlayBin::get-audio-tags + * @playbin: a #GstPlayBin + * @stream: an audio stream number + * + * Action signal to retrieve the tags of a specific audio stream number. + * This information can be used to select a stream. + * + * Returns: a GstTagList with tags or NULL when the stream number does not + * exist. + */ + gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] = + g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL, + gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT); + /** + * GstPlayBin::get-text-tags + * @playbin: a #GstPlayBin + * @stream: a text stream number + * + * Action signal to retrieve the tags of a specific text stream number. + * This information can be used to select a stream. + * + * Returns: a GstTagList with tags or NULL when the stream number does not + * exist. + */ + gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] = + g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL, + gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT); + + klass->get_video_tags = gst_play_bin_get_video_tags; + klass->get_audio_tags = gst_play_bin_get_audio_tags; + klass->get_text_tags = gst_play_bin_get_text_tags; + gst_element_class_set_details (gstelement_klass, &gst_play_bin_details); gstelement_klass->change_state = @@ -604,18 +721,27 @@ gst_play_bin_class_init (GstPlayBinClass * klass) static void init_group (GstPlayBin * playbin, GstSourceGroup * group) { + /* store the array for the different channels */ + group->video_channels = g_ptr_array_new (); + group->audio_channels = g_ptr_array_new (); + group->text_channels = g_ptr_array_new (); /* init selectors */ group->playbin = playbin; group->selector[0].media = "audio/x-raw-"; group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW; + group->selector[0].channels = group->audio_channels; group->selector[1].media = "audio/"; group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO; + group->selector[1].channels = group->audio_channels; group->selector[2].media = "video/x-raw-"; group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW; + group->selector[2].channels = group->video_channels; group->selector[3].media = "video/"; group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO; + group->selector[3].channels = group->video_channels; group->selector[4].media = "text/"; group->selector[4].type = GST_PLAY_SINK_TYPE_TEXT; + group->selector[4].channels = group->text_channels; } static void @@ -639,7 +765,9 @@ gst_play_bin_init (GstPlayBin * playbin) gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink)); gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS); - /* get the caps */ + playbin->current_video = DEFAULT_CURRENT_VIDEO; + playbin->current_audio = DEFAULT_CURRENT_AUDIO; + playbin->current_text = DEFAULT_CURRENT_TEXT; } static void @@ -698,6 +826,202 @@ done: GST_OBJECT_UNLOCK (playbin); } +/* 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 GstTagList * +get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream) +{ + GstTagList *result; + GstPad *sinkpad; + + if (!channels || channels->len < stream) + return NULL; + + sinkpad = g_ptr_array_index (channels, stream); + g_object_get (sinkpad, "tags", &result, NULL); + + return result; +} + +static GstTagList * +gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream) +{ + GstTagList *result; + GstSourceGroup *group; + + GST_OBJECT_LOCK (playbin); + group = get_group (playbin); + result = get_tags (playbin, group->video_channels, stream); + GST_OBJECT_UNLOCK (playbin); + + return result; +} + +static GstTagList * +gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream) +{ + GstTagList *result; + GstSourceGroup *group; + + GST_OBJECT_LOCK (playbin); + group = get_group (playbin); + result = get_tags (playbin, group->audio_channels, stream); + GST_OBJECT_UNLOCK (playbin); + + return result; +} + +static GstTagList * +gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream) +{ + GstTagList *result; + GstSourceGroup *group; + + GST_OBJECT_LOCK (playbin); + group = get_group (playbin); + result = get_tags (playbin, group->text_channels, stream); + GST_OBJECT_UNLOCK (playbin); + + return result; +} + +static gboolean +gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream) +{ + GstSourceGroup *group; + GPtrArray *channels; + GstPad *sinkpad; + + GST_OBJECT_LOCK (playbin); + group = get_group (playbin); + if (!(channels = group->video_channels)) + goto no_channels; + + if (stream == -1 || channels->len < stream) { + sinkpad = NULL; + } else { + /* take channel from selected stream */ + sinkpad = g_ptr_array_index (channels, stream); + } + + if (sinkpad) + gst_object_ref (sinkpad); + GST_OBJECT_UNLOCK (playbin); + + if (sinkpad) { + GstObject *selector; + + if ((selector = gst_pad_get_parent (sinkpad))) { + /* activate the selected pad */ + g_object_set (selector, "active-pad", sinkpad, NULL); + gst_object_unref (selector); + } + gst_object_unref (sinkpad); + } + return TRUE; + +no_channels: + { + GST_OBJECT_UNLOCK (playbin); + return FALSE; + } +} + +static gboolean +gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream) +{ + GstSourceGroup *group; + GPtrArray *channels; + GstPad *sinkpad; + + GST_OBJECT_LOCK (playbin); + group = get_group (playbin); + if (!(channels = group->audio_channels)) + goto no_channels; + + if (stream == -1 || channels->len < stream) { + sinkpad = NULL; + } else { + /* take channel from selected stream */ + sinkpad = g_ptr_array_index (channels, stream); + } + + if (sinkpad) + gst_object_ref (sinkpad); + GST_OBJECT_UNLOCK (playbin); + + if (sinkpad) { + GstObject *selector; + + if ((selector = gst_pad_get_parent (sinkpad))) { + /* activate the selected pad */ + g_object_set (selector, "active-pad", sinkpad, NULL); + gst_object_unref (selector); + } + gst_object_unref (sinkpad); + } + return TRUE; + +no_channels: + { + GST_OBJECT_UNLOCK (playbin); + return FALSE; + } +} + +static gboolean +gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream) +{ + GstSourceGroup *group; + GPtrArray *channels; + GstPad *sinkpad; + + GST_OBJECT_LOCK (playbin); + group = get_group (playbin); + if (!(channels = group->text_channels)) + goto no_channels; + + if (stream == -1 || channels->len < stream) { + sinkpad = NULL; + } else { + /* take channel from selected stream */ + sinkpad = g_ptr_array_index (channels, stream); + } + + if (sinkpad) + gst_object_ref (sinkpad); + GST_OBJECT_UNLOCK (playbin); + + if (sinkpad) { + GstObject *selector; + + if ((selector = gst_pad_get_parent (sinkpad))) { + /* activate the selected pad */ + g_object_set (selector, "active-pad", sinkpad, NULL); + gst_object_unref (selector); + } + gst_object_unref (sinkpad); + } + return TRUE; + +no_channels: + { + GST_OBJECT_UNLOCK (playbin); + return FALSE; + } +} + static void gst_play_bin_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -717,10 +1041,13 @@ gst_play_bin_set_property (GObject * object, guint prop_id, gst_play_sink_set_flags (playbin->playsink, g_value_get_flags (value)); break; case PROP_CURRENT_VIDEO: + gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value)); break; case PROP_CURRENT_AUDIO: + gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value)); break; case PROP_CURRENT_TEXT: + gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value)); break; case PROP_SUBTITLE_ENCODING: break; @@ -731,6 +1058,7 @@ gst_play_bin_set_property (GObject * object, guint prop_id, case PROP_VIS_PLUGIN: break; case PROP_VOLUME: + gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value)); break; case PROP_FONT_DESC: break; @@ -745,32 +1073,6 @@ 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) @@ -808,37 +1110,53 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value, case PROP_N_VIDEO: { GstSourceGroup *group; - gint n_rawvideo, n_video; + gint 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); + n_video = (group->video_channels ? group->video_channels->len : 0); + g_value_set_int (value, n_video); GST_OBJECT_UNLOCK (playbin); break; } case PROP_CURRENT_VIDEO: + GST_OBJECT_LOCK (playbin); + g_value_set_int (value, playbin->current_video); + GST_OBJECT_UNLOCK (playbin); break; case PROP_N_AUDIO: { GstSourceGroup *group; - gint n_rawaudio, n_audio; + gint 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); + n_audio = (group->audio_channels ? group->audio_channels->len : 0); + g_value_set_int (value, n_audio); GST_OBJECT_UNLOCK (playbin); break; } - break; case PROP_CURRENT_AUDIO: + GST_OBJECT_LOCK (playbin); + g_value_set_int (value, playbin->current_audio); + GST_OBJECT_UNLOCK (playbin); break; case PROP_N_TEXT: + { + GstSourceGroup *group; + gint n_text; + + GST_OBJECT_LOCK (playbin); + group = get_group (playbin); + n_text = (group->text_channels ? group->text_channels->len : 0); + g_value_set_int (value, n_text); + GST_OBJECT_UNLOCK (playbin); break; + } case PROP_CURRENT_TEXT: + GST_OBJECT_LOCK (playbin); + g_value_set_int (value, playbin->current_text); + GST_OBJECT_UNLOCK (playbin); break; case PROP_SUBTITLE_ENCODING: break; @@ -849,6 +1167,7 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value, case PROP_VIS_PLUGIN: break; case PROP_VOLUME: + g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink)); break; case PROP_FRAME: break; @@ -929,6 +1248,9 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) if (select == NULL) goto unknown_type; + /* store the selector for the pad */ + g_object_set_data (G_OBJECT (pad), "playbin2.select", select); + if (select->selector == NULL) { /* no selector, create one */ GST_DEBUG_OBJECT (playbin, "creating new selector"); @@ -948,12 +1270,16 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) { GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector", GST_DEBUG_PAD_NAME (sinkpad)); + + /* store the pad in the array */ + g_ptr_array_add (select->channels, sinkpad); + res = gst_pad_link (pad, sinkpad); if (GST_PAD_LINK_FAILED (res)) goto link_failed; /* store selector pad so we can release it */ - g_object_set_data (G_OBJECT (pad), "playbin2.selector", sinkpad); + g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad); } GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p", GST_DEBUG_PAD_NAME (pad), select->selector); @@ -990,15 +1316,20 @@ pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) GstPlayBin *playbin; GstPad *peer; GstElement *selector; + GstSourceSelect *select; playbin = group->playbin; GST_DEBUG_OBJECT (playbin, "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group); + if ((select = g_object_get_data (G_OBJECT (pad), "playbin2.select"))) { + /* remove the pad from the array */ + g_ptr_array_remove (select->channels, pad); + } + /* get the selector sinkpad */ - peer = g_object_get_data (G_OBJECT (pad), "playbin2.selector"); - if (!peer) + if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad"))) goto not_linked; /* unlink the pad now (can fail, the pad is unlinked before it's removed) */ diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index 105233f..8eedf00 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -33,7 +33,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_play_sink_debug); #define GST_CAT_DEFAULT gst_play_sink_debug #define VOLUME_MAX_DOUBLE 10.0 -#define CONNECTION_SPEED_DEFAULT 0 /* holds the common data fields for the audio and video pipelines. We keep them * in a structure to more easily have all the info available. */ @@ -519,6 +518,39 @@ gst_play_sink_set_vis_plugin (GstPlaySink * playsink, } } +void +gst_play_sink_set_volume (GstPlaySink * playsink, gdouble volume) +{ + GstPlayAudioChain *chain; + + GST_PLAY_SINK_LOCK (playsink); + playsink->volume = volume; + chain = (GstPlayAudioChain *) playsink->audiochain; + if (chain && chain->volume) { + g_object_set (chain->volume, "volume", volume, NULL); + } + GST_PLAY_SINK_UNLOCK (playsink); +} + +gdouble +gst_play_sink_get_volume (GstPlaySink * playsink) +{ + gdouble result; + GstPlayAudioChain *chain; + + GST_PLAY_SINK_LOCK (playsink); + chain = (GstPlayAudioChain *) playsink->audiochain; + if (chain && chain->volume) { + g_object_get (chain->volume, "volume", &result, NULL); + playsink->volume = result; + } else { + result = playsink->volume; + } + GST_PLAY_SINK_UNLOCK (playsink); + + return result; +} + static void gst_play_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -538,9 +570,7 @@ gst_play_sink_set_property (GObject * object, guint prop_id, gst_play_sink_set_vis_plugin (playsink, g_value_get_object (value)); break; case PROP_VOLUME: - GST_OBJECT_LOCK (playsink); - playsink->volume = g_value_get_double (value); - GST_OBJECT_UNLOCK (playsink); + gst_play_sink_set_volume (playsink, g_value_get_double (value)); break; case PROP_FONT_DESC: GST_OBJECT_LOCK (playsink); @@ -583,9 +613,7 @@ gst_play_sink_get_property (GObject * object, guint prop_id, GValue * value, GST_OBJECT_UNLOCK (playsink); break; case PROP_VOLUME: - GST_OBJECT_LOCK (playsink); - g_value_set_double (value, playsink->volume); - GST_OBJECT_UNLOCK (playsink); + g_value_set_double (value, gst_play_sink_get_volume (playsink)); break; case PROP_FRAME: { @@ -914,8 +942,11 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw) res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink"); + /* FIXME check if the sink has the volume property */ + if (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) { chain->volume = gst_element_factory_make ("volume", "volume"); + /* configure with the latest volume */ g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL); gst_bin_add (bin, chain->volume); diff --git a/gst/playback/gstplaysink.h b/gst/playback/gstplaysink.h index 6373edd..ec89f41 100644 --- a/gst/playback/gstplaysink.h +++ b/gst/playback/gstplaysink.h @@ -69,6 +69,9 @@ void gst_play_sink_set_video_sink (GstPlaySink * playsink, GstElemen void gst_play_sink_set_audio_sink (GstPlaySink * playsink, GstElement * sink); void gst_play_sink_set_vis_plugin (GstPlaySink * playsink, GstElement * vis); +void gst_play_sink_set_volume (GstPlaySink *playsink, gdouble volume); +gdouble gst_play_sink_get_volume (GstPlaySink *playsink); + gboolean gst_play_sink_set_flags (GstPlaySink * playsink, GstPlayFlags flags); GstPlayFlags gst_play_sink_get_flags (GstPlaySink * playsink); diff --git a/gst/playback/gststreamselector.c b/gst/playback/gststreamselector.c index 9681f01..87604b9 100644 --- a/gst/playback/gststreamselector.c +++ b/gst/playback/gststreamselector.c @@ -91,6 +91,7 @@ struct _GstSelectorPad gboolean eos; gboolean segment_pending; GstSegment segment; + GstTagList *tags; }; struct _GstSelectorPadClass @@ -102,6 +103,9 @@ static void gst_selector_pad_class_init (GstSelectorPadClass * klass); static void gst_selector_pad_init (GstSelectorPad * pad); static void gst_selector_pad_finalize (GObject * object); +static void gst_selector_pad_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); + static GstPadClass *selector_pad_parent_class = NULL; static void gst_selector_pad_reset (GstSelectorPad * pad); @@ -112,6 +116,14 @@ static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf); static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); +enum +{ + PROP_PAD_0, + PROP_PAD_TAGS, + PROP_PAD_ACTIVE, + PROP_PAD_LAST +}; + static GType gst_selector_pad_get_type (void) { @@ -147,6 +159,17 @@ gst_selector_pad_class_init (GstSelectorPadClass * klass) selector_pad_parent_class = g_type_class_peek_parent (klass); gobject_class->finalize = gst_selector_pad_finalize; + gobject_class->get_property = + GST_DEBUG_FUNCPTR (gst_selector_pad_get_property); + + g_object_class_install_property (gobject_class, PROP_PAD_TAGS, + g_param_spec_boxed ("tags", "Tags", + "The currently active tags on the pad", GST_TYPE_TAG_LIST, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_PAD_ACTIVE, + g_param_spec_boolean ("active", "Active", + "If the pad is currently active", FALSE, G_PARAM_READABLE)); } static void @@ -162,10 +185,43 @@ gst_selector_pad_finalize (GObject * object) pad = GST_SELECTOR_PAD_CAST (object); + if (pad->tags) + gst_tag_list_free (pad->tags); + G_OBJECT_CLASS (selector_pad_parent_class)->finalize (object); } static void +gst_selector_pad_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstSelectorPad *pad; + + pad = GST_SELECTOR_PAD (object); + + switch (prop_id) { + case PROP_PAD_TAGS: + GST_OBJECT_LOCK (object); + g_value_set_boxed (value, pad->tags); + GST_OBJECT_UNLOCK (object); + break; + case PROP_PAD_ACTIVE: + { + GstStreamSelector *sel; + + sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); + g_value_set_boolean (value, gst_stream_selector_is_active_sinkpad (sel, + GST_PAD_CAST (pad))); + gst_object_unref (sel); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gst_selector_pad_reset (GstSelectorPad * pad) { pad->active = FALSE; @@ -232,6 +288,21 @@ gst_selector_pad_event (GstPad * pad, GstEvent * event) selpad->segment_pending = TRUE; break; } + case GST_EVENT_TAG: + { + GstTagList *tags; + + GST_OBJECT_LOCK (selpad); + if (selpad->tags) + gst_tag_list_free (selpad->tags); + gst_event_parse_tag (event, &tags); + if (tags) + tags = gst_tag_list_copy (tags); + selpad->tags = tags; + GST_DEBUG_OBJECT (sel, "received tags %" GST_PTR_FORMAT, selpad->tags); + GST_OBJECT_UNLOCK (selpad); + break; + } case GST_EVENT_EOS: selpad->eos = TRUE; break; @@ -364,19 +435,24 @@ ignore: } static void gst_stream_selector_dispose (GObject * object); +static void gst_stream_selector_finalize (GObject * object); + static void gst_stream_selector_init (GstStreamSelector * sel); static void gst_stream_selector_base_init (GstStreamSelectorClass * klass); static void gst_stream_selector_class_init (GstStreamSelectorClass * klass); + static void gst_stream_selector_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_stream_selector_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); + static GstPad *gst_stream_selector_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * unused); static void gst_stream_selector_release_pad (GstElement * element, GstPad * pad); static GList *gst_stream_selector_get_linked_pads (GstPad * pad); static GstCaps *gst_stream_selector_getcaps (GstPad * pad); + static GstElementClass *parent_class = NULL; GType @@ -427,17 +503,19 @@ gst_stream_selector_class_init (GstStreamSelectorClass * klass) parent_class = g_type_class_peek_parent (klass); gobject_class->dispose = gst_stream_selector_dispose; + gobject_class->finalize = gst_stream_selector_finalize; + 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_param_spec_uint ("n-pads", "Number of Pads", + "The number of sink pads", 0, G_MAXUINT, 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)); + g_param_spec_object ("active-pad", "Active Pad", + "The currently active sink pad", GST_TYPE_PAD, G_PARAM_READWRITE)); gstelement_class->request_new_pad = gst_stream_selector_request_new_pad; gstelement_class->release_pad = gst_stream_selector_release_pad; @@ -453,9 +531,8 @@ gst_stream_selector_init (GstStreamSelector * sel) GST_DEBUG_FUNCPTR (gst_stream_selector_getcaps)); gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad); /* sinkpad management */ - sel->active_sinkpad = NULL; sel->padcount = 0; - sel->n_pads = 0; + sel->active_sinkpad = NULL; gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED); } @@ -473,19 +550,29 @@ gst_stream_selector_dispose (GObject * object) } static void +gst_stream_selector_finalize (GObject * object) +{ + GstStreamSelector *sel; + + sel = GST_STREAM_SELECTOR (object); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void gst_stream_selector_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstStreamSelector *sel = GST_STREAM_SELECTOR (object); switch (prop_id) { - case PROP_ACTIVE_PAD:{ - const gchar *pad_name = g_value_get_string (value); + case PROP_ACTIVE_PAD: + { GstPad *pad = NULL; GstPad **active_pad_p; - if (strcmp (pad_name, "") != 0) - pad = gst_element_get_pad (GST_ELEMENT (object), pad_name); + pad = g_value_get_object (value); + GST_OBJECT_LOCK (object); if (pad != sel->active_sinkpad) { GstSelectorPad *selpad; @@ -504,8 +591,6 @@ gst_stream_selector_set_property (GObject * object, guint prop_id, } } GST_OBJECT_UNLOCK (object); - if (pad) - gst_object_unref (pad); break; } default: @@ -523,16 +608,12 @@ gst_stream_selector_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_N_PADS: GST_OBJECT_LOCK (object); - g_value_set_int (value, sel->n_pads); + g_value_set_uint (value, sel->n_pads); GST_OBJECT_UNLOCK (object); break; case PROP_ACTIVE_PAD:{ GST_OBJECT_LOCK (object); - if (sel->active_sinkpad != NULL) { - g_value_take_string (value, gst_pad_get_name (sel->active_sinkpad)); - } else { - g_value_set_string (value, ""); - } + g_value_set_object (value, sel->active_sinkpad); GST_OBJECT_UNLOCK (object); break; } @@ -549,6 +630,7 @@ gst_stream_selector_get_linked_pad (GstPad * pad, gboolean strict) GstPad *otherpad = NULL; sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); + GST_OBJECT_LOCK (sel); if (pad == sel->srcpad) otherpad = sel->active_sinkpad; @@ -653,10 +735,10 @@ gst_stream_selector_request_new_pad (GstElement * element, GST_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount); GST_OBJECT_LOCK (sel); 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); + sel->n_pads++; GST_OBJECT_UNLOCK (sel); gst_pad_set_event_function (sinkpad, diff --git a/gst/playback/gststreamselector.h b/gst/playback/gststreamselector.h index d64da77..5200a0b 100644 --- a/gst/playback/gststreamselector.h +++ b/gst/playback/gststreamselector.h @@ -44,10 +44,9 @@ struct _GstStreamSelector { GstPad *srcpad; - guint padcount; - GstPad *active_sinkpad; guint n_pads; + guint padcount; GstSegment segment; }; -- 2.7.4