gst/playback/: Cleanups and some more documentation.

Original commit message from CVS:
* gst/playback/README:
* gst/playback/gstdecodebin.c: (close_pad_link), (try_to_link_1):
* gst/playback/gstplaybin.c: (gst_play_bin_init),
(gst_play_bin_dispose), (gst_play_bin_set_property),
(remove_sinks), (setup_sinks), (gst_play_bin_change_state),
(gst_play_bin_get_event_masks), (gst_play_bin_send_event),
(gst_play_bin_get_formats), (gst_play_bin_convert),
(gst_play_bin_get_query_types), (gst_play_bin_query):
Cleanups and some more documentation.
This commit is contained in:
Wim Taymans 2004-11-09 14:37:51 +00:00
parent d40b44c61f
commit 5d374bf5ea
4 changed files with 111 additions and 34 deletions

View File

@ -1,3 +1,15 @@
2004-11-09 Wim Taymans <wim@fluendo.com>
* gst/playback/README:
* gst/playback/gstdecodebin.c: (close_pad_link), (try_to_link_1):
* gst/playback/gstplaybin.c: (gst_play_bin_init),
(gst_play_bin_dispose), (gst_play_bin_set_property),
(remove_sinks), (setup_sinks), (gst_play_bin_change_state),
(gst_play_bin_get_event_masks), (gst_play_bin_send_event),
(gst_play_bin_get_formats), (gst_play_bin_convert),
(gst_play_bin_get_query_types), (gst_play_bin_query):
Cleanups and some more documentation.
2004-11-09 Jan Schmidt <thaytan@mad.scientist.com> 2004-11-09 Jan Schmidt <thaytan@mad.scientist.com>
* ext/libcaca/gstcacasink.c: (gst_cacasink_class_init), * ext/libcaca/gstcacasink.c: (gst_cacasink_class_init),

View File

@ -11,6 +11,7 @@ decoderbin:
- reuse of decoderbin, cleanup in READY state - reuse of decoderbin, cleanup in READY state
- threading after demuxing? - threading after demuxing?
- new_media events should be handled. - new_media events should be handled.
- caching of elements.
baseplaybin: baseplaybin:

View File

@ -406,7 +406,7 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
/* FIXME, iterate over more structures? I guess it is possible that /* FIXME, iterate over more structures? I guess it is possible that
* this pad has some encoded and some raw pads. This code will fail * this pad has some encoded and some raw pads. This code will fail
* then... */ * then if the first structure is not the raw type... */
structure = gst_caps_get_structure (caps, 0); structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure); mimetype = gst_structure_get_name (structure);

View File

