gst-libs/gst/play/gstplay.c: Another try in visualization implementation. Still have an issue with switch blocking wh...

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

* gst-libs/gst/play/gstplay.c: (gst_play_pipeline_setup),
(gst_play_identity_handoff), (gst_play_set_location),
(gst_play_set_visualization), (gst_play_connect_visualization): Another
try in visualization implementation. Still have an issue with switch
blocking when pulling from video_queue and only audio comes out of
spider.
* gst/switch/gstswitch.c: (gst_switch_release_pad),
(gst_switch_poll_sinkpads), (gst_switch_class_init): Implementing pad
release method. And check if the pad is usable before pulling.
This commit is contained in:
Julien Moutte 2004-01-25 12:28:05 +00:00
parent 2827abc66f
commit ff322c28e2
3 changed files with 310 additions and 268 deletions

View file

@ -1,3 +1,15 @@
2004-01-25 Julien MOUTTE <julien@moutte.net>
* gst-libs/gst/play/gstplay.c: (gst_play_pipeline_setup),
(gst_play_identity_handoff), (gst_play_set_location),
(gst_play_set_visualization), (gst_play_connect_visualization): Another
try in visualization implementation. Still have an issue with switch
blocking when pulling from video_queue and only audio comes out of
spider.
* gst/switch/gstswitch.c: (gst_switch_release_pad),
(gst_switch_poll_sinkpads), (gst_switch_class_init): Implementing pad
release method. And check if the pad is usable before pulling.
2004-01-25 Ronald Bultje <rbultje@ronald.bitfreak.net> 2004-01-25 Ronald Bultje <rbultje@ronald.bitfreak.net>
* gst/videofilter/gstvideobalance.c: (gst_videobalance_dispose), * gst/videofilter/gstvideobalance.c: (gst_videobalance_dispose),

View file

