gst-libs/gst/play/gstplay.c: Reworked the pipeline from scratch. Visualization is back and switch went out as i reali...

Original commit message from CVS:
2004-01-23  Julien MOUTTE  <julien@moutte.net>

* gst-libs/gst/play/gstplay.c: (gst_play_pipeline_setup),
(gst_play_set_location), (gst_play_seek_to_time),
(gst_play_set_audio_sink), (gst_play_set_visualization),
(gst_play_connect_visualization), (gst_play_get_sink_element): Reworked
the pipeline from scratch. Visualization is back and switch went out as
i realized it was not possible to use the way i wanted.
* sys/ximage/ximagesink.c: (gst_ximagesink_imagepool_clear),
(gst_ximagesink_change_state), (gst_ximagesink_dispose): Move xcontext
clearing in state change from READY to NULL. So that one can clean the
X ressources keeping the element.
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
(gst_xvimagesink_imagepool_clear), (gst_xvimagesink_change_state),
(gst_xvimagesink_colorbalance_set_value),
(gst_xvimagesink_colorbalance_get_value),
(gst_xvimagesink_set_property), (gst_xvimagesink_dispose),
(gst_xvimagesink_init): Same xcontext cleaning than ximagesink in state
change from READY to NULL and fixed some stupid bugs in colorbalance
get/set values. Also added the following feature : when nobody tries to
set some values to the colorbalance levels before the xcontext is
grabbed, then when creating channels list from Xv attributes we set the
internal values to the Xv defaults. This way we handle buggy Xv drivers
that set default hue values far from the middle of the range (Thanks
to Jon Trowbridge for pointing that issue).
* sys/xvimage/xvimagesink.h: Adding a cb_changed boolean to know if
colorbalance levels have been set before xcontext is grabbed.
This commit is contained in:
Julien Moutte 2004-01-22 23:54:34 +00:00
parent 5ea7e1a94a
commit 15289fa2dd
6 changed files with 635 additions and 470 deletions

View file

@ -1,3 +1,31 @@
2004-01-23 Julien MOUTTE <julien@moutte.net>
* gst-libs/gst/play/gstplay.c: (gst_play_pipeline_setup),
(gst_play_set_location), (gst_play_seek_to_time),
(gst_play_set_audio_sink), (gst_play_set_visualization),
(gst_play_connect_visualization), (gst_play_get_sink_element): Reworked
the pipeline from scratch. Visualization is back and switch went out as
i realized it was not possible to use the way i wanted.
* sys/ximage/ximagesink.c: (gst_ximagesink_imagepool_clear),
(gst_ximagesink_change_state), (gst_ximagesink_dispose): Move xcontext
clearing in state change from READY to NULL. So that one can clean the
X ressources keeping the element.
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xcontext_get),
(gst_xvimagesink_imagepool_clear), (gst_xvimagesink_change_state),
(gst_xvimagesink_colorbalance_set_value),
(gst_xvimagesink_colorbalance_get_value),
(gst_xvimagesink_set_property), (gst_xvimagesink_dispose),
(gst_xvimagesink_init): Same xcontext cleaning than ximagesink in state
change from READY to NULL and fixed some stupid bugs in colorbalance
get/set values. Also added the following feature : when nobody tries to
set some values to the colorbalance levels before the xcontext is
grabbed, then when creating channels list from Xv attributes we set the
internal values to the Xv defaults. This way we handle buggy Xv drivers
that set default hue values far from the middle of the range (Thanks
to Jon Trowbridge for pointing that issue).
* sys/xvimage/xvimagesink.h: Adding a cb_changed boolean to know if
colorbalance levels have been set before xcontext is grabbed.
2004-01-22 Ronald Bultje <rbultje@ronald.bitfreak.net>
* sys/oss/gstosselement.c: (gst_osselement_class_probe_devices):

View file

