/* connection speed in bits/sec (0 = unknown) */
guint connection_speed;
+
+ /* indication if the pipeline is live */
+ gboolean is_live;
};
struct _GstPlayBinClass
static gboolean gst_play_bin_send_event (GstElement * element,
GstEvent * event);
+static gboolean gst_play_bin_set_clock_func (GstElement * element,
+ GstClock * clock);
static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
GstStateChange transition);
+
static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
static GstElementClass *parent_class;
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_play_bin_send_event);
+ gstelement_klass->set_clock = GST_DEBUG_FUNCPTR (gst_play_bin_set_clock_func);
gstbin_klass->handle_message =
GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
}
vis_bin =
- GST_BIN (gst_object_get_parent (GST_OBJECT (play_bin->visualisation)));
+ GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST (play_bin->
+ visualisation)));
if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) {
goto beach;
play_bin->video_sink = g_value_get_object (value);
if (play_bin->video_sink != NULL) {
gst_object_ref (play_bin->video_sink);
- gst_object_sink (GST_OBJECT (play_bin->video_sink));
+ gst_object_sink (GST_OBJECT_CAST (play_bin->video_sink));
}
/* when changing the videosink, we just remove the
* video pipeline from the cache so that it will be
play_bin->audio_sink = g_value_get_object (value);
if (play_bin->audio_sink != NULL) {
gst_object_ref (play_bin->audio_sink);
- gst_object_sink (GST_OBJECT (play_bin->audio_sink));
+ gst_object_sink (GST_OBJECT_CAST (play_bin->audio_sink));
}
g_hash_table_remove (play_bin->cache, "abin");
break;
/* Take ownership */
if (play_bin->pending_visualisation) {
gst_object_ref (play_bin->pending_visualisation);
- gst_object_sink (GST_OBJECT (play_bin->pending_visualisation));
+ gst_object_sink (GST_OBJECT_CAST (play_bin->pending_visualisation));
}
} else {
play_bin->pending_visualisation = g_value_get_object (value);
/* Take ownership */
if (play_bin->pending_visualisation) {
gst_object_ref (play_bin->pending_visualisation);
- gst_object_sink (GST_OBJECT (play_bin->pending_visualisation));
+ gst_object_sink (GST_OBJECT_CAST (play_bin->pending_visualisation));
}
/* Was there a visualisation already set ? */
GstBin *vis_bin = NULL;
vis_bin =
- GST_BIN (gst_object_get_parent (GST_OBJECT (play_bin->
+ GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST (play_bin->
visualisation)));
/* Check if the visualisation is already in a bin */
* +----------|--------------------------------------------------+
* handoff
*/
-/* FIXME: this might return NULL if no videosink was found, handle
- * this in callers */
static GstElement *
gen_video_element (GstPlayBin * play_bin)
{
if (sink == NULL) {
sink = gst_element_factory_make ("xvimagesink", "videosink");
}
- /* FIXME: this warrants adding a CORE error category for missing
- * elements/plugins */
- if (sink == NULL) {
- GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
- (_("Both autovideosink and xvimagesink elements are missing.")),
- (NULL));
- return NULL;
- }
+ if (sink == NULL)
+ goto no_sinks;
}
gst_object_ref (sink);
g_hash_table_insert (play_bin->cache, "video_sink", sink);
-
+ /* create a bin to hold objects, as we create them we add them to this bin so
+ * that when something goes wrong we only need to unref the bin */
element = gst_bin_new ("vbin");
- identity = gst_element_factory_make ("identity", "id");
- g_object_set (identity, "silent", TRUE, NULL);
- g_signal_connect (identity, "handoff", G_CALLBACK (handoff), play_bin);
- gst_bin_add (GST_BIN (element), identity);
+ gst_bin_add (GST_BIN_CAST (element), sink);
+
conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
if (conv == NULL)
goto no_colorspace;
+ gst_bin_add (GST_BIN_CAST (element), conv);
+
scale = gst_element_factory_make ("videoscale", "vscale");
if (scale == NULL)
goto no_videoscale;
- gst_bin_add (GST_BIN (element), conv);
- gst_bin_add (GST_BIN (element), scale);
- gst_bin_add (GST_BIN (element), sink);
+ gst_bin_add (GST_BIN_CAST (element), scale);
+
+ identity = gst_element_factory_make ("identity", "id");
+ g_object_set (identity, "silent", TRUE, NULL);
+ g_signal_connect (identity, "handoff", G_CALLBACK (handoff), play_bin);
+ gst_bin_add (GST_BIN_CAST (element), identity);
+
gst_element_link_pads (identity, "src", conv, "sink");
gst_element_link_pads (conv, "src", scale, "sink");
- gst_element_link_pads (scale, "src", sink, "sink");
+ /* be more careful with the pad from the custom sink element, it might not
+ * be named 'sink' */
+ if (!gst_element_link_pads (scale, "src", sink, NULL))
+ goto link_failed;
pad = gst_element_get_pad (identity, "sink");
gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
return element;
+ /* ERRORS */
+no_sinks:
+ {
+ /* FIXME: this warrants adding a CORE error category for missing
+ * elements/plugins */
+ GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
+ (_("Both autovideosink and xvimagesink elements are missing.")),
+ (NULL));
+ return NULL;
+ }
no_colorspace:
{
GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
gst_object_unref (element);
return NULL;
}
+link_failed:
+ {
+ GST_ELEMENT_ERROR (play_bin, CORE, PAD,
+ (NULL), ("Failed to configure the video sink."));
+ gst_object_unref (element);
+ return NULL;
+ }
}
/* make an element for playback of video with subtitles embedded.
* | +-----+ | +-------------+ +------+ |
* text_sink-------------+ |
* +--------------------------------------------------+
+ *
+ * If there is no subtitle renderer this function will simply return the
+ * videosink without the text_sink pad.
*/
-
static GstElement *
gen_text_element (GstPlayBin * play_bin)
{
GstElement *element, *csp, *overlay, *vbin;
GstPad *pad;
- /* Create our bin */
- element = gst_bin_new ("textbin");
+ /* Create the video rendering bin, error is posted when this fails. */
+ vbin = gen_video_element (play_bin);
+ if (!vbin)
+ return NULL;
/* Text overlay */
overlay = gst_element_factory_make ("textoverlay", "overlay");
- /* Create the video rendering bin */
- vbin = gen_video_element (play_bin);
+ /* If no overlay return the video bin without subtitle support. */
+ if (!overlay)
+ goto no_overlay;
- /* If no overlay return the video bin */
- if (!overlay) {
- GST_WARNING ("No overlay (pango) element, subtitles disabled");
- return vbin;
- }
+ /* Create our bin */
+ element = gst_bin_new ("textbin");
/* Set some parameters */
g_object_set (G_OBJECT (overlay),
}
/* Take a ref */
- play_bin->textoverlay_element = GST_ELEMENT (gst_object_ref (overlay));
+ play_bin->textoverlay_element = GST_ELEMENT_CAST (gst_object_ref (overlay));
/* we know this will succeed, as the video bin already created one before */
csp = gst_element_factory_make ("ffmpegcolorspace", "subtitlecsp");
/* Add our elements */
- gst_bin_add_many (GST_BIN (element), csp, overlay, vbin, NULL);
+ gst_bin_add_many (GST_BIN_CAST (element), csp, overlay, vbin, NULL);
/* Link */
gst_element_link_pads (csp, "src", overlay, "video_sink");
gst_element_set_state (element, GST_STATE_READY);
return element;
+
+ /* ERRORS */
+no_overlay:
+ {
+ GST_WARNING_OBJECT (play_bin,
+ "No overlay (pango) element, subtitles disabled");
+ return vbin;
+ }
}
/* make the element (bin) that contains the elements needed to perform
* | | +---------+ +----------+ +---------+ +---------+ |
* sink-+ |
* +-------------------------------------------------------------+
- *
*/
static GstElement *
gen_audio_element (GstPlayBin * play_bin)
{
+ gboolean res;
GstElement *element;
GstElement *conv;
GstElement *scale;
GstPad *pad;
element = g_hash_table_lookup (play_bin->cache, "abin");
- if (element != NULL) {
+ if (element != NULL)
return element;
- }
- element = gst_bin_new ("abin");
- conv = gst_element_factory_make ("audioconvert", "aconv");
- if (conv == NULL)
- goto no_audioconvert;
-
- scale = gst_element_factory_make ("audioresample", "aresample");
- if (scale == NULL)
- goto no_audioresample;
-
- volume = gst_element_factory_make ("volume", "volume");
- g_object_set (G_OBJECT (volume), "volume", play_bin->volume, NULL);
- play_bin->volume_element = volume;
if (play_bin->audio_sink) {
sink = play_bin->audio_sink;
if (sink == NULL) {
sink = gst_element_factory_make ("alsasink", "audiosink");
}
- if (sink == NULL) {
- GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
- (_("Both autoaudiosink and alsasink elements are missing.")), (NULL));
- return NULL;
- }
- play_bin->audio_sink = GST_ELEMENT (gst_object_ref (sink));
+ if (sink == NULL)
+ goto no_sinks;
+
+ play_bin->audio_sink = GST_ELEMENT_CAST (gst_object_ref (sink));
}
gst_object_ref (sink);
g_hash_table_insert (play_bin->cache, "audio_sink", sink);
- gst_bin_add (GST_BIN (element), conv);
- gst_bin_add (GST_BIN (element), scale);
- gst_bin_add (GST_BIN (element), volume);
- gst_bin_add (GST_BIN (element), sink);
+ element = gst_bin_new ("abin");
+ gst_bin_add (GST_BIN_CAST (element), sink);
- gst_element_link_pads (conv, "src", scale, "sink");
- gst_element_link_pads (scale, "src", volume, "sink");
- gst_element_link_pads (volume, "src", sink, "sink");
+ conv = gst_element_factory_make ("audioconvert", "aconv");
+ if (conv == NULL)
+ goto no_audioconvert;
+ gst_bin_add (GST_BIN_CAST (element), conv);
+
+ scale = gst_element_factory_make ("audioresample", "aresample");
+ if (scale == NULL)
+ goto no_audioresample;
+ gst_bin_add (GST_BIN_CAST (element), scale);
+
+ volume = gst_element_factory_make ("volume", "volume");
+ g_object_set (G_OBJECT (volume), "volume", play_bin->volume, NULL);
+ play_bin->volume_element = volume;
+ gst_bin_add (GST_BIN_CAST (element), volume);
+
+ res = gst_element_link_pads (conv, "src", scale, "sink");
+ res &= gst_element_link_pads (scale, "src", volume, "sink");
+ res &= gst_element_link_pads (volume, "src", sink, NULL);
+ if (!res)
+ goto link_failed;
pad = gst_element_get_pad (conv, "sink");
gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
return element;
+ /* ERRORS */
+no_sinks:
+ {
+ GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
+ (_("Both autoaudiosink and alsasink elements are missing.")), (NULL));
+ return NULL;
+ }
no_audioconvert:
{
GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
gst_object_unref (element);
return NULL;
}
+link_failed:
+ {
+ GST_ELEMENT_ERROR (play_bin, CORE, PAD,
+ (NULL), ("Failed to configure the audio sink."));
+ gst_object_unref (element);
+ return NULL;
+ }
}
/* make the element (bin) that contains the elements needed to perform
static GstElement *
gen_vis_element (GstPlayBin * play_bin)
{
+ gboolean res;
GstElement *element;
GstElement *tee;
GstElement *asink;
GstElement *vqueue, *aqueue;
GstPad *pad, *rpad;
+ /* errors are already posted when these fail. */
asink = gen_audio_element (play_bin);
if (!asink)
return NULL;
vqueue = gst_element_factory_make ("queue", "vqueue");
aqueue = gst_element_factory_make ("queue", "aqueue");
- gst_bin_add (GST_BIN (element), asink);
- gst_bin_add (GST_BIN (element), vqueue);
- gst_bin_add (GST_BIN (element), aqueue);
- gst_bin_add (GST_BIN (element), vsink);
- gst_bin_add (GST_BIN (element), tee);
+ gst_bin_add (GST_BIN_CAST (element), asink);
+ gst_bin_add (GST_BIN_CAST (element), vqueue);
+ gst_bin_add (GST_BIN_CAST (element), aqueue);
+ gst_bin_add (GST_BIN_CAST (element), vsink);
+ gst_bin_add (GST_BIN_CAST (element), tee);
conv = gst_element_factory_make ("audioconvert", "aconv");
if (conv == NULL)
goto no_audioconvert;
+ gst_bin_add (GST_BIN_CAST (element), conv);
if (play_bin->visualisation) {
gst_object_ref (play_bin->visualisation);
vis = play_bin->visualisation;
} else {
vis = gst_element_factory_make ("goom", "vis");
+ if (!vis)
+ goto no_goom;
}
+ gst_bin_add (GST_BIN_CAST (element), vis);
- gst_bin_add (GST_BIN (element), conv);
- gst_bin_add (GST_BIN (element), vis);
-
- gst_element_link_pads (vqueue, "src", conv, "sink");
- gst_element_link_pads (conv, "src", vis, "sink");
- gst_element_link_pads (vis, "src", vsink, "sink");
+ res = gst_element_link_pads (vqueue, "src", conv, "sink");
+ res &= gst_element_link_pads (conv, "src", vis, "sink");
+ res &= gst_element_link_pads (vis, "src", vsink, "sink");
+ if (!res)
+ goto link_failed;
pad = gst_element_get_pad (aqueue, "sink");
rpad = gst_element_get_request_pad (tee, "src%d");
return element;
+ /* ERRORS */
no_audioconvert:
{
GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
gst_object_unref (element);
return NULL;
}
+no_goom:
+ {
+ GST_ELEMENT_ERROR (play_bin, CORE, MISSING_PLUGIN,
+ (_("Missing element '%s' - check your GStreamer installation."),
+ "goom"), (NULL));
+ gst_object_unref (element);
+ return NULL;
+ }
+link_failed:
+ {
+ GST_ELEMENT_ERROR (play_bin, CORE, PAD,
+ (NULL), ("Failed to configure the visualisation element."));
+ gst_object_unref (element);
+ return NULL;
+ }
}
/* get rid of all installed sinks */
GstElement *element;
GstPad *pad, *peer;
+ if (play_bin->cache == NULL)
+ return;
+
GST_DEBUG ("removesinks");
element = g_hash_table_lookup (play_bin->cache, "abin");
if (element != NULL) {
* is disposed */
play_bin->sinks = g_list_remove (play_bin->sinks, element);
gst_element_set_state (element, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (parent), element);
+ gst_bin_remove (GST_BIN_CAST (parent), element);
gst_object_unref (parent);
}
pad = gst_element_get_pad (element, "sink");
if (parent != NULL) {
play_bin->sinks = g_list_remove (play_bin->sinks, element);
gst_element_set_state (element, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (parent), element);
+ gst_bin_remove (GST_BIN_CAST (parent), element);
gst_object_unref (parent);
}
pad = gst_element_get_pad (element, "sink");
}
for (sinks = play_bin->sinks; sinks; sinks = g_list_next (sinks)) {
- GstElement *element = GST_ELEMENT (sinks->data);
+ GstElement *element = GST_ELEMENT_CAST (sinks->data);
GstPad *pad;
GstPad *peer;
gst_object_unref (pad);
gst_element_set_state (element, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (play_bin), element);
+ gst_bin_remove (GST_BIN_CAST (play_bin), element);
}
g_list_free (play_bin->sinks);
play_bin->sinks = NULL;
- /* FIXME: this is probably some refcounting problem */
- if (play_bin->visualisation && GST_OBJECT_PARENT (play_bin->visualisation)) {
+ if (play_bin->visualisation) {
+ GstElement *vis_bin;
+
+ vis_bin =
+ GST_ELEMENT_CAST (gst_element_get_parent (play_bin->visualisation));
+
gst_element_set_state (play_bin->visualisation, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (GST_OBJECT_PARENT (play_bin->visualisation)),
- play_bin->visualisation);
+ gst_bin_remove (GST_BIN_CAST (vis_bin), play_bin->visualisation);
+
+ gst_object_unref (vis_bin);
}
if (play_bin->frame) {
* Also make sure to only connect the first audio and video pad. FIXME
* this should eventually be handled with a tuner interface so that
* one can switch the streams.
+ *
+ * This function takes ownership of @sink.*
*/
static gboolean
add_sink (GstPlayBin * play_bin, GstElement * sink, GstPad * srcpad,
GstPadLinkReturn linkres;
GstElement *parent;
GstStateChangeReturn stateret;
+ GstState state;
g_return_val_if_fail (sink != NULL, FALSE);
+
+ /* For live pipelines we need to add the bin in the same state as the
+ * parent so that it starts as soon as it is prerolled. */
+ if (play_bin->is_live)
+ state = GST_STATE_PLAYING;
+ else
+ state = GST_STATE_PAUSED;
+
/* this is only for debugging */
parent = gst_pad_get_parent_element (srcpad);
if (parent) {
GST_STATE (sink), GST_STATE (play_bin), GST_STATE (parent));
gst_object_unref (parent);
}
+ gst_bin_add (GST_BIN_CAST (play_bin), sink);
+
+ /* for live pipelines, disable the sync in the sinks until core handles this
+ * correctly. */
+ if (play_bin->is_live)
+ gst_element_set_clock (sink, NULL);
/* bring it to the PAUSED state so we can link to the peer without
* breaking the flow */
- if ((stateret = gst_element_set_state (sink, GST_STATE_PAUSED)) ==
- GST_STATE_CHANGE_FAILURE)
+ stateret = gst_element_set_state (sink, state);
+ if (stateret == GST_STATE_CHANGE_FAILURE)
goto state_failed;
- gst_bin_add (GST_BIN (play_bin), sink);
-
/* we found a sink for this stream, now try to install it */
sinkpad = gst_element_get_pad (sink, "sink");
linkres = gst_pad_link (srcpad, sinkpad);
gst_object_unref (sinkpad);
}
- /* try to link the subtitle pad of the sink to the stream */
- if (GST_PAD_LINK_FAILED (linkres)) {
+ /* try to link the subtitle pad of the sink to the stream, this is not
+ * fatal. */
+ if (GST_PAD_LINK_FAILED (linkres))
goto subtitle_failed;
- }
+done:
/* we got the sink succesfully linked, now keep the sink
* in our internal list */
play_bin->sinks = g_list_prepend (play_bin->sinks, sink);
/* ERRORS */
state_failed:
{
+ gst_element_set_state (sink, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN_CAST (play_bin), sink);
GST_DEBUG_OBJECT (play_bin, "state change failure when adding sink");
return FALSE;
}
gst_caps_unref (caps);
gst_element_set_state (sink, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (play_bin), sink);
+ gst_bin_remove (GST_BIN_CAST (play_bin), sink);
return FALSE;
}
subtitle_failed:
g_free (capsstr);
gst_caps_unref (caps);
- return TRUE;
+ /* not fatal */
+ goto done;
}
}
}
if (!sink)
return FALSE;
+
pad = gst_element_get_pad (group->type[GST_STREAM_TYPE_AUDIO - 1].preroll,
"src");
res = add_sink (play_bin, sink, pad, NULL);
"src");
/* This pad is from subtitle-bin, we need to create a ghost pad to have
common grandparents */
- parent = gst_object_get_parent (GST_OBJECT (textsrcpad));
+ parent = gst_object_get_parent (GST_OBJECT_CAST (textsrcpad));
if (!parent) {
GST_WARNING_OBJECT (textsrcpad, "subtitle pad has no parent !");
gst_object_unref (textsrcpad);
goto beach;
}
- if (gst_element_add_pad (GST_ELEMENT (grandparent), ghost)) {
+ if (gst_element_add_pad (GST_ELEMENT_CAST (grandparent), ghost)) {
gst_object_unref (textsrcpad);
textsrcpad = gst_object_ref (ghost);
} else {
"src");
res = add_sink (play_bin, sink, pad, textsrcpad);
gst_object_unref (pad);
- if (textsrcpad) {
+ if (textsrcpad)
gst_object_unref (textsrcpad);
- }
}
/* remove the sinks now, pipeline get_state will now wait for the
* sinks to preroll */
if (play_bin->fakesink) {
gst_element_set_state (play_bin->fakesink, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (play_bin), play_bin->fakesink);
+ gst_bin_remove (GST_BIN_CAST (play_bin), play_bin->fakesink);
play_bin->fakesink = NULL;
}
return res;
}
+/* Override the set_clock function, we don't want to set a clock on the sinks
+ * when we are live pipeline so that they don't synchronize until this is
+ * fixed in core. */
+static gboolean
+gst_play_bin_set_clock_func (GstElement * element, GstClock * clock)
+{
+ GList *children;
+ GstBin *bin;
+ GstPlayBin *play_bin;
+ gboolean res = TRUE;
+ GstElement *asink, *vsink;
+
+ bin = GST_BIN (element);
+ play_bin = GST_PLAY_BIN (element);
+
+ asink = g_hash_table_lookup (play_bin->cache, "audio_sink");
+ vsink = g_hash_table_lookup (play_bin->cache, "video_sink");
+
+ GST_DEBUG_OBJECT (play_bin, "setting clock, is_live %d", play_bin->is_live);
+
+ GST_OBJECT_LOCK (bin);
+ if (element->clock != clock) {
+ for (children = bin->children; children; children = g_list_next (children)) {
+ GstElement *child = GST_ELEMENT (children->data);
+
+ if (play_bin->is_live && (child == asink || child == vsink))
+ res &= gst_element_set_clock (child, NULL);
+ else
+ res &= gst_element_set_clock (child, clock);
+ }
+ }
+ GST_OBJECT_UNLOCK (bin);
+
+ return res;
+}
+
static void
value_list_append_structure_list (GValue * list_val, GstStructure ** first,
GList * structure_list)
* ASYNC until we added the sinks */
if (!play_bin->fakesink) {
play_bin->fakesink = gst_element_factory_make ("fakesink", "test");
- gst_bin_add (GST_BIN (play_bin), play_bin->fakesink);
+ gst_bin_add (GST_BIN_CAST (play_bin), play_bin->fakesink);
}
break;
default:
return ret;
switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ /* remember us being a live pipeline */
+ play_bin->is_live = (ret == GST_STATE_CHANGE_NO_PREROLL);
+ GST_DEBUG_OBJECT (play_bin, "is live: %d", play_bin->is_live);
+ break;
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- /* Set audio sink state to NULL to release the sound device,
- * but only if we own it (else we might be in chain-transition). */
- //if (play_bin->audio_sink != NULL &&
- // GST_STATE (play_bin->audio_sink) == GST_STATE_PAUSED) {
- // gst_element_set_state (play_bin->audio_sink, GST_STATE_NULL);
- //}
+ /* FIXME Release audio device when we implement that */
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
- /* Check for NULL because the state transition may be done by
- * gst_bin_dispose which is called by gst_play_bin_dispose, and in that
- * case, we don't want to run remove_sinks.
- * FIXME: should the NULL test be done in remove_sinks? Should we just
- * set the state to NULL in gst_play_bin_dispose?
- */
- if (play_bin->cache != NULL) {
- remove_sinks (play_bin);
- }
+ /* remove sinks we added */
+ remove_sinks (play_bin);
+ /* and there might be a fakesink we need to clean up now */
if (play_bin->fakesink) {
gst_element_set_state (play_bin->fakesink, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (play_bin), play_bin->fakesink);
+ gst_bin_remove (GST_BIN_CAST (play_bin), play_bin->fakesink);
play_bin->fakesink = NULL;
}
break;