@ -44,18 +44,23 @@ struct _GstPlayBin
{ {
GstPlayBaseBin parent; GstPlayBaseBin parent;
/* the configurable elements */
GstElement *audio_sink; GstElement *audio_sink;
GstElement *video_sink; GstElement *video_sink;
GstElement *visualisation; GstElement *visualisation;
GstElement *volume_element; GstElement *volume_element;
gfloat volume; gfloat volume;
/* these are the currently active sinks */
GList *sinks; GList *sinks;
/* these are the sink elements used for seeking/query etc.. */
GList *seekables; GList *seekables;
/* the last captured frame for snapshots */
GstBuffer *frame; GstBuffer *frame;
/* our cache for the sinks */
GHashTable *cache; GHashTable *cache;
}; };
@ -86,6 +91,7 @@ static void gst_play_bin_init (GstPlayBin * play_bin);
static void gst_play_bin_dispose (GObject * object); static void gst_play_bin_dispose (GObject * object);
static void setup_sinks (GstPlayBaseBin * play_base_bin); static void setup_sinks (GstPlayBaseBin * play_base_bin);
static void remove_sinks (GstPlayBin * play_bin);
static void gst_play_bin_set_property (GObject * object, guint prop_id, static void gst_play_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * spec); const GValue * value, GParamSpec * spec);
@ -116,7 +122,6 @@ static GstElementDetails gst_play_bin_details = {
"Wim Taymans <wim@fluendo.com>" "Wim Taymans <wim@fluendo.com>"
}; };
static GType static GType
gst_play_bin_get_type (void) gst_play_bin_get_type (void)
{ {
@ -210,8 +215,10 @@ gst_play_bin_init (GstPlayBin * play_bin)
play_bin->seekables = NULL; play_bin->seekables = NULL;
play_bin->sinks = NULL; play_bin->sinks = NULL;
play_bin->frame = NULL; play_bin->frame = NULL;
play_bin->cache = g_hash_table_new (g_str_hash, g_str_equal); play_bin->cache = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, g_object_unref);
/* no iterate is needed */
GST_FLAG_SET (play_bin, GST_BIN_SELF_SCHEDULABLE); GST_FLAG_SET (play_bin, GST_BIN_SELF_SCHEDULABLE);
} }
@ -222,6 +229,9 @@ gst_play_bin_dispose (GObject * object)
play_bin = GST_PLAY_BIN (object); play_bin = GST_PLAY_BIN (object);
remove_sinks (play_bin);
g_hash_table_destroy (play_bin->cache);
if (G_OBJECT_CLASS (parent_class)->dispose) { if (G_OBJECT_CLASS (parent_class)->dispose) {
G_OBJECT_CLASS (parent_class)->dispose (object); G_OBJECT_CLASS (parent_class)->dispose (object);
} }
@ -239,37 +249,22 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
switch (prop_id) { switch (prop_id) {
case ARG_VIDEO_SINK: case ARG_VIDEO_SINK:
{
GstElement *element;
play_bin->video_sink = g_value_get_object (value); play_bin->video_sink = g_value_get_object (value);
/* when changing the videosink, we just remove the
element = g_hash_table_lookup (play_bin->cache, "vbin"); * video pipeline from the cache so that it will be
if (element != NULL) { * regenerated with the new sink element */
g_hash_table_remove (play_bin->cache, "vbin"); g_hash_table_remove (play_bin->cache, "vbin");
g_object_unref (G_OBJECT (element));
}
break; break;
}
case ARG_AUDIO_SINK: case ARG_AUDIO_SINK:
{
GstElement *element;
play_bin->audio_sink = g_value_get_object (value); play_bin->audio_sink = g_value_get_object (value);
g_hash_table_remove (play_bin->cache, "abin");
element = g_hash_table_lookup (play_bin->cache, "abin");
if (element != NULL) {
g_hash_table_remove (play_bin->cache, "abin");
g_object_unref (G_OBJECT (element));
}
break; break;
}
case ARG_VIS_PLUGIN: case ARG_VIS_PLUGIN:
play_bin->visualisation = g_value_get_object (value); play_bin->visualisation = g_value_get_object (value);
break; break;
case ARG_VOLUME: case ARG_VOLUME:
play_bin->volume = g_value_get_double (value);
if (play_bin->volume_element) { if (play_bin->volume_element) {
play_bin->volume = g_value_get_double (value);
g_object_set (G_OBJECT (play_bin->volume_element), "volume", g_object_set (G_OBJECT (play_bin->volume_element), "volume",
play_bin->volume, NULL); play_bin->volume, NULL);
} }
@ -327,7 +322,18 @@ handoff (GstElement * identity, GstBuffer * frame, gpointer data)
} }
/* make the element (bin) that contains the elements needed to perform /* make the element (bin) that contains the elements needed to perform
* video display/ * video display. We connect a handoff signal to identity so that we
* can grab snapshots. Identity's sinkpad is ghosted to vbin.
*
* +-------------------------------------------------------------+
* | vbin |
* | +--------+ +----------+ +----------+ +---------+ |
* | |identity| |colorspace| |videoscale| |videosink| |
* | +-sink src-sink src-sink src-sink | |
* | | +---+----+ +----------+ +----------+ +---------+ |
* sink-+ | |
* +----------|--------------------------------------------------+
* handoff
*/ */
static GstElement * static GstElement *
gen_video_element (GstPlayBin * play_bin) gen_video_element (GstPlayBin * play_bin)
@ -384,6 +390,19 @@ done:
return element; return element;
} }
/* make the element (bin) that contains the elements needed to perform
* audio playback.
*
* +-------------------------------------------------------------+
* | abin |
* | +---------+ +----------+ +---------+ +---------+ |
* | |audioconv| |audioscale| | volume | |audiosink| |
* | +-sink src-sink src-sink src-sink | |
* | | +---------+ +----------+ +---------+ +---------+ |
* sink-+ |
* +-------------------------------------------------------------+
*
*/
static GstElement * static GstElement *
gen_audio_element (GstPlayBin * play_bin) gen_audio_element (GstPlayBin * play_bin)
{ {
@ -439,6 +458,29 @@ done:
return element; return element;
} }
/* make the element (bin) that contains the elements needed to perform
* visualisation ouput. The idea is to split the audio using tee, then
* sending the output to the regular audio bin and the other output to
* the vis plugin that transforms it into a video that is rendered with the
* normal video bin. The video bin is run in a thread to make sure it does
* not block the audio playback pipeline.
*
* +--------------------------------------------------------------------------+
* | visbin |
* | +------+ +----------------+ |
* | | tee | | abin ... | |
* | +-sink src-sink | |
* | | | | +----------------+ +-------------------+ |
* | | | | | vthread | |
* | | | | +---------+ +------+ +------+ | +--------------+ | |
* | | | | |audioconv| | vis | |vqueue| | | vbin ... | | |
* | | | src-sink src-sink src-sink src-sink | | |
* | | | | +---------+ +------+ +------+ | +--------------+ | |
* | | | | +-------------------+ |
* | | +------+ |
* sink-+ |
* +--------------------------------------------------------------------------+
*/
static GstElement * static GstElement *
gen_vis_element (GstPlayBin * play_bin) gen_vis_element (GstPlayBin * play_bin)
{ {
@ -494,6 +536,7 @@ gen_vis_element (GstPlayBin * play_bin)
return element; return element;
} }
/* get rid of all installed sinks */
static void static void
remove_sinks (GstPlayBin * play_bin) remove_sinks (GstPlayBin * play_bin)
{ {
@ -538,7 +581,13 @@ remove_sinks (GstPlayBin * play_bin)
} }
/* loop over the streams and set up the pipeline to play this /* loop over the streams and set up the pipeline to play this
* media file * media file. First we count the number of audio and video streams.
* If there is no video stream but there exists an audio stream,
* we install a visualisation pipeline.
*
* Also make sure to only connect the first audio and video pad. FIXME
* this should eventually be handled with a tuner interface so that
* one can switch the streams.
*/ */
static void static void
setup_sinks (GstPlayBaseBin * play_base_bin) setup_sinks (GstPlayBaseBin * play_base_bin)
@ -550,7 +599,9 @@ setup_sinks (GstPlayBaseBin * play_base_bin)
gint num_video = 0; gint num_video = 0;
gboolean need_vis = FALSE; gboolean need_vis = FALSE;
/* FIXME: do this nicer */ /* FIXME: do this nicer, like taking a look at the installed
* bins and figuring out if we can simply reconnect them, remove
* or add them. */
if (GST_STATE (play_base_bin) == GST_STATE_PLAYING) { if (GST_STATE (play_base_bin) == GST_STATE_PLAYING) {
remove_sinks (play_bin); remove_sinks (play_bin);
} }
@ -611,6 +662,7 @@ setup_sinks (GstPlayBaseBin * play_base_bin)
srcpad = GST_PAD (object); srcpad = GST_PAD (object);
/* pas is allready linked, go to the next pad */
if (gst_pad_is_linked (srcpad)) if (gst_pad_is_linked (srcpad))
continue; continue;
@ -641,6 +693,7 @@ setup_sinks (GstPlayBaseBin * play_base_bin)
mute = TRUE; mute = TRUE;
} }
/* we found a sink for this stream, now try to install it */
if (sink != NULL) { if (sink != NULL) {
gst_object_ref (GST_OBJECT (sink)); gst_object_ref (GST_OBJECT (sink));
gst_bin_add (GST_BIN (play_bin), sink); gst_bin_add (GST_BIN (play_bin), sink);
@ -648,10 +701,12 @@ setup_sinks (GstPlayBaseBin * play_base_bin)
GST_STATE (sink), GST_STATE (play_bin), GST_STATE (sink), GST_STATE (play_bin),
GST_STATE (gst_pad_get_parent (srcpad))); GST_STATE (gst_pad_get_parent (srcpad)));
sinkpad = gst_element_get_pad (sink, "sink"); sinkpad = gst_element_get_pad (sink, "sink");
/* try to link the pad of the sink to the stream */
res = gst_pad_link (srcpad, sinkpad); res = gst_pad_link (srcpad, sinkpad);
if (!res) { if (!res) {
gchar *capsstr; gchar *capsstr;
/* could not link this stream */
capsstr = gst_caps_to_string (gst_pad_get_caps (srcpad)); capsstr = gst_caps_to_string (gst_pad_get_caps (srcpad));
g_warning ("could not link %s", capsstr); g_warning ("could not link %s", capsstr);
g_free (capsstr); g_free (capsstr);
@ -659,10 +714,14 @@ setup_sinks (GstPlayBaseBin * play_base_bin)
gst_bin_remove (GST_BIN (play_bin), sink); gst_bin_remove (GST_BIN (play_bin), sink);
mute = TRUE; mute = TRUE;
} else { } else {
/* we got the sink succesfully linked, now keep the sink
* in out internal list */
play_bin->sinks = g_list_prepend (play_bin->sinks, sink); play_bin->sinks = g_list_prepend (play_bin->sinks, sink);
} }
} }
if (mute) { if (mute) {
/* no sink found/needed for this stream. We mute the stream
* so that it does not take any resources */
g_object_set (G_OBJECT (obj), "mute", TRUE, NULL); g_object_set (G_OBJECT (obj), "mute", TRUE, NULL);
} }
} }
@ -687,9 +746,9 @@ gst_play_bin_change_state (GstElement * element)
case GST_STATE_NULL_TO_READY: case GST_STATE_NULL_TO_READY:
break; break;
case GST_STATE_READY_TO_PAUSED: case GST_STATE_READY_TO_PAUSED:
//setup_sinks (play_bin);
break; break;
case GST_STATE_PAUSED_TO_PLAYING: case GST_STATE_PAUSED_TO_PLAYING:
break;
case GST_STATE_PLAYING_TO_PAUSED: case GST_STATE_PLAYING_TO_PAUSED:
break; break;
case GST_STATE_PAUSED_TO_READY: case GST_STATE_PAUSED_TO_READY:
@ -708,9 +767,11 @@ gst_play_bin_change_state (GstElement * element)
static const GstEventMask * static const GstEventMask *
gst_play_bin_get_event_masks (GstElement * element) gst_play_bin_get_event_masks (GstElement * element)
{ {
/* FIXME, get the list from the number of installed sinks */
return NULL; return NULL;
} }
/* send an event to all the sinks */
static gboolean static gboolean
gst_play_bin_send_event (GstElement * element, GstEvent * event) gst_play_bin_send_event (GstElement * element, GstEvent * event)
{ {
@ -723,23 +784,26 @@ gst_play_bin_send_event (GstElement * element, GstEvent * event)
play_bin = GST_PLAY_BIN (element); play_bin = GST_PLAY_BIN (element);
state = gst_element_get_state (element); state = gst_element_get_state (element);
/* we pause the pipeline first before sending the event. We only
* do this if the pipeline was playing. */
if (state == GST_STATE_PLAYING) { if (state == GST_STATE_PLAYING) {
need_pause = TRUE; need_pause = TRUE;
gst_element_set_state (element, GST_STATE_PAUSED); gst_element_set_state (element, GST_STATE_PAUSED);
} }
s = play_bin->seekables; /* loop over all seekables and send the event to them */
for (s = play_bin->seekables; s; s = g_list_next (s)) { for (s = play_bin->seekables; s; s = g_list_next (s)) {
GstElement *element = GST_ELEMENT (s->data); GstElement *element = GST_ELEMENT (s->data);
gboolean ok; gboolean ok;
/* ref each event before sending it */
gst_event_ref (event); gst_event_ref (event);
ok = gst_element_send_event (element, event); ok = gst_element_send_event (element, event);
res |= ok; res |= ok;
} }
gst_event_unref (event); gst_event_unref (event);
/* and restart the pipeline if we paused it */
if (need_pause) if (need_pause)
gst_element_set_state (element, GST_STATE_PLAYING); gst_element_set_state (element, GST_STATE_PLAYING);
@ -749,6 +813,7 @@ gst_play_bin_send_event (GstElement * element, GstEvent * event)
static const GstFormat * static const GstFormat *
gst_play_bin_get_formats (GstElement * element) gst_play_bin_get_formats (GstElement * element)
{ {
/* FIXME, compile this list from the installed sinks */
static GstFormat formats[] = { static GstFormat formats[] = {
GST_FORMAT_TIME, GST_FORMAT_TIME,
0, 0,
@ -768,8 +833,8 @@ gst_play_bin_convert (GstElement * element,
play_bin = GST_PLAY_BIN (element); play_bin = GST_PLAY_BIN (element);
s = play_bin->seekables; /* do a conversion, loop over all sinks, stop as soon as one of the
* sinks returns a successful result */
for (s = play_bin->seekables; s; s = g_list_next (s)) { for (s = play_bin->seekables; s; s = g_list_next (s)) {
GstElement *element = GST_ELEMENT (s->data); GstElement *element = GST_ELEMENT (s->data);
@ -784,6 +849,7 @@ gst_play_bin_convert (GstElement * element,
static const GstQueryType * static const GstQueryType *
gst_play_bin_get_query_types (GstElement * element) gst_play_bin_get_query_types (GstElement * element)
{ {
/* FIXME, compile from the installed sinks */
static const GstQueryType query_types[] = { static const GstQueryType query_types[] = {
GST_QUERY_TOTAL, GST_QUERY_TOTAL,
GST_QUERY_POSITION, GST_QUERY_POSITION,
@ -803,8 +869,6 @@ gst_play_bin_query (GstElement * element, GstQueryType type,
play_bin = GST_PLAY_BIN (element); play_bin = GST_PLAY_BIN (element);
s = play_bin->seekables;
for (s = play_bin->seekables; s; s = g_list_next (s)) { for (s = play_bin->seekables; s; s = g_list_next (s)) {
GstElement *element = GST_ELEMENT (s->data); GstElement *element = GST_ELEMENT (s->data);