@ -44,6 +44,8 @@ struct _GstPlayPrivate {
guint tick_id; guint tick_id;
guint length_id; guint length_id;
gulong handoff_hid;
}; };
static guint gst_play_signals[LAST_SIGNAL] = { 0 }; static guint gst_play_signals[LAST_SIGNAL] = { 0 };
@ -62,10 +64,13 @@ gst_play_pipeline_setup (GstPlay *play)
/* Threads */ /* Threads */
GstElement *work_thread, *audio_thread, *video_thread; GstElement *work_thread, *audio_thread, *video_thread;
/* Main Thread elements */ /* Main Thread elements */
GstElement *source, *autoplugger, *audioconvert, *volume, *tee, *vis_element; GstElement *source, *autoplugger, *audioconvert, *volume, *tee, *identity;
GstElement *identity_cs;
/* Visualization bin */
GstElement *vis_bin, *vis_queue, *vis_element, *vis_cs;
/* Video Thread elements */ /* Video Thread elements */
GstElement *video_queue, *video_cs, *video_balance, *balance_cs; GstElement *video_queue, *video_switch, *video_cs, *video_balance;
GstElement *video_scaler, *video_sink; GstElement *balance_cs, *video_scaler, *video_sink;
/* Audio Thread elements */ /* Audio Thread elements */
GstElement *audio_queue, *audio_sink; GstElement *audio_queue, *audio_sink;
/* Some useful pads */ /* Some useful pads */
@ -74,8 +79,7 @@ gst_play_pipeline_setup (GstPlay *play)
g_return_val_if_fail (play != NULL, FALSE); g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE); g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
/* Creating main thread and its elements /* Creating main thread and its elements */
{ fakesrc ! spider ! audioconvert ! volume ! tee } */
{ {
work_thread = gst_element_factory_make ("thread", "work_thread"); work_thread = gst_element_factory_make ("thread", "work_thread");
if (!GST_IS_ELEMENT (work_thread)) if (!GST_IS_ELEMENT (work_thread))
@ -128,14 +132,62 @@ gst_play_pipeline_setup (GstPlay *play)
volume, tee, NULL); volume, tee, NULL);
gst_element_link_many (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 /* identity ! colorspace ! switch */
yet) */ identity = gst_element_factory_make ("identity", "identity");
if (!GST_IS_ELEMENT (identity))
return FALSE;
g_hash_table_insert (play->priv->elements, "identity", identity);
identity_cs = gst_element_factory_make ("ffcolorspace", "identity_cs");
if (!GST_IS_ELEMENT (identity_cs)) {
identity_cs = gst_element_factory_make ("colorspace", "identity_cs");
if (!GST_IS_ELEMENT (identity_cs))
return FALSE;
}
g_hash_table_insert (play->priv->elements, "identity_cs", identity_cs);
gst_bin_add_many (GST_BIN (work_thread), identity, identity_cs, NULL);
gst_element_link_many (autoplugger, identity, identity_cs, NULL);
}
/* Visualization bin (note: it s not added to the pipeline yet) */
{
vis_bin = gst_bin_new ("vis_bin");
if (!GST_IS_ELEMENT (vis_bin))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_bin", vis_bin);
/* Buffer queue for video data */
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);
/* Visualization element placeholder */
vis_element = gst_element_factory_make ("identity", "vis_element"); vis_element = gst_element_factory_make ("identity", "vis_element");
if (!GST_IS_ELEMENT (vis_element)) if (!GST_IS_ELEMENT (vis_element))
return FALSE; return FALSE;
g_hash_table_insert (play->priv->elements, "vis_element", vis_element); g_hash_table_insert (play->priv->elements, "vis_element", vis_element);
/* Colorspace conversion */
vis_cs = gst_element_factory_make ("ffcolorspace", "vis_cs");
if (!GST_IS_ELEMENT (vis_cs)) {
vis_cs = gst_element_factory_make ("colorspace", "vis_cs");
if (!GST_IS_ELEMENT (vis_cs))
return FALSE;
}
g_hash_table_insert (play->priv->elements, "vis_cs", vis_cs);
gst_bin_add_many (GST_BIN (vis_bin), vis_queue, vis_element, vis_cs, NULL);
gst_element_link_many (vis_queue, vis_element, vis_cs, NULL);
gst_element_add_ghost_pad (vis_bin,
gst_element_get_pad (vis_cs, "src"), "src");
} }
/* Creating our video output bin */ /* Creating our video output bin */
{ {
@ -153,6 +205,12 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "video_queue", video_queue); g_hash_table_insert (play->priv->elements, "video_queue", video_queue);
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);
/* Colorspace conversion */ /* Colorspace conversion */
video_cs = gst_element_factory_make ("ffcolorspace", "video_cs"); video_cs = gst_element_factory_make ("ffcolorspace", "video_cs");
if (!GST_IS_ELEMENT (video_cs)) { if (!GST_IS_ELEMENT (video_cs)) {
@ -196,14 +254,14 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "video_sink", video_sink); g_hash_table_insert (play->priv->elements, "video_sink", video_sink);
gst_bin_add_many (GST_BIN (video_thread), video_queue, video_cs, gst_bin_add_many (GST_BIN (video_thread), video_queue, video_switch, video_cs,
video_balance, balance_cs, video_scaler, video_sink, NULL); video_balance, balance_cs, video_scaler, video_sink, NULL);
gst_element_link_many (video_queue, video_cs, video_balance, balance_cs, gst_element_link_many (video_queue, video_switch, video_cs, video_balance,
video_scaler, video_sink, NULL); balance_cs, video_scaler, video_sink, NULL);
gst_element_add_ghost_pad (video_thread, gst_element_add_ghost_pad (video_thread,
gst_element_get_pad (video_queue, "sink"), gst_element_get_pad (video_queue, "sink"),
"sink"); "sink");
gst_element_link (autoplugger, video_thread); gst_element_link (identity_cs, video_thread);
} }
/* Creating our audio output bin /* Creating our audio output bin
{ queue ! fakesink } */ { queue ! fakesink } */
@ -365,6 +423,14 @@ gst_play_state_change (GstElement *element, GstElementState old,
GST_ELEMENT_CLASS (parent_class)->state_change (element, old, state); GST_ELEMENT_CLASS (parent_class)->state_change (element, old, state);
} }
static void
gst_play_identity_handoff (GstElement *identity, GstBuffer *buf, GstPlay *play)
{
g_signal_handler_disconnect (G_OBJECT (identity), play->priv->handoff_hid);
play->priv->handoff_hid = 0;
gst_play_connect_visualization (play, FALSE);
}
/* =========================================== */ /* =========================================== */
/* */ /* */
/* Init & Dispose & Class init */ /* Init & Dispose & Class init */
@ -465,7 +531,7 @@ gboolean
gst_play_set_location (GstPlay *play, const char *location) gst_play_set_location (GstPlay *play, const char *location)
{ {
GstElement *work_thread, *source, *autoplugger; GstElement *work_thread, *source, *autoplugger;
GstElement *audioconvert, *video_thread; GstElement *audioconvert, *identity;
g_return_val_if_fail (play != NULL, FALSE); g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE); g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
@ -490,14 +556,14 @@ gst_play_set_location (GstPlay *play, const char *location)
audioconvert = g_hash_table_lookup (play->priv->elements, "audioconvert"); audioconvert = g_hash_table_lookup (play->priv->elements, "audioconvert");
if (!GST_IS_ELEMENT (audioconvert)) if (!GST_IS_ELEMENT (audioconvert))
return FALSE; return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread"); identity = g_hash_table_lookup (play->priv->elements, "identity");
if (!GST_IS_ELEMENT (video_thread)) if (!GST_IS_ELEMENT (identity))
return FALSE; return FALSE;
/* Spider can autoplugg only once. We remove the actual one and put a new /* Spider can autoplugg only once. We remove the actual one and put a new
autoplugger */ autoplugger */
gst_element_unlink (source, autoplugger); gst_element_unlink (source, autoplugger);
gst_element_unlink (autoplugger, video_thread); gst_element_unlink (autoplugger, identity);
gst_element_unlink (autoplugger, audioconvert); gst_element_unlink (autoplugger, audioconvert);
gst_bin_remove (GST_BIN (work_thread), autoplugger); gst_bin_remove (GST_BIN (work_thread), autoplugger);
@ -507,7 +573,7 @@ gst_play_set_location (GstPlay *play, const char *location)
gst_bin_add (GST_BIN (work_thread), autoplugger); gst_bin_add (GST_BIN (work_thread), autoplugger);
gst_element_link (source, autoplugger); gst_element_link (source, autoplugger);
gst_element_link (autoplugger, video_thread); gst_element_link (autoplugger, identity);
gst_element_link (autoplugger, audioconvert); gst_element_link (autoplugger, audioconvert);
g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger); g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger);
@ -760,8 +826,7 @@ gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink)
gboolean gboolean
gst_play_set_visualization (GstPlay *play, GstElement *vis_element) gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
{ {
GstElement *work_thread, *old_vis_element, *video_thread; GstElement *vis_bin, *vis_queue, *old_vis_element, *vis_cs;
GstPad *tee_pad1;
gboolean was_playing = FALSE; gboolean was_playing = FALSE;
g_return_val_if_fail (play != NULL, FALSE); g_return_val_if_fail (play != NULL, FALSE);
@ -770,47 +835,30 @@ gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
g_return_val_if_fail (GST_IS_ELEMENT (vis_element), FALSE); g_return_val_if_fail (GST_IS_ELEMENT (vis_element), FALSE);
/* Getting needed objects */ /* Getting needed objects */
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread"); vis_bin = g_hash_table_lookup (play->priv->elements, "vis_bin");
if (!GST_IS_ELEMENT (work_thread)) if (!GST_IS_ELEMENT (vis_bin))
return FALSE;
vis_queue = g_hash_table_lookup (play->priv->elements, "vis_queue");
if (!GST_IS_ELEMENT (vis_queue))
return FALSE; return FALSE;
old_vis_element = g_hash_table_lookup (play->priv->elements, old_vis_element = g_hash_table_lookup (play->priv->elements,
"vis_element"); "vis_element");
if (!GST_IS_ELEMENT (old_vis_element)) if (!GST_IS_ELEMENT (old_vis_element))
return FALSE; return FALSE;
tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1"); vis_cs = g_hash_table_lookup (play->priv->elements, "vis_cs");
if (!GST_IS_PAD (tee_pad1)) if (!GST_IS_ELEMENT (vis_cs))
return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE; return FALSE;
/* Let's check if the current vis element has a managing bin. If yes that /* We bring back the pipeline to PAUSED */
means the element is inside the pipeline and need to be unlinked and if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
removed. We also need to pause the pipeline if it is currently playing. */ gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
if (gst_element_get_managing_bin (old_vis_element)) { was_playing = TRUE;
GstPad *vis_element_pad; }
/* We bring back the pipeline to PAUSED */ gst_element_unlink_many (vis_queue, old_vis_element, vis_cs, NULL);
if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) { gst_bin_remove (GST_BIN (vis_bin), old_vis_element);
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED); gst_bin_add (GST_BIN (vis_bin), vis_element);
was_playing = TRUE; gst_element_link_many (vis_queue, vis_element, vis_cs, NULL);
}
/* 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); g_hash_table_replace (play->priv->elements, "vis_element", vis_element);
@ -833,121 +881,88 @@ gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
gboolean gboolean
gst_play_connect_visualization (GstPlay * play, gboolean connect) gst_play_connect_visualization (GstPlay * play, gboolean connect)
{ {
GstElement *work_thread, *vis_element, *autoplugger, *video_thread; GstElement *video_thread, *vis_queue, *vis_bin, *video_switch, *identity;
GstElement *audioconvert, *source; GstPad *tee_pad1, *vis_queue_pad, *vis_bin_pad, *switch_pad;
GstPad *tee_pad1, *vis_element_pad; gboolean was_playing = FALSE;
g_return_val_if_fail (play != NULL, FALSE); g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE); g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
/* Getting needed objects */ /* Getting needed objects */
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread"); video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (work_thread)) if (!GST_IS_ELEMENT (video_thread))
return FALSE; return FALSE;
vis_element = g_hash_table_lookup (play->priv->elements, "vis_element"); vis_bin = g_hash_table_lookup (play->priv->elements, "vis_bin");
if (!GST_IS_ELEMENT (vis_element)) if (!GST_IS_ELEMENT (vis_bin))
return FALSE;
vis_queue = g_hash_table_lookup (play->priv->elements, "vis_queue");
if (!GST_IS_ELEMENT (vis_queue))
return FALSE;
video_switch = g_hash_table_lookup (play->priv->elements, "video_switch");
if (!GST_IS_ELEMENT (video_switch))
return FALSE;
identity = g_hash_table_lookup (play->priv->elements, "identity");
if (!GST_IS_ELEMENT (identity))
return FALSE; return FALSE;
tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1"); tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1");
if (!GST_IS_PAD (tee_pad1)) if (!GST_IS_PAD (tee_pad1))
return FALSE; return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread)) vis_queue_pad = gst_element_get_pad (vis_queue, "sink");
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;
/* Check if the vis element is in the pipeline. That means visualization is /* Check if the vis element is in the pipeline. That means visualization is
connected already */ connected already */
if (gst_element_get_managing_bin (vis_element)) { if (gst_element_get_managing_bin (vis_bin)) {
/* If we are supposed to connect then nothing to do we return */ /* If we are supposed to connect then nothing to do we return */
if (connect) { if (connect) {
return TRUE; return TRUE;
} }
/* We have to modify the pipeline. Changing autoplugger requires going to /* Disconnecting visualization */
READY */
gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
/* Otherwise we unlink and remove the vis element refing it so that /* We bring back the pipeline to PAUSED */
it won't be destroyed when removed from the bin. */ if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
vis_element_pad = gst_element_get_pad (vis_element, "sink"); gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
if (GST_IS_PAD (vis_element_pad)) was_playing = TRUE;
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 */ /* Unlinking, removing */
gst_element_unlink (source, autoplugger); gst_pad_unlink (tee_pad1, vis_queue_pad);
gst_element_unlink (autoplugger, audioconvert); vis_bin_pad = gst_element_get_pad (vis_bin, "src");
gst_bin_remove (GST_BIN (work_thread), autoplugger); switch_pad = gst_pad_get_peer (vis_bin_pad);
gst_pad_unlink (vis_bin_pad, switch_pad);
autoplugger = gst_element_factory_make ("spider", "autoplugger"); gst_element_release_request_pad (video_switch, switch_pad);
if (!GST_IS_ELEMENT (autoplugger)) gst_object_ref (GST_OBJECT (vis_bin));
return FALSE; gst_bin_remove (GST_BIN (video_thread), vis_bin);
/* 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 { else {
GstCaps *filtered_caps;
/* If we are supposed to disconnect then nothing to do we return */ /* If we are supposed to disconnect then nothing to do we return */
if (!connect) { if (!connect) {
return TRUE; return TRUE;
} }
/* We have to modify the pipeline. Changing autoplugger requires going to /* Connecting visualization */
READY */
gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
/* Removing autoplugger */ /* We bring back the pipeline to PAUSED */
gst_element_unlink (source, autoplugger); if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
gst_element_unlink (autoplugger, video_thread); gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
gst_element_unlink (autoplugger, audioconvert); was_playing = TRUE;
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); /* Adding, linking */
play->priv->handoff_hid = g_signal_connect (G_OBJECT (identity),
/* Otherwise we add the element to the bin and link it to video_thread */ "handoff",
gst_bin_add (GST_BIN (work_thread), vis_element); G_CALLBACK (gst_play_identity_handoff), play);
vis_element_pad = gst_element_get_pad (vis_element, "sink"); gst_bin_add (GST_BIN (video_thread), vis_bin);
if (GST_IS_PAD (vis_element_pad)) gst_pad_link (tee_pad1, vis_queue_pad);
gst_pad_link (tee_pad1, vis_element_pad); gst_element_link (vis_bin, video_switch);
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);
} }
if (was_playing)
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING);
return TRUE; return TRUE;
} }

