From 105da803ade859fb299ed3c5265d6acdd168ca8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 15 Mar 2011 12:51:04 +0100 Subject: [PATCH] playbin2/playsink: Decide if A/V caps are raw only inside playsink Before playbin2 would use different selectors for raw audio and compressed audio (and the same for video) and used different pads from playsink. This made the involved logic much more complex and was not implemented completely in playsink, which made it impossible to support files with a compressed and uncompressed stream that is support by the sink. playbin2 handles raw/non-raw streams the same now and the decision is left to playsink, which now can also handle caps changes from raw to non-raw and the other way around. Fixes bug #632788. --- gst/playback/gstplaybin2.c | 84 +++++----- gst/playback/gstplaysink.c | 303 +++++++++++++++++++++++++++++++++---- gst/playback/gstplaysink.h | 10 +- 3 files changed, 328 insertions(+), 69 deletions(-) diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index 5f0f964cd8..c46f1108f4 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) <2007> Wim Taymans + * Copyright (C) <2011> Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -271,6 +272,14 @@ struct _GstSourceSelect #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group))) #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group))) +enum +{ + PLAYBIN_STREAM_AUDIO = 0, + PLAYBIN_STREAM_VIDEO, + PLAYBIN_STREAM_TEXT, + PLAYBIN_STREAM_LAST +}; + /* a structure to hold the objects for decoding a uri and the subtitle uri */ struct _GstSourceGroup @@ -319,7 +328,7 @@ struct _GstSourceGroup GList *stream_changed_pending; /* selectors for different streams */ - GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST]; + GstSourceSelect selector[PLAYBIN_STREAM_LAST]; }; #define GST_PLAY_BIN_GET_LOCK(bin) (&((GstPlayBin*)(bin))->lock) @@ -1089,30 +1098,25 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group) /* If you add any items to these lists, check that media_list[] is defined * above to be large enough to hold MAX(items)+1, so as to accomodate a * NULL terminator (set when the memory is zeroed on allocation) */ - group->selector[0].media_list[0] = "audio/x-raw-"; - group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW; - group->selector[0].channels = group->audio_channels; - group->selector[1].media_list[0] = "audio/"; - group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO; - group->selector[1].channels = group->audio_channels; - group->selector[2].media_list[0] = "text/"; - group->selector[2].media_list[1] = "application/x-subtitle"; - group->selector[2].media_list[2] = "application/x-ssa"; - group->selector[2].media_list[3] = "application/x-ass"; - group->selector[2].media_list[4] = "video/x-dvd-subpicture"; - group->selector[2].media_list[5] = "subpicture/"; - group->selector[2].media_list[6] = "subtitle/"; - group->selector[2].get_media_caps = gst_subtitle_overlay_create_factory_caps; - group->selector[2].type = GST_PLAY_SINK_TYPE_TEXT; - group->selector[2].channels = group->text_channels; - group->selector[3].media_list[0] = "video/x-raw-"; - group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO_RAW; - group->selector[3].channels = group->video_channels; - group->selector[4].media_list[0] = "video/"; - group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO; - group->selector[4].channels = group->video_channels; + group->selector[PLAYBIN_STREAM_AUDIO].media_list[0] = "audio/"; + group->selector[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO; + group->selector[PLAYBIN_STREAM_AUDIO].channels = group->audio_channels; + group->selector[PLAYBIN_STREAM_VIDEO].media_list[0] = "video/"; + group->selector[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO; + group->selector[PLAYBIN_STREAM_VIDEO].channels = group->video_channels; + group->selector[PLAYBIN_STREAM_TEXT].media_list[0] = "text/"; + group->selector[PLAYBIN_STREAM_TEXT].media_list[1] = "application/x-subtitle"; + group->selector[PLAYBIN_STREAM_TEXT].media_list[2] = "application/x-ssa"; + group->selector[PLAYBIN_STREAM_TEXT].media_list[3] = "application/x-ass"; + group->selector[PLAYBIN_STREAM_TEXT].media_list[4] = "video/x-dvd-subpicture"; + group->selector[PLAYBIN_STREAM_TEXT].media_list[5] = "subpicture/"; + group->selector[PLAYBIN_STREAM_TEXT].media_list[6] = "subtitle/"; + group->selector[PLAYBIN_STREAM_TEXT].get_media_caps = + gst_subtitle_overlay_create_factory_caps; + group->selector[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT; + group->selector[PLAYBIN_STREAM_TEXT].channels = group->text_channels; - for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) { + for (n = 0; n < PLAYBIN_STREAM_LAST; n++) { GstSourceSelect *select = &group->selector[n]; select->sinkpad_delayed_event = NULL; select->sinkpad_data_probe = 0; @@ -1124,7 +1128,7 @@ free_group (GstPlayBin * playbin, GstSourceGroup * group) { int n; - for (n = 0; n < GST_PLAY_SINK_TYPE_LAST; n++) { + for (n = 0; n < PLAYBIN_STREAM_LAST; n++) { GstSourceSelect *select = &group->selector[n]; if (select->sinkpad && select->sinkpad_data_probe) gst_pad_remove_data_probe (select->sinkpad, select->sinkpad_data_probe); @@ -1493,6 +1497,10 @@ gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream) GstPad *sinkpad; GST_PLAY_BIN_LOCK (playbin); + + GST_DEBUG_OBJECT (playbin, "Changing current video stream %d -> %d", + playbin->current_video, stream); + group = get_group (playbin); if (!(channels = group->video_channels)) goto no_channels; @@ -1536,6 +1544,10 @@ gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream) GstPad *sinkpad; GST_PLAY_BIN_LOCK (playbin); + + GST_DEBUG_OBJECT (playbin, "Changing current audio stream %d -> %d", + playbin->current_audio, stream); + group = get_group (playbin); if (!(channels = group->audio_channels)) goto no_channels; @@ -1647,6 +1659,10 @@ gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream) GstPad *sinkpad; GST_PLAY_BIN_LOCK (playbin); + + GST_DEBUG_OBJECT (playbin, "Changing current text stream %d -> %d", + playbin->current_text, stream); + group = get_group (playbin); if (!(channels = group->text_channels)) goto no_channels; @@ -2306,7 +2322,7 @@ selector_active_pad_changed (GObject * selector, GParamSpec * pspec, GST_PLAY_BIN_LOCK (playbin); group = get_group (playbin); - for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { + for (i = 0; i < PLAYBIN_STREAM_LAST; i++) { if (selector == G_OBJECT (group->selector[i].selector)) { select = &group->selector[i]; } @@ -2392,7 +2408,7 @@ array_has_value (const gchar * values[], const gchar * value) gint i; for (i = 0; values[i]; i++) { - if (g_str_has_prefix (value, values[i])) + if (values[i] && g_str_has_prefix (value, values[i])) return TRUE; } return FALSE; @@ -2464,7 +2480,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 < GST_PLAY_SINK_TYPE_LAST; i++) { + for (i = 0; i < PLAYBIN_STREAM_LAST; i++) { if (array_has_value (group->selector[i].media_list, name)) { select = &group->selector[i]; break; @@ -2723,7 +2739,7 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group) GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown); GST_SOURCE_GROUP_LOCK (group); - for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { + for (i = 0; i < PLAYBIN_STREAM_LAST; i++) { GstSourceSelect *select = &group->selector[i]; /* check if the specific media type was detected and thus has a selector @@ -2786,14 +2802,10 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group) GST_SOURCE_GROUP_UNLOCK (group); - GST_LOG_OBJECT (playbin, "reconfigure sink"); - /* we configure the modes if we were the last decodebin to complete. */ - gst_play_sink_reconfigure (playbin->playsink); - /* signal the other decodebins that they can continue now. */ GST_SOURCE_GROUP_LOCK (group); /* unblock all selectors */ - for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { + for (i = 0; i < PLAYBIN_STREAM_LAST; i++) { GstSourceSelect *select = &group->selector[i]; /* All streamsynchronizer streams should see stream-changed message, @@ -2859,7 +2871,7 @@ shutdown: * instead of a NOT_LINKED error. */ GST_SOURCE_GROUP_LOCK (group); - for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { + for (i = 0; i < PLAYBIN_STREAM_LAST; i++) { GstSourceSelect *select = &group->selector[i]; if (select->srcpad) { @@ -3457,7 +3469,7 @@ deactivate_group (GstPlayBin * playbin, GstSourceGroup * group) GST_SOURCE_GROUP_LOCK (group); group->active = FALSE; - for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { + for (i = 0; i < PLAYBIN_STREAM_LAST; i++) { GstSourceSelect *select = &group->selector[i]; GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]); diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index 326baa6917..3661af363c 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) <2007> Wim Taymans + * Copyright (C) <2011> Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -149,6 +150,7 @@ struct _GstPlaySink /* audio */ GstPad *audio_pad; gboolean audio_pad_raw; + gboolean audio_pad_blocked; GstPad *audio_srcpad_stream_synchronizer; GstPad *audio_sinkpad_stream_synchronizer; /* audio tee */ @@ -159,10 +161,12 @@ struct _GstPlaySink /* video */ GstPad *video_pad; gboolean video_pad_raw; + gboolean video_pad_blocked; GstPad *video_srcpad_stream_synchronizer; GstPad *video_sinkpad_stream_synchronizer; /* text */ GstPad *text_pad; + gboolean text_pad_blocked; GstPad *text_srcpad_stream_synchronizer; GstPad *text_sinkpad_stream_synchronizer; @@ -191,21 +195,12 @@ struct _GstPlaySinkClass GstBuffer *(*convert_frame) (GstPlaySink * playsink, GstCaps * caps); }; -static GstStaticPadTemplate audiorawtemplate = -GST_STATIC_PAD_TEMPLATE ("audio_raw_sink", - GST_PAD_SINK, - GST_PAD_REQUEST, - GST_STATIC_CAPS_ANY); + static GstStaticPadTemplate audiotemplate = GST_STATIC_PAD_TEMPLATE ("audio_sink", GST_PAD_SINK, GST_PAD_REQUEST, GST_STATIC_CAPS_ANY); -static GstStaticPadTemplate videorawtemplate = -GST_STATIC_PAD_TEMPLATE ("video_raw_sink", - GST_PAD_SINK, - GST_PAD_REQUEST, - GST_STATIC_CAPS_ANY); static GstStaticPadTemplate videotemplate = GST_STATIC_PAD_TEMPLATE ("video_sink", GST_PAD_SINK, @@ -216,6 +211,19 @@ static GstStaticPadTemplate texttemplate = GST_STATIC_PAD_TEMPLATE ("text_sink", GST_PAD_REQUEST, GST_STATIC_CAPS_ANY); +/* FIXME 0.11: Remove */ +static GstStaticPadTemplate audiorawtemplate = +GST_STATIC_PAD_TEMPLATE ("audio_raw_sink", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS_ANY); +static GstStaticPadTemplate videorawtemplate = +GST_STATIC_PAD_TEMPLATE ("video_raw_sink", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS_ANY); + + /* props */ enum { @@ -613,6 +621,7 @@ gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type) GST_PLAY_SINK_LOCK (playsink); switch (type) { case GST_PLAY_SINK_TYPE_AUDIO: + case GST_PLAY_SINK_TYPE_AUDIO_RAW: { GstPlayAudioChain *chain; if ((chain = (GstPlayAudioChain *) playsink->audiochain)) @@ -621,6 +630,7 @@ gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type) break; } case GST_PLAY_SINK_TYPE_VIDEO: + case GST_PLAY_SINK_TYPE_VIDEO_RAW: { GstPlayVideoChain *chain; if ((chain = (GstPlayVideoChain *) playsink->videochain)) @@ -1077,7 +1087,7 @@ try_element (GstPlaySink * playsink, GstElement * element, gboolean unref) } /* make the element (bin) that contains the elements needed to perform - * video display. + * video display. Only used for *raw* video streams. * * +------------------------------------------------------------+ * | vbin | @@ -1378,13 +1388,13 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) chain = playsink->videochain; + if (chain->chain.raw != raw) + return FALSE; + /* if the chain was active we don't do anything */ if (GST_PLAY_CHAIN (chain)->activated == TRUE) return TRUE; - if (chain->chain.raw != raw) - return FALSE; - /* try to set the sink element to READY again */ ret = gst_element_set_state (chain->sink, GST_STATE_READY); if (ret == GST_STATE_CHANGE_FAILURE) @@ -1413,6 +1423,7 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) } /* make an element for playback of video with subtitles embedded. + * Only used for *raw* video streams. * * +--------------------------------------------+ * | tbin | @@ -1910,13 +1921,13 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw) chain = playsink->audiochain; + if (chain->chain.raw != raw) + return FALSE; + /* if the chain was active we don't do anything */ if (GST_PLAY_CHAIN (chain)->activated == TRUE) return TRUE; - if (chain->chain.raw != raw) - return FALSE; - /* try to set the sink element to READY again */ ret = gst_element_set_state (chain->sink, GST_STATE_READY); if (ret == GST_STATE_CHANGE_FAILURE) @@ -2849,6 +2860,200 @@ gst_play_sink_convert_frame (GstPlaySink * playsink, GstCaps * caps) return result; } +static gboolean +is_raw_structure (GstStructure * s) +{ + const gchar *name; + + name = gst_structure_get_name (s); + + if (g_str_has_prefix (name, "video/x-raw-") || + g_str_has_prefix (name, "audio/x-raw-")) + return TRUE; + return FALSE; +} + +static gboolean +is_raw_pad (GstPad * pad) +{ + GstPad *peer = gst_pad_get_peer (pad); + GstCaps *caps; + gboolean raw = TRUE; + + if (!peer) + return raw; + + caps = gst_pad_get_negotiated_caps (peer); + if (!caps) { + guint i, n; + + caps = gst_pad_get_caps_reffed (peer); + + n = gst_caps_get_size (caps); + for (i = 0; i < n; i++) { + gboolean r = is_raw_structure (gst_caps_get_structure (caps, i)); + + if (i == 0) { + raw = r; + } else if (raw != r) { + GST_ERROR_OBJECT (pad, + "Caps contains raw and non-raw structures: %" GST_PTR_FORMAT, caps); + raw = FALSE; + break; + } + } + } else { + raw = is_raw_structure (gst_caps_get_structure (caps, 0)); + } + gst_caps_unref (caps); + gst_object_unref (peer); + + return raw; +} + +static GstPad * +get_internally_linked_pad (GstPad * pad) +{ + GstIterator *it; + GstPad *res = NULL; + + it = gst_pad_iterate_internal_links (pad); + if (!it) + return NULL; + + gst_iterator_next (it, (gpointer) & res); + gst_iterator_free (it); + + return res; +} + +static void +sinkpad_blocked_cb (GstPad * blockedpad, gboolean blocked, gpointer user_data) +{ + GstPlaySink *playsink = (GstPlaySink *) user_data; + GstPad *pad; + + GST_PLAY_SINK_LOCK (playsink); + + pad = get_internally_linked_pad (blockedpad); + if (pad == playsink->video_pad) { + playsink->video_pad_blocked = blocked; + GST_DEBUG_OBJECT (pad, "Video pad blocked: %d", blocked); + } else if (pad == playsink->audio_pad) { + playsink->audio_pad_blocked = blocked; + GST_DEBUG_OBJECT (pad, "Audio pad blocked: %d", blocked); + } else if (pad == playsink->text_pad) { + playsink->text_pad_blocked = blocked; + GST_DEBUG_OBJECT (pad, "Text pad blocked: %d", blocked); + } + + if (!blocked) { + gst_object_unref (pad); + GST_PLAY_SINK_UNLOCK (playsink); + return; + } + + if ((!playsink->video_pad || playsink->video_pad_blocked) && + (!playsink->audio_pad || playsink->audio_pad_blocked) && + (!playsink->text_pad || playsink->text_pad_blocked)) { + GST_DEBUG_OBJECT (playsink, "All pads blocked -- reconfiguring"); + + if (playsink->video_pad) { + playsink->video_pad_raw = is_raw_pad (playsink->video_pad); + GST_DEBUG_OBJECT (playsink, "Video pad is raw: %d", + playsink->video_pad_raw); + } + + if (playsink->audio_pad) { + playsink->audio_pad_raw = is_raw_pad (playsink->audio_pad); + GST_DEBUG_OBJECT (playsink, "Audio pad is raw: %d", + playsink->audio_pad_raw); + } + + gst_play_sink_reconfigure (playsink); + + if (playsink->video_pad) { + GstPad *opad = get_internally_linked_pad (playsink->video_pad); + gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + gst_object_unref (opad); + } + + if (playsink->audio_pad) { + GstPad *opad = get_internally_linked_pad (playsink->audio_pad); + gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + gst_object_unref (opad); + } + + if (playsink->text_pad) { + GstPad *opad = get_internally_linked_pad (playsink->text_pad); + gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + gst_object_unref (opad); + } + } + + gst_object_unref (pad); + + GST_PLAY_SINK_UNLOCK (playsink); +} + +static void +caps_notify_cb (GstPad * pad, GParamSpec * unused, GstPlaySink * playsink) +{ + gboolean reconfigure = FALSE; + GstCaps *caps; + gboolean raw; + + g_object_get (pad, "caps", &caps, NULL); + if (!caps) + return; + + if (pad == playsink->audio_pad) { + raw = is_raw_pad (pad); + reconfigure = (! !playsink->audio_pad_raw != ! !raw) + && playsink->audiochain; + GST_DEBUG_OBJECT (pad, + "Audio caps changed: raw %d reconfigure %d caps %" GST_PTR_FORMAT, raw, + reconfigure, caps); + } else if (pad == playsink->video_pad) { + raw = is_raw_pad (pad); + reconfigure = (! !playsink->video_pad_raw != ! !raw) + && playsink->videochain; + GST_DEBUG_OBJECT (pad, + "Video caps changed: raw %d reconfigure %d caps %" GST_PTR_FORMAT, raw, + reconfigure, caps); + } + + gst_caps_unref (caps); + + if (reconfigure) { + GST_PLAY_SINK_LOCK (playsink); + if (playsink->video_pad) { + GstPad *opad = get_internally_linked_pad (playsink->video_pad); + gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + gst_object_unref (opad); + } + + if (playsink->audio_pad) { + GstPad *opad = get_internally_linked_pad (playsink->audio_pad); + gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + gst_object_unref (opad); + } + + if (playsink->text_pad) { + GstPad *opad = get_internally_linked_pad (playsink->text_pad); + gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + gst_object_unref (opad); + } + GST_PLAY_SINK_UNLOCK (playsink); + } +} + /** * gst_play_sink_request_pad * @playsink: a #GstPlaySink @@ -2863,7 +3068,6 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type) { GstPad *res = NULL; gboolean created = FALSE; - gboolean raw = FALSE; gboolean activate = TRUE; const gchar *pad_name = NULL; @@ -2872,11 +3076,8 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type) GST_PLAY_SINK_LOCK (playsink); switch (type) { case GST_PLAY_SINK_TYPE_AUDIO_RAW: - pad_name = "audio_raw_sink"; - raw = TRUE; case GST_PLAY_SINK_TYPE_AUDIO: - if (pad_name == NULL) - pad_name = "audio_sink"; + pad_name = "audio_sink"; if (!playsink->audio_tee) { GST_LOG_OBJECT (playsink, "creating tee"); /* create tee when needed. This element will feed the audio sink chain @@ -2902,24 +3103,25 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type) GST_LOG_OBJECT (playsink, "ghosting tee sinkpad"); playsink->audio_pad = gst_ghost_pad_new (pad_name, playsink->audio_tee_sink); + g_signal_connect (G_OBJECT (playsink->audio_pad), "notify::caps", + G_CALLBACK (caps_notify_cb), playsink); created = TRUE; } - playsink->audio_pad_raw = raw; + playsink->audio_pad_raw = FALSE; res = playsink->audio_pad; break; case GST_PLAY_SINK_TYPE_VIDEO_RAW: - pad_name = "video_raw_sink"; - raw = TRUE; case GST_PLAY_SINK_TYPE_VIDEO: - if (pad_name == NULL) - pad_name = "video_sink"; + pad_name = "video_sink"; if (!playsink->video_pad) { GST_LOG_OBJECT (playsink, "ghosting videosink"); playsink->video_pad = gst_ghost_pad_new_no_target (pad_name, GST_PAD_SINK); + g_signal_connect (G_OBJECT (playsink->video_pad), "notify::caps", + G_CALLBACK (caps_notify_cb), playsink); created = TRUE; } - playsink->video_pad_raw = raw; + playsink->video_pad_raw = FALSE; res = playsink->video_pad; break; case GST_PLAY_SINK_TYPE_TEXT: @@ -2955,6 +3157,13 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type) * element is 'running' */ gst_pad_set_active (res, TRUE); gst_element_add_pad (GST_ELEMENT_CAST (playsink), res); + if (type != GST_PLAY_SINK_TYPE_FLUSHING) { + GstPad *blockpad = get_internally_linked_pad (res); + + gst_pad_set_blocked_async_full (blockpad, TRUE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + gst_object_unref (blockpad); + } if (!activate) gst_pad_set_active (res, activate); } @@ -3011,8 +3220,12 @@ gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad) GST_PLAY_SINK_LOCK (playsink); if (pad == playsink->video_pad) { res = &playsink->video_pad; + g_signal_handlers_disconnect_by_func (playsink->video_pad, caps_notify_cb, + playsink); } else if (pad == playsink->audio_pad) { res = &playsink->audio_pad; + g_signal_handlers_disconnect_by_func (playsink->audio_pad, caps_notify_cb, + playsink); } else if (pad == playsink->text_pad) { res = &playsink->text_pad; } else { @@ -3193,6 +3406,40 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) ret = GST_STATE_CHANGE_ASYNC; break; case GST_STATE_CHANGE_PAUSED_TO_READY: + /* unblock all pads here */ + GST_PLAY_SINK_LOCK (playsink); + if (playsink->video_pad) { + GstPad *opad = get_internally_linked_pad (playsink->video_pad); + if (gst_pad_is_blocked (opad)) { + gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + } + gst_object_unref (opad); + playsink->video_pad_blocked = FALSE; + } + + if (playsink->audio_pad) { + GstPad *opad = get_internally_linked_pad (playsink->audio_pad); + + if (gst_pad_is_blocked (opad)) { + gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + } + gst_object_unref (opad); + playsink->audio_pad_blocked = FALSE; + } + + if (playsink->text_pad) { + GstPad *opad = get_internally_linked_pad (playsink->text_pad); + if (gst_pad_is_blocked (opad)) { + gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb, + gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); + } + gst_object_unref (opad); + playsink->text_pad_blocked = FALSE; + } + GST_PLAY_SINK_UNLOCK (playsink); + /* fall through */ case GST_STATE_CHANGE_READY_TO_NULL: if (playsink->audiochain && playsink->audiochain->sink_volume) { /* remove our links to the mute and volume elements when they were diff --git a/gst/playback/gstplaysink.h b/gst/playback/gstplaysink.h index 3ca96d3fbd..6759ea438e 100644 --- a/gst/playback/gstplaysink.h +++ b/gst/playback/gstplaysink.h @@ -41,11 +41,11 @@ G_BEGIN_DECLS /** * GstPlaySinkType: - * @GST_PLAY_SINK_TYPE_AUDIO: A non-raw audio pad - * @GST_PLAY_SINK_TYPE_AUDIO_RAW: a raw audio pad - * @GST_PLAY_SINK_TYPE_VIDEO: a non-raw video pad - * @GST_PLAY_SINK_TYPE_VIDEO_RAW: a raw video pad - * @GST_PLAY_SINK_TYPE_TEXT: a raw text pad + * @GST_PLAY_SINK_TYPE_AUDIO: an audio pad + * @GST_PLAY_SINK_TYPE_AUDIO_RAW: a raw audio pad. Deprecated. + * @GST_PLAY_SINK_TYPE_VIDEO: a video pad + * @GST_PLAY_SINK_TYPE_VIDEO_RAW: a raw video pad. Deprecated. + * @GST_PLAY_SINK_TYPE_TEXT: a text pad * @GST_PLAY_SINK_TYPE_LAST: the last type * @GST_PLAY_SINK_TYPE_FLUSHING: a flushing pad, used when shutting down *