Use new ghostpad API; now they actually work in Totem, also.

Original commit message from CVS:
* ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_reset),
(gst_gconf_audio_sink_init), (do_toggle_element),
(cb_toggle_element), (gst_gconf_audio_sink_change_state):
* ext/gconf/gstgconfaudiosink.h:
* ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_reset),
(gst_gconf_video_sink_init), (do_toggle_element),
(cb_toggle_element), (gst_gconf_video_sink_change_state):
* ext/gconf/gstgconfvideosink.h:
* gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_reset),
(gst_auto_audio_sink_init), (gst_auto_audio_sink_detect),
(gst_auto_audio_sink_change_state):
* gst/autodetect/gstautoaudiosink.h:
* gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_reset),
(gst_auto_video_sink_init), (gst_auto_video_sink_detect),
(gst_auto_video_sink_change_state):
* gst/autodetect/gstautovideosink.h:
Use new ghostpad API; now they actually work in Totem, also.
This commit is contained in:
Ronald S. Bultje 2005-08-03 17:18:31 +00:00
parent 1b23cf61a8
commit 7e8df65cc2
9 changed files with 225 additions and 170 deletions

View file

@ -1,3 +1,23 @@
2005-08-03 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_reset),
(gst_gconf_audio_sink_init), (do_toggle_element),
(cb_toggle_element), (gst_gconf_audio_sink_change_state):
* ext/gconf/gstgconfaudiosink.h:
* ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_reset),
(gst_gconf_video_sink_init), (do_toggle_element),
(cb_toggle_element), (gst_gconf_video_sink_change_state):
* ext/gconf/gstgconfvideosink.h:
* gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_reset),
(gst_auto_audio_sink_init), (gst_auto_audio_sink_detect),
(gst_auto_audio_sink_change_state):
* gst/autodetect/gstautoaudiosink.h:
* gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_reset),
(gst_auto_video_sink_init), (gst_auto_video_sink_detect),
(gst_auto_video_sink_change_state):
* gst/autodetect/gstautovideosink.h:
Use new ghostpad API; now they actually work in Totem, also.
2005-08-03 Ronald S. Bultje <rbultje@ronald.bitfreak.net> 2005-08-03 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/libpng/Makefile.am: * ext/libpng/Makefile.am:

View file