View file

@ -44,6 +44,8 @@ struct _GstPlayPrivate {
guint tick_id; guint tick_id;
guint length_id; guint length_id;
gulong handoff_hid;
}; };
static guint gst_play_signals[LAST_SIGNAL] = { 0 }; static guint gst_play_signals[LAST_SIGNAL] = { 0 };
@ -62,10 +64,13 @@ gst_play_pipeline_setup (GstPlay *play)
/* Threads */ /* Threads */
GstElement *work_thread, *audio_thread, *video_thread; GstElement *work_thread, *audio_thread, *video_thread;
/* Main Thread elements */ /* Main Thread elements */
GstElement *source, *autoplugger, *audioconvert, *volume, *tee, *vis_element; GstElement *source, *autoplugger, *audioconvert, *volume, *tee, *identity;
GstElement *identity_cs;
/* Visualization bin */
GstElement *vis_bin, *vis_queue, *vis_element, *vis_cs;
/* Video Thread elements */ /* Video Thread elements */
GstElement *video_queue, *video_cs, *video_balance, *balance_cs; GstElement *video_queue, *video_switch, *video_cs, *video_balance;
GstElement *video_scaler, *video_sink; GstElement *balance_cs, *video_scaler, *video_sink;
/* Audio Thread elements */ /* Audio Thread elements */
GstElement *audio_queue, *audio_sink; GstElement *audio_queue, *audio_sink;
/* Some useful pads */ /* Some useful pads */
@ -74,8 +79,7 @@ gst_play_pipeline_setup (GstPlay *play)
g_return_val_if_fail (play != NULL, FALSE); g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE); g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
/* Creating main thread and its elements /* Creating main thread and its elements */
{ fakesrc ! spider ! audioconvert ! volume ! tee } */
{ {
work_thread = gst_element_factory_make ("thread", "work_thread"); work_thread = gst_element_factory_make ("thread", "work_thread");
if (!GST_IS_ELEMENT (work_thread)) if (!GST_IS_ELEMENT (work_thread))
@ -128,14 +132,62 @@ gst_play_pipeline_setup (GstPlay *play)
volume, tee, NULL); volume, tee, NULL);
gst_element_link_many (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 /* identity ! colorspace ! switch */
yet) */ identity = gst_element_factory_make ("identity", "identity");
if (!GST_IS_ELEMENT (identity))
return FALSE;
g_hash_table_insert (play->priv->elements, "identity", identity);
identity_cs = gst_element_factory_make ("ffcolorspace", "identity_cs");
if (!GST_IS_ELEMENT (identity_cs)) {
identity_cs = gst_element_factory_make ("colorspace", "identity_cs");
if (!GST_IS_ELEMENT (identity_cs))
return FALSE;
}
g_hash_table_insert (play->priv->elements, "identity_cs", identity_cs);
gst_bin_add_many (GST_BIN (work_thread), identity, identity_cs, NULL);
gst_element_link_many (autoplugger, identity, identity_cs, NULL);
}
/* Visualization bin (note: it s not added to the pipeline yet) */
{
vis_bin = gst_bin_new ("vis_bin");
if (!GST_IS_ELEMENT (vis_bin))
return FALSE;
g_hash_table_insert (play->priv->elements, "vis_bin", vis_bin);
/* Buffer queue for video data */
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);
/* Visualization element placeholder */
vis_element = gst_element_factory_make ("identity", "vis_element"); vis_element = gst_element_factory_make ("identity", "vis_element");
if (!GST_IS_ELEMENT (vis_element)) if (!GST_IS_ELEMENT (vis_element))
return FALSE; return FALSE;
g_hash_table_insert (play->priv->elements, "vis_element", vis_element); g_hash_table_insert (play->priv->elements, "vis_element", vis_element);
/* Colorspace conversion */
vis_cs = gst_element_factory_make ("ffcolorspace", "vis_cs");
if (!GST_IS_ELEMENT (vis_cs)) {
vis_cs = gst_element_factory_make ("colorspace", "vis_cs");
if (!GST_IS_ELEMENT (vis_cs))
return FALSE;
}
g_hash_table_insert (play->priv->elements, "vis_cs", vis_cs);
gst_bin_add_many (GST_BIN (vis_bin), vis_queue, vis_element, vis_cs, NULL);
gst_element_link_many (vis_queue, vis_element, vis_cs, NULL);
gst_element_add_ghost_pad (vis_bin,
gst_element_get_pad (vis_cs, "src"), "src");
} }
/* Creating our video output bin */ /* Creating our video output bin */
{ {
@ -153,6 +205,12 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "video_queue", video_queue); g_hash_table_insert (play->priv->elements, "video_queue", video_queue);
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);
/* Colorspace conversion */ /* Colorspace conversion */
video_cs = gst_element_factory_make ("ffcolorspace", "video_cs"); video_cs = gst_element_factory_make ("ffcolorspace", "video_cs");
if (!GST_IS_ELEMENT (video_cs)) { if (!GST_IS_ELEMENT (video_cs)) {
@ -196,14 +254,14 @@ gst_play_pipeline_setup (GstPlay *play)
g_hash_table_insert (play->priv->elements, "video_sink", video_sink); g_hash_table_insert (play->priv->elements, "video_sink", video_sink);
gst_bin_add_many (GST_BIN (video_thread), video_queue, video_cs, gst_bin_add_many (GST_BIN (video_thread), video_queue, video_switch, video_cs,
video_balance, balance_cs, video_scaler, video_sink, NULL); video_balance, balance_cs, video_scaler, video_sink, NULL);
gst_element_link_many (video_queue, video_cs, video_balance, balance_cs, gst_element_link_many (video_queue, video_switch, video_cs, video_balance,
video_scaler, video_sink, NULL); balance_cs, video_scaler, video_sink, NULL);
gst_element_add_ghost_pad (video_thread, gst_element_add_ghost_pad (video_thread,
gst_element_get_pad (video_queue, "sink"), gst_element_get_pad (video_queue, "sink"),
"sink"); "sink");
gst_element_link (autoplugger, video_thread); gst_element_link (identity_cs, video_thread);
} }
/* Creating our audio output bin /* Creating our audio output bin
{ queue ! fakesink } */ { queue ! fakesink } */
@ -365,6 +423,14 @@ gst_play_state_change (GstElement *element, GstElementState old,
GST_ELEMENT_CLASS (parent_class)->state_change (element, old, state); GST_ELEMENT_CLASS (parent_class)->state_change (element, old, state);
} }
static void
gst_play_identity_handoff (GstElement *identity, GstBuffer *buf, GstPlay *play)
{
g_signal_handler_disconnect (G_OBJECT (identity), play->priv->handoff_hid);
play->priv->handoff_hid = 0;
gst_play_connect_visualization (play, FALSE);
}
/* =========================================== */ /* =========================================== */
/* */ /* */
/* Init & Dispose & Class init */ /* Init & Dispose & Class init */
@ -465,7 +531,7 @@ gboolean
gst_play_set_location (GstPlay *play, const char *location) gst_play_set_location (GstPlay *play, const char *location)
{ {
GstElement *work_thread, *source, *autoplugger; GstElement *work_thread, *source, *autoplugger;
GstElement *audioconvert, *video_thread; GstElement *audioconvert, *identity;
g_return_val_if_fail (play != NULL, FALSE); g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE); g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
@ -490,14 +556,14 @@ gst_play_set_location (GstPlay *play, const char *location)
audioconvert = g_hash_table_lookup (play->priv->elements, "audioconvert"); audioconvert = g_hash_table_lookup (play->priv->elements, "audioconvert");
if (!GST_IS_ELEMENT (audioconvert)) if (!GST_IS_ELEMENT (audioconvert))
return FALSE; return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread"); identity = g_hash_table_lookup (play->priv->elements, "identity");
if (!GST_IS_ELEMENT (video_thread)) if (!GST_IS_ELEMENT (identity))
return FALSE; return FALSE;
/* Spider can autoplugg only once. We remove the actual one and put a new /* Spider can autoplugg only once. We remove the actual one and put a new
autoplugger */ autoplugger */
gst_element_unlink (source, autoplugger); gst_element_unlink (source, autoplugger);
gst_element_unlink (autoplugger, video_thread); gst_element_unlink (autoplugger, identity);
gst_element_unlink (autoplugger, audioconvert); gst_element_unlink (autoplugger, audioconvert);
gst_bin_remove (GST_BIN (work_thread), autoplugger); gst_bin_remove (GST_BIN (work_thread), autoplugger);
@ -507,7 +573,7 @@ gst_play_set_location (GstPlay *play, const char *location)
gst_bin_add (GST_BIN (work_thread), autoplugger); gst_bin_add (GST_BIN (work_thread), autoplugger);
gst_element_link (source, autoplugger); gst_element_link (source, autoplugger);
gst_element_link (autoplugger, video_thread); gst_element_link (autoplugger, identity);
gst_element_link (autoplugger, audioconvert); gst_element_link (autoplugger, audioconvert);
g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger); g_hash_table_replace (play->priv->elements, "autoplugger", autoplugger);
@ -760,8 +826,7 @@ gst_play_set_audio_sink (GstPlay *play, GstElement *audio_sink)
gboolean gboolean
gst_play_set_visualization (GstPlay *play, GstElement *vis_element) gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
{ {
GstElement *work_thread, *old_vis_element, *video_thread; GstElement *vis_bin, *vis_queue, *old_vis_element, *vis_cs;
GstPad *tee_pad1;
gboolean was_playing = FALSE; gboolean was_playing = FALSE;
g_return_val_if_fail (play != NULL, FALSE); g_return_val_if_fail (play != NULL, FALSE);
@ -770,47 +835,30 @@ gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
g_return_val_if_fail (GST_IS_ELEMENT (vis_element), FALSE); g_return_val_if_fail (GST_IS_ELEMENT (vis_element), FALSE);
/* Getting needed objects */ /* Getting needed objects */
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread"); vis_bin = g_hash_table_lookup (play->priv->elements, "vis_bin");
if (!GST_IS_ELEMENT (work_thread)) if (!GST_IS_ELEMENT (vis_bin))
return FALSE;
vis_queue = g_hash_table_lookup (play->priv->elements, "vis_queue");
if (!GST_IS_ELEMENT (vis_queue))
return FALSE; return FALSE;
old_vis_element = g_hash_table_lookup (play->priv->elements, old_vis_element = g_hash_table_lookup (play->priv->elements,
"vis_element"); "vis_element");
if (!GST_IS_ELEMENT (old_vis_element)) if (!GST_IS_ELEMENT (old_vis_element))
return FALSE; return FALSE;
tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1"); vis_cs = g_hash_table_lookup (play->priv->elements, "vis_cs");
if (!GST_IS_PAD (tee_pad1)) if (!GST_IS_ELEMENT (vis_cs))
return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread))
return FALSE; return FALSE;
/* Let's check if the current vis element has a managing bin. If yes that /* We bring back the pipeline to PAUSED */
means the element is inside the pipeline and need to be unlinked and if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
removed. We also need to pause the pipeline if it is currently playing. */ gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
if (gst_element_get_managing_bin (old_vis_element)) { was_playing = TRUE;
GstPad *vis_element_pad; }
/* We bring back the pipeline to PAUSED */ gst_element_unlink_many (vis_queue, old_vis_element, vis_cs, NULL);
if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) { gst_bin_remove (GST_BIN (vis_bin), old_vis_element);
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED); gst_bin_add (GST_BIN (vis_bin), vis_element);
was_playing = TRUE; gst_element_link_many (vis_queue, vis_element, vis_cs, NULL);
}
/* 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); g_hash_table_replace (play->priv->elements, "vis_element", vis_element);
@ -833,121 +881,88 @@ gst_play_set_visualization (GstPlay *play, GstElement *vis_element)
gboolean gboolean
gst_play_connect_visualization (GstPlay * play, gboolean connect) gst_play_connect_visualization (GstPlay * play, gboolean connect)
{ {
GstElement *work_thread, *vis_element, *autoplugger, *video_thread; GstElement *video_thread, *vis_queue, *vis_bin, *video_switch, *identity;
GstElement *audioconvert, *source; GstPad *tee_pad1, *vis_queue_pad, *vis_bin_pad, *switch_pad;
GstPad *tee_pad1, *vis_element_pad; gboolean was_playing = FALSE;
g_return_val_if_fail (play != NULL, FALSE); g_return_val_if_fail (play != NULL, FALSE);
g_return_val_if_fail (GST_IS_PLAY (play), FALSE); g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
/* Getting needed objects */ /* Getting needed objects */
work_thread = g_hash_table_lookup (play->priv->elements, "work_thread"); video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (work_thread)) if (!GST_IS_ELEMENT (video_thread))
return FALSE; return FALSE;
vis_element = g_hash_table_lookup (play->priv->elements, "vis_element"); vis_bin = g_hash_table_lookup (play->priv->elements, "vis_bin");
if (!GST_IS_ELEMENT (vis_element)) if (!GST_IS_ELEMENT (vis_bin))
return FALSE;
vis_queue = g_hash_table_lookup (play->priv->elements, "vis_queue");
if (!GST_IS_ELEMENT (vis_queue))
return FALSE;
video_switch = g_hash_table_lookup (play->priv->elements, "video_switch");
if (!GST_IS_ELEMENT (video_switch))
return FALSE;
identity = g_hash_table_lookup (play->priv->elements, "identity");
if (!GST_IS_ELEMENT (identity))
return FALSE; return FALSE;
tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1"); tee_pad1 = g_hash_table_lookup (play->priv->elements, "tee_pad1");
if (!GST_IS_PAD (tee_pad1)) if (!GST_IS_PAD (tee_pad1))
return FALSE; return FALSE;
video_thread = g_hash_table_lookup (play->priv->elements, "video_thread");
if (!GST_IS_ELEMENT (video_thread)) vis_queue_pad = gst_element_get_pad (vis_queue, "sink");
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;
/* Check if the vis element is in the pipeline. That means visualization is /* Check if the vis element is in the pipeline. That means visualization is
connected already */ connected already */
if (gst_element_get_managing_bin (vis_element)) { if (gst_element_get_managing_bin (vis_bin)) {
/* If we are supposed to connect then nothing to do we return */ /* If we are supposed to connect then nothing to do we return */
if (connect) { if (connect) {
return TRUE; return TRUE;
} }
/* We have to modify the pipeline. Changing autoplugger requires going to /* Disconnecting visualization */
READY */
gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
/* Otherwise we unlink and remove the vis element refing it so that /* We bring back the pipeline to PAUSED */
it won't be destroyed when removed from the bin. */ if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
vis_element_pad = gst_element_get_pad (vis_element, "sink"); gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
if (GST_IS_PAD (vis_element_pad)) was_playing = TRUE;
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 */ /* Unlinking, removing */
gst_element_unlink (source, autoplugger); gst_pad_unlink (tee_pad1, vis_queue_pad);
gst_element_unlink (autoplugger, audioconvert); vis_bin_pad = gst_element_get_pad (vis_bin, "src");
gst_bin_remove (GST_BIN (work_thread), autoplugger); switch_pad = gst_pad_get_peer (vis_bin_pad);
gst_pad_unlink (vis_bin_pad, switch_pad);
autoplugger = gst_element_factory_make ("spider", "autoplugger"); gst_element_release_request_pad (video_switch, switch_pad);
if (!GST_IS_ELEMENT (autoplugger)) gst_object_ref (GST_OBJECT (vis_bin));
return FALSE; gst_bin_remove (GST_BIN (video_thread), vis_bin);
/* 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 { else {
GstCaps *filtered_caps;
/* If we are supposed to disconnect then nothing to do we return */ /* If we are supposed to disconnect then nothing to do we return */
if (!connect) { if (!connect) {
return TRUE; return TRUE;
} }
/* We have to modify the pipeline. Changing autoplugger requires going to /* Connecting visualization */
READY */
gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY);
/* Removing autoplugger */ /* We bring back the pipeline to PAUSED */
gst_element_unlink (source, autoplugger); if (GST_STATE (GST_ELEMENT (play)) == GST_STATE_PLAYING) {
gst_element_unlink (autoplugger, video_thread); gst_element_set_state (GST_ELEMENT (play), GST_STATE_PAUSED);
gst_element_unlink (autoplugger, audioconvert); was_playing = TRUE;
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); /* Adding, linking */
play->priv->handoff_hid = g_signal_connect (G_OBJECT (identity),
/* Otherwise we add the element to the bin and link it to video_thread */ "handoff",
gst_bin_add (GST_BIN (work_thread), vis_element); G_CALLBACK (gst_play_identity_handoff), play);
vis_element_pad = gst_element_get_pad (vis_element, "sink"); gst_bin_add (GST_BIN (video_thread), vis_bin);
if (GST_IS_PAD (vis_element_pad)) gst_pad_link (tee_pad1, vis_queue_pad);
gst_pad_link (tee_pad1, vis_element_pad); gst_element_link (vis_bin, video_switch);
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);
} }
if (was_playing)
gst_element_set_state (GST_ELEMENT (play), GST_STATE_PLAYING);
return TRUE; return TRUE;
} }