mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 10:41:04 +00:00
playsink: fix passthrough mode (hopefully)
The code was doing counterintuitive rewiring of pads when the bin did not contain any elements. We now add an identity element in that case, which makes it simpler, and should fix the AC3 passthrough mode when using pulseaudio (but I don't see the bug here so can't test). https://bugzilla.gnome.org/show_bug.cgi?id=661262
This commit is contained in:
parent
2b84b328b1
commit
c8e0d215cb
4 changed files with 140 additions and 62 deletions
|
@ -94,12 +94,45 @@ distribute_running_time (GstElement * element, const GstSegment * segment)
|
|||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_play_sink_audio_convert_add_identity (GstPlaySinkAudioConvert * self)
|
||||
{
|
||||
self->identity = gst_element_factory_make ("identity", "identity");
|
||||
if (self->identity == NULL) {
|
||||
post_missing_element_message (self, "identity");
|
||||
GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
|
||||
(_("Missing element '%s' - check your GStreamer installation."),
|
||||
"identity"), ("audio rendering might fail"));
|
||||
} else {
|
||||
gst_bin_add (GST_BIN_CAST (self), self->identity);
|
||||
gst_element_sync_state_with_parent (self->identity);
|
||||
distribute_running_time (self->identity, &self->segment);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_play_sink_audio_convert_set_targets (GstPlaySinkAudioConvert * self,
|
||||
GstElement * head, GstElement * tail)
|
||||
{
|
||||
GstPad *pad;
|
||||
|
||||
pad = gst_element_get_static_pad (head, "sink");
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad);
|
||||
gst_object_unref (pad);
|
||||
|
||||
pad = gst_element_get_static_pad (tail, "src");
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
static void
|
||||
pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkAudioConvert * self)
|
||||
{
|
||||
GstPad *peer;
|
||||
GstCaps *caps;
|
||||
gboolean raw;
|
||||
GstElement *head = NULL, *prev = NULL;
|
||||
GstBin *bin = GST_BIN_CAST (self);
|
||||
|
||||
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
|
||||
self->sink_proxypad_blocked = blocked;
|
||||
|
@ -123,10 +156,6 @@ pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkAudioConvert * self)
|
|||
self->raw = raw;
|
||||
|
||||
if (raw) {
|
||||
GstBin *bin = GST_BIN_CAST (self);
|
||||
GstElement *head = NULL, *prev = NULL;
|
||||
GstPad *pad;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Creating raw conversion pipeline");
|
||||
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
|
||||
|
@ -181,26 +210,8 @@ pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkAudioConvert * self)
|
|||
prev = self->volume;
|
||||
}
|
||||
|
||||
if (head) {
|
||||
pad = gst_element_get_static_pad (head, "sink");
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
pad = gst_element_get_static_pad (prev, "src");
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
if (!head && !prev) {
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
|
||||
self->sink_proxypad);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Raw conversion pipeline created");
|
||||
} else {
|
||||
GstBin *bin = GST_BIN_CAST (self);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Removing raw conversion pipeline");
|
||||
|
||||
|
@ -224,12 +235,20 @@ pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkAudioConvert * self)
|
|||
}
|
||||
}
|
||||
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
|
||||
self->sink_proxypad);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Raw conversion pipeline removed");
|
||||
}
|
||||
|
||||
g_assert ((head != NULL) == (prev != NULL));
|
||||
|
||||
/* to make things simple and avoid counterintuitive pad juggling,
|
||||
ensure there is at least one element in the list */
|
||||
if (!head) {
|
||||
gst_play_sink_audio_convert_add_identity (self);
|
||||
prev = head = self->identity;
|
||||
}
|
||||
|
||||
gst_play_sink_audio_convert_set_targets (self, head, prev);
|
||||
|
||||
unblock:
|
||||
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
|
||||
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
|
||||
|
@ -243,8 +262,12 @@ link_failed:
|
|||
{
|
||||
GST_ELEMENT_ERROR (self, CORE, PAD,
|
||||
(NULL), ("Failed to configure the audio converter."));
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
|
||||
self->sink_proxypad);
|
||||
|
||||
/* use a simple identity, better than nothing */
|
||||
gst_play_sink_audio_convert_add_identity (self);
|
||||
gst_play_sink_audio_convert_set_targets (self, self->identity,
|
||||
self->identity);
|
||||
|
||||
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
|
||||
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
|
||||
(GDestroyNotify) gst_object_unref);
|
||||
|
@ -355,8 +378,13 @@ gst_play_sink_audio_convert_getcaps (GstPad * pad)
|
|||
if (!otherpad) {
|
||||
if (pad == self->srcpad) {
|
||||
otherpad = self->sink_proxypad;
|
||||
} else if (pad == self->sinkpad) {
|
||||
otherpad =
|
||||
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
|
||||
(self->sinkpad)));
|
||||
} else {
|
||||
GST_ERROR_OBJECT (pad, "Not one of our pads");
|
||||
}
|
||||
/* no equivalent for the sink pad */
|
||||
}
|
||||
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
|
||||
|
||||
|
@ -436,8 +464,11 @@ gst_play_sink_audio_convert_change_state (GstElement * element,
|
|||
gst_bin_remove (GST_BIN_CAST (self), self->volume);
|
||||
}
|
||||
}
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
|
||||
self->sink_proxypad);
|
||||
if (!self->identity) {
|
||||
gst_play_sink_audio_convert_add_identity (self);
|
||||
}
|
||||
gst_play_sink_audio_convert_set_targets (self, self->identity,
|
||||
self->identity);
|
||||
self->raw = FALSE;
|
||||
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
|
||||
break;
|
||||
|
@ -448,6 +479,14 @@ gst_play_sink_audio_convert_change_state (GstElement * element,
|
|||
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
|
||||
(GDestroyNotify) gst_object_unref);
|
||||
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
if (self->identity) {
|
||||
gst_element_set_state (self->identity, GST_STATE_NULL);
|
||||
gst_bin_remove (GST_BIN_CAST (self), self->identity);
|
||||
self->identity = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -512,9 +551,6 @@ gst_play_sink_audio_convert_init (GstPlaySinkAudioConvert * self)
|
|||
gst_element_add_pad (GST_ELEMENT_CAST (self), self->srcpad);
|
||||
gst_object_unref (templ);
|
||||
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
|
||||
self->sink_proxypad);
|
||||
|
||||
/* FIXME: Only create this on demand but for now we need
|
||||
* it to always exist because of playsink's volume proxying
|
||||
* logic.
|
||||
|
|
|
@ -71,6 +71,7 @@ struct _GstPlaySinkAudioConvert
|
|||
|
||||
gboolean raw;
|
||||
GstElement *conv, *resample;
|
||||
GstElement *identity;
|
||||
|
||||
/* < pseudo public > */
|
||||
GstElement *volume;
|
||||
|
|
|
@ -94,12 +94,45 @@ distribute_running_time (GstElement * element, const GstSegment * segment)
|
|||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_play_sink_video_convert_add_identity (GstPlaySinkVideoConvert * self)
|
||||
{
|
||||
self->identity = gst_element_factory_make ("identity", "identity");
|
||||
if (self->identity == NULL) {
|
||||
post_missing_element_message (self, "identity");
|
||||
GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
|
||||
(_("Missing element '%s' - check your GStreamer installation."),
|
||||
"identity"), ("video rendering might fail"));
|
||||
} else {
|
||||
gst_bin_add (GST_BIN_CAST (self), self->identity);
|
||||
gst_element_sync_state_with_parent (self->identity);
|
||||
distribute_running_time (self->identity, &self->segment);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_play_sink_video_convert_set_targets (GstPlaySinkVideoConvert * self,
|
||||
GstElement * head, GstElement * tail)
|
||||
{
|
||||
GstPad *pad;
|
||||
|
||||
pad = gst_element_get_static_pad (head, "sink");
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad);
|
||||
gst_object_unref (pad);
|
||||
|
||||
pad = gst_element_get_static_pad (tail, "src");
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
static void
|
||||
pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self)
|
||||
{
|
||||
GstPad *peer;
|
||||
GstCaps *caps;
|
||||
gboolean raw;
|
||||
GstBin *bin = GST_BIN_CAST (self);
|
||||
GstElement *head = NULL, *prev = NULL;
|
||||
|
||||
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
|
||||
self->sink_proxypad_blocked = blocked;
|
||||
|
@ -123,9 +156,6 @@ pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self)
|
|||
self->raw = raw;
|
||||
|
||||
if (raw) {
|
||||
GstBin *bin = GST_BIN_CAST (self);
|
||||
GstElement *head = NULL, *prev = NULL;
|
||||
GstPad *pad;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Creating raw conversion pipeline");
|
||||
|
||||
|
@ -167,26 +197,8 @@ pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self)
|
|||
prev = self->scale;
|
||||
}
|
||||
|
||||
if (head) {
|
||||
pad = gst_element_get_static_pad (head, "sink");
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
pad = gst_element_get_static_pad (prev, "src");
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
if (!head && !prev) {
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
|
||||
self->sink_proxypad);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Raw conversion pipeline created");
|
||||
} else {
|
||||
GstBin *bin = GST_BIN_CAST (self);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Removing raw conversion pipeline");
|
||||
|
||||
|
@ -204,12 +216,20 @@ pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self)
|
|||
self->scale = NULL;
|
||||
}
|
||||
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
|
||||
self->sink_proxypad);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Raw conversion pipeline removed");
|
||||
}
|
||||
|
||||
g_assert ((head != NULL) == (prev != NULL));
|
||||
|
||||
/* to make things simple and avoid counterintuitive pad juggling,
|
||||
ensure there is at least one element in the list */
|
||||
if (!head) {
|
||||
gst_play_sink_video_convert_add_identity (self);
|
||||
prev = head = self->identity;
|
||||
}
|
||||
|
||||
gst_play_sink_video_convert_set_targets (self, head, prev);
|
||||
|
||||
unblock:
|
||||
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
|
||||
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
|
||||
|
@ -223,8 +243,12 @@ link_failed:
|
|||
{
|
||||
GST_ELEMENT_ERROR (self, CORE, PAD,
|
||||
(NULL), ("Failed to configure the video converter."));
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
|
||||
self->sink_proxypad);
|
||||
|
||||
/* use a simple identity, better than nothing */
|
||||
gst_play_sink_video_convert_add_identity (self);
|
||||
gst_play_sink_video_convert_set_targets (self, self->identity,
|
||||
self->identity);
|
||||
|
||||
gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
|
||||
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
|
||||
(GDestroyNotify) gst_object_unref);
|
||||
|
@ -335,8 +359,13 @@ gst_play_sink_video_convert_getcaps (GstPad * pad)
|
|||
if (!otherpad) {
|
||||
if (pad == self->srcpad) {
|
||||
otherpad = self->sink_proxypad;
|
||||
} else if (pad == self->sinkpad) {
|
||||
otherpad =
|
||||
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
|
||||
(self->sinkpad)));
|
||||
} else {
|
||||
GST_ERROR_OBJECT (pad, "Not one of our pads");
|
||||
}
|
||||
/* no equivalent for the sink pad */
|
||||
}
|
||||
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
|
||||
|
||||
|
@ -408,8 +437,11 @@ gst_play_sink_video_convert_change_state (GstElement * element,
|
|||
gst_bin_remove (GST_BIN_CAST (self), self->scale);
|
||||
self->scale = NULL;
|
||||
}
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
|
||||
self->sink_proxypad);
|
||||
if (!self->identity) {
|
||||
gst_play_sink_video_convert_add_identity (self);
|
||||
}
|
||||
gst_play_sink_video_convert_set_targets (self, self->identity,
|
||||
self->identity);
|
||||
self->raw = FALSE;
|
||||
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
|
||||
break;
|
||||
|
@ -420,6 +452,14 @@ gst_play_sink_video_convert_change_state (GstElement * element,
|
|||
(GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
|
||||
(GDestroyNotify) gst_object_unref);
|
||||
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
if (self->identity) {
|
||||
gst_element_set_state (self->identity, GST_STATE_NULL);
|
||||
gst_bin_remove (GST_BIN_CAST (self), self->identity);
|
||||
self->identity = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ struct _GstPlaySinkVideoConvert
|
|||
|
||||
gboolean raw;
|
||||
GstElement *conv, *scale;
|
||||
GstElement *identity;
|
||||
};
|
||||
|
||||
struct _GstPlaySinkVideoConvertClass
|
||||
|
|
Loading…
Reference in a new issue