@ -62,20 +62,40 @@ gst_gconf_audio_sink_class_init (GstGConfAudioSinkClass * klass)
eklass->change_state = gst_gconf_audio_sink_change_state; eklass->change_state = gst_gconf_audio_sink_change_state;
} }
/*
* Hack to make negotiation work.
*/
static void
gst_gconf_audio_sink_reset (GstGConfAudioSink * sink)
{
GstPad *targetpad;
/* fakesink */
if (sink->kid) {
gst_bin_remove (GST_BIN (sink), sink->kid);
}
sink->kid = gst_element_factory_make ("fakesink", "testsink");
gst_bin_add (GST_BIN (sink), sink->kid);
targetpad = gst_element_get_pad (sink->kid, "sink");
gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
gst_object_unref (targetpad);
}
static void static void
gst_gconf_audio_sink_init (GstGConfAudioSink * sink) gst_gconf_audio_sink_init (GstGConfAudioSink * sink)
{ {
sink->pad = NULL; sink->pad = gst_ghost_pad_new_notarget ("sink", GST_PAD_SINK);
sink->kid = NULL; gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
gst_gconf_audio_sink_reset (sink);
sink->client = gconf_client_get_default (); sink->client = gconf_client_get_default ();
gconf_client_add_dir (sink->client, GST_GCONF_DIR, gconf_client_add_dir (sink->client, GST_GCONF_DIR,
GCONF_CLIENT_PRELOAD_RECURSIVE, NULL); GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
gconf_client_notify_add (sink->client, GST_GCONF_DIR "/default/audiosink", gconf_client_notify_add (sink->client, GST_GCONF_DIR "/default/audiosink",
cb_toggle_element, sink, NULL, NULL); cb_toggle_element, sink, NULL, NULL);
cb_toggle_element (sink->client, 0, NULL, sink);
sink->init = FALSE;
} }
static void static void
@ -91,23 +111,10 @@ gst_gconf_audio_sink_dispose (GObject * object)
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
} }
static void static gboolean
cb_toggle_element (GConfClient * client, do_toggle_element (GstGConfAudioSink * sink)
guint connection_id, GConfEntry * entry, gpointer data)
{ {
GstGConfAudioSink *sink = GST_GCONF_AUDIO_SINK (data); GstPad *targetpad;
GstPad *peer = NULL, *targetpad;
/* save ghostpad */
if (sink->pad) {
peer = GST_PAD_PEER (sink->pad);
if (peer) {
gst_pad_unlink (peer, sink->pad);
GST_DEBUG_OBJECT (sink, "Caching peer %p", peer);
}
gst_element_remove_pad (GST_ELEMENT (sink), sink->pad);
sink->pad = NULL;
}
/* kill old element */ /* kill old element */
if (sink->kid) { if (sink->kid) {
@ -116,31 +123,30 @@ cb_toggle_element (GConfClient * client,
sink->kid = NULL; sink->kid = NULL;
} }
GST_DEBUG_OBJECT (sink, "Creating new kid (%ssink)", GST_DEBUG_OBJECT (sink, "Creating new kid");
entry ? "audio" : "fake"); if (!(sink->kid = gst_gconf_get_default_audio_sink ())) {
sink->kid = entry ? gst_gconf_get_default_audio_sink () :
gst_element_factory_make ("fakesink", "temporary-element");
if (!sink->kid) {
GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL), GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
("Failed to render audio sink from GConf")); ("Failed to render audio sink from GConf"));
return; return FALSE;
} }
gst_element_set_state (sink->kid, GST_STATE (sink));
gst_bin_add (GST_BIN (sink), sink->kid); gst_bin_add (GST_BIN (sink), sink->kid);
/* re-attach ghostpad */ /* re-attach ghostpad */
GST_DEBUG_OBJECT (sink, "Creating new ghostpad"); GST_DEBUG_OBJECT (sink, "Creating new ghostpad");
targetpad = gst_element_get_pad (sink->kid, "sink"); targetpad = gst_element_get_pad (sink->kid, "sink");
sink->pad = gst_ghost_pad_new ("sink", targetpad); gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
gst_object_unref (targetpad); gst_object_unref (targetpad);
gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
if (peer) {
GST_DEBUG_OBJECT (sink, "Linking...");
gst_pad_link (peer, sink->pad);
}
GST_DEBUG_OBJECT (sink, "done changing gconf audio sink"); GST_DEBUG_OBJECT (sink, "done changing gconf audio sink");
sink->init = TRUE;
return TRUE;
}
static void
cb_toggle_element (GConfClient * client,
guint connection_id, GConfEntry * entry, gpointer data)
{
do_toggle_element (GST_GCONF_AUDIO_SINK (data));
} }
static GstElementStateReturn static GstElementStateReturn
@ -148,12 +154,16 @@ gst_gconf_audio_sink_change_state (GstElement * element)
{ {
GstGConfAudioSink *sink = GST_GCONF_AUDIO_SINK (element); GstGConfAudioSink *sink = GST_GCONF_AUDIO_SINK (element);
if (GST_STATE_TRANSITION (element) == GST_STATE_NULL_TO_READY && !sink->init) { switch (GST_STATE_TRANSITION (element)) {
cb_toggle_element (sink->client, 0, case GST_STATE_NULL_TO_READY:
gconf_client_get_entry (sink->client, if (!do_toggle_element (sink))
GST_GCONF_DIR "/default/audiosink", NULL, TRUE, NULL), sink);
if (!sink->init)
return GST_STATE_FAILURE; return GST_STATE_FAILURE;
break;
case GST_STATE_READY_TO_NULL:
gst_gconf_audio_sink_reset (sink);
break;
default:
break;
} }
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state, return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,

View file

@ -45,7 +45,6 @@ typedef struct _GstGConfAudioSink {
GConfClient *client; GConfClient *client;
GstElement *kid; GstElement *kid;
GstPad *pad; GstPad *pad;
gboolean init;
} GstGConfAudioSink; } GstGConfAudioSink;
typedef struct _GstGConfAudioSinkClass { typedef struct _GstGConfAudioSinkClass {

View file

@ -62,20 +62,40 @@ gst_gconf_video_sink_class_init (GstGConfVideoSinkClass * klass)
eklass->change_state = gst_gconf_video_sink_change_state; eklass->change_state = gst_gconf_video_sink_change_state;
} }
/*
* Hack to make negotiation work.
*/
static void
gst_gconf_video_sink_reset (GstGConfVideoSink * sink)
{
GstPad *targetpad;
/* fakesink */
if (sink->kid) {
gst_bin_remove (GST_BIN (sink), sink->kid);
}
sink->kid = gst_element_factory_make ("fakesink", "testsink");
gst_bin_add (GST_BIN (sink), sink->kid);
targetpad = gst_element_get_pad (sink->kid, "sink");
gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
gst_object_unref (targetpad);
}
static void static void
gst_gconf_video_sink_init (GstGConfVideoSink * sink) gst_gconf_video_sink_init (GstGConfVideoSink * sink)
{ {
sink->pad = NULL; sink->pad = gst_ghost_pad_new_notarget ("sink", GST_PAD_SINK);
sink->kid = NULL; gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
gst_gconf_video_sink_reset (sink);
sink->client = gconf_client_get_default (); sink->client = gconf_client_get_default ();
gconf_client_add_dir (sink->client, GST_GCONF_DIR, gconf_client_add_dir (sink->client, GST_GCONF_DIR,
GCONF_CLIENT_PRELOAD_RECURSIVE, NULL); GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
gconf_client_notify_add (sink->client, GST_GCONF_DIR "/default/videosink", gconf_client_notify_add (sink->client, GST_GCONF_DIR "/default/videosink",
cb_toggle_element, sink, NULL, NULL); cb_toggle_element, sink, NULL, NULL);
cb_toggle_element (sink->client, 0, NULL, sink);
sink->init = FALSE;
} }
static void static void
@ -91,23 +111,10 @@ gst_gconf_video_sink_dispose (GObject * object)
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
} }
static void static gboolean
cb_toggle_element (GConfClient * client, do_toggle_element (GstGConfVideoSink * sink)
guint connection_id, GConfEntry * entry, gpointer data)
{ {
GstGConfVideoSink *sink = GST_GCONF_VIDEO_SINK (data); GstPad *targetpad;
GstPad *peer = NULL, *targetpad;
/* save ghostpad */
if (sink->pad) {
peer = GST_PAD_PEER (sink->pad);
if (peer) {
gst_pad_unlink (peer, sink->pad);
GST_DEBUG_OBJECT (sink, "Caching peer %p", peer);
}
gst_element_remove_pad (GST_ELEMENT (sink), sink->pad);
sink->pad = NULL;
}
/* kill old element */ /* kill old element */
if (sink->kid) { if (sink->kid) {
@ -116,31 +123,30 @@ cb_toggle_element (GConfClient * client,
sink->kid = NULL; sink->kid = NULL;
} }
GST_DEBUG_OBJECT (sink, "Creating new kid (%ssink)", GST_DEBUG_OBJECT (sink, "Creating new kid");
entry ? "video" : "fake"); if (!(sink->kid = gst_gconf_get_default_video_sink ())) {
sink->kid = entry ? gst_gconf_get_default_video_sink () :
gst_element_factory_make ("fakesink", "temporary-element");
if (!sink->kid) {
GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL), GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
("Failed to render video sink from GConf")); ("Failed to render video sink from GConf"));
return; return FALSE;
} }
gst_element_set_state (sink->kid, GST_STATE (sink));
gst_bin_add (GST_BIN (sink), sink->kid); gst_bin_add (GST_BIN (sink), sink->kid);
/* re-attach ghostpad */ /* re-attach ghostpad */
GST_DEBUG_OBJECT (sink, "Creating new ghostpad"); GST_DEBUG_OBJECT (sink, "Creating new ghostpad");
targetpad = gst_element_get_pad (sink->kid, "sink"); targetpad = gst_element_get_pad (sink->kid, "sink");
sink->pad = gst_ghost_pad_new ("sink", targetpad); gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
gst_object_unref (targetpad); gst_object_unref (targetpad);
gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
if (peer) {
GST_DEBUG_OBJECT (sink, "Linking...");
gst_pad_link (peer, sink->pad);
}
GST_DEBUG_OBJECT (sink, "done changing gconf video sink"); GST_DEBUG_OBJECT (sink, "done changing gconf video sink");
sink->init = TRUE;
return TRUE;
}
static void
cb_toggle_element (GConfClient * client,
guint connection_id, GConfEntry * entry, gpointer data)
{
do_toggle_element (GST_GCONF_VIDEO_SINK (data));
} }
static GstElementStateReturn static GstElementStateReturn
@ -148,12 +154,16 @@ gst_gconf_video_sink_change_state (GstElement * element)
{ {
GstGConfVideoSink *sink = GST_GCONF_VIDEO_SINK (element); GstGConfVideoSink *sink = GST_GCONF_VIDEO_SINK (element);
if (GST_STATE_TRANSITION (element) == GST_STATE_NULL_TO_READY && !sink->init) { switch (GST_STATE_TRANSITION (element)) {
cb_toggle_element (sink->client, 0, case GST_STATE_NULL_TO_READY:
gconf_client_get_entry (sink->client, if (!do_toggle_element (sink))
GST_GCONF_DIR "/default/videosink", NULL, TRUE, NULL), sink);
if (!sink->init)
return GST_STATE_FAILURE; return GST_STATE_FAILURE;
break;
case GST_STATE_READY_TO_NULL:
gst_gconf_video_sink_reset (sink);
break;
default:
break;
} }
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state, return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,

View file

@ -45,7 +45,6 @@ typedef struct _GstGConfVideoSink {
GConfClient *client; GConfClient *client;
GstElement *kid; GstElement *kid;
GstPad *pad; GstPad *pad;
gboolean init;
} GstGConfVideoSink; } GstGConfVideoSink;
typedef struct _GstGConfVideoSinkClass { typedef struct _GstGConfVideoSinkClass {

View file

@ -26,7 +26,6 @@
#include "gstautoaudiosink.h" #include "gstautoaudiosink.h"
#include "gstautodetect.h" #include "gstautodetect.h"
static void gst_auto_audio_sink_detect (GstAutoAudioSink * sink, gboolean fake);
static GstElementStateReturn static GstElementStateReturn
gst_auto_audio_sink_change_state (GstElement * element); gst_auto_audio_sink_change_state (GstElement * element);
@ -60,13 +59,36 @@ gst_auto_audio_sink_class_init (GstAutoAudioSinkClass * klass)
eklass->change_state = gst_auto_audio_sink_change_state; eklass->change_state = gst_auto_audio_sink_change_state;
} }
/*
* Hack to make initial linking work; ideally, this'd work even when
* no target has been assigned to the ghostpad yet.
*/
static void
gst_auto_audio_sink_reset (GstAutoAudioSink * sink)
{
GstPad *targetpad;
/* fakesink placeholder */
if (sink->kid) {
gst_bin_remove (GST_BIN (sink), sink->kid);
}
sink->kid = gst_element_factory_make ("fakesink", "tempsink");
gst_bin_add (GST_BIN (sink), sink->kid);
/* pad */
targetpad = gst_element_get_pad (sink->kid, "sink");
gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
gst_object_unref (targetpad);
}
static void static void
gst_auto_audio_sink_init (GstAutoAudioSink * sink) gst_auto_audio_sink_init (GstAutoAudioSink * sink)
{ {
sink->pad = NULL; sink->pad = gst_ghost_pad_new_notarget ("sink", GST_PAD_SINK);
sink->kid = NULL; gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
gst_auto_audio_sink_detect (sink, TRUE);
sink->init = FALSE; gst_auto_audio_sink_reset (sink);
} }
static gboolean static gboolean
@ -171,56 +193,35 @@ done:
return choice; return choice;
} }
static void static gboolean
gst_auto_audio_sink_detect (GstAutoAudioSink * sink, gboolean fake) gst_auto_audio_sink_detect (GstAutoAudioSink * sink)
{ {
GstElement *esink; GstElement *esink;
GstPad *targetpad, *peer = NULL; GstPad *targetpad;
/* save ghostpad */
if (sink->pad) {
peer = GST_PAD_PEER (sink->pad);
if (peer) {
gst_pad_unlink (peer, sink->pad);
GST_DEBUG_OBJECT (sink, "Element was linked, caching peer %p", peer);
}
gst_element_remove_pad (GST_ELEMENT (sink), sink->pad);
sink->pad = NULL;
}
/* kill old element */
if (sink->kid) { if (sink->kid) {
GST_DEBUG_OBJECT (sink, "Removing old kid");
gst_bin_remove (GST_BIN (sink), sink->kid); gst_bin_remove (GST_BIN (sink), sink->kid);
sink->kid = NULL; sink->kid = NULL;
} }
/* find element */ /* find element */
GST_DEBUG_OBJECT (sink, "Creating new kid (%ssink)", fake ? "fake" : "audio"); GST_DEBUG_OBJECT (sink, "Creating new kid");
if (fake) { if (!(esink = gst_auto_audio_sink_find_best (sink))) {
esink = gst_element_factory_make ("fakesink", "temporary-sink");
} else if (!(esink = gst_auto_audio_sink_find_best (sink))) {
GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL),
("Failed to find a supported audio sink")); ("Failed to find a supported audio sink"));
return; return FALSE;
} }
sink->kid = esink; sink->kid = esink;
gst_bin_add (GST_BIN (sink), esink); gst_bin_add (GST_BIN (sink), esink);
/* attach ghost pad */ /* attach ghost pad */
GST_DEBUG_OBJECT (sink, "Creating new ghostpad"); GST_DEBUG_OBJECT (sink, "Re-assigning ghostpad");
targetpad = gst_element_get_pad (sink->kid, "sink"); targetpad = gst_element_get_pad (sink->kid, "sink");
sink->pad = gst_ghost_pad_new ("sink", targetpad); gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
gst_object_unref (targetpad); gst_object_unref (targetpad);
gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
if (peer) {
GST_DEBUG_OBJECT (sink, "Linking...");
gst_pad_link (peer, sink->pad);
}
GST_DEBUG_OBJECT (sink, "done changing auto audio sink"); GST_DEBUG_OBJECT (sink, "done changing auto audio sink");
sink->init = TRUE;
return TRUE;
} }
static GstElementStateReturn static GstElementStateReturn
@ -228,12 +229,20 @@ gst_auto_audio_sink_change_state (GstElement * element)
{ {
GstAutoAudioSink *sink = GST_AUTO_AUDIO_SINK (element); GstAutoAudioSink *sink = GST_AUTO_AUDIO_SINK (element);
if (GST_STATE_TRANSITION (element) == GST_STATE_NULL_TO_READY && !sink->init) { GST_DEBUG_OBJECT (element, "Change state 0x%x",
gst_auto_audio_sink_detect (sink, FALSE); GST_STATE_TRANSITION (element));
if (!sink->init)
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
if (!gst_auto_audio_sink_detect (sink))
return GST_STATE_FAILURE; return GST_STATE_FAILURE;
break;
case GST_STATE_READY_TO_NULL:
gst_auto_audio_sink_reset (sink);
break;
default:
break;
} }
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state, return GST_ELEMENT_CLASS (parent_class)->change_state (element);
(element), GST_STATE_SUCCESS);
} }