@ -59,41 +59,86 @@ static GstPipelineClass *parent_class = NULL;
static gboolean
gst_play_pipeline_setup (GstPlay *play)
{
GstElement *work_thread, *video_thread, *source;
GstElement *autoplugger, *switch_colorspace, *video_switch, *video_queue;
GstElement *video_balance, *video_colorspace, *video_scaler, *video_sink;
GstElement *audio_thread, *audio_queue, *audio_volume, *audio_sink;
GstElement *audio_tee, *vis_thread, *vis_queue, *vis_element, *end_vis_queue;
GstPad *audio_tee_pad1, *audio_tee_pad2, *vis_thread_pad, *audio_sink_pad;
/* Threads */
GstElement *work_thread, *audio_thread, *video_thread;
/* Main Thread elements */
GstElement *source, *autoplugger, *audioconvert, *volume, *tee, *vis_element;
/* Video Thread elements */
GstElement *video_queue, *video_cs, *video_balance, *balance_cs;
GstElement *video_scaler, *video_sink;
/* Audio Thread elements */
GstElement *audio_queue, *audio_sink;
/* Some useful pads */
GstPad *tee_pad1, *tee_pad2;
g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
/* Creating main thread and its elements
{ fakesrc ! spider ! audioconvert ! volume ! tee } */
{
work_thread = gst_element_factory_make ("thread", "work_thread");
if (!GST_IS_ELEMENT (work_thread))
return FALSE;
g_hash_table_insert (play->priv->elements, "work_thread", work_thread);
gst_bin_add (GST_BIN (play), work_thread);
/* Placeholder for the source and autoplugger { fakesrc ! spider } */
/* Placeholder for datasrc */
source = gst_element_factory_make ("fakesrc", "source");
if (!GST_IS_ELEMENT (source))
return FALSE;
g_hash_table_insert (play->priv->elements, "source", source);
/* Autoplugger */
autoplugger = gst_element_factory_make ("spider", "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
g_hash_table_insert (play->priv->elements, "autoplugger", autoplugger);
gst_bin_add_many (GST_BIN (work_thread), source, autoplugger, NULL);
gst_element_link (source, autoplugger);
/* Make sure we convert audio to the needed format */
audioconvert = gst_element_factory_make ("audioconvert",
"audioconvert");
if (!GST_IS_ELEMENT (audioconvert))
return FALSE;
/* Creating our video output bin
{ queue ! videobalance ! colorspace ! videoscale ! fakesink } */
g_hash_table_insert (play->priv->elements, "volume", audioconvert);
/* Volume control */
volume = gst_element_factory_make ("volume", "volume");
if (!GST_IS_ELEMENT (volume))
return FALSE;
g_hash_table_insert (play->priv->elements, "audioconvert", volume);
/* Duplicate audio signal to audio sink and visualization thread */
tee = gst_element_factory_make ("tee", "tee");
if (!GST_IS_ELEMENT (tee))
return FALSE;
tee_pad1 = gst_element_get_request_pad (tee, "src%d");
tee_pad2 = gst_element_get_request_pad (tee, "src%d");
g_hash_table_insert (play->priv->elements, "tee_pad1", tee_pad1);
g_hash_table_insert (play->priv->elements, "tee_pad2", tee_pad2);
g_hash_table_insert (play->priv->elements, "tee", tee);
gst_bin_add_many (GST_BIN (work_thread), source, autoplugger,/* audioconvert,*/
volume, tee, NULL);
gst_element_link_many (source, autoplugger,/* audioconvert,*/ volume, tee, NULL);
/* Visualization element placeholder (note: it s not added to the pipeline
yet) */
vis_element = gst_element_factory_make ("identity", "vis_element");
if (!GST_IS_ELEMENT (vis_element))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_element", vis_element);
}
/* Creating our video output bin */
{
video_thread = gst_element_factory_make ("thread", "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE;
@ -101,13 +146,24 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "video_thread", video_thread);
gst_bin_add (GST_BIN (work_thread), video_thread);
/* Buffer queue for our video thread */
/* Buffer queue for video data */
video_queue = gst_element_factory_make ("queue", "video_queue");
if (!GST_IS_ELEMENT (video_queue))
return FALSE;
g_hash_table_insert (play->priv->elements, "video_queue", video_queue);
/* Colorspace conversion */
video_cs = gst_element_factory_make ("ffcolorspace", "video_cs");
if (!GST_IS_ELEMENT (video_cs)) {
video_cs = gst_element_factory_make ("colorspace", "video_cs");
if (!GST_IS_ELEMENT (video_cs))
return FALSE;
}
g_hash_table_insert (play->priv->elements, "video_cs", video_cs);
/* Software colorbalance */
video_balance = gst_element_factory_make ("videobalance",
"video_balance");
if (!GST_IS_ELEMENT (video_balance))
@ -117,17 +173,14 @@ gst_play_pipeline_setup (GstPlay *play)
video_balance);
/* Colorspace conversion */
video_colorspace = gst_element_factory_make ("ffcolorspace",
"video_colorspace");
if (!GST_IS_ELEMENT (video_colorspace)) {
video_colorspace = gst_element_factory_make ("colorspace",
"video_colorspace");
if (!GST_IS_ELEMENT (video_colorspace))
balance_cs = gst_element_factory_make ("ffcolorspace", "balance_cs");
if (!GST_IS_ELEMENT (balance_cs)) {
balance_cs = gst_element_factory_make ("colorspace", "balance_cs");
if (!GST_IS_ELEMENT (balance_cs))
return FALSE;
}
g_hash_table_insert (play->priv->elements, "video_colorspace",
video_colorspace);
g_hash_table_insert (play->priv->elements, "balance_cs", balance_cs);
/* Software scaling of video stream */
video_scaler = gst_element_factory_make ("videoscale", "video_scaler");
@ -143,46 +196,18 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "video_sink", video_sink);
/* Linking, Adding, Ghosting */
gst_element_link_many (video_queue, video_balance, video_colorspace,
gst_bin_add_many (GST_BIN (video_thread), video_queue, video_cs,
video_balance, balance_cs, video_scaler, video_sink, NULL);
gst_element_link_many (video_queue, video_cs, video_balance, balance_cs,
video_scaler, video_sink, NULL);
gst_bin_add_many (GST_BIN (video_thread), video_queue, video_balance,
video_colorspace, video_scaler, video_sink, NULL);
gst_element_add_ghost_pad (video_thread,
gst_element_get_pad (video_queue, "sink"),
"sink");
/* autoplugger ! ffcolorspace ! switch */
switch_colorspace = NULL;
switch_colorspace = gst_element_factory_make ("ffcolorspace",
"switch_colorspace");
if (!GST_IS_ELEMENT (switch_colorspace)) {
switch_colorspace = gst_element_factory_make ("colorspace",
"switch_colorspace");
if (!GST_IS_ELEMENT (switch_colorspace))
return FALSE;
gst_element_link (autoplugger, video_thread);
}
g_hash_table_insert (play->priv->elements, "switch_colorspace",
switch_colorspace);
video_switch = gst_element_factory_make ("switch",
"video_switch");
if (!GST_IS_ELEMENT (video_switch))
return FALSE;
g_hash_table_insert (play->priv->elements, "video_switch", video_switch);
gst_bin_add_many (GST_BIN (work_thread), switch_colorspace,
/*video_switch,*/ NULL);
/* Connecting autoplugger to video switch and video switch to video output */
gst_element_link_many (autoplugger, switch_colorspace,
/*video_switch,*/ video_thread, NULL);
/* gst_element_link (autoplugger, video_thread); */
/* Creating our audio output bin
{ queue ! volume ! tee ! { queue ! goom } ! fakesink } */
{ queue ! fakesink } */
{
audio_thread = gst_element_factory_make ("thread", "audio_thread");
if (!GST_IS_ELEMENT (audio_thread))
return FALSE;
@ -197,85 +222,20 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "audio_queue", audio_queue);
/* Volume control */
audio_volume = gst_element_factory_make ("volume", "audio_volume");
if (!GST_IS_ELEMENT (audio_volume))
return FALSE;
g_hash_table_insert (play->priv->elements, "audio_volume", audio_volume);
/* Duplicate audio signal to sink and visualization thread */
audio_tee = gst_element_factory_make ("tee", "audio_tee");
if (!GST_IS_ELEMENT (audio_tee))
return FALSE;
audio_tee_pad1 = gst_element_get_request_pad (audio_tee, "src%d");
audio_tee_pad2 = gst_element_get_request_pad (audio_tee, "src%d");
g_hash_table_insert (play->priv->elements, "audio_tee_pad1",
audio_tee_pad1);
g_hash_table_insert (play->priv->elements, "audio_tee_pad2",
audio_tee_pad2);
g_hash_table_insert (play->priv->elements, "audio_tee", audio_tee);
/* Placeholder for future audio sink bin */
audio_sink = gst_element_factory_make ("fakesink", "audio_sink");
if (!GST_IS_ELEMENT (audio_sink))
return FALSE;
audio_sink_pad = gst_element_get_pad (audio_sink, "sink");
g_hash_table_insert (play->priv->elements, "audio_sink_pad",
audio_sink_pad);
g_hash_table_insert (play->priv->elements, "audio_sink", audio_sink);
/* Visualization thread */
vis_thread = gst_element_factory_make ("thread", "vis_thread");
if (!GST_IS_ELEMENT (vis_thread))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_thread", vis_thread);
/* Buffer queue for our visualization thread */
vis_queue = gst_element_factory_make ("queue", "vis_queue");
if (!GST_IS_ELEMENT (vis_queue))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_queue", vis_queue);
vis_element = gst_element_factory_make ("identity", "vis_element");
if (!GST_IS_ELEMENT (vis_element))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_element", vis_element);
end_vis_queue = gst_element_factory_make ("queue", "end_vis_queue");
if (!GST_IS_ELEMENT (end_vis_queue))
return FALSE;
g_hash_table_insert (play->priv->elements, "end_vis_queue",
end_vis_queue);
/* Adding, Linking, Ghosting in visualization */
gst_bin_add_many (GST_BIN (vis_thread), vis_queue, vis_element,
end_vis_queue, NULL);
gst_element_link_many (vis_queue, vis_element, end_vis_queue, NULL);
vis_thread_pad = gst_element_add_ghost_pad (vis_thread,
gst_element_get_pad (vis_queue, "sink"),
"sink");
g_hash_table_insert (play->priv->elements, "vis_thread_pad",
vis_thread_pad);
/* Linking, Adding, Ghosting in audio */
gst_element_link_many (audio_queue, audio_volume, audio_tee, NULL);
gst_pad_link (audio_tee_pad1, audio_sink_pad);
gst_bin_add_many (GST_BIN (audio_thread), audio_queue, audio_volume,
audio_tee, vis_thread, audio_sink, NULL);
gst_bin_add_many (GST_BIN (audio_thread), audio_queue, audio_sink, NULL);
gst_element_link (audio_queue, audio_sink);
gst_element_add_ghost_pad (audio_thread,
gst_element_get_pad (audio_queue, "sink"),
"sink");
/* Connecting audio output to autoplugger */
gst_element_link (autoplugger, audio_thread);
gst_pad_link (tee_pad2, gst_element_get_pad (audio_queue, "sink"));
}
return TRUE;
}
@ -505,7 +465,7 @@ gboolean
gst_play_set_location (GstPlay *play, const char *location)
{
GstElement *work_thread, *source, *autoplugger;
GstElement *switch_colorspace, *audio_thread;
GstElement *audioconvert, *video_thread;
g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
@ -521,25 +481,24 @@ gst_play_set_location (GstPlay *play, const char *location)
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread");
if (!GST_IS_ELEMENT (work_thread))
return FALSE;
switch_colorspace = g_hash_table_lookup (play->priv->elements,
"switch_colorspace");
if (!GST_IS_ELEMENT (switch_colorspace))
return FALSE;
audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread");
if (!GST_IS_ELEMENT (audio_thread))
return FALSE;
source = g_hash_table_lookup (play->priv->elements, "source");
if (!GST_IS_ELEMENT (source))
return FALSE;
autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
audioconvert = g_hash_table_lookup (play->priv->elements, "audioconvert");
if (!GST_IS_ELEMENT (audioconvert))
return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE;
/* Spider can autoplugg only once. We remove the actual one and put a new
autoplugger */
gst_element_unlink (source, autoplugger);
gst_element_unlink (autoplugger, switch_colorspace);
gst_element_unlink (autoplugger, audio_thread);
gst_element_unlink (autoplugger, video_thread);
gst_element_unlink (autoplugger, audioconvert);
gst_bin_remove (GST_BIN (work_thread), autoplugger);
autoplugger = gst_element_factory_make ("spider", "autoplugger");
@ -548,8 +507,8 @@ gst_play_set_location (GstPlay *play, const char *location)
gst_bin_add (GST_BIN (work_thread), autoplugger);
gst_element_link (source, autoplugger);
gst_element_link (autoplugger, switch_colorspace);
gst_element_link (autoplugger, audio_thread);
gst_element_link (autoplugger, video_thread);
gst_element_link (autoplugger, audioconvert);
g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger);
@ -618,8 +577,9 @@ gst_play_seek_to_time (GstPlay * play, gint64 time_nanos)
}
if (s) {
GstClock *clock = gst_bin_get_clock (GST_BIN (play));
play->priv->time_nanos = gst_clock_get_time (clock);
GstClockTime time;
time = gst_element_get_time (audio_sink_element);
play->priv->time_nanos = GST_CLOCK_TIME_IS_VALID (time) ? time : 0;
g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK],
0,play->priv->time_nanos);
}
@ -745,8 +705,7 @@ gst_play_set_video_sink (GstPlay *play, GstElement *video_sink)
gboolean
gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink)
{
GstElement *old_audio_sink, *audio_thread, *audio_sink_element;
GstPad *audio_tee_pad1, *audio_sink_pad, *old_audio_sink_pad;
GstElement *old_audio_sink, *audio_thread, *audio_queue, *audio_sink_element;
g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
@ -761,31 +720,21 @@ gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink)
old_audio_sink = g_hash_table_lookup (play->priv->elements, "audio_sink");
if (!GST_IS_ELEMENT (old_audio_sink))
return FALSE;
old_audio_sink_pad = g_hash_table_lookup (play->priv->elements,
"audio_sink_pad");
if (!GST_IS_PAD (old_audio_sink_pad))
return FALSE;
audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread");
if (!GST_IS_ELEMENT (audio_thread))
return FALSE;
audio_tee_pad1 = g_hash_table_lookup (play->priv->elements,
"audio_tee_pad1");
if (!GST_IS_PAD (audio_tee_pad1))
return FALSE;
audio_sink_pad = gst_element_get_pad (audio_sink, "sink");
if (!GST_IS_PAD (audio_sink_pad))
audio_queue = g_hash_table_lookup (play->priv->elements, "audio_queue");
if (!GST_IS_ELEMENT (audio_queue))
return FALSE;
/* Unlinking old audiosink, removing it from pipeline, putting the new one
and linking it */
gst_pad_unlink (audio_tee_pad1, old_audio_sink_pad);
gst_element_unlink (audio_queue, old_audio_sink);
gst_bin_remove (GST_BIN (audio_thread), old_audio_sink);
gst_bin_add (GST_BIN (audio_thread), audio_sink);
gst_pad_link (audio_tee_pad1, audio_sink_pad);
gst_element_link (audio_queue, audio_sink);
g_hash_table_replace (play->priv->elements, "audio_sink", audio_sink);
g_hash_table_replace (play->priv->elements, "audio_sink_pad",
audio_sink_pad);
audio_sink_element = gst_play_get_sink_element (play, audio_sink,
GST_PLAY_SINK_TYPE_AUDIO);
@ -811,7 +760,8 @@ gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink)
gboolean
gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
{
GstElement *old_vis_element, *vis_thread, *vis_queue, *end_vis_queue;
GstElement *work_thread, *old_vis_element, *video_thread;
GstPad *tee_pad1;
gboolean was_playing = FALSE;
g_return_val_if_fail (play != NULL, FALSE);
@ -819,34 +769,50 @@ gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
g_return_val_if_fail (vis_element != NULL, FALSE);
g_return_val_if_fail (GST_IS_ELEMENT (vis_element), FALSE);
/* We bring back the pipeline to READY */
if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
was_playing = TRUE;
}
/* Getting needed objects */
vis_thread = g_hash_table_lookup (play->priv->elements, "vis_thread");
if (!GST_IS_ELEMENT (vis_thread))
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread");
if (!GST_IS_ELEMENT (work_thread))
return FALSE;
old_vis_element = g_hash_table_lookup (play->priv->elements,
"vis_element");
if (!GST_IS_ELEMENT (old_vis_element))
return FALSE;
vis_queue = g_hash_table_lookup (play->priv->elements, "vis_queue");
if (!GST_IS_ELEMENT (vis_queue))
tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1");
if (!GST_IS_PAD (tee_pad1))
return FALSE;
end_vis_queue = g_hash_table_lookup (play->priv->elements, "end_vis_queue");
if (!GST_IS_ELEMENT (end_vis_queue))
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE;
/* Let's check if the current vis element has a managing bin. If yes that
means the element is inside the pipeline and need to be unlinked and
removed. We also need to pause the pipeline if it is currently playing. */
if (gst_element_get_managing_bin (old_vis_element)) {
GstPad *vis_element_pad;
/* We bring back the pipeline to PAUSED */
if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
was_playing = TRUE;
}
/* Unlinking, removing the old element then adding and linking the new one */
gst_element_unlink (vis_queue, old_vis_element);
gst_element_unlink (old_vis_element, end_vis_queue);
gst_bin_remove (GST_BIN (vis_thread), old_vis_element);
gst_bin_add (GST_BIN (vis_thread), vis_element);
gst_element_link (vis_queue, vis_element);
gst_element_link (vis_element, end_vis_queue);
/* Unlinking, removing the old element then adding and linking the new one */
vis_element_pad = gst_element_get_pad (old_vis_element, "sink");
if (GST_IS_PAD (vis_element_pad))
gst_pad_unlink (tee_pad1, vis_element_pad);
gst_element_unlink (old_vis_element, video_thread);
gst_bin_remove (GST_BIN (work_thread), old_vis_element);
gst_bin_add (GST_BIN (work_thread), vis_element);
vis_element_pad = gst_element_get_pad (vis_element, "sink");
if (GST_IS_PAD (vis_element_pad))
gst_pad_link (tee_pad1, vis_element_pad);
gst_element_link (vis_element, video_thread);
}
else {
gst_object_unref (GST_OBJECT (old_vis_element));
}
g_hash_table_replace (play->priv->elements, "vis_element", vis_element);
if (was_playing)
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING);
@ -867,39 +833,121 @@ gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
gboolean
gst_play_connect_visualization (GstPlay * play, gboolean connect)
{
GstPad *audio_tee_pad2, *vis_thread_pad;
gboolean connected = FALSE, was_playing = FALSE;
GstElement *work_thread, *vis_element, *autoplugger, *video_thread;
GstElement *audioconvert, *source;
GstPad *tee_pad1, *vis_element_pad;
g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
vis_thread_pad = g_hash_table_lookup (play->priv->elements,
"vis_thread_pad");
if (!GST_IS_PAD (vis_thread_pad))
/* Getting needed objects */
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread");
if (!GST_IS_ELEMENT (work_thread))
return FALSE;
audio_tee_pad2 = g_hash_table_lookup (play->priv->elements,
"audio_tee_pad2");
if (!GST_IS_PAD (audio_tee_pad2))
vis_element = g_hash_table_lookup (play->priv->elements, "vis_element");
if (!GST_IS_ELEMENT (vis_element))
return FALSE;
tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1");
if (!GST_IS_PAD (tee_pad1))
return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE;
autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
source = g_hash_table_lookup (play->priv->elements, "source");
if (!GST_IS_ELEMENT (source))
return FALSE;
audioconvert = g_hash_table_lookup (play->priv->elements, "audioconvert");
if (!GST_IS_ELEMENT (audioconvert))
return FALSE;
if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
was_playing = TRUE;
}
if (gst_pad_get_peer (vis_thread_pad) != NULL)
connected = TRUE;
else
connected = FALSE;
if ((connect) && (!connected))
gst_pad_link (audio_tee_pad2, vis_thread_pad);
else if ((!connect) && (connected))
gst_pad_unlink (audio_tee_pad2, vis_thread_pad);
if (was_playing)
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING);
/* Check if the vis element is in the pipeline. That means visualization is
connected already */
if (gst_element_get_managing_bin (vis_element)) {
/* If we are supposed to connect then nothing to do we return */
if (connect) {
return TRUE;
}
/* We have to modify the pipeline. Changing autoplugger requires going to
READY */
gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
/* Otherwise we unlink and remove the vis element refing it so that
it won't be destroyed when removed from the bin. */
vis_element_pad = gst_element_get_pad (vis_element, "sink");
if (GST_IS_PAD (vis_element_pad))
gst_pad_unlink (tee_pad1, vis_element_pad);
gst_element_unlink (vis_element, video_thread);
gst_object_ref (GST_OBJECT (vis_element));
gst_bin_remove (GST_BIN (work_thread), vis_element);
/* Removing autoplugger */
gst_element_unlink (source, autoplugger);
gst_element_unlink (autoplugger, audioconvert);
gst_bin_remove (GST_BIN (work_thread), autoplugger);
autoplugger = gst_element_factory_make ("spider", "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
/* Adding and connecting a new autoplugger connected to video_thread */
gst_bin_add (GST_BIN (work_thread), autoplugger);
gst_element_link (source, autoplugger);
gst_element_link (autoplugger, video_thread);
gst_element_link (autoplugger, audioconvert);
g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger);
}
else {
GstCaps *filtered_caps;
/* If we are supposed to disconnect then nothing to do we return */
if (!connect) {
return TRUE;
}
/* We have to modify the pipeline. Changing autoplugger requires going to
READY */
gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
/* Removing autoplugger */
gst_element_unlink (source, autoplugger);
gst_element_unlink (autoplugger, video_thread);
gst_element_unlink (autoplugger, audioconvert);
gst_bin_remove (GST_BIN (work_thread), autoplugger);
autoplugger = gst_element_factory_make ("spider", "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
/* Adding and connecting a new autoplugger */
gst_bin_add (GST_BIN (work_thread), autoplugger);
gst_element_link (source, autoplugger);
gst_element_link (autoplugger, audioconvert);
g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger);
/* Otherwise we add the element to the bin and link it to video_thread */
gst_bin_add (GST_BIN (work_thread), vis_element);
vis_element_pad = gst_element_get_pad (vis_element, "sink");
if (GST_IS_PAD (vis_element_pad))
gst_pad_link (tee_pad1, vis_element_pad);
filtered_caps = gst_caps_from_string ("video/x-raw-rgb, "
"framerate = 30.0; "
"video/x-raw-yuv, "
"framerate = 30.0");
if (!gst_element_link_filtered (vis_element, video_thread, filtered_caps))
g_message ("failed linking filtered vis with video thread");
gst_caps_free (filtered_caps);
}
return TRUE;
}
@ -916,7 +964,7 @@ gst_play_connect_visualization (GstPlay * play, gboolean connect)
*/
GstElement *
gst_play_get_sink_element (GstPlay *play,
GstElement *element, GstPlaySinkType sink_type)
GstElement *element, GstPlaySinkType sink_type)
{
GList *elements = NULL;
const GList *pads = NULL;

View file

@ -59,41 +59,86 @@ static GstPipelineClass *parent_class = NULL;
static gboolean
gst_play_pipeline_setup (GstPlay *play)
{
GstElement *work_thread, *video_thread, *source;
GstElement *autoplugger, *switch_colorspace, *video_switch, *video_queue;
GstElement *video_balance, *video_colorspace, *video_scaler, *video_sink;
GstElement *audio_thread, *audio_queue, *audio_volume, *audio_sink;
GstElement *audio_tee, *vis_thread, *vis_queue, *vis_element, *end_vis_queue;
GstPad *audio_tee_pad1, *audio_tee_pad2, *vis_thread_pad, *audio_sink_pad;
/* Threads */
GstElement *work_thread, *audio_thread, *video_thread;
/* Main Thread elements */
GstElement *source, *autoplugger, *audioconvert, *volume, *tee, *vis_element;
/* Video Thread elements */
GstElement *video_queue, *video_cs, *video_balance, *balance_cs;
GstElement *video_scaler, *video_sink;
/* Audio Thread elements */
GstElement *audio_queue, *audio_sink;
/* Some useful pads */
GstPad *tee_pad1, *tee_pad2;
g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
/* Creating main thread and its elements
{ fakesrc ! spider ! audioconvert ! volume ! tee } */
{
work_thread = gst_element_factory_make ("thread", "work_thread");
if (!GST_IS_ELEMENT (work_thread))
return FALSE;
g_hash_table_insert (play->priv->elements, "work_thread", work_thread);
gst_bin_add (GST_BIN (play), work_thread);
/* Placeholder for the source and autoplugger { fakesrc ! spider } */
/* Placeholder for datasrc */
source = gst_element_factory_make ("fakesrc", "source");
if (!GST_IS_ELEMENT (source))
return FALSE;
g_hash_table_insert (play->priv->elements, "source", source);
/* Autoplugger */
autoplugger = gst_element_factory_make ("spider", "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
g_hash_table_insert (play->priv->elements, "autoplugger", autoplugger);
gst_bin_add_many (GST_BIN (work_thread), source, autoplugger, NULL);
gst_element_link (source, autoplugger);
/* Make sure we convert audio to the needed format */
audioconvert = gst_element_factory_make ("audioconvert",
"audioconvert");
if (!GST_IS_ELEMENT (audioconvert))
return FALSE;
/* Creating our video output bin
{ queue ! videobalance ! colorspace ! videoscale ! fakesink } */
g_hash_table_insert (play->priv->elements, "volume", audioconvert);
/* Volume control */
volume = gst_element_factory_make ("volume", "volume");
if (!GST_IS_ELEMENT (volume))
return FALSE;
g_hash_table_insert (play->priv->elements, "audioconvert", volume);
/* Duplicate audio signal to audio sink and visualization thread */
tee = gst_element_factory_make ("tee", "tee");
if (!GST_IS_ELEMENT (tee))
return FALSE;
tee_pad1 = gst_element_get_request_pad (tee, "src%d");
tee_pad2 = gst_element_get_request_pad (tee, "src%d");
g_hash_table_insert (play->priv->elements, "tee_pad1", tee_pad1);
g_hash_table_insert (play->priv->elements, "tee_pad2", tee_pad2);
g_hash_table_insert (play->priv->elements, "tee", tee);
gst_bin_add_many (GST_BIN (work_thread), source, autoplugger,/* audioconvert,*/
volume, tee, NULL);
gst_element_link_many (source, autoplugger,/* audioconvert,*/ volume, tee, NULL);
/* Visualization element placeholder (note: it s not added to the pipeline
yet) */
vis_element = gst_element_factory_make ("identity", "vis_element");
if (!GST_IS_ELEMENT (vis_element))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_element", vis_element);
}
/* Creating our video output bin */
{
video_thread = gst_element_factory_make ("thread", "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE;
@ -101,13 +146,24 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "video_thread", video_thread);
gst_bin_add (GST_BIN (work_thread), video_thread);
/* Buffer queue for our video thread */
/* Buffer queue for video data */
video_queue = gst_element_factory_make ("queue", "video_queue");
if (!GST_IS_ELEMENT (video_queue))
return FALSE;
g_hash_table_insert (play->priv->elements, "video_queue", video_queue);
/* Colorspace conversion */
video_cs = gst_element_factory_make ("ffcolorspace", "video_cs");
if (!GST_IS_ELEMENT (video_cs)) {
video_cs = gst_element_factory_make ("colorspace", "video_cs");
if (!GST_IS_ELEMENT (video_cs))
return FALSE;
}
g_hash_table_insert (play->priv->elements, "video_cs", video_cs);
/* Software colorbalance */
video_balance = gst_element_factory_make ("videobalance",
"video_balance");
if (!GST_IS_ELEMENT (video_balance))
@ -117,17 +173,14 @@ gst_play_pipeline_setup (GstPlay *play)
video_balance);
/* Colorspace conversion */
video_colorspace = gst_element_factory_make ("ffcolorspace",
"video_colorspace");
if (!GST_IS_ELEMENT (video_colorspace)) {
video_colorspace = gst_element_factory_make ("colorspace",
"video_colorspace");
if (!GST_IS_ELEMENT (video_colorspace))
balance_cs = gst_element_factory_make ("ffcolorspace", "balance_cs");
if (!GST_IS_ELEMENT (balance_cs)) {
balance_cs = gst_element_factory_make ("colorspace", "balance_cs");
if (!GST_IS_ELEMENT (balance_cs))
return FALSE;
}
g_hash_table_insert (play->priv->elements, "video_colorspace",
video_colorspace);
g_hash_table_insert (play->priv->elements, "balance_cs", balance_cs);
/* Software scaling of video stream */
video_scaler = gst_element_factory_make ("videoscale", "video_scaler");
@ -143,46 +196,18 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "video_sink", video_sink);
/* Linking, Adding, Ghosting */
gst_element_link_many (video_queue, video_balance, video_colorspace,
gst_bin_add_many (GST_BIN (video_thread), video_queue, video_cs,
video_balance, balance_cs, video_scaler, video_sink, NULL);
gst_element_link_many (video_queue, video_cs, video_balance, balance_cs,
video_scaler, video_sink, NULL);
gst_bin_add_many (GST_BIN (video_thread), video_queue, video_balance,
video_colorspace, video_scaler, video_sink, NULL);
gst_element_add_ghost_pad (video_thread,
gst_element_get_pad (video_queue, "sink"),
"sink");
/* autoplugger ! ffcolorspace ! switch */
switch_colorspace = NULL;
switch_colorspace = gst_element_factory_make ("ffcolorspace",
"switch_colorspace");
if (!GST_IS_ELEMENT (switch_colorspace)) {
switch_colorspace = gst_element_factory_make ("colorspace",
"switch_colorspace");
if (!GST_IS_ELEMENT (switch_colorspace))
return FALSE;
gst_element_link (autoplugger, video_thread);
}
g_hash_table_insert (play->priv->elements, "switch_colorspace",
switch_colorspace);
video_switch = gst_element_factory_make ("switch",
"video_switch");
if (!GST_IS_ELEMENT (video_switch))
return FALSE;
g_hash_table_insert (play->priv->elements, "video_switch", video_switch);
gst_bin_add_many (GST_BIN (work_thread), switch_colorspace,
/*video_switch,*/ NULL);
/* Connecting autoplugger to video switch and video switch to video output */
gst_element_link_many (autoplugger, switch_colorspace,
/*video_switch,*/ video_thread, NULL);
/* gst_element_link (autoplugger, video_thread); */
/* Creating our audio output bin
{ queue ! volume ! tee ! { queue ! goom } ! fakesink } */
{ queue ! fakesink } */
{
audio_thread = gst_element_factory_make ("thread", "audio_thread");
if (!GST_IS_ELEMENT (audio_thread))
return FALSE;
@ -197,85 +222,20 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "audio_queue", audio_queue);
/* Volume control */
audio_volume = gst_element_factory_make ("volume", "audio_volume");
if (!GST_IS_ELEMENT (audio_volume))
return FALSE;
g_hash_table_insert (play->priv->elements, "audio_volume", audio_volume);
/* Duplicate audio signal to sink and visualization thread */
audio_tee = gst_element_factory_make ("tee", "audio_tee");
if (!GST_IS_ELEMENT (audio_tee))
return FALSE;
audio_tee_pad1 = gst_element_get_request_pad (audio_tee, "src%d");
audio_tee_pad2 = gst_element_get_request_pad (audio_tee, "src%d");
g_hash_table_insert (play->priv->elements, "audio_tee_pad1",
audio_tee_pad1);
g_hash_table_insert (play->priv->elements, "audio_tee_pad2",
audio_tee_pad2);
g_hash_table_insert (play->priv->elements, "audio_tee", audio_tee);
/* Placeholder for future audio sink bin */
audio_sink = gst_element_factory_make ("fakesink", "audio_sink");
if (!GST_IS_ELEMENT (audio_sink))
return FALSE;
audio_sink_pad = gst_element_get_pad (audio_sink, "sink");
g_hash_table_insert (play->priv->elements, "audio_sink_pad",
audio_sink_pad);
g_hash_table_insert (play->priv->elements, "audio_sink", audio_sink);
/* Visualization thread */
vis_thread = gst_element_factory_make ("thread", "vis_thread");
if (!GST_IS_ELEMENT (vis_thread))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_thread", vis_thread);
/* Buffer queue for our visualization thread */
vis_queue = gst_element_factory_make ("queue", "vis_queue");
if (!GST_IS_ELEMENT (vis_queue))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_queue", vis_queue);
vis_element = gst_element_factory_make ("identity", "vis_element");
if (!GST_IS_ELEMENT (vis_element))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_element", vis_element);
end_vis_queue = gst_element_factory_make ("queue", "end_vis_queue");
if (!GST_IS_ELEMENT (end_vis_queue))
return FALSE;
g_hash_table_insert (play->priv->elements, "end_vis_queue",
end_vis_queue);
/* Adding, Linking, Ghosting in visualization */
gst_bin_add_many (GST_BIN (vis_thread), vis_queue, vis_element,
end_vis_queue, NULL);
gst_element_link_many (vis_queue, vis_element, end_vis_queue, NULL);
vis_thread_pad = gst_element_add_ghost_pad (vis_thread,
gst_element_get_pad (vis_queue, "sink"),
"sink");
g_hash_table_insert (play->priv->elements, "vis_thread_pad",
vis_thread_pad);
/* Linking, Adding, Ghosting in audio */
gst_element_link_many (audio_queue, audio_volume, audio_tee, NULL);
gst_pad_link (audio_tee_pad1, audio_sink_pad);
gst_bin_add_many (GST_BIN (audio_thread), audio_queue, audio_volume,
audio_tee, vis_thread, audio_sink, NULL);
gst_bin_add_many (GST_BIN (audio_thread), audio_queue, audio_sink, NULL);
gst_element_link (audio_queue, audio_sink);
gst_element_add_ghost_pad (audio_thread,
gst_element_get_pad (audio_queue, "sink"),
"sink");
/* Connecting audio output to autoplugger */
gst_element_link (autoplugger, audio_thread);
gst_pad_link (tee_pad2, gst_element_get_pad (audio_queue, "sink"));
}
return TRUE;
}
@ -505,7 +465,7 @@ gboolean
gst_play_set_location (GstPlay *play, const char *location)
{
GstElement *work_thread, *source, *autoplugger;
GstElement *switch_colorspace, *audio_thread;
GstElement *audioconvert, *video_thread;
g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
@ -521,25 +481,24 @@ gst_play_set_location (GstPlay *play, const char *location)
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread");
if (!GST_IS_ELEMENT (work_thread))
return FALSE;
switch_colorspace = g_hash_table_lookup (play->priv->elements,
"switch_colorspace");
if (!GST_IS_ELEMENT (switch_colorspace))
return FALSE;
audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread");
if (!GST_IS_ELEMENT (audio_thread))
return FALSE;
source = g_hash_table_lookup (play->priv->elements, "source");
if (!GST_IS_ELEMENT (source))
return FALSE;
autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
audioconvert = g_hash_table_lookup (play->priv->elements, "audioconvert");
if (!GST_IS_ELEMENT (audioconvert))
return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE;
/* Spider can autoplugg only once. We remove the actual one and put a new
autoplugger */
gst_element_unlink (source, autoplugger);
gst_element_unlink (autoplugger, switch_colorspace);
gst_element_unlink (autoplugger, audio_thread);
gst_element_unlink (autoplugger, video_thread);
gst_element_unlink (autoplugger, audioconvert);
gst_bin_remove (GST_BIN (work_thread), autoplugger);
autoplugger = gst_element_factory_make ("spider", "autoplugger");
@ -548,8 +507,8 @@ gst_play_set_location (GstPlay *play, const char *location)
gst_bin_add (GST_BIN (work_thread), autoplugger);
gst_element_link (source, autoplugger);
gst_element_link (autoplugger, switch_colorspace);
gst_element_link (autoplugger, audio_thread);
gst_element_link (autoplugger, video_thread);
gst_element_link (autoplugger, audioconvert);
g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger);
@ -618,8 +577,9 @@ gst_play_seek_to_time (GstPlay * play, gint64 time_nanos)
}
if (s) {
GstClock *clock = gst_bin_get_clock (GST_BIN (play));
play->priv->time_nanos = gst_clock_get_time (clock);
GstClockTime time;
time = gst_element_get_time (audio_sink_element);
play->priv->time_nanos = GST_CLOCK_TIME_IS_VALID (time) ? time : 0;
g_signal_emit (G_OBJECT (play), gst_play_signals[TIME_TICK],
0,play->priv->time_nanos);
}
@ -745,8 +705,7 @@ gst_play_set_video_sink (GstPlay *play, GstElement *video_sink)
gboolean
gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink)
{
GstElement *old_audio_sink, *audio_thread, *audio_sink_element;
GstPad *audio_tee_pad1, *audio_sink_pad, *old_audio_sink_pad;
GstElement *old_audio_sink, *audio_thread, *audio_queue, *audio_sink_element;
g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
@ -761,31 +720,21 @@ gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink)
old_audio_sink = g_hash_table_lookup (play->priv->elements, "audio_sink");
if (!GST_IS_ELEMENT (old_audio_sink))
return FALSE;
old_audio_sink_pad = g_hash_table_lookup (play->priv->elements,
"audio_sink_pad");
if (!GST_IS_PAD (old_audio_sink_pad))
return FALSE;
audio_thread = g_hash_table_lookup (play->priv->elements, "audio_thread");
if (!GST_IS_ELEMENT (audio_thread))
return FALSE;
audio_tee_pad1 = g_hash_table_lookup (play->priv->elements,
"audio_tee_pad1");
if (!GST_IS_PAD (audio_tee_pad1))
return FALSE;
audio_sink_pad = gst_element_get_pad (audio_sink, "sink");
if (!GST_IS_PAD (audio_sink_pad))
audio_queue = g_hash_table_lookup (play->priv->elements, "audio_queue");
if (!GST_IS_ELEMENT (audio_queue))
return FALSE;
/* Unlinking old audiosink, removing it from pipeline, putting the new one
and linking it */
gst_pad_unlink (audio_tee_pad1, old_audio_sink_pad);
gst_element_unlink (audio_queue, old_audio_sink);
gst_bin_remove (GST_BIN (audio_thread), old_audio_sink);
gst_bin_add (GST_BIN (audio_thread), audio_sink);
gst_pad_link (audio_tee_pad1, audio_sink_pad);
gst_element_link (audio_queue, audio_sink);
g_hash_table_replace (play->priv->elements, "audio_sink", audio_sink);
g_hash_table_replace (play->priv->elements, "audio_sink_pad",
audio_sink_pad);
audio_sink_element = gst_play_get_sink_element (play, audio_sink,
GST_PLAY_SINK_TYPE_AUDIO);
@ -811,7 +760,8 @@ gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink)
gboolean
gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
{
GstElement *old_vis_element, *vis_thread, *vis_queue, *end_vis_queue;
GstElement *work_thread, *old_vis_element, *video_thread;
GstPad *tee_pad1;
gboolean was_playing = FALSE;
g_return_val_if_fail (play != NULL, FALSE);
@ -819,34 +769,50 @@ gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
g_return_val_if_fail (vis_element != NULL, FALSE);
g_return_val_if_fail (GST_IS_ELEMENT (vis_element), FALSE);
/* We bring back the pipeline to READY */
if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
was_playing = TRUE;
}
/* Getting needed objects */
vis_thread = g_hash_table_lookup (play->priv->elements, "vis_thread");
if (!GST_IS_ELEMENT (vis_thread))
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread");
if (!GST_IS_ELEMENT (work_thread))
return FALSE;
old_vis_element = g_hash_table_lookup (play->priv->elements,
"vis_element");
if (!GST_IS_ELEMENT (old_vis_element))
return FALSE;
vis_queue = g_hash_table_lookup (play->priv->elements, "vis_queue");
if (!GST_IS_ELEMENT (vis_queue))
tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1");
if (!GST_IS_PAD (tee_pad1))
return FALSE;
end_vis_queue = g_hash_table_lookup (play->priv->elements, "end_vis_queue");
if (!GST_IS_ELEMENT (end_vis_queue))
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE;
/* Let's check if the current vis element has a managing bin. If yes that
means the element is inside the pipeline and need to be unlinked and
removed. We also need to pause the pipeline if it is currently playing. */
if (gst_element_get_managing_bin (old_vis_element)) {
GstPad *vis_element_pad;
/* We bring back the pipeline to PAUSED */
if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
was_playing = TRUE;
}
/* Unlinking, removing the old element then adding and linking the new one */
gst_element_unlink (vis_queue, old_vis_element);
gst_element_unlink (old_vis_element, end_vis_queue);
gst_bin_remove (GST_BIN (vis_thread), old_vis_element);
gst_bin_add (GST_BIN (vis_thread), vis_element);
gst_element_link (vis_queue, vis_element);
gst_element_link (vis_element, end_vis_queue);
/* Unlinking, removing the old element then adding and linking the new one */
vis_element_pad = gst_element_get_pad (old_vis_element, "sink");
if (GST_IS_PAD (vis_element_pad))
gst_pad_unlink (tee_pad1, vis_element_pad);
gst_element_unlink (old_vis_element, video_thread);
gst_bin_remove (GST_BIN (work_thread), old_vis_element);
gst_bin_add (GST_BIN (work_thread), vis_element);
vis_element_pad = gst_element_get_pad (vis_element, "sink");
if (GST_IS_PAD (vis_element_pad))
gst_pad_link (tee_pad1, vis_element_pad);
gst_element_link (vis_element, video_thread);
}
else {
gst_object_unref (GST_OBJECT (old_vis_element));
}
g_hash_table_replace (play->priv->elements, "vis_element", vis_element);
if (was_playing)
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING);
@ -867,39 +833,121 @@ gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
gboolean
gst_play_connect_visualization (GstPlay * play, gboolean connect)
{
GstPad *audio_tee_pad2, *vis_thread_pad;
gboolean connected = FALSE, was_playing = FALSE;
GstElement *work_thread, *vis_element, *autoplugger, *video_thread;
GstElement *audioconvert, *source;
GstPad *tee_pad1, *vis_element_pad;
g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
vis_thread_pad = g_hash_table_lookup (play->priv->elements,
"vis_thread_pad");
if (!GST_IS_PAD (vis_thread_pad))
/* Getting needed objects */
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread");
if (!GST_IS_ELEMENT (work_thread))
return FALSE;
audio_tee_pad2 = g_hash_table_lookup (play->priv->elements,
"audio_tee_pad2");
if (!GST_IS_PAD (audio_tee_pad2))
vis_element = g_hash_table_lookup (play->priv->elements, "vis_element");
if (!GST_IS_ELEMENT (vis_element))
return FALSE;
tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1");
if (!GST_IS_PAD (tee_pad1))
return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE;
autoplugger = g_hash_table_lookup (play->priv->elements, "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
source = g_hash_table_lookup (play->priv->elements, "source");
if (!GST_IS_ELEMENT (source))
return FALSE;
audioconvert = g_hash_table_lookup (play->priv->elements, "audioconvert");
if (!GST_IS_ELEMENT (audioconvert))
return FALSE;
if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
was_playing = TRUE;
}
if (gst_pad_get_peer (vis_thread_pad) != NULL)
connected = TRUE;
else
connected = FALSE;
if ((connect) && (!connected))
gst_pad_link (audio_tee_pad2, vis_thread_pad);
else if ((!connect) && (connected))
gst_pad_unlink (audio_tee_pad2, vis_thread_pad);
if (was_playing)
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING);
/* Check if the vis element is in the pipeline. That means visualization is
connected already */
if (gst_element_get_managing_bin (vis_element)) {
/* If we are supposed to connect then nothing to do we return */
if (connect) {
return TRUE;
}
/* We have to modify the pipeline. Changing autoplugger requires going to
READY */
gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
/* Otherwise we unlink and remove the vis element refing it so that
it won't be destroyed when removed from the bin. */
vis_element_pad = gst_element_get_pad (vis_element, "sink");
if (GST_IS_PAD (vis_element_pad))
gst_pad_unlink (tee_pad1, vis_element_pad);
gst_element_unlink (vis_element, video_thread);
gst_object_ref (GST_OBJECT (vis_element));
gst_bin_remove (GST_BIN (work_thread), vis_element);
/* Removing autoplugger */
gst_element_unlink (source, autoplugger);
gst_element_unlink (autoplugger, audioconvert);
gst_bin_remove (GST_BIN (work_thread), autoplugger);
autoplugger = gst_element_factory_make ("spider", "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
/* Adding and connecting a new autoplugger connected to video_thread */
gst_bin_add (GST_BIN (work_thread), autoplugger);
gst_element_link (source, autoplugger);
gst_element_link (autoplugger, video_thread);
gst_element_link (autoplugger, audioconvert);
g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger);
}
else {
GstCaps *filtered_caps;
/* If we are supposed to disconnect then nothing to do we return */
if (!connect) {
return TRUE;
}
/* We have to modify the pipeline. Changing autoplugger requires going to
READY */
gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
/* Removing autoplugger */
gst_element_unlink (source, autoplugger);
gst_element_unlink (autoplugger, video_thread);
gst_element_unlink (autoplugger, audioconvert);
gst_bin_remove (GST_BIN (work_thread), autoplugger);
autoplugger = gst_element_factory_make ("spider", "autoplugger");
if (!GST_IS_ELEMENT (autoplugger))
return FALSE;
/* Adding and connecting a new autoplugger */
gst_bin_add (GST_BIN (work_thread), autoplugger);
gst_element_link (source, autoplugger);
gst_element_link (autoplugger, audioconvert);
g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger);
/* Otherwise we add the element to the bin and link it to video_thread */
gst_bin_add (GST_BIN (work_thread), vis_element);
vis_element_pad = gst_element_get_pad (vis_element, "sink");
if (GST_IS_PAD (vis_element_pad))
gst_pad_link (tee_pad1, vis_element_pad);
filtered_caps = gst_caps_from_string ("video/x-raw-rgb, "
"framerate = 30.0; "
"video/x-raw-yuv, "
"framerate = 30.0");
if (!gst_element_link_filtered (vis_element, video_thread, filtered_caps))
g_message ("failed linking filtered vis with video thread");
gst_caps_free (filtered_caps);
}
return TRUE;
}
@ -916,7 +964,7 @@ gst_play_connect_visualization (GstPlay * play, gboolean connect)
*/
GstElement *
gst_play_get_sink_element (GstPlay *play,
GstElement *element, GstPlaySinkType sink_type)
GstElement *element, GstPlaySinkType sink_type)
{
GList *elements = NULL;
const GList *pads = NULL;

View file

@ -548,6 +548,22 @@ gst_ximagesink_xcontext_clear (GstXImageSink *ximagesink)
ximagesink->xcontext = NULL;
}
static void
gst_ximagesink_imagepool_clear (GstXImageSink *ximagesink)
{
g_mutex_lock(ximagesink->pool_lock);
while (ximagesink->image_pool)
{
GstXImage *ximage = ximagesink->image_pool->data;
ximagesink->image_pool = g_slist_delete_link (ximagesink->image_pool,
ximagesink->image_pool);
gst_ximagesink_ximage_destroy (ximagesink, ximage);
}
g_mutex_unlock(ximagesink->pool_lock);
}
/* Element stuff */
static GstCaps *
@ -693,6 +709,26 @@ gst_ximagesink_change_state (GstElement *element)
GST_VIDEOSINK_HEIGHT (ximagesink) = 0;
break;
case GST_STATE_READY_TO_NULL:
if (ximagesink->ximage)
{
gst_ximagesink_ximage_destroy (ximagesink, ximagesink->ximage);
ximagesink->ximage = NULL;
}
if (ximagesink->image_pool)
gst_ximagesink_imagepool_clear (ximagesink);
if (ximagesink->xwindow)
{
gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow);
ximagesink->xwindow = NULL;
}
if (ximagesink->xcontext)
{
gst_ximagesink_xcontext_clear (ximagesink);
ximagesink->xcontext = NULL;
}
break;
}
@ -851,22 +887,6 @@ gst_ximagesink_buffer_alloc (GstPad *pad, guint64 offset, guint size)
return NULL;
}
static void
gst_ximagesink_imagepool_clear (GstXImageSink *ximagesink)
{
g_mutex_lock(ximagesink->pool_lock);
while (ximagesink->image_pool)
{
GstXImage *ximage = ximagesink->image_pool->data;
ximagesink->image_pool = g_slist_delete_link (ximagesink->image_pool,
ximagesink->image_pool);
gst_ximagesink_ximage_destroy (ximagesink, ximage);
}
g_mutex_unlock(ximagesink->pool_lock);
}
/* Interfaces stuff */
static gboolean
@ -1129,25 +1149,7 @@ gst_ximagesink_dispose (GObject *object)
g_free (ximagesink->display_name);
ximagesink->display_name = NULL;
}
if (ximagesink->ximage)
{
gst_ximagesink_ximage_destroy (ximagesink, ximagesink->ximage);
ximagesink->ximage = NULL;
}
if (ximagesink->image_pool)
gst_ximagesink_imagepool_clear (ximagesink);
if (ximagesink->xwindow)
{
gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow);
ximagesink->xwindow = NULL;
}
if (ximagesink->xcontext)
gst_ximagesink_xcontext_clear (ximagesink);
g_mutex_free (ximagesink->x_lock);
g_mutex_free (ximagesink->pool_lock);

