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.
This commit is contained in:
Sebastian Dröge 2011-03-15 12:51:04 +01:00
parent 22dae31c2d
commit 105da803ad
3 changed files with 328 additions and 69 deletions

View file

@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
* Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* 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]);

View file

@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
* Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* 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

View file

@ -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
*