View file

@ -43,7 +43,6 @@ typedef struct _GstAutoAudioSink {
/* explicit pointers to stuff used */ /* explicit pointers to stuff used */
GstPad *pad; GstPad *pad;
GstElement *kid; GstElement *kid;
gboolean init;
} GstAutoAudioSink; } GstAutoAudioSink;
typedef struct _GstAutoAudioSinkClass { typedef struct _GstAutoAudioSinkClass {

View file

@ -26,7 +26,6 @@
#include "gstautovideosink.h" #include "gstautovideosink.h"
#include "gstautodetect.h" #include "gstautodetect.h"
static void gst_auto_video_sink_detect (GstAutoVideoSink * sink, gboolean fake);
static GstElementStateReturn static GstElementStateReturn
gst_auto_video_sink_change_state (GstElement * element); gst_auto_video_sink_change_state (GstElement * element);
@ -60,13 +59,36 @@ gst_auto_video_sink_class_init (GstAutoVideoSinkClass * klass)
eklass->change_state = gst_auto_video_sink_change_state; eklass->change_state = gst_auto_video_sink_change_state;
} }
/*
* Hack to make initial linking work; ideally, this'd work even when
* no target has been assigned to the ghostpad yet.
*/
static void
gst_auto_video_sink_reset (GstAutoVideoSink * sink)
{
GstPad *targetpad;
/* fakesink placeholder */
if (sink->kid) {
gst_bin_remove (GST_BIN (sink), sink->kid);
}
sink->kid = gst_element_factory_make ("fakesink", "tempsink");
gst_bin_add (GST_BIN (sink), sink->kid);
/* pad */
targetpad = gst_element_get_pad (sink->kid, "sink");
gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
gst_object_unref (targetpad);
}
static void static void
gst_auto_video_sink_init (GstAutoVideoSink * sink) gst_auto_video_sink_init (GstAutoVideoSink * sink)
{ {
sink->pad = NULL; sink->pad = gst_ghost_pad_new_notarget ("sink", GST_PAD_SINK);
sink->kid = NULL; gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
gst_auto_video_sink_detect (sink, TRUE);
sink->init = FALSE; gst_auto_video_sink_reset (sink);
} }
static gboolean static gboolean
@ -132,56 +154,35 @@ gst_auto_video_sink_find_best (GstAutoVideoSink * sink)
return NULL; return NULL;
} }
static void static gboolean
gst_auto_video_sink_detect (GstAutoVideoSink * sink, gboolean fake) gst_auto_video_sink_detect (GstAutoVideoSink * sink)
{ {
GstElement *esink; GstElement *esink;
GstPad *targetpad, *peer = NULL; GstPad *targetpad;
/* save ghostpad */
if (sink->pad) {
peer = GST_PAD_PEER (sink->pad);
if (peer) {
gst_pad_unlink (peer, sink->pad);
GST_DEBUG_OBJECT (sink, "Element was linked, caching peer %p", peer);
}
gst_element_remove_pad (GST_ELEMENT (sink), sink->pad);
sink->pad = NULL;
}
/* kill old element */
if (sink->kid) { if (sink->kid) {
GST_DEBUG_OBJECT (sink, "Removing old kid");
gst_bin_remove (GST_BIN (sink), sink->kid); gst_bin_remove (GST_BIN (sink), sink->kid);
sink->kid = NULL; sink->kid = NULL;
} }
/* find element */ /* find element */
GST_DEBUG_OBJECT (sink, "Creating new kid (%ssink)", fake ? "fake" : "video"); GST_DEBUG_OBJECT (sink, "Creating new kid");
if (fake) { if (!(esink = gst_auto_video_sink_find_best (sink))) {
esink = gst_element_factory_make ("fakesink", "temporary-sink");
} else if (!(esink = gst_auto_video_sink_find_best (sink))) {
GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL),
("Failed to find a supported video sink")); ("Failed to find a supported video sink"));
return; return FALSE;
} }
sink->kid = esink; sink->kid = esink;
gst_bin_add (GST_BIN (sink), esink); gst_bin_add (GST_BIN (sink), esink);
/* attach ghost pad */ /* attach ghost pad */
GST_DEBUG_OBJECT (sink, "Creating new ghostpad"); GST_DEBUG_OBJECT (sink, "Re-assigning ghostpad");
targetpad = gst_element_get_pad (sink->kid, "sink"); targetpad = gst_element_get_pad (sink->kid, "sink");
sink->pad = gst_ghost_pad_new ("sink", targetpad); gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
gst_object_unref (targetpad); gst_object_unref (targetpad);
gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
if (peer) {
GST_DEBUG_OBJECT (sink, "Linking...");
gst_pad_link (peer, sink->pad);
}
GST_DEBUG_OBJECT (sink, "done changing auto video sink"); GST_DEBUG_OBJECT (sink, "done changing auto video sink");
sink->init = TRUE;
return TRUE;
} }
static GstElementStateReturn static GstElementStateReturn
@ -189,10 +190,19 @@ gst_auto_video_sink_change_state (GstElement * element)
{ {
GstAutoVideoSink *sink = GST_AUTO_VIDEO_SINK (element); GstAutoVideoSink *sink = GST_AUTO_VIDEO_SINK (element);
if (GST_STATE_TRANSITION (element) == GST_STATE_NULL_TO_READY && !sink->init) { GST_DEBUG_OBJECT (element, "Change state 0x%x",
gst_auto_video_sink_detect (sink, FALSE); GST_STATE_TRANSITION (element));
if (!sink->init)
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
if (!gst_auto_video_sink_detect (sink))
return GST_STATE_FAILURE; return GST_STATE_FAILURE;
break;
case GST_STATE_READY_TO_NULL:
gst_auto_video_sink_reset (sink);
break;
default:
break;
} }
return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_ELEMENT_CLASS (parent_class)->change_state (element);

View file

@ -43,7 +43,6 @@ typedef struct _GstAutoVideoSink {
/* explicit pointers to stuff used */ /* explicit pointers to stuff used */
GstPad *pad; GstPad *pad;
GstElement *kid; GstElement *kid;
gboolean init;
} GstAutoVideoSink; } GstAutoVideoSink;
typedef struct _GstAutoVideoSinkClass { typedef struct _GstAutoVideoSinkClass {