View file

@ -733,6 +733,27 @@ gst_xvimagesink_xcontext_get (GstXvImageSink *xvimagesink)
xcontext->channels_list = g_list_append (xcontext->channels_list,
channel);
/* If the colorbalance settings have not been touched we get Xv values
as defaults and update our internal variables */
if (!xvimagesink->cb_changed) {
gint val;
XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id,
XInternAtom (xcontext->disp, channel->label, 1),
&val);
/* Normalize val to [-1000, 1000] */
val = -1000 + 2000 * (val - channel->min_value) /
(channel->max_value - channel->min_value);
if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
xvimagesink->hue = val;
else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
xvimagesink->saturation = val;
else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
xvimagesink->brightness = val;
else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
xvimagesink->contrast = val;
}
}
}
@ -793,6 +814,22 @@ gst_xvimagesink_xcontext_clear (GstXvImageSink *xvimagesink)
xvimagesink->xcontext = NULL;
}
static void
gst_xvimagesink_imagepool_clear (GstXvImageSink *xvimagesink)
{
g_mutex_lock(xvimagesink->pool_lock);
while (xvimagesink->image_pool)
{
GstXvImage *xvimage = xvimagesink->image_pool->data;
xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
xvimagesink->image_pool);
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimage);
}
g_mutex_unlock(xvimagesink->pool_lock);
}
/* Element stuff */
static GstCaps *
@ -981,6 +1018,26 @@ gst_xvimagesink_change_state (GstElement *element)
GST_VIDEOSINK_HEIGHT (xvimagesink) = 0;
break;
case GST_STATE_READY_TO_NULL:
if (xvimagesink->xvimage)
{
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimagesink->xvimage);
xvimagesink->xvimage = NULL;
}
if (xvimagesink->image_pool)
gst_xvimagesink_imagepool_clear (xvimagesink);
if (xvimagesink->xwindow)
{
gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
xvimagesink->xwindow = NULL;
}
if (xvimagesink->xcontext)
{
gst_xvimagesink_xcontext_clear (xvimagesink);
xvimagesink->xcontext = NULL;
}
break;
}
@ -1140,22 +1197,6 @@ gst_xvimagesink_buffer_alloc (GstPad *pad, guint64 offset, guint size)
return NULL;
}
static void
gst_xvimagesink_imagepool_clear (GstXvImageSink *xvimagesink)
{
g_mutex_lock(xvimagesink->pool_lock);
while (xvimagesink->image_pool)
{
GstXvImage *xvimage = xvimagesink->image_pool->data;
xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
xvimagesink->image_pool);
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimage);
}
g_mutex_unlock(xvimagesink->pool_lock);
}
/* Interfaces stuff */
static gboolean
@ -1343,6 +1384,12 @@ gst_xvimagesink_colorbalance_set_value (GstColorBalance *balance,
g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
g_return_if_fail (channel->label != NULL);
xvimagesink->cb_changed = TRUE;
/* Normalize val to [-1000, 1000] */
value = -1000 + 2000 * (value - channel->min_value) /
(channel->max_value - channel->min_value);
if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0)
{
xvimagesink->hue = value;
@ -1400,6 +1447,10 @@ gst_xvimagesink_colorbalance_get_value (GstColorBalance *balance,
g_warning ("got an unknown channel %s", channel->label);
}
/* Normalize val to [channel->min_value, channel->max_value] */
value = channel->min_value + (channel->max_value - channel->min_value) *
(value + 1000) / 2000;
return value;
}
@ -1432,18 +1483,22 @@ gst_xvimagesink_set_property (GObject *object, guint prop_id,
{
case ARG_HUE:
xvimagesink->hue = g_value_get_int (value);
xvimagesink->cb_changed = TRUE;
gst_xvimagesink_update_colorbalance (xvimagesink);
break;
case ARG_CONTRAST:
xvimagesink->contrast = g_value_get_int (value);
xvimagesink->cb_changed = TRUE;
gst_xvimagesink_update_colorbalance (xvimagesink);
break;
case ARG_BRIGHTNESS:
xvimagesink->brightness = g_value_get_int (value);
xvimagesink->cb_changed = TRUE;
gst_xvimagesink_update_colorbalance (xvimagesink);
break;
case ARG_SATURATION:
xvimagesink->saturation = g_value_get_int (value);
xvimagesink->cb_changed = TRUE;
gst_xvimagesink_update_colorbalance (xvimagesink);
break;
case ARG_DISPLAY:
@ -1510,25 +1565,7 @@ gst_xvimagesink_dispose (GObject *object)
g_free (xvimagesink->display_name);
xvimagesink->display_name = NULL;
}
if (xvimagesink->xvimage)
{
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimagesink->xvimage);
xvimagesink->xvimage = NULL;
}
if (xvimagesink->image_pool)
gst_xvimagesink_imagepool_clear (xvimagesink);
if (xvimagesink->xwindow)
{
gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
xvimagesink->xwindow = NULL;
}
if (xvimagesink->xcontext)
gst_xvimagesink_xcontext_clear (xvimagesink);
g_mutex_free (xvimagesink->x_lock);
g_mutex_free (xvimagesink->pool_lock);
@ -1563,6 +1600,7 @@ gst_xvimagesink_init (GstXvImageSink *xvimagesink)
xvimagesink->hue = xvimagesink->saturation = 0;
xvimagesink->contrast = xvimagesink->brightness = 0;
xvimagesink->cb_changed = FALSE;
xvimagesink->framerate = 0;

View file

@ -134,6 +134,7 @@ struct _GstXvImageSink {
gint contrast;
gint hue;
gint saturation;
gboolean cb_changed;
GMutex *x_lock;