GstPlayBin *playbin;
gboolean valid; /* the group has valid info to start playback */
+ gboolean active; /* the group is active */
/* properties */
gchar *uri;
GstSourceGroup *curr_group; /* pointer to the currently playing group */
GstSourceGroup *next_group; /* pointer to the next group */
+ gboolean about_to_finish; /* the about-to-finish signal is emited */
+
/* properties */
guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
PROP_0,
PROP_URI,
PROP_SUBURI,
- PROP_NEXT_URI,
- PROP_NEXT_SUBURI,
PROP_STREAMINFO,
PROP_SOURCE,
PROP_CURRENT_VIDEO,
};
static void gst_play_bin_class_init (GstPlayBinClass * klass);
-static void gst_play_bin_init (GstPlayBin * play_bin);
+static void gst_play_bin_init (GstPlayBin * playbin);
static void gst_play_bin_finalize (GObject * object);
static void gst_play_bin_set_property (GObject * object, guint prop_id,
g_object_class_install_property (gobject_klass, PROP_SUBURI,
g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
NULL, G_PARAM_READWRITE));
- g_object_class_install_property (gobject_klass, PROP_NEXT_URI,
- g_param_spec_string ("next-uri", "Next URI",
- "URI of the next media to play", NULL, G_PARAM_READWRITE));
- g_object_class_install_property (gobject_klass, PROP_NEXT_SUBURI,
- g_param_spec_string ("next-suburi", "Next .sub-URI",
- "Optional URI of a next subtitle", NULL, G_PARAM_READWRITE));
g_object_class_install_property (gobject_klass, PROP_STREAMINFO,
g_param_spec_value_array ("stream-info",
static void
gst_play_bin_finalize (GObject * object)
{
- GstPlayBin *play_bin;
+ GstPlayBin *playbin;
- play_bin = GST_PLAY_BIN (object);
+ playbin = GST_PLAY_BIN (object);
- g_value_array_free (play_bin->elements);
+ g_value_array_free (playbin->elements);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
-gst_play_bin_set_uri (GstPlayBin * play_bin, const gchar * uri)
+gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
{
GstSourceGroup *group;
return;
}
- GST_OBJECT_LOCK (play_bin);
- group = play_bin->next_group;
+ GST_OBJECT_LOCK (playbin);
+ group = playbin->next_group;
/* if we have no previous uri, or the new uri is different from the
* old one, replug */
group->valid = TRUE;
GST_DEBUG ("setting new uri to %s", uri);
- GST_OBJECT_UNLOCK (play_bin);
+ GST_OBJECT_UNLOCK (playbin);
}
static void
-gst_play_bin_set_suburi (GstPlayBin * play_bin, const gchar * suburi)
+gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
{
GstSourceGroup *group;
- GST_OBJECT_LOCK (play_bin);
- group = play_bin->next_group;
+ GST_OBJECT_LOCK (playbin);
+ group = playbin->next_group;
if ((!suburi && !group->suburi) ||
(suburi && group->suburi && !strcmp (group->suburi, suburi)))
GST_DEBUG ("setting new .sub uri to %s", suburi);
done:
- GST_OBJECT_UNLOCK (play_bin);
+ GST_OBJECT_UNLOCK (playbin);
}
static void
gst_play_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
- GstPlayBin *play_bin;
+ GstPlayBin *playbin;
- play_bin = GST_PLAY_BIN (object);
+ playbin = GST_PLAY_BIN (object);
switch (prop_id) {
case PROP_URI:
- gst_play_bin_set_uri (play_bin, g_value_get_string (value));
+ gst_play_bin_set_uri (playbin, g_value_get_string (value));
break;
case PROP_SUBURI:
- gst_play_bin_set_suburi (play_bin, g_value_get_string (value));
- break;
- case PROP_NEXT_URI:
- gst_play_bin_set_uri (play_bin, g_value_get_string (value));
- break;
- case PROP_NEXT_SUBURI:
- gst_play_bin_set_suburi (play_bin, g_value_get_string (value));
+ gst_play_bin_set_suburi (playbin, g_value_get_string (value));
break;
case PROP_VIDEO_SINK:
break;
case PROP_FONT_DESC:
break;
case PROP_CONNECTION_SPEED:
- GST_OBJECT_LOCK (play_bin);
- play_bin->connection_speed = g_value_get_uint (value) * 1000;
- GST_OBJECT_UNLOCK (play_bin);
+ GST_OBJECT_LOCK (playbin);
+ playbin->connection_speed = g_value_get_uint (value) * 1000;
+ GST_OBJECT_UNLOCK (playbin);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
- GstPlayBin *play_bin;
+ GstPlayBin *playbin;
- play_bin = GST_PLAY_BIN (object);
+ playbin = GST_PLAY_BIN (object);
switch (prop_id) {
case PROP_URI:
- GST_OBJECT_LOCK (play_bin);
- /* get the currently playing group first, then the queued one */
- if (play_bin->curr_group)
- g_value_set_string (value, play_bin->curr_group->uri);
+ GST_OBJECT_LOCK (playbin);
+ /* get the currently playing group first, then the queued one, just in
+ * case we did not yet start playback. */
+ if (playbin->curr_group)
+ g_value_set_string (value, playbin->curr_group->uri);
else
- g_value_set_string (value, play_bin->next_group->uri);
- GST_OBJECT_UNLOCK (play_bin);
+ g_value_set_string (value, playbin->next_group->uri);
+ GST_OBJECT_UNLOCK (playbin);
break;
case PROP_SUBURI:
- GST_OBJECT_LOCK (play_bin);
+ GST_OBJECT_LOCK (playbin);
/* get the currently playing group first, then the queued one */
- if (play_bin->curr_group)
- g_value_set_string (value, play_bin->curr_group->suburi);
+ if (playbin->curr_group)
+ g_value_set_string (value, playbin->curr_group->suburi);
else
- g_value_set_string (value, play_bin->next_group->suburi);
- GST_OBJECT_UNLOCK (play_bin);
- break;
- case PROP_NEXT_URI:
- GST_OBJECT_LOCK (play_bin);
- g_value_set_string (value, play_bin->next_group->uri);
- GST_OBJECT_UNLOCK (play_bin);
- break;
- case PROP_NEXT_SUBURI:
- GST_OBJECT_LOCK (play_bin);
- g_value_set_string (value, play_bin->next_group->suburi);
- GST_OBJECT_UNLOCK (play_bin);
+ g_value_set_string (value, playbin->next_group->suburi);
+ GST_OBJECT_UNLOCK (playbin);
break;
case PROP_VIDEO_SINK:
break;
case PROP_FRAME:
break;
case PROP_CONNECTION_SPEED:
- GST_OBJECT_LOCK (play_bin);
- g_value_set_uint (value, play_bin->connection_speed / 1000);
- GST_OBJECT_UNLOCK (play_bin);
+ GST_OBJECT_LOCK (playbin);
+ g_value_set_uint (value, playbin->connection_speed / 1000);
+ GST_OBJECT_UNLOCK (playbin);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
/* unlink the pad now (can fail, the pad is unlinked before it's removed) */
gst_pad_unlink (pad, peer);
- /* get selector */
+ /* get selector, this can be NULL when the element is removing the pads
+ * because it's being disposed. */
selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
+ if (!selector)
+ goto no_selector;
/* release the pad to the selector, this will make the selector choose a new
* pad. */
GST_DEBUG_OBJECT (playbin, "pad not linked");
return;
}
+no_selector:
+ {
+ GST_DEBUG_OBJECT (playbin, "selector not found");
+ return;
+ }
}
/* we get called when all pads are available and we must connect the sinks to
GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
+ /* mark use as sending out the about-to-finish signal. When the app sets a URI
+ * when this signal is emited, we're marking it as next-uri */
+ playbin->about_to_finish = TRUE;
+
/* after this call, we should have a next group to activate or we EOS */
g_signal_emit (G_OBJECT (playbin),
gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
+ playbin->about_to_finish = FALSE;
+
/* now activate the next group. If the app did not set a next-uri, this will
* fail and we can do EOS */
if (!setup_next_source (playbin)) {
return GST_AUTOPLUG_SELECT_EXPOSE;
}
-/* unlink a group of uridecodebins from the sink */
-static void
-unlink_group (GstPlayBin * playbin, GstSourceGroup * group)
-{
- gint i;
-
- GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
-
- for (i = 0; i < 3; i++) {
- GstSourceSelect *select = &group->selector[i];
-
- if (!select->selector)
- continue;
-
- GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media);
- gst_pad_unlink (select->srcpad, select->sinkpad);
-
- /* release back */
- gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
- select->sinkpad = NULL;
-
- gst_object_unref (select->srcpad);
- select->srcpad = NULL;
-
- gst_element_set_state (select->selector, GST_STATE_NULL);
- gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
- select->selector = NULL;
- }
- group->valid = FALSE;
-}
-
static gboolean
activate_group (GstPlayBin * playbin, GstSourceGroup * group)
{
GstElement *uridecodebin;
+ g_return_val_if_fail (group->valid, FALSE);
+ g_return_val_if_fail (!group->active, FALSE);
+
+ if (group->uridecodebin) {
+ gst_element_set_state (group->uridecodebin, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
+ group->uridecodebin = NULL;
+ }
+
uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
if (!uridecodebin)
goto no_decodebin;
gst_element_set_state (uridecodebin, GST_STATE_PAUSED);
+ group->active = TRUE;
+
return TRUE;
/* ERRORS */
}
}
-/* setup the next group to play */
+/* unlink a group of uridecodebins from the sink */
+static gboolean
+deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
+{
+ gint i;
+
+ g_return_val_if_fail (group->valid, FALSE);
+ g_return_val_if_fail (group->active, FALSE);
+
+ GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
+
+ for (i = 0; i < 3; i++) {
+ GstSourceSelect *select = &group->selector[i];
+
+ if (!select->selector)
+ continue;
+
+ GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media);
+ gst_pad_unlink (select->srcpad, select->sinkpad);
+
+ /* release back */
+ gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
+ select->sinkpad = NULL;
+
+ gst_object_unref (select->srcpad);
+ select->srcpad = NULL;
+
+ gst_element_set_state (select->selector, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
+ select->selector = NULL;
+ }
+ group->active = FALSE;
+
+ return TRUE;
+}
+
+/* setup the next group to play, this assumes the next_group is valid and
+ * configured. It swaps out the current_group and activates the valid
+ * next_group. */
static gboolean
setup_next_source (GstPlayBin * playbin)
{
old_group = playbin->curr_group;
if (old_group && old_group->valid) {
/* unlink our pads with the sink */
- unlink_group (playbin, old_group);
+ deactivate_group (playbin, old_group);
+ old_group->valid = FALSE;
}
/* activate the new group */
}
}
+/* The group that is currently playing is copied again to the
+ * next_group.
+ */
+static gboolean
+save_current_group (GstPlayBin * playbin)
+{
+ GstSourceGroup *curr_group;
+
+ GST_DEBUG_OBJECT (playbin, "save current group");
+
+ /* see if there is a current group */
+ curr_group = playbin->curr_group;
+ if (curr_group && curr_group->valid) {
+ /* unlink our pads with the sink */
+ deactivate_group (playbin, curr_group);
+ }
+ /* swap old and new */
+ playbin->curr_group = playbin->next_group;
+ playbin->next_group = curr_group;
+
+ return TRUE;
+}
+
static GstStateChangeReturn
gst_play_bin_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
- GstPlayBin *play_bin;
+ GstPlayBin *playbin;
- play_bin = GST_PLAY_BIN (element);
+ playbin = GST_PLAY_BIN (element);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
- if (play_bin->playsink == NULL) {
- play_bin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
- gst_bin_add (GST_BIN_CAST (play_bin),
- GST_ELEMENT_CAST (play_bin->playsink));
+ if (playbin->playsink == NULL) {
+ playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
+ gst_bin_add (GST_BIN_CAST (playbin),
+ GST_ELEMENT_CAST (playbin->playsink));
}
- if (!setup_next_source (play_bin))
+ if (!setup_next_source (playbin))
goto source_failed;
break;
default:
/* FIXME Release audio device when we implement that */
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
- if (play_bin->playsink) {
- gst_bin_remove (GST_BIN_CAST (play_bin),
- GST_ELEMENT_CAST (play_bin->playsink));
- play_bin->playsink = NULL;
+ save_current_group (playbin);
+ if (playbin->playsink) {
+ gst_element_set_state (GST_ELEMENT_CAST (playbin->playsink),
+ GST_STATE_NULL);
+ gst_bin_remove (GST_BIN_CAST (playbin),
+ GST_ELEMENT_CAST (playbin->playsink));
+ playbin->playsink = NULL;
}
break;
default:
GstElement *sink;
} GstPlayVideoChain;
+#define GST_PLAY_SINK_GET_LOCK(playsink) (((GstPlaySink *)playsink)->lock)
+#define GST_PLAY_SINK_LOCK(playsink) g_mutex_lock (GST_PLAY_SINK_GET_LOCK (playsink))
+#define GST_PLAY_SINK_UNLOCK(playsink) g_mutex_unlock (GST_PLAY_SINK_GET_LOCK (playsink))
+
struct _GstPlaySink
{
GstBin bin;
+ GMutex *lock;
+
GstPlaySinkMode mode;
+ GstPlaySinkFlags flags;
GstPlayChain *audiochain;
GstPlayChain *videochain;
};
static void gst_play_sink_class_init (GstPlaySinkClass * klass);
-static void gst_play_sink_init (GstPlaySink * play_sink);
+static void gst_play_sink_init (GstPlaySink * playsink);
static void gst_play_sink_dispose (GObject * object);
+static void gst_play_sink_finalize (GObject * object);
static void gst_play_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * spec);
gobject_klass->get_property = gst_play_sink_get_property;
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_sink_dispose);
+ gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_sink_finalize);
g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
g_param_spec_object ("video-sink", "Video Sink",
}
static void
-gst_play_sink_init (GstPlaySink * play_sink)
+gst_play_sink_init (GstPlaySink * playsink)
{
/* init groups */
- play_sink->video_sink = NULL;
- play_sink->audio_sink = NULL;
- play_sink->visualisation = NULL;
- play_sink->pending_visualisation = NULL;
- play_sink->textoverlay_element = NULL;
- play_sink->volume = 1.0;
- play_sink->font_desc = NULL;
+ playsink->video_sink = NULL;
+ playsink->audio_sink = NULL;
+ playsink->visualisation = NULL;
+ playsink->pending_visualisation = NULL;
+ playsink->textoverlay_element = NULL;
+ playsink->volume = 1.0;
+ playsink->font_desc = NULL;
+ playsink->flags = GST_PLAY_SINK_FLAG_SOFT_VOLUME;
+
+ playsink->lock = g_mutex_new ();
}
static void
gst_play_sink_dispose (GObject * object)
{
- GstPlaySink *play_sink;
+ GstPlaySink *playsink;
- play_sink = GST_PLAY_SINK (object);
+ playsink = GST_PLAY_SINK (object);
- if (play_sink->audio_sink != NULL) {
- gst_element_set_state (play_sink->audio_sink, GST_STATE_NULL);
- gst_object_unref (play_sink->audio_sink);
- play_sink->audio_sink = NULL;
+ if (playsink->audio_sink != NULL) {
+ gst_element_set_state (playsink->audio_sink, GST_STATE_NULL);
+ gst_object_unref (playsink->audio_sink);
+ playsink->audio_sink = NULL;
}
- if (play_sink->video_sink != NULL) {
- gst_element_set_state (play_sink->video_sink, GST_STATE_NULL);
- gst_object_unref (play_sink->video_sink);
- play_sink->video_sink = NULL;
+ if (playsink->video_sink != NULL) {
+ gst_element_set_state (playsink->video_sink, GST_STATE_NULL);
+ gst_object_unref (playsink->video_sink);
+ playsink->video_sink = NULL;
}
- if (play_sink->visualisation != NULL) {
- gst_element_set_state (play_sink->visualisation, GST_STATE_NULL);
- gst_object_unref (play_sink->visualisation);
- play_sink->visualisation = NULL;
+ if (playsink->visualisation != NULL) {
+ gst_element_set_state (playsink->visualisation, GST_STATE_NULL);
+ gst_object_unref (playsink->visualisation);
+ playsink->visualisation = NULL;
}
- if (play_sink->pending_visualisation != NULL) {
- gst_element_set_state (play_sink->pending_visualisation, GST_STATE_NULL);
- gst_object_unref (play_sink->pending_visualisation);
- play_sink->pending_visualisation = NULL;
+ if (playsink->pending_visualisation != NULL) {
+ gst_element_set_state (playsink->pending_visualisation, GST_STATE_NULL);
+ gst_object_unref (playsink->pending_visualisation);
+ playsink->pending_visualisation = NULL;
}
- if (play_sink->textoverlay_element != NULL) {
- gst_object_unref (play_sink->textoverlay_element);
- play_sink->textoverlay_element = NULL;
+ if (playsink->textoverlay_element != NULL) {
+ gst_object_unref (playsink->textoverlay_element);
+ playsink->textoverlay_element = NULL;
}
- g_free (play_sink->font_desc);
- play_sink->font_desc = NULL;
+ g_free (playsink->font_desc);
+ playsink->font_desc = NULL;
G_OBJECT_CLASS (parent_class)->dispose (object);
}
+static void
+gst_play_sink_finalize (GObject * object)
+{
+ GstPlaySink *playsink;
+
+ playsink = GST_PLAY_SINK (object);
+
+ g_mutex_free (playsink->lock);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
static void
gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked,
gpointer user_data)
{
- GstPlaySink *play_sink = GST_PLAY_SINK (user_data);
+ GstPlaySink *playsink = GST_PLAY_SINK (user_data);
- if (play_sink->pending_visualisation)
+ if (playsink->pending_visualisation)
gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
- play_sink);
+ playsink);
}
static void
gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
gpointer user_data)
{
- GstPlaySink *play_sink = GST_PLAY_SINK (user_data);
+ GstPlaySink *playsink = GST_PLAY_SINK (user_data);
GstBin *vis_bin = NULL;
GstPad *vis_sink_pad = NULL, *vis_src_pad = NULL, *vqueue_pad = NULL;
GstState bin_state;
GstElement *pending_visualisation;
- GST_OBJECT_LOCK (play_sink);
- pending_visualisation = play_sink->pending_visualisation;
- play_sink->pending_visualisation = NULL;
- GST_OBJECT_UNLOCK (play_sink);
+ GST_OBJECT_LOCK (playsink);
+ pending_visualisation = playsink->pending_visualisation;
+ playsink->pending_visualisation = NULL;
+ GST_OBJECT_UNLOCK (playsink);
/* We want to disable visualisation */
if (!GST_IS_ELEMENT (pending_visualisation)) {
/* Set visualisation element to READY */
- gst_element_set_state (play_sink->visualisation, GST_STATE_READY);
+ gst_element_set_state (playsink->visualisation, GST_STATE_READY);
goto beach;
}
vis_bin =
- GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST (play_sink->
+ GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST (playsink->
visualisation)));
if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) {
goto beach;
}
- vis_src_pad = gst_element_get_pad (play_sink->visualisation, "src");
+ vis_src_pad = gst_element_get_pad (playsink->visualisation, "src");
vis_sink_pad = gst_pad_get_peer (tee_pad);
/* Can be fakesink */
}
/* Remove from vis_bin */
- gst_bin_remove (vis_bin, play_sink->visualisation);
+ gst_bin_remove (vis_bin, playsink->visualisation);
/* Set state to NULL */
- gst_element_set_state (play_sink->visualisation, GST_STATE_NULL);
+ gst_element_set_state (playsink->visualisation, GST_STATE_NULL);
/* And loose our ref */
- gst_object_unref (play_sink->visualisation);
+ gst_object_unref (playsink->visualisation);
if (pending_visualisation) {
/* Ref this new visualisation element before adding to the bin */
}
/* We are done */
- gst_object_unref (play_sink->visualisation);
- play_sink->visualisation = pending_visualisation;
+ gst_object_unref (playsink->visualisation);
+ playsink->visualisation = pending_visualisation;
beach:
if (vis_sink_pad) {
/* Unblock the pad */
gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
- play_sink);
+ playsink);
}
void
-gst_play_sink_set_video_sink (GstPlaySink * play_sink, GstElement * sink)
+gst_play_sink_set_video_sink (GstPlaySink * playsink, GstElement * sink)
{
- GST_OBJECT_LOCK (play_sink);
- if (play_sink->video_sink)
- gst_object_unref (play_sink->video_sink);
+ GST_OBJECT_LOCK (playsink);
+ if (playsink->video_sink)
+ gst_object_unref (playsink->video_sink);
if (sink) {
gst_object_ref (sink);
gst_object_sink (sink);
}
- play_sink->video_sink = sink;
- GST_OBJECT_UNLOCK (play_sink);
+ playsink->video_sink = sink;
+ GST_OBJECT_UNLOCK (playsink);
}
void
-gst_play_sink_set_audio_sink (GstPlaySink * play_sink, GstElement * sink)
+gst_play_sink_set_audio_sink (GstPlaySink * playsink, GstElement * sink)
{
- GST_OBJECT_LOCK (play_sink);
- if (play_sink->audio_sink)
- gst_object_unref (play_sink->audio_sink);
+ GST_OBJECT_LOCK (playsink);
+ if (playsink->audio_sink)
+ gst_object_unref (playsink->audio_sink);
if (sink) {
gst_object_ref (sink);
gst_object_sink (sink);
}
- play_sink->audio_sink = sink;
- GST_OBJECT_UNLOCK (play_sink);
+ playsink->audio_sink = sink;
+ GST_OBJECT_UNLOCK (playsink);
}
void
-gst_play_sink_set_vis_plugin (GstPlaySink * play_sink,
+gst_play_sink_set_vis_plugin (GstPlaySink * playsink,
GstElement * pending_visualisation)
{
/* Take ownership */
/* Do we already have a visualisation change pending? If yes, change the
* pending vis with the new one. */
- GST_OBJECT_LOCK (play_sink);
- if (play_sink->pending_visualisation) {
- gst_object_unref (play_sink->pending_visualisation);
- play_sink->pending_visualisation = pending_visualisation;
- GST_OBJECT_UNLOCK (play_sink);
+ GST_OBJECT_LOCK (playsink);
+ if (playsink->pending_visualisation) {
+ gst_object_unref (playsink->pending_visualisation);
+ playsink->pending_visualisation = pending_visualisation;
+ GST_OBJECT_UNLOCK (playsink);
} else {
- GST_OBJECT_UNLOCK (play_sink);
+ GST_OBJECT_UNLOCK (playsink);
/* Was there a visualisation already set ? */
- if (play_sink->visualisation != NULL) {
+ if (playsink->visualisation != NULL) {
GstBin *vis_bin = NULL;
vis_bin =
- GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST (play_sink->
+ GST_BIN_CAST (gst_object_get_parent (GST_OBJECT_CAST (playsink->
visualisation)));
/* Check if the visualisation is already in a bin */
GstPad *vis_sink_pad = NULL, *tee_pad = NULL;
/* Now get tee pad and block it async */
- vis_sink_pad = gst_element_get_pad (play_sink->visualisation, "sink");
+ vis_sink_pad = gst_element_get_pad (playsink->visualisation, "sink");
if (!GST_IS_PAD (vis_sink_pad)) {
goto beach;
}
goto beach;
}
- play_sink->pending_visualisation = pending_visualisation;
+ playsink->pending_visualisation = pending_visualisation;
/* Block with callback */
gst_pad_set_blocked_async (tee_pad, TRUE, gst_play_sink_vis_blocked,
- play_sink);
+ playsink);
beach:
if (vis_sink_pad) {
gst_object_unref (vis_sink_pad);
}
gst_object_unref (vis_bin);
} else {
- play_sink->visualisation = pending_visualisation;
+ playsink->visualisation = pending_visualisation;
}
} else {
- play_sink->visualisation = pending_visualisation;
+ playsink->visualisation = pending_visualisation;
}
}
}
gst_play_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
- GstPlaySink *play_sink;
+ GstPlaySink *playsink;
- play_sink = GST_PLAY_SINK (object);
+ playsink = GST_PLAY_SINK (object);
switch (prop_id) {
case PROP_VIDEO_SINK:
- gst_play_sink_set_video_sink (play_sink, g_value_get_object (value));
+ gst_play_sink_set_video_sink (playsink, g_value_get_object (value));
break;
case PROP_AUDIO_SINK:
- gst_play_sink_set_audio_sink (play_sink, g_value_get_object (value));
+ gst_play_sink_set_audio_sink (playsink, g_value_get_object (value));
break;
case PROP_VIS_PLUGIN:
- gst_play_sink_set_vis_plugin (play_sink, g_value_get_object (value));
+ gst_play_sink_set_vis_plugin (playsink, g_value_get_object (value));
break;
case PROP_VOLUME:
- GST_OBJECT_LOCK (play_sink);
- play_sink->volume = g_value_get_double (value);
- GST_OBJECT_UNLOCK (play_sink);
+ GST_OBJECT_LOCK (playsink);
+ playsink->volume = g_value_get_double (value);
+ GST_OBJECT_UNLOCK (playsink);
break;
case PROP_FONT_DESC:
- GST_OBJECT_LOCK (play_sink);
- g_free (play_sink->font_desc);
- play_sink->font_desc = g_strdup (g_value_get_string (value));
- if (play_sink->textoverlay_element) {
- g_object_set (G_OBJECT (play_sink->textoverlay_element),
+ GST_OBJECT_LOCK (playsink);
+ g_free (playsink->font_desc);
+ playsink->font_desc = g_strdup (g_value_get_string (value));
+ if (playsink->textoverlay_element) {
+ g_object_set (G_OBJECT (playsink->textoverlay_element),
"font-desc", g_value_get_string (value), NULL);
}
- GST_OBJECT_UNLOCK (play_sink);
+ GST_OBJECT_UNLOCK (playsink);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
gst_play_sink_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
- GstPlaySink *play_sink;
+ GstPlaySink *playsink;
- play_sink = GST_PLAY_SINK (object);
+ playsink = GST_PLAY_SINK (object);
switch (prop_id) {
case PROP_VIDEO_SINK:
- GST_OBJECT_LOCK (play_sink);
- g_value_set_object (value, play_sink->video_sink);
- GST_OBJECT_UNLOCK (play_sink);
+ GST_OBJECT_LOCK (playsink);
+ g_value_set_object (value, playsink->video_sink);
+ GST_OBJECT_UNLOCK (playsink);
break;
case PROP_AUDIO_SINK:
- GST_OBJECT_LOCK (play_sink);
- g_value_set_object (value, play_sink->audio_sink);
- GST_OBJECT_UNLOCK (play_sink);
+ GST_OBJECT_LOCK (playsink);
+ g_value_set_object (value, playsink->audio_sink);
+ GST_OBJECT_UNLOCK (playsink);
break;
case PROP_VIS_PLUGIN:
- GST_OBJECT_LOCK (play_sink);
- g_value_set_object (value, play_sink->visualisation);
- GST_OBJECT_UNLOCK (play_sink);
+ GST_OBJECT_LOCK (playsink);
+ g_value_set_object (value, playsink->visualisation);
+ GST_OBJECT_UNLOCK (playsink);
break;
case PROP_VOLUME:
- GST_OBJECT_LOCK (play_sink);
- g_value_set_double (value, play_sink->volume);
- GST_OBJECT_UNLOCK (play_sink);
+ GST_OBJECT_LOCK (playsink);
+ g_value_set_double (value, playsink->volume);
+ GST_OBJECT_UNLOCK (playsink);
break;
case PROP_FRAME:
{
*
*/
static GstPlayChain *
-gen_video_chain (GstPlaySink * play_sink, gboolean raw)
+gen_video_chain (GstPlaySink * playsink, gboolean raw)
{
GstPlayVideoChain *chain;
GstBin *bin;
GstPad *pad;
chain = g_new0 (GstPlayVideoChain, 1);
- chain->chain.playsink = gst_object_ref (play_sink);
+ chain->chain.playsink = gst_object_ref (playsink);
- if (play_sink->video_sink) {
- chain->sink = play_sink->video_sink;
+ if (playsink->video_sink) {
+ chain->sink = playsink->video_sink;
} else {
chain->sink = gst_element_factory_make ("autovideosink", "videosink");
if (chain->sink == NULL) {
/* ERRORS */
no_sinks:
{
- post_missing_element_message (play_sink, "autovideosink");
- GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN,
+ post_missing_element_message (playsink, "autovideosink");
+ GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Both autovideosink and xvimagesink elements are missing.")),
(NULL));
free_chain ((GstPlayChain *) chain);
}
no_colorspace:
{
- post_missing_element_message (play_sink, "ffmpegcolorspace");
- GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN,
+ post_missing_element_message (playsink, "ffmpegcolorspace");
+ GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"ffmpegcolorspace"), (NULL));
free_chain ((GstPlayChain *) chain);
no_videoscale:
{
- post_missing_element_message (play_sink, "videoscale");
- GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN,
+ post_missing_element_message (playsink, "videoscale");
+ GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"videoscale"), ("possibly a liboil version mismatch?"));
free_chain ((GstPlayChain *) chain);
}
link_failed:
{
- GST_ELEMENT_ERROR (play_sink, CORE, PAD,
+ GST_ELEMENT_ERROR (playsink, CORE, PAD,
(NULL), ("Failed to configure the video sink."));
free_chain ((GstPlayChain *) chain);
return NULL;
* videosink without the text_sink pad.
*/
static GstElement *
-gen_text_element (GstPlaySink * play_sink)
+gen_text_element (GstPlaySink * playsink)
{
GstElement *element, *csp, *overlay, *vbin;
GstPad *pad;
/* Create the video rendering bin, error is posted when this fails. */
- vbin = gen_video_element (play_sink);
+ vbin = gen_video_element (playsink);
if (!vbin)
return NULL;
/* Set some parameters */
g_object_set (G_OBJECT (overlay),
"halign", "center", "valign", "bottom", NULL);
- if (play_sink->font_desc) {
- g_object_set (G_OBJECT (overlay), "font-desc", play_sink->font_desc, NULL);
+ if (playsink->font_desc) {
+ g_object_set (G_OBJECT (overlay), "font-desc", playsink->font_desc, NULL);
}
/* Take a ref */
- play_sink->textoverlay_element = GST_ELEMENT_CAST (gst_object_ref (overlay));
+ playsink->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");
/* ERRORS */
no_overlay:
{
- post_missing_element_message (play_sink, "textoverlay");
- GST_WARNING_OBJECT (play_sink,
+ post_missing_element_message (playsink, "textoverlay");
+ GST_WARNING_OBJECT (playsink,
"No overlay (pango) element, subtitles disabled");
return vbin;
}
* +-------------------------------------------------------------+
*/
static GstPlayChain *
-gen_audio_chain (GstPlaySink * play_sink, gboolean raw)
+gen_audio_chain (GstPlaySink * playsink, gboolean raw)
{
GstPlayAudioChain *chain;
GstBin *bin;
GstPad *pad;
chain = g_new0 (GstPlayAudioChain, 1);
- chain->chain.playsink = gst_object_ref (play_sink);
+ chain->chain.playsink = gst_object_ref (playsink);
- if (play_sink->audio_sink) {
- chain->sink = play_sink->audio_sink;
+ if (playsink->audio_sink) {
+ chain->sink = playsink->audio_sink;
} else {
chain->sink = gst_element_factory_make ("autoaudiosink", "audiosink");
if (chain->sink == NULL) {
goto no_audioresample;
gst_bin_add (bin, chain->resample);
- chain->volume = gst_element_factory_make ("volume", "volume");
- g_object_set (G_OBJECT (chain->volume), "volume", play_sink->volume, NULL);
- gst_bin_add (bin, chain->volume);
-
res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink");
- res &=
- gst_element_link_pads (chain->resample, "src", chain->volume, "sink");
- res &= gst_element_link_pads (chain->volume, "src", chain->sink, NULL);
+
+ if (playsink->flags & GST_PLAY_SINK_FLAG_SOFT_VOLUME) {
+ chain->volume = gst_element_factory_make ("volume", "volume");
+ g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
+ gst_bin_add (bin, chain->volume);
+
+ res &=
+ gst_element_link_pads (chain->resample, "src", chain->volume, "sink");
+ res &= gst_element_link_pads (chain->volume, "src", chain->sink, NULL);
+ } else {
+ res &= gst_element_link_pads (chain->resample, "src", chain->sink, NULL);
+ }
if (!res)
goto link_failed;
/* ERRORS */
no_sinks:
{
- post_missing_element_message (play_sink, "autoaudiosink");
- GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN,
+ post_missing_element_message (playsink, "autoaudiosink");
+ GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Both autoaudiosink and alsasink elements are missing.")), (NULL));
free_chain ((GstPlayChain *) chain);
return NULL;
}
no_audioconvert:
{
- post_missing_element_message (play_sink, "audioconvert");
- GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN,
+ post_missing_element_message (playsink, "audioconvert");
+ GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"audioconvert"), ("possibly a liboil version mismatch?"));
free_chain ((GstPlayChain *) chain);
no_audioresample:
{
- post_missing_element_message (play_sink, "audioresample");
- GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN,
+ post_missing_element_message (playsink, "audioresample");
+ GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"audioresample"), ("possibly a liboil version mismatch?"));
free_chain ((GstPlayChain *) chain);
}
link_failed:
{
- GST_ELEMENT_ERROR (play_sink, CORE, PAD,
+ GST_ELEMENT_ERROR (playsink, CORE, PAD,
(NULL), ("Failed to configure the audio sink."));
free_chain ((GstPlayChain *) chain);
return NULL;
* +-----------------------------------------------------------------------+
*/
static GstElement *
-gen_vis_element (GstPlaySink * play_sink)
+gen_vis_element (GstPlaySink * playsink)
{
gboolean res;
GstElement *element;
GstPad *pad, *rpad;
/* errors are already posted when these fail. */
- asink = gen_audio_element (play_sink);
+ asink = gen_audio_element (playsink);
if (!asink)
return NULL;
- vsink = gen_video_element (play_sink);
+ vsink = gen_video_element (playsink);
if (!vsink) {
gst_object_unref (asink);
return NULL;
goto no_audioconvert;
gst_bin_add (GST_BIN_CAST (element), conv2);
- if (play_sink->visualisation) {
- gst_object_ref (play_sink->visualisation);
- vis = play_sink->visualisation;
+ if (playsink->visualisation) {
+ gst_object_ref (playsink->visualisation);
+ vis = playsink->visualisation;
} else {
vis = gst_element_factory_make ("goom", "vis");
if (!vis)
/* ERRORS */
no_audioconvert:
{
- post_missing_element_message (play_sink, "audioconvert");
- GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN,
+ post_missing_element_message (playsink, "audioconvert");
+ GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"audioconvert"), ("possibly a liboil version mismatch?"));
gst_object_unref (element);
}
no_audioresample:
{
- post_missing_element_message (play_sink, "audioresample");
- GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN,
+ post_missing_element_message (playsink, "audioresample");
+ GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"audioresample"), (NULL));
gst_object_unref (element);
}
no_goom:
{
- post_missing_element_message (play_sink, "goom");
- GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN,
+ post_missing_element_message (playsink, "goom");
+ GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
"goom"), (NULL));
gst_object_unref (element);
}
link_failed:
{
- GST_ELEMENT_ERROR (play_sink, CORE, PAD,
+ GST_ELEMENT_ERROR (playsink, CORE, PAD,
(NULL), ("Failed to configure the visualisation element."));
gst_object_unref (element);
return NULL;
{
GstPlaySinkMode res;
- GST_OBJECT_LOCK (playsink);
+ GST_PLAY_SINK_LOCK (playsink);
res = playsink->mode;
- GST_OBJECT_LOCK (playsink);
+ GST_PLAY_SINK_UNLOCK (playsink);
return res;
}
gboolean
gst_play_sink_set_mode (GstPlaySink * playsink, GstPlaySinkMode mode)
{
+ GST_DEBUG_OBJECT (playsink, "setting mode to %d", mode);
+
+ GST_PLAY_SINK_LOCK (playsink);
if (mode & GST_PLAY_SINK_MODE_AUDIO && playsink->audio_pad) {
if (!playsink->audiochain)
playsink->audiochain =
}
playsink->mode = mode;
+ GST_PLAY_SINK_UNLOCK (playsink);
+
+ return TRUE;
+}
+
+gboolean
+gst_play_sink_set_flags (GstPlaySink * playsink, GstPlaySinkFlags flags)
+{
+ g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), FALSE);
+
+ GST_OBJECT_LOCK (playsink);
+ playsink->flags = flags;
+ GST_OBJECT_LOCK (playsink);
return TRUE;
}
+GstPlaySinkFlags
+gst_play_sink_get_flags (GstPlaySink * playsink)
+{
+ GstPlaySinkFlags res;
+
+ g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), 0);
+
+ GST_OBJECT_LOCK (playsink);
+ res = playsink->flags;
+ GST_OBJECT_LOCK (playsink);
+
+ return res;
+}
+
+
GstPad *
gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
{
gboolean created = FALSE;
gboolean raw = FALSE;
+ GST_PLAY_SINK_LOCK (playsink);
switch (type) {
case GST_PLAY_SINK_TYPE_AUDIO_RAW:
raw = TRUE;
res = NULL;
break;
}
+ GST_PLAY_SINK_UNLOCK (playsink);
+
if (created && res) {
gst_pad_set_active (res, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (playsink), res);
}
+
return res;
}
{
GstPad **res = NULL;
+ GST_PLAY_SINK_LOCK (playsink);
if (pad == playsink->video_pad) {
res = &playsink->video_pad;
} else if (pad == playsink->audio_pad) {
} else if (pad == playsink->text_pad) {
res = &playsink->text_pad;
}
+ GST_PLAY_SINK_UNLOCK (playsink);
if (*res) {
gst_pad_set_active (*res, FALSE);
* remaining sinks (unlike GstBin)
*/
static gboolean
-gst_play_sink_send_event_to_sink (GstPlaySink * play_sink, GstEvent * event)
+gst_play_sink_send_event_to_sink (GstPlaySink * playsink, GstEvent * event)
{
gboolean res = TRUE;
- if (play_sink->audiochain) {
+ if (playsink->audiochain) {
gst_event_ref (event);
- if ((res = gst_element_send_event (play_sink->audiochain->bin, event))) {
- GST_DEBUG_OBJECT (play_sink, "Sent event succesfully to audio sink");
+ if ((res = gst_element_send_event (playsink->audiochain->bin, event))) {
+ GST_DEBUG_OBJECT (playsink, "Sent event succesfully to audio sink");
goto done;
}
- GST_DEBUG_OBJECT (play_sink, "Event failed when sent to audio sink");
+ GST_DEBUG_OBJECT (playsink, "Event failed when sent to audio sink");
}
- if (play_sink->videochain) {
+ if (playsink->videochain) {
gst_event_ref (event);
- if ((res = gst_element_send_event (play_sink->videochain->bin, event))) {
- GST_DEBUG_OBJECT (play_sink, "Sent event succesfully to video sink");
+ if ((res = gst_element_send_event (playsink->videochain->bin, event))) {
+ GST_DEBUG_OBJECT (playsink, "Sent event succesfully to video sink");
goto done;
}
- GST_DEBUG_OBJECT (play_sink, "Event failed when sent to video sink");
+ GST_DEBUG_OBJECT (playsink, "Event failed when sent to video sink");
}
done:
gst_event_unref (event);
gst_play_sink_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
- GstPlaySink *play_sink;
+ GstPlaySink *playsink;
- play_sink = GST_PLAY_SINK (element);
+ playsink = GST_PLAY_SINK (element);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED: