gst/playback/gstplaybin2.c: Code cleanups.

Original commit message from CVS:
* gst/playback/gstplaybin2.c: (gst_play_bin_class_init),
(gst_play_bin_finalize), (gst_play_bin_set_uri),
(gst_play_bin_set_suburi), (gst_play_bin_set_property),
(gst_play_bin_get_property), (pad_removed_cb), (drained_cb),
(autoplug_select_cb), (activate_group), (deactivate_group),
(setup_next_source), (save_current_group),
(gst_play_bin_change_state):
Code cleanups.
Remove next-uri, we can use the uri property just fine.
Fix some crasher.
Unref uridecodebin when switching.
Fix going to READY.
* gst/playback/gstplaysink.c: (gst_play_sink_class_init),
(gst_play_sink_init), (gst_play_sink_dispose),
(gst_play_sink_finalize), (gst_play_sink_vis_unblocked),
(gst_play_sink_vis_blocked), (gst_play_sink_set_video_sink),
(gst_play_sink_set_audio_sink), (gst_play_sink_set_vis_plugin),
(gst_play_sink_set_property), (gst_play_sink_get_property),
(gen_video_chain), (gen_text_element), (gen_audio_chain),
(gen_vis_element), (gst_play_sink_get_mode),
(gst_play_sink_set_mode), (gst_play_sink_set_flags),
(gst_play_sink_get_flags), (gst_play_sink_request_pad),
(gst_play_sink_release_pad), (gst_play_sink_send_event_to_sink),
(gst_play_sink_change_state):
* gst/playback/gstplaysink.h:
Add some locking to make things threadsafe.
* gst/playback/test7.c: (about_to_finish_cb):
Fix test.
This commit is contained in:
Wim Taymans 2007-12-28 09:00:27 +00:00
parent bd01fd3a57
commit 7cb7bffb9e
5 changed files with 431 additions and 274 deletions

View File

@ -1,3 +1,36 @@
2007-12-28 Wim Taymans <wim.taymans@collabora.co.uk>
* gst/playback/gstplaybin2.c: (gst_play_bin_class_init),
(gst_play_bin_finalize), (gst_play_bin_set_uri),
(gst_play_bin_set_suburi), (gst_play_bin_set_property),
(gst_play_bin_get_property), (pad_removed_cb), (drained_cb),
(autoplug_select_cb), (activate_group), (deactivate_group),
(setup_next_source), (save_current_group),
(gst_play_bin_change_state):
Code cleanups.
Remove next-uri, we can use the uri property just fine.
Fix some crasher.
Unref uridecodebin when switching.
Fix going to READY.
* gst/playback/gstplaysink.c: (gst_play_sink_class_init),
(gst_play_sink_init), (gst_play_sink_dispose),
(gst_play_sink_finalize), (gst_play_sink_vis_unblocked),
(gst_play_sink_vis_blocked), (gst_play_sink_set_video_sink),
(gst_play_sink_set_audio_sink), (gst_play_sink_set_vis_plugin),
(gst_play_sink_set_property), (gst_play_sink_get_property),
(gen_video_chain), (gen_text_element), (gen_audio_chain),
(gen_vis_element), (gst_play_sink_get_mode),
(gst_play_sink_set_mode), (gst_play_sink_set_flags),
(gst_play_sink_get_flags), (gst_play_sink_request_pad),
(gst_play_sink_release_pad), (gst_play_sink_send_event_to_sink),
(gst_play_sink_change_state):
* gst/playback/gstplaysink.h:
Add some locking to make things threadsafe.
* gst/playback/test7.c: (about_to_finish_cb):
Fix test.
2007-12-22 Tim-Philipp Müller <tim at centricular dot net> 2007-12-22 Tim-Philipp Müller <tim at centricular dot net>
* gst/videoscale/gstvideoscale.c: (gst_video_scale_set_property), * gst/videoscale/gstvideoscale.c: (gst_video_scale_set_property),

View File

@ -291,6 +291,7 @@ struct _GstSourceGroup
GstPlayBin *playbin; GstPlayBin *playbin;
gboolean valid; /* the group has valid info to start playback */ gboolean valid; /* the group has valid info to start playback */
gboolean active; /* the group is active */
/* properties */ /* properties */
gchar *uri; gchar *uri;
@ -316,6 +317,8 @@ struct _GstPlayBin
GstSourceGroup *curr_group; /* pointer to the currently playing group */ GstSourceGroup *curr_group; /* pointer to the currently playing group */
GstSourceGroup *next_group; /* pointer to the next group */ GstSourceGroup *next_group; /* pointer to the next group */
gboolean about_to_finish; /* the about-to-finish signal is emited */
/* properties */ /* properties */
guint connection_speed; /* connection speed in bits/sec (0 = unknown) */ guint connection_speed; /* connection speed in bits/sec (0 = unknown) */
@ -338,8 +341,6 @@ enum
PROP_0, PROP_0,
PROP_URI, PROP_URI,
PROP_SUBURI, PROP_SUBURI,
PROP_NEXT_URI,
PROP_NEXT_SUBURI,
PROP_STREAMINFO, PROP_STREAMINFO,
PROP_SOURCE, PROP_SOURCE,
PROP_CURRENT_VIDEO, PROP_CURRENT_VIDEO,
@ -363,7 +364,7 @@ enum
}; };
static void gst_play_bin_class_init (GstPlayBinClass * klass); 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_finalize (GObject * object);
static void gst_play_bin_set_property (GObject * object, guint prop_id, static void gst_play_bin_set_property (GObject * object, guint prop_id,
@ -438,12 +439,6 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
g_object_class_install_property (gobject_klass, PROP_SUBURI, g_object_class_install_property (gobject_klass, PROP_SUBURI,
g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle", g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
NULL, G_PARAM_READWRITE)); 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_object_class_install_property (gobject_klass, PROP_STREAMINFO,
g_param_spec_value_array ("stream-info", g_param_spec_value_array ("stream-info",
@ -569,17 +564,17 @@ gst_play_bin_init (GstPlayBin * playbin)
static void static void
gst_play_bin_finalize (GObject * object) 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); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
static void 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; GstSourceGroup *group;
@ -588,8 +583,8 @@ gst_play_bin_set_uri (GstPlayBin * play_bin, const gchar * uri)
return; return;
} }
GST_OBJECT_LOCK (play_bin); GST_OBJECT_LOCK (playbin);
group = play_bin->next_group; group = playbin->next_group;
/* if we have no previous uri, or the new uri is different from the /* if we have no previous uri, or the new uri is different from the
* old one, replug */ * old one, replug */
@ -598,16 +593,16 @@ gst_play_bin_set_uri (GstPlayBin * play_bin, const gchar * uri)
group->valid = TRUE; group->valid = TRUE;
GST_DEBUG ("setting new uri to %s", uri); GST_DEBUG ("setting new uri to %s", uri);
GST_OBJECT_UNLOCK (play_bin); GST_OBJECT_UNLOCK (playbin);
} }
static void 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; GstSourceGroup *group;
GST_OBJECT_LOCK (play_bin); GST_OBJECT_LOCK (playbin);
group = play_bin->next_group; group = playbin->next_group;
if ((!suburi && !group->suburi) || if ((!suburi && !group->suburi) ||
(suburi && group->suburi && !strcmp (group->suburi, suburi))) (suburi && group->suburi && !strcmp (group->suburi, suburi)))
@ -619,29 +614,23 @@ gst_play_bin_set_suburi (GstPlayBin * play_bin, const gchar * suburi)
GST_DEBUG ("setting new .sub uri to %s", suburi); GST_DEBUG ("setting new .sub uri to %s", suburi);
done: done:
GST_OBJECT_UNLOCK (play_bin); GST_OBJECT_UNLOCK (playbin);
} }
static void static void
gst_play_bin_set_property (GObject * object, guint prop_id, gst_play_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
{ {
GstPlayBin *play_bin; GstPlayBin *playbin;
play_bin = GST_PLAY_BIN (object); playbin = GST_PLAY_BIN (object);
switch (prop_id) { switch (prop_id) {
case PROP_URI: 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; break;
case PROP_SUBURI: case PROP_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_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));
break; break;
case PROP_VIDEO_SINK: case PROP_VIDEO_SINK:
break; break;
@ -654,9 +643,9 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
case PROP_FONT_DESC: case PROP_FONT_DESC:
break; break;
case PROP_CONNECTION_SPEED: case PROP_CONNECTION_SPEED:
GST_OBJECT_LOCK (play_bin); GST_OBJECT_LOCK (playbin);
play_bin->connection_speed = g_value_get_uint (value) * 1000; playbin->connection_speed = g_value_get_uint (value) * 1000;
GST_OBJECT_UNLOCK (play_bin); GST_OBJECT_UNLOCK (playbin);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -668,38 +657,29 @@ static void
gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value, gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec) GParamSpec * pspec)
{ {
GstPlayBin *play_bin; GstPlayBin *playbin;
play_bin = GST_PLAY_BIN (object); playbin = GST_PLAY_BIN (object);
switch (prop_id) { switch (prop_id) {
case PROP_URI: case PROP_URI:
GST_OBJECT_LOCK (play_bin); GST_OBJECT_LOCK (playbin);
/* get the currently playing group first, then the queued one */ /* get the currently playing group first, then the queued one, just in
if (play_bin->curr_group) * case we did not yet start playback. */
g_value_set_string (value, play_bin->curr_group->uri); if (playbin->curr_group)
g_value_set_string (value, playbin->curr_group->uri);
else else
g_value_set_string (value, play_bin->next_group->uri); g_value_set_string (value, playbin->next_group->uri);
GST_OBJECT_UNLOCK (play_bin); GST_OBJECT_UNLOCK (playbin);
break; break;
case PROP_SUBURI: case PROP_SUBURI:
GST_OBJECT_LOCK (play_bin); GST_OBJECT_LOCK (playbin);
/* get the currently playing group first, then the queued one */ /* get the currently playing group first, then the queued one */
if (play_bin->curr_group) if (playbin->curr_group)
g_value_set_string (value, play_bin->curr_group->suburi); g_value_set_string (value, playbin->curr_group->suburi);
else else
g_value_set_string (value, play_bin->next_group->suburi); g_value_set_string (value, playbin->next_group->suburi);
GST_OBJECT_UNLOCK (play_bin); GST_OBJECT_UNLOCK (playbin);
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);
break; break;
case PROP_VIDEO_SINK: case PROP_VIDEO_SINK:
break; break;
@ -712,9 +692,9 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_FRAME: case PROP_FRAME:
break; break;
case PROP_CONNECTION_SPEED: case PROP_CONNECTION_SPEED:
GST_OBJECT_LOCK (play_bin); GST_OBJECT_LOCK (playbin);
g_value_set_uint (value, play_bin->connection_speed / 1000); g_value_set_uint (value, playbin->connection_speed / 1000);
GST_OBJECT_UNLOCK (play_bin); GST_OBJECT_UNLOCK (playbin);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -861,8 +841,11 @@ pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
/* unlink the pad now (can fail, the pad is unlinked before it's removed) */ /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
gst_pad_unlink (pad, peer); 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)); 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 /* release the pad to the selector, this will make the selector choose a new
* pad. */ * pad. */
@ -878,6 +861,11 @@ not_linked:
GST_DEBUG_OBJECT (playbin, "pad not linked"); GST_DEBUG_OBJECT (playbin, "pad not linked");
return; 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 /* we get called when all pads are available and we must connect the sinks to
@ -947,10 +935,16 @@ drained_cb (GstElement * decodebin, GstSourceGroup * group)
GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group); 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 */ /* after this call, we should have a next group to activate or we EOS */
g_signal_emit (G_OBJECT (playbin), g_signal_emit (G_OBJECT (playbin),
gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL); 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 /* now activate the next group. If the app did not set a next-uri, this will
* fail and we can do EOS */ * fail and we can do EOS */
if (!setup_next_source (playbin)) { if (!setup_next_source (playbin)) {
@ -1048,42 +1042,20 @@ autoplug_select_cb (GstElement * decodebin, GstPad * pad,
return GST_AUTOPLUG_SELECT_EXPOSE; 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 static gboolean
activate_group (GstPlayBin * playbin, GstSourceGroup * group) activate_group (GstPlayBin * playbin, GstSourceGroup * group)
{ {
GstElement *uridecodebin; 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); uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
if (!uridecodebin) if (!uridecodebin)
goto no_decodebin; goto no_decodebin;
@ -1116,6 +1088,8 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group)
gst_element_set_state (uridecodebin, GST_STATE_PAUSED); gst_element_set_state (uridecodebin, GST_STATE_PAUSED);
group->active = TRUE;
return TRUE; return TRUE;
/* ERRORS */ /* ERRORS */
@ -1125,7 +1099,45 @@ no_decodebin:
} }
} }
/* 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 static gboolean
setup_next_source (GstPlayBin * playbin) setup_next_source (GstPlayBin * playbin)
{ {
@ -1142,7 +1154,8 @@ setup_next_source (GstPlayBin * playbin)
old_group = playbin->curr_group; old_group = playbin->curr_group;
if (old_group && old_group->valid) { if (old_group && old_group->valid) {
/* unlink our pads with the sink */ /* unlink our pads with the sink */
unlink_group (playbin, old_group); deactivate_group (playbin, old_group);
old_group->valid = FALSE;
} }
/* activate the new group */ /* activate the new group */
@ -1168,22 +1181,45 @@ activate_failed:
} }
} }
/* 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 static GstStateChangeReturn
gst_play_bin_change_state (GstElement * element, GstStateChange transition) gst_play_bin_change_state (GstElement * element, GstStateChange transition)
{ {
GstStateChangeReturn ret; GstStateChangeReturn ret;
GstPlayBin *play_bin; GstPlayBin *playbin;
play_bin = GST_PLAY_BIN (element); playbin = GST_PLAY_BIN (element);
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_READY_TO_PAUSED:
if (play_bin->playsink == NULL) { if (playbin->playsink == NULL) {
play_bin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL); playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
gst_bin_add (GST_BIN_CAST (play_bin), gst_bin_add (GST_BIN_CAST (playbin),
GST_ELEMENT_CAST (play_bin->playsink)); GST_ELEMENT_CAST (playbin->playsink));
} }
if (!setup_next_source (play_bin)) if (!setup_next_source (playbin))
goto source_failed; goto source_failed;
break; break;
default: default:
@ -1201,10 +1237,13 @@ gst_play_bin_change_state (GstElement * element, GstStateChange transition)
/* FIXME Release audio device when we implement that */ /* FIXME Release audio device when we implement that */
break; break;
case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_READY:
if (play_bin->playsink) { save_current_group (playbin);
gst_bin_remove (GST_BIN_CAST (play_bin), if (playbin->playsink) {
GST_ELEMENT_CAST (play_bin->playsink)); gst_element_set_state (GST_ELEMENT_CAST (playbin->playsink),
play_bin->playsink = NULL; GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (playbin),
GST_ELEMENT_CAST (playbin->playsink));
playbin->playsink = NULL;
} }
break; break;
default: default:

View File

@ -64,11 +64,18 @@ typedef struct
GstElement *sink; GstElement *sink;
} GstPlayVideoChain; } 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 struct _GstPlaySink
{ {
GstBin bin; GstBin bin;
GMutex *lock;
GstPlaySinkMode mode; GstPlaySinkMode mode;
GstPlaySinkFlags flags;
GstPlayChain *audiochain; GstPlayChain *audiochain;
GstPlayChain *videochain; GstPlayChain *videochain;
@ -120,8 +127,9 @@ enum
}; };
static void gst_play_sink_class_init (GstPlaySinkClass * klass); 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_dispose (GObject * object);
static void gst_play_sink_finalize (GObject * object);
static void gst_play_sink_set_property (GObject * object, guint prop_id, static void gst_play_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * spec); const GValue * value, GParamSpec * spec);
@ -186,6 +194,7 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
gobject_klass->get_property = gst_play_sink_get_property; gobject_klass->get_property = gst_play_sink_get_property;
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_sink_dispose); 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_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
g_param_spec_object ("video-sink", "Video Sink", g_param_spec_object ("video-sink", "Video Sink",
@ -222,97 +231,112 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
} }
static void static void
gst_play_sink_init (GstPlaySink * play_sink) gst_play_sink_init (GstPlaySink * playsink)
{ {
/* init groups */ /* init groups */
play_sink->video_sink = NULL; playsink->video_sink = NULL;
play_sink->audio_sink = NULL; playsink->audio_sink = NULL;
play_sink->visualisation = NULL; playsink->visualisation = NULL;
play_sink->pending_visualisation = NULL; playsink->pending_visualisation = NULL;
play_sink->textoverlay_element = NULL; playsink->textoverlay_element = NULL;
play_sink->volume = 1.0; playsink->volume = 1.0;
play_sink->font_desc = NULL; playsink->font_desc = NULL;
playsink->flags = GST_PLAY_SINK_FLAG_SOFT_VOLUME;
playsink->lock = g_mutex_new ();
} }
static void static void
gst_play_sink_dispose (GObject * object) 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) { if (playsink->audio_sink != NULL) {
gst_element_set_state (play_sink->audio_sink, GST_STATE_NULL); gst_element_set_state (playsink->audio_sink, GST_STATE_NULL);
gst_object_unref (play_sink->audio_sink); gst_object_unref (playsink->audio_sink);
play_sink->audio_sink = NULL; playsink->audio_sink = NULL;
} }
if (play_sink->video_sink != NULL) { if (playsink->video_sink != NULL) {
gst_element_set_state (play_sink->video_sink, GST_STATE_NULL); gst_element_set_state (playsink->video_sink, GST_STATE_NULL);
gst_object_unref (play_sink->video_sink); gst_object_unref (playsink->video_sink);
play_sink->video_sink = NULL; playsink->video_sink = NULL;
} }
if (play_sink->visualisation != NULL) { if (playsink->visualisation != NULL) {
gst_element_set_state (play_sink->visualisation, GST_STATE_NULL); gst_element_set_state (playsink->visualisation, GST_STATE_NULL);
gst_object_unref (play_sink->visualisation); gst_object_unref (playsink->visualisation);
play_sink->visualisation = NULL; playsink->visualisation = NULL;
} }
if (play_sink->pending_visualisation != NULL) { if (playsink->pending_visualisation != NULL) {
gst_element_set_state (play_sink->pending_visualisation, GST_STATE_NULL); gst_element_set_state (playsink->pending_visualisation, GST_STATE_NULL);
gst_object_unref (play_sink->pending_visualisation); gst_object_unref (playsink->pending_visualisation);
play_sink->pending_visualisation = NULL; playsink->pending_visualisation = NULL;
} }
if (play_sink->textoverlay_element != NULL) { if (playsink->textoverlay_element != NULL) {
gst_object_unref (play_sink->textoverlay_element); gst_object_unref (playsink->textoverlay_element);
play_sink->textoverlay_element = NULL; playsink->textoverlay_element = NULL;
} }
g_free (play_sink->font_desc); g_free (playsink->font_desc);
play_sink->font_desc = NULL; playsink->font_desc = NULL;
G_OBJECT_CLASS (parent_class)->dispose (object); 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 static void
gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked, gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked,
gpointer user_data) 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, gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
play_sink); playsink);
} }
static void static void
gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked, gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
gpointer user_data) gpointer user_data)
{ {
GstPlaySink *play_sink = GST_PLAY_SINK (user_data); GstPlaySink *playsink = GST_PLAY_SINK (user_data);
GstBin *vis_bin = NULL; GstBin *vis_bin = NULL;
GstPad *vis_sink_pad = NULL, *vis_src_pad = NULL, *vqueue_pad = NULL; GstPad *vis_sink_pad = NULL, *vis_src_pad = NULL, *vqueue_pad = NULL;
GstState bin_state; GstState bin_state;
GstElement *pending_visualisation; GstElement *pending_visualisation;
GST_OBJECT_LOCK (play_sink); GST_OBJECT_LOCK (playsink);
pending_visualisation = play_sink->pending_visualisation; pending_visualisation = playsink->pending_visualisation;
play_sink->pending_visualisation = NULL; playsink->pending_visualisation = NULL;
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
/* We want to disable visualisation */ /* We want to disable visualisation */
if (!GST_IS_ELEMENT (pending_visualisation)) { if (!GST_IS_ELEMENT (pending_visualisation)) {
/* Set visualisation element to READY */ /* 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; goto beach;
} }
vis_bin = 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))); visualisation)));
if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) { if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) {
goto beach; 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); vis_sink_pad = gst_pad_get_peer (tee_pad);
/* Can be fakesink */ /* Can be fakesink */
@ -341,11 +365,11 @@ gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
} }
/* Remove from vis_bin */ /* Remove from vis_bin */
gst_bin_remove (vis_bin, play_sink->visualisation); gst_bin_remove (vis_bin, playsink->visualisation);
/* Set state to NULL */ /* 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 */ /* And loose our ref */
gst_object_unref (play_sink->visualisation); gst_object_unref (playsink->visualisation);
if (pending_visualisation) { if (pending_visualisation) {
/* Ref this new visualisation element before adding to the bin */ /* Ref this new visualisation element before adding to the bin */
@ -368,8 +392,8 @@ gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
} }
/* We are done */ /* We are done */
gst_object_unref (play_sink->visualisation); gst_object_unref (playsink->visualisation);
play_sink->visualisation = pending_visualisation; playsink->visualisation = pending_visualisation;
beach: beach:
if (vis_sink_pad) { if (vis_sink_pad) {
@ -387,41 +411,41 @@ beach:
/* Unblock the pad */ /* Unblock the pad */
gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked, gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
play_sink); playsink);
} }
void 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); GST_OBJECT_LOCK (playsink);
if (play_sink->video_sink) if (playsink->video_sink)
gst_object_unref (play_sink->video_sink); gst_object_unref (playsink->video_sink);
if (sink) { if (sink) {
gst_object_ref (sink); gst_object_ref (sink);
gst_object_sink (sink); gst_object_sink (sink);
} }
play_sink->video_sink = sink; playsink->video_sink = sink;
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
} }
void 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); GST_OBJECT_LOCK (playsink);
if (play_sink->audio_sink) if (playsink->audio_sink)
gst_object_unref (play_sink->audio_sink); gst_object_unref (playsink->audio_sink);
if (sink) { if (sink) {
gst_object_ref (sink); gst_object_ref (sink);
gst_object_sink (sink); gst_object_sink (sink);
} }
play_sink->audio_sink = sink; playsink->audio_sink = sink;
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
} }
void void
gst_play_sink_set_vis_plugin (GstPlaySink * play_sink, gst_play_sink_set_vis_plugin (GstPlaySink * playsink,
GstElement * pending_visualisation) GstElement * pending_visualisation)
{ {
/* Take ownership */ /* Take ownership */
@ -432,19 +456,19 @@ gst_play_sink_set_vis_plugin (GstPlaySink * play_sink,
/* Do we already have a visualisation change pending? If yes, change the /* Do we already have a visualisation change pending? If yes, change the
* pending vis with the new one. */ * pending vis with the new one. */
GST_OBJECT_LOCK (play_sink); GST_OBJECT_LOCK (playsink);
if (play_sink->pending_visualisation) { if (playsink->pending_visualisation) {
gst_object_unref (play_sink->pending_visualisation); gst_object_unref (playsink->pending_visualisation);
play_sink->pending_visualisation = pending_visualisation; playsink->pending_visualisation = pending_visualisation;
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
} else { } else {
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
/* Was there a visualisation already set ? */ /* Was there a visualisation already set ? */
if (play_sink->visualisation != NULL) { if (playsink->visualisation != NULL) {
GstBin *vis_bin = NULL; GstBin *vis_bin = NULL;
vis_bin = 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))); visualisation)));
/* Check if the visualisation is already in a bin */ /* Check if the visualisation is already in a bin */
@ -452,7 +476,7 @@ gst_play_sink_set_vis_plugin (GstPlaySink * play_sink,
GstPad *vis_sink_pad = NULL, *tee_pad = NULL; GstPad *vis_sink_pad = NULL, *tee_pad = NULL;
/* Now get tee pad and block it async */ /* 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)) { if (!GST_IS_PAD (vis_sink_pad)) {
goto beach; goto beach;
} }
@ -461,10 +485,10 @@ gst_play_sink_set_vis_plugin (GstPlaySink * play_sink,
goto beach; goto beach;
} }
play_sink->pending_visualisation = pending_visualisation; playsink->pending_visualisation = pending_visualisation;
/* Block with callback */ /* Block with callback */
gst_pad_set_blocked_async (tee_pad, TRUE, gst_play_sink_vis_blocked, gst_pad_set_blocked_async (tee_pad, TRUE, gst_play_sink_vis_blocked,
play_sink); playsink);
beach: beach:
if (vis_sink_pad) { if (vis_sink_pad) {
gst_object_unref (vis_sink_pad); gst_object_unref (vis_sink_pad);
@ -474,10 +498,10 @@ gst_play_sink_set_vis_plugin (GstPlaySink * play_sink,
} }
gst_object_unref (vis_bin); gst_object_unref (vis_bin);
} else { } else {
play_sink->visualisation = pending_visualisation; playsink->visualisation = pending_visualisation;
} }
} else { } else {
play_sink->visualisation = pending_visualisation; playsink->visualisation = pending_visualisation;
} }
} }
} }
@ -486,34 +510,34 @@ static void
gst_play_sink_set_property (GObject * object, guint prop_id, gst_play_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
{ {
GstPlaySink *play_sink; GstPlaySink *playsink;
play_sink = GST_PLAY_SINK (object); playsink = GST_PLAY_SINK (object);
switch (prop_id) { switch (prop_id) {
case PROP_VIDEO_SINK: 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; break;
case PROP_AUDIO_SINK: 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; break;
case PROP_VIS_PLUGIN: 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; break;
case PROP_VOLUME: case PROP_VOLUME:
GST_OBJECT_LOCK (play_sink); GST_OBJECT_LOCK (playsink);
play_sink->volume = g_value_get_double (value); playsink->volume = g_value_get_double (value);
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
break; break;
case PROP_FONT_DESC: case PROP_FONT_DESC:
GST_OBJECT_LOCK (play_sink); GST_OBJECT_LOCK (playsink);
g_free (play_sink->font_desc); g_free (playsink->font_desc);
play_sink->font_desc = g_strdup (g_value_get_string (value)); playsink->font_desc = g_strdup (g_value_get_string (value));
if (play_sink->textoverlay_element) { if (playsink->textoverlay_element) {
g_object_set (G_OBJECT (play_sink->textoverlay_element), g_object_set (G_OBJECT (playsink->textoverlay_element),
"font-desc", g_value_get_string (value), NULL); "font-desc", g_value_get_string (value), NULL);
} }
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -525,30 +549,30 @@ static void
gst_play_sink_get_property (GObject * object, guint prop_id, GValue * value, gst_play_sink_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec) GParamSpec * pspec)
{ {
GstPlaySink *play_sink; GstPlaySink *playsink;
play_sink = GST_PLAY_SINK (object); playsink = GST_PLAY_SINK (object);
switch (prop_id) { switch (prop_id) {
case PROP_VIDEO_SINK: case PROP_VIDEO_SINK:
GST_OBJECT_LOCK (play_sink); GST_OBJECT_LOCK (playsink);
g_value_set_object (value, play_sink->video_sink); g_value_set_object (value, playsink->video_sink);
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
break; break;
case PROP_AUDIO_SINK: case PROP_AUDIO_SINK:
GST_OBJECT_LOCK (play_sink); GST_OBJECT_LOCK (playsink);
g_value_set_object (value, play_sink->audio_sink); g_value_set_object (value, playsink->audio_sink);
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
break; break;
case PROP_VIS_PLUGIN: case PROP_VIS_PLUGIN:
GST_OBJECT_LOCK (play_sink); GST_OBJECT_LOCK (playsink);
g_value_set_object (value, play_sink->visualisation); g_value_set_object (value, playsink->visualisation);
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
break; break;
case PROP_VOLUME: case PROP_VOLUME:
GST_OBJECT_LOCK (play_sink); GST_OBJECT_LOCK (playsink);
g_value_set_double (value, play_sink->volume); g_value_set_double (value, playsink->volume);
GST_OBJECT_UNLOCK (play_sink); GST_OBJECT_UNLOCK (playsink);
break; break;
case PROP_FRAME: case PROP_FRAME:
{ {
@ -624,17 +648,17 @@ activate_chain (GstPlayChain * chain, gboolean activate)
* *
*/ */
static GstPlayChain * static GstPlayChain *
gen_video_chain (GstPlaySink * play_sink, gboolean raw) gen_video_chain (GstPlaySink * playsink, gboolean raw)
{ {
GstPlayVideoChain *chain; GstPlayVideoChain *chain;
GstBin *bin; GstBin *bin;
GstPad *pad; GstPad *pad;
chain = g_new0 (GstPlayVideoChain, 1); 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) { if (playsink->video_sink) {
chain->sink = play_sink->video_sink; chain->sink = playsink->video_sink;
} else { } else {
chain->sink = gst_element_factory_make ("autovideosink", "videosink"); chain->sink = gst_element_factory_make ("autovideosink", "videosink");
if (chain->sink == NULL) { if (chain->sink == NULL) {
@ -697,8 +721,8 @@ gen_video_chain (GstPlaySink * play_sink, gboolean raw)
/* ERRORS */ /* ERRORS */
no_sinks: no_sinks:
{ {
post_missing_element_message (play_sink, "autovideosink"); post_missing_element_message (playsink, "autovideosink");
GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN, GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Both autovideosink and xvimagesink elements are missing.")), (_("Both autovideosink and xvimagesink elements are missing.")),
(NULL)); (NULL));
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
@ -706,8 +730,8 @@ no_sinks:
} }
no_colorspace: no_colorspace:
{ {
post_missing_element_message (play_sink, "ffmpegcolorspace"); post_missing_element_message (playsink, "ffmpegcolorspace");
GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN, GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."), (_("Missing element '%s' - check your GStreamer installation."),
"ffmpegcolorspace"), (NULL)); "ffmpegcolorspace"), (NULL));
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
@ -716,8 +740,8 @@ no_colorspace:
no_videoscale: no_videoscale:
{ {
post_missing_element_message (play_sink, "videoscale"); post_missing_element_message (playsink, "videoscale");
GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN, GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."), (_("Missing element '%s' - check your GStreamer installation."),
"videoscale"), ("possibly a liboil version mismatch?")); "videoscale"), ("possibly a liboil version mismatch?"));
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
@ -725,7 +749,7 @@ no_videoscale:
} }
link_failed: link_failed:
{ {
GST_ELEMENT_ERROR (play_sink, CORE, PAD, GST_ELEMENT_ERROR (playsink, CORE, PAD,
(NULL), ("Failed to configure the video sink.")); (NULL), ("Failed to configure the video sink."));
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
return NULL; return NULL;
@ -748,13 +772,13 @@ link_failed:
* videosink without the text_sink pad. * videosink without the text_sink pad.
*/ */
static GstElement * static GstElement *
gen_text_element (GstPlaySink * play_sink) gen_text_element (GstPlaySink * playsink)
{ {
GstElement *element, *csp, *overlay, *vbin; GstElement *element, *csp, *overlay, *vbin;
GstPad *pad; GstPad *pad;
/* Create the video rendering bin, error is posted when this fails. */ /* Create the video rendering bin, error is posted when this fails. */
vbin = gen_video_element (play_sink); vbin = gen_video_element (playsink);
if (!vbin) if (!vbin)
return NULL; return NULL;
@ -771,12 +795,12 @@ gen_text_element (GstPlaySink * play_sink)
/* Set some parameters */ /* Set some parameters */
g_object_set (G_OBJECT (overlay), g_object_set (G_OBJECT (overlay),
"halign", "center", "valign", "bottom", NULL); "halign", "center", "valign", "bottom", NULL);
if (play_sink->font_desc) { if (playsink->font_desc) {
g_object_set (G_OBJECT (overlay), "font-desc", play_sink->font_desc, NULL); g_object_set (G_OBJECT (overlay), "font-desc", playsink->font_desc, NULL);
} }
/* Take a ref */ /* 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 */ /* we know this will succeed, as the video bin already created one before */
csp = gst_element_factory_make ("ffmpegcolorspace", "subtitlecsp"); csp = gst_element_factory_make ("ffmpegcolorspace", "subtitlecsp");
@ -805,8 +829,8 @@ gen_text_element (GstPlaySink * play_sink)
/* ERRORS */ /* ERRORS */
no_overlay: no_overlay:
{ {
post_missing_element_message (play_sink, "textoverlay"); post_missing_element_message (playsink, "textoverlay");
GST_WARNING_OBJECT (play_sink, GST_WARNING_OBJECT (playsink,
"No overlay (pango) element, subtitles disabled"); "No overlay (pango) element, subtitles disabled");
return vbin; return vbin;
} }
@ -827,7 +851,7 @@ no_overlay:
* +-------------------------------------------------------------+ * +-------------------------------------------------------------+
*/ */
static GstPlayChain * static GstPlayChain *
gen_audio_chain (GstPlaySink * play_sink, gboolean raw) gen_audio_chain (GstPlaySink * playsink, gboolean raw)
{ {
GstPlayAudioChain *chain; GstPlayAudioChain *chain;
GstBin *bin; GstBin *bin;
@ -835,10 +859,10 @@ gen_audio_chain (GstPlaySink * play_sink, gboolean raw)
GstPad *pad; GstPad *pad;
chain = g_new0 (GstPlayAudioChain, 1); 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) { if (playsink->audio_sink) {
chain->sink = play_sink->audio_sink; chain->sink = playsink->audio_sink;
} else { } else {
chain->sink = gst_element_factory_make ("autoaudiosink", "audiosink"); chain->sink = gst_element_factory_make ("autoaudiosink", "audiosink");
if (chain->sink == NULL) { if (chain->sink == NULL) {
@ -864,14 +888,19 @@ gen_audio_chain (GstPlaySink * play_sink, gboolean raw)
goto no_audioresample; goto no_audioresample;
gst_bin_add (bin, chain->resample); 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->conv, "src", chain->resample, "sink");
res &=
gst_element_link_pads (chain->resample, "src", chain->volume, "sink"); if (playsink->flags & GST_PLAY_SINK_FLAG_SOFT_VOLUME) {
res &= gst_element_link_pads (chain->volume, "src", chain->sink, NULL); 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) if (!res)
goto link_failed; goto link_failed;
@ -888,16 +917,16 @@ gen_audio_chain (GstPlaySink * play_sink, gboolean raw)
/* ERRORS */ /* ERRORS */
no_sinks: no_sinks:
{ {
post_missing_element_message (play_sink, "autoaudiosink"); post_missing_element_message (playsink, "autoaudiosink");
GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN, GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Both autoaudiosink and alsasink elements are missing.")), (NULL)); (_("Both autoaudiosink and alsasink elements are missing.")), (NULL));
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
return NULL; return NULL;
} }
no_audioconvert: no_audioconvert:
{ {
post_missing_element_message (play_sink, "audioconvert"); post_missing_element_message (playsink, "audioconvert");
GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN, GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."), (_("Missing element '%s' - check your GStreamer installation."),
"audioconvert"), ("possibly a liboil version mismatch?")); "audioconvert"), ("possibly a liboil version mismatch?"));
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
@ -906,8 +935,8 @@ no_audioconvert:
no_audioresample: no_audioresample:
{ {
post_missing_element_message (play_sink, "audioresample"); post_missing_element_message (playsink, "audioresample");
GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN, GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."), (_("Missing element '%s' - check your GStreamer installation."),
"audioresample"), ("possibly a liboil version mismatch?")); "audioresample"), ("possibly a liboil version mismatch?"));
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
@ -915,7 +944,7 @@ no_audioresample:
} }
link_failed: link_failed:
{ {
GST_ELEMENT_ERROR (play_sink, CORE, PAD, GST_ELEMENT_ERROR (playsink, CORE, PAD,
(NULL), ("Failed to configure the audio sink.")); (NULL), ("Failed to configure the audio sink."));
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
return NULL; return NULL;
@ -947,7 +976,7 @@ link_failed:
* +-----------------------------------------------------------------------+ * +-----------------------------------------------------------------------+
*/ */
static GstElement * static GstElement *
gen_vis_element (GstPlaySink * play_sink) gen_vis_element (GstPlaySink * playsink)
{ {
gboolean res; gboolean res;
GstElement *element; GstElement *element;
@ -962,10 +991,10 @@ gen_vis_element (GstPlaySink * play_sink)
GstPad *pad, *rpad; GstPad *pad, *rpad;
/* errors are already posted when these fail. */ /* errors are already posted when these fail. */
asink = gen_audio_element (play_sink); asink = gen_audio_element (playsink);
if (!asink) if (!asink)
return NULL; return NULL;
vsink = gen_video_element (play_sink); vsink = gen_video_element (playsink);
if (!vsink) { if (!vsink) {
gst_object_unref (asink); gst_object_unref (asink);
return NULL; return NULL;
@ -998,9 +1027,9 @@ gen_vis_element (GstPlaySink * play_sink)
goto no_audioconvert; goto no_audioconvert;
gst_bin_add (GST_BIN_CAST (element), conv2); gst_bin_add (GST_BIN_CAST (element), conv2);
if (play_sink->visualisation) { if (playsink->visualisation) {
gst_object_ref (play_sink->visualisation); gst_object_ref (playsink->visualisation);
vis = play_sink->visualisation; vis = playsink->visualisation;
} else { } else {
vis = gst_element_factory_make ("goom", "vis"); vis = gst_element_factory_make ("goom", "vis");
if (!vis) if (!vis)
@ -1038,8 +1067,8 @@ gen_vis_element (GstPlaySink * play_sink)
/* ERRORS */ /* ERRORS */
no_audioconvert: no_audioconvert:
{ {
post_missing_element_message (play_sink, "audioconvert"); post_missing_element_message (playsink, "audioconvert");
GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN, GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."), (_("Missing element '%s' - check your GStreamer installation."),
"audioconvert"), ("possibly a liboil version mismatch?")); "audioconvert"), ("possibly a liboil version mismatch?"));
gst_object_unref (element); gst_object_unref (element);
@ -1047,8 +1076,8 @@ no_audioconvert:
} }
no_audioresample: no_audioresample:
{ {
post_missing_element_message (play_sink, "audioresample"); post_missing_element_message (playsink, "audioresample");
GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN, GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."), (_("Missing element '%s' - check your GStreamer installation."),
"audioresample"), (NULL)); "audioresample"), (NULL));
gst_object_unref (element); gst_object_unref (element);
@ -1056,8 +1085,8 @@ no_audioresample:
} }
no_goom: no_goom:
{ {
post_missing_element_message (play_sink, "goom"); post_missing_element_message (playsink, "goom");
GST_ELEMENT_ERROR (play_sink, CORE, MISSING_PLUGIN, GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."), (_("Missing element '%s' - check your GStreamer installation."),
"goom"), (NULL)); "goom"), (NULL));
gst_object_unref (element); gst_object_unref (element);
@ -1065,7 +1094,7 @@ no_goom:
} }
link_failed: link_failed:
{ {
GST_ELEMENT_ERROR (play_sink, CORE, PAD, GST_ELEMENT_ERROR (playsink, CORE, PAD,
(NULL), ("Failed to configure the visualisation element.")); (NULL), ("Failed to configure the visualisation element."));
gst_object_unref (element); gst_object_unref (element);
return NULL; return NULL;
@ -1078,9 +1107,9 @@ gst_play_sink_get_mode (GstPlaySink * playsink)
{ {
GstPlaySinkMode res; GstPlaySinkMode res;
GST_OBJECT_LOCK (playsink); GST_PLAY_SINK_LOCK (playsink);
res = playsink->mode; res = playsink->mode;
GST_OBJECT_LOCK (playsink); GST_PLAY_SINK_UNLOCK (playsink);
return res; return res;
} }
@ -1091,6 +1120,9 @@ gst_play_sink_get_mode (GstPlaySink * playsink)
gboolean gboolean
gst_play_sink_set_mode (GstPlaySink * playsink, GstPlaySinkMode mode) 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 (mode & GST_PLAY_SINK_MODE_AUDIO && playsink->audio_pad) {
if (!playsink->audiochain) if (!playsink->audiochain)
playsink->audiochain = playsink->audiochain =
@ -1126,10 +1158,38 @@ gst_play_sink_set_mode (GstPlaySink * playsink, GstPlaySinkMode mode)
} }
playsink->mode = mode; playsink->mode = mode;
GST_PLAY_SINK_UNLOCK (playsink);
return TRUE; 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 * GstPad *
gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type) gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
{ {
@ -1137,6 +1197,7 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
gboolean created = FALSE; gboolean created = FALSE;
gboolean raw = FALSE; gboolean raw = FALSE;
GST_PLAY_SINK_LOCK (playsink);
switch (type) { switch (type) {
case GST_PLAY_SINK_TYPE_AUDIO_RAW: case GST_PLAY_SINK_TYPE_AUDIO_RAW:
raw = TRUE; raw = TRUE;
@ -1172,10 +1233,13 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
res = NULL; res = NULL;
break; break;
} }
GST_PLAY_SINK_UNLOCK (playsink);
if (created && res) { if (created && res) {
gst_pad_set_active (res, TRUE); gst_pad_set_active (res, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (playsink), res); gst_element_add_pad (GST_ELEMENT_CAST (playsink), res);
} }
return res; return res;
} }
@ -1184,6 +1248,7 @@ gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad)
{ {
GstPad **res = NULL; GstPad **res = NULL;
GST_PLAY_SINK_LOCK (playsink);
if (pad == playsink->video_pad) { if (pad == playsink->video_pad) {
res = &playsink->video_pad; res = &playsink->video_pad;
} else if (pad == playsink->audio_pad) { } else if (pad == playsink->audio_pad) {
@ -1191,6 +1256,7 @@ gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad)
} else if (pad == playsink->text_pad) { } else if (pad == playsink->text_pad) {
res = &playsink->text_pad; res = &playsink->text_pad;
} }
GST_PLAY_SINK_UNLOCK (playsink);
if (*res) { if (*res) {
gst_pad_set_active (*res, FALSE); gst_pad_set_active (*res, FALSE);
@ -1203,25 +1269,25 @@ gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad)
* remaining sinks (unlike GstBin) * remaining sinks (unlike GstBin)
*/ */
static gboolean 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; gboolean res = TRUE;
if (play_sink->audiochain) { if (playsink->audiochain) {
gst_event_ref (event); gst_event_ref (event);
if ((res = gst_element_send_event (play_sink->audiochain->bin, event))) { if ((res = gst_element_send_event (playsink->audiochain->bin, event))) {
GST_DEBUG_OBJECT (play_sink, "Sent event succesfully to audio sink"); GST_DEBUG_OBJECT (playsink, "Sent event succesfully to audio sink");
goto done; 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); gst_event_ref (event);
if ((res = gst_element_send_event (play_sink->videochain->bin, event))) { if ((res = gst_element_send_event (playsink->videochain->bin, event))) {
GST_DEBUG_OBJECT (play_sink, "Sent event succesfully to video sink"); GST_DEBUG_OBJECT (playsink, "Sent event succesfully to video sink");
goto done; 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: done:
gst_event_unref (event); gst_event_unref (event);
@ -1253,9 +1319,9 @@ static GstStateChangeReturn
gst_play_sink_change_state (GstElement * element, GstStateChange transition) gst_play_sink_change_state (GstElement * element, GstStateChange transition)
{ {
GstStateChangeReturn ret; GstStateChangeReturn ret;
GstPlaySink *play_sink; GstPlaySink *playsink;
play_sink = GST_PLAY_SINK (element); playsink = GST_PLAY_SINK (element);
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_READY_TO_PAUSED:

View File

@ -71,6 +71,22 @@ typedef enum {
GST_PLAY_SINK_TYPE_LAST = 5 GST_PLAY_SINK_TYPE_LAST = 5
} GstPlaySinkType; } GstPlaySinkType;
/**
* GstPlaySinkFlags:
* @GST_PLAY_SINK_FLAG_SOFT_VOLUME: Use software volume in the sink
* @GST_PLAY_SINK_FLAG_NATIVE_AUDIO: only allow native audio formats, this omits
* configuration of audioconvert and audioresample.
* @GST_PLAY_SINK_FLAG_NATIVE_VIDEO: only allow native video formats, this omits
* configuration of ffmpegcolorspace and videoscale.
*
* Extra flags to configure the behaviour of the sinks.
*/
typedef enum {
GST_PLAY_SINK_FLAG_SOFT_VOLUME = (1 << 0),
GST_PLAY_SINK_FLAG_NATIVE_AUDIO = (1 << 1),
GST_PLAY_SINK_FLAG_NATIVE_VIDEO = (1 << 2)
} GstPlaySinkFlags;
typedef struct _GstPlaySink GstPlaySink; typedef struct _GstPlaySink GstPlaySink;
typedef struct _GstPlaySinkClass GstPlaySinkClass; typedef struct _GstPlaySinkClass GstPlaySinkClass;
@ -79,12 +95,15 @@ GType gst_play_sink_get_type (void);
GstPad * gst_play_sink_request_pad (GstPlaySink *playsink, GstPlaySinkType type); GstPad * gst_play_sink_request_pad (GstPlaySink *playsink, GstPlaySinkType type);
void gst_play_sink_release_pad (GstPlaySink *playsink, GstPad *pad); void gst_play_sink_release_pad (GstPlaySink *playsink, GstPad *pad);
void gst_play_sink_set_video_sink (GstPlaySink * play_sink, GstElement * sink); void gst_play_sink_set_video_sink (GstPlaySink * playsink, GstElement * sink);
void gst_play_sink_set_audio_sink (GstPlaySink * play_sink, GstElement * sink); void gst_play_sink_set_audio_sink (GstPlaySink * playsink, GstElement * sink);
void gst_play_sink_set_vis_plugin (GstPlaySink * play_sink, GstElement * vis); void gst_play_sink_set_vis_plugin (GstPlaySink * playsink, GstElement * vis);
gboolean gst_play_sink_set_flags (GstPlaySink * playsink, GstPlaySinkFlags flags);
GstPlaySinkFlags gst_play_sink_get_flags (GstPlaySink * playsink);
GstPlaySinkMode gst_play_sink_get_mode (GstPlaySink *playsink);
gboolean gst_play_sink_set_mode (GstPlaySink *playsink, GstPlaySinkMode mode); gboolean gst_play_sink_set_mode (GstPlaySink *playsink, GstPlaySinkMode mode);
GstPlaySinkMode gst_play_sink_get_mode (GstPlaySink *playsink);
G_END_DECLS G_END_DECLS

View File

@ -92,7 +92,7 @@ static void
about_to_finish_cb (GstElement * element, gchar * uri[]) about_to_finish_cb (GstElement * element, gchar * uri[])
{ {
if (arg_count < max_count) { if (arg_count < max_count) {
g_object_set (G_OBJECT (element), "next-uri", uri[arg_count], NULL); g_object_set (G_OBJECT (element), "uri", uri[arg_count], NULL);
arg_count++; arg_count++;
} }
} }