From 7f41fdf9d2e2ae40162a0672e6930cb31df464f4 Mon Sep 17 00:00:00 2001 From: Julien Moutte Date: Wed, 2 Apr 2003 21:33:12 +0000 Subject: [PATCH] Incorporating visualisation in libgstplay adding have_vis_xid signal and a new type of GstPlay object (VIDEO_VISUALIS... Original commit message from CVS: Incorporating visualisation in libgstplay adding have_vis_xid signal and a new type of GstPlay object (VIDEO_VISUALISATION) --- gst-libs/gst/play/play.old.c | 44 +++ gst-libs/gst/play/play.old.h | 14 + gst-libs/gst/play/playpipelines.c | 510 +++++++++++++++++++++++++++++- 3 files changed, 567 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/play/play.old.c b/gst-libs/gst/play/play.old.c index afef677f14..88a370d5db 100644 --- a/gst-libs/gst/play/play.old.c +++ b/gst-libs/gst/play/play.old.c @@ -31,6 +31,7 @@ enum { STREAM_LENGTH, TIME_TICK, HAVE_XID, + HAVE_VIS_XID, HAVE_VIDEO_SIZE, LAST_SIGNAL, }; @@ -315,6 +316,10 @@ gst_play_idle_signal (GstPlay *play) g_signal_emit (G_OBJECT (play), gst_play_signals[HAVE_XID], 0, signal->signal_data.video_xid.xid); break; + case HAVE_VIS_XID: + g_signal_emit (G_OBJECT (play), gst_play_signals[HAVE_VIS_XID], 0, + signal->signal_data.video_xid.xid); + break; case HAVE_VIDEO_SIZE: g_signal_emit (G_OBJECT (play), gst_play_signals[HAVE_VIDEO_SIZE], 0, signal->signal_data.video_size.width, signal->signal_data.video_size.height); @@ -367,6 +372,22 @@ callback_video_have_xid ( GstElement *element, play->idle_add_func ((GSourceFunc) gst_play_idle_signal, play); } +static void +callback_video_have_vis_xid ( GstElement *element, + gint xid, + GstPlay *play) +{ + GstPlaySignal *signal; + + signal = g_new0(GstPlaySignal, 1); + signal->signal_id = HAVE_VIS_XID; + signal->signal_data.video_xid.xid = xid; + + g_async_queue_push(play->signal_queue, signal); + + play->idle_add_func ((GSourceFunc) gst_play_idle_signal, play); +} + static void callback_video_have_size ( GstElement *element, gint width, @@ -593,6 +614,16 @@ gst_play_class_init (GstPlayClass *klass) gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + + gst_play_signals [HAVE_VIS_XID] = + g_signal_new ("have_vis_xid", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstPlayClass, have_vis_xid), + NULL, NULL, + gst_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); gst_play_signals [HAVE_VIDEO_SIZE] = g_signal_new ("have_video_size", @@ -709,11 +740,16 @@ gst_play_seek_to_time ( GstPlay *play, void gst_play_need_new_video_window (GstPlay *play) { + g_return_if_fail (play != NULL); g_return_if_fail (GST_IS_PLAY (play)); if (GST_IS_ELEMENT(play->video_sink_element)){ g_object_set( G_OBJECT(play->video_sink_element), "need_new_window", TRUE, NULL); } + if (GST_IS_ELEMENT(play->visualisation_sink_element)){ + g_object_set( G_OBJECT(play->visualisation_sink_element), + "need_new_window", TRUE, NULL); + } } void @@ -1144,6 +1180,14 @@ gst_play_new ( GstPlayPipeType pipe_type, play->set_video_sink = gst_play_video_set_video; play->set_audio_sink = gst_play_video_set_audio; break; + case GST_PLAY_PIPE_VIDEO_VISUALISATION: + play->setup_pipeline = gst_play_video_vis_setup; + play->teardown_pipeline = NULL; + play->set_data_src = gst_play_video_set_data_src; + play->set_autoplugger = gst_play_video_set_auto; + play->set_video_sink = gst_play_video_vis_set_video; + play->set_audio_sink = gst_play_video_vis_set_audio; + break; case GST_PLAY_PIPE_AUDIO: /* we can reuse the threaded set functions */ play->setup_pipeline = gst_play_audio_setup; diff --git a/gst-libs/gst/play/play.old.h b/gst-libs/gst/play/play.old.h index 7603da7cd6..90f9a5ce71 100644 --- a/gst-libs/gst/play/play.old.h +++ b/gst-libs/gst/play/play.old.h @@ -52,6 +52,7 @@ typedef enum { GST_PLAY_PIPE_AUDIO_THREADED, GST_PLAY_PIPE_AUDIO_HYPER_THREADED, GST_PLAY_PIPE_VIDEO, + GST_PLAY_PIPE_VIDEO_VISUALISATION, } GstPlayPipeType; typedef enum { @@ -151,6 +152,8 @@ struct _GstPlayClass gint64 length_nanos); void (*have_xid) ( GstPlay* play, gint xid); + void (*have_vis_xid) ( GstPlay* play, + gint xid); void (*have_video_size) ( GstPlay* play, gint width, gint height); @@ -220,9 +223,20 @@ gboolean gst_play_set_video_sink ( GstPlay *play, GstElement *video_sink); gboolean +gst_play_set_visualisation_video_sink ( GstPlay *play, + GstElement *video_sink); +gboolean gst_play_set_audio_sink ( GstPlay *play, GstElement *audio_sink); +gboolean +gst_play_set_visualisation_element ( GstPlay *play, + GstElement *element); + +gboolean +gst_play_connect_visualisation ( GstPlay *play, + gboolean connect); + GType gst_play_get_type (void); diff --git a/gst-libs/gst/play/playpipelines.c b/gst-libs/gst/play/playpipelines.c index 952ca8a76f..163d1a2dd8 100644 --- a/gst-libs/gst/play/playpipelines.c +++ b/gst-libs/gst/play/playpipelines.c @@ -401,7 +401,7 @@ gst_play_audioht_set_auto ( GstPlay *play, /* * GST_PLAY_PIPE_VIDEO - * { gnomevfssrc ! spider ! { queue ! volume ! osssink } + * { gnomevfssrc ! spider ! { queue ! volume ! (audiosink) } * spider0.src2 ! { queue ! colorspace ! (videosink) } } */ @@ -571,6 +571,7 @@ gst_play_video_set_auto ( GstPlay *play, GstElement *audio_bin, *video_bin, *work_thread; + 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_ELEMENT (autoplugger), FALSE); @@ -683,5 +684,512 @@ gst_play_video_set_audio ( GstPlay *play, return TRUE; } +/* + * GST_PLAY_PIPE_VIDEO_VISUALISATION + * { gnomevfssrc ! spider ! { queue ! volume ! (audiosink) } + * spider0.src2 ! { queue ! colorspace ! (videosink) } } + */ + +static gboolean +gst_play_video_vis_setup ( GstPlay *play, + GError **error) +{ + + GstElement *work_thread, *tee_element; + GstPad *tee_vis_pad, *tee_audio_pad, *vis_video_thread_pad; + GstElement *vis_audio_thread, *vis_video_thread; + GstElement *vis_audio_queue, *vis_video_queue; + GstElement *vis_colorspace, *vis_audio_sink, *vis_video_sink; + GstElement *video_queue, *video_bin, *colorspace; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY(play), FALSE); + + /* creating pipeline */ + play->pipeline = gst_pipeline_new ("main_pipeline"); + g_return_val_if_fail (GST_IS_PIPELINE (play->pipeline), FALSE); + + /* creating work thread */ + work_thread = gst_thread_new ("work_thread"); + g_return_val_if_fail (GST_IS_THREAD (work_thread), FALSE); + g_hash_table_insert(play->other_elements, "work_thread", work_thread); + + gst_bin_add (GST_BIN (play->pipeline), work_thread); + + /* create source element */ + play->source = gst_element_factory_make ("gnomevfssrc", "source"); + if (!play->source) + { + gst_play_error_plugin (GST_PLAY_ERROR_GNOMEVFSSRC, error); + return FALSE; + } + gst_bin_add (GST_BIN (work_thread), play->source); + + /* BEGIN VIS STUFF */ + + /* Creating here the audio vis bin */ + + play->audio_sink = gst_element_factory_make ( "bin", "audio_bin"); + if (!play->audio_sink) + { + gst_play_error_plugin (GST_PLAY_ERROR_THREAD, error); + return FALSE; + } + g_hash_table_insert( play->other_elements, + "audio_bin", + play->audio_sink); + + play->volume = gst_element_factory_make ("volume", "audio_volume"); + if (!play->volume) + { + gst_play_error_plugin (GST_PLAY_ERROR_VOLUME, error); + return FALSE; + } + g_hash_table_insert ( play->other_elements, + "audio_volume", + play->volume); + + tee_element = gst_element_factory_make ("tee", "audio_tee"); + g_return_val_if_fail(GST_IS_ELEMENT(tee_element), FALSE); + g_hash_table_insert( play->other_elements, + "vis_tee", + play->audio_sink); + + tee_vis_pad = gst_element_get_request_pad (tee_element, "src%d"); + tee_audio_pad = gst_element_get_request_pad (tee_element, "src%d"); + g_hash_table_insert( play->other_elements, + "tee_vis_pad", + tee_vis_pad); + g_hash_table_insert( play->other_elements, + "tee_audio_pad", + tee_audio_pad); + + gst_bin_add_many ( GST_BIN (play->audio_sink), + play->volume, tee_element, NULL); + gst_element_link_many (play->volume, tee_element, NULL); + gst_element_add_ghost_pad ( play->audio_sink, + gst_element_get_pad (play->volume, "sink"), + "sink"); + + /* Creating audio part of the visualisation bin + { queue ! volume ! (audiosink) } + */ + + vis_audio_thread = gst_thread_new ("vis_audio_thread"); + if (!vis_audio_thread) + { + gst_play_error_plugin (GST_PLAY_ERROR_THREAD, error); + return FALSE; + } + g_hash_table_insert( play->other_elements, + "vis_audio_thread", + vis_audio_thread); + + vis_audio_queue = gst_element_factory_make ("queue", "vis_audio_queue"); + if (!vis_audio_queue) + { + gst_play_error_plugin (GST_PLAY_ERROR_QUEUE, error); + return FALSE; + } + g_hash_table_insert ( play->other_elements, + "vis_audio_queue", + vis_audio_queue); + + vis_audio_sink = gst_element_factory_make ("fakesink", "vis_audio_sink"); + if (!vis_audio_sink) + { + gst_play_error_plugin (GST_PLAY_ERROR_FAKESINK, error); + return FALSE; + } + g_hash_table_insert ( play->other_elements, + "vis_audio_sink", + vis_audio_sink); + play->audio_sink_element = NULL; + + gst_bin_add_many ( GST_BIN (vis_audio_thread), vis_audio_queue, + vis_audio_sink, NULL); + + gst_element_link_many ( vis_audio_queue, vis_audio_sink, NULL); + + /* setting up iterate functions */ + gst_bin_set_pre_iterate_function ( + GST_BIN (vis_audio_thread), + (GstBinPrePostIterateFunction) callback_bin_pre_iterate, + play->audio_bin_mutex); + gst_bin_set_post_iterate_function ( + GST_BIN (vis_audio_thread), + (GstBinPrePostIterateFunction) callback_bin_post_iterate, + play->audio_bin_mutex); + + gst_bin_add ( GST_BIN(play->audio_sink), vis_audio_thread); + + gst_pad_link ( tee_audio_pad, + gst_element_add_ghost_pad ( + vis_audio_thread, + gst_element_get_pad (vis_audio_queue, "sink"), + "sink")); + + /* Creating video part of the visualisation bin + { queue ! (visualisation) ! colorspace ! (videosink) } + */ + + vis_video_thread = gst_thread_new ("vis_video_thread"); + if (!vis_video_thread) + { + gst_play_error_plugin (GST_PLAY_ERROR_THREAD, error); + return FALSE; + } + g_hash_table_insert ( play->other_elements, + "vis_video_thread", + vis_video_thread); + + vis_video_queue = gst_element_factory_make ("queue", "vis_video_queue"); + if (!vis_video_queue) + { + gst_play_error_plugin (GST_PLAY_ERROR_QUEUE, error); + return FALSE; + } + g_hash_table_insert ( play->other_elements, + "vis_video_queue", + vis_video_queue); + + vis_colorspace = gst_element_factory_make ("colorspace", "vis_colorspace"); + if (!vis_colorspace) + { + gst_play_error_plugin (GST_PLAY_ERROR_COLORSPACE, error); + return FALSE; + } + g_hash_table_insert ( play->other_elements, + "vis_colorspace", + vis_colorspace); + + vis_video_sink = gst_element_factory_make ("fakesink", "vis_video_sink"); + if (!vis_video_sink) + { + gst_play_error_plugin (GST_PLAY_ERROR_FAKESINK, error); + return FALSE; + } + g_hash_table_insert ( play->other_elements, + "vis_video_sink", + vis_video_sink); + play->video_sink_element = NULL; + + gst_bin_add_many ( GST_BIN (vis_video_thread), vis_video_queue, + vis_colorspace, vis_video_sink, NULL); + + /* Not linking now as we miss too much stuff */ + + /* setting up iterate functions + gst_bin_set_pre_iterate_function ( + GST_BIN (vis_video_thread), + (GstBinPrePostIterateFunction) callback_bin_pre_iterate, + play->video_bin_mutex); + gst_bin_set_post_iterate_function ( + GST_BIN (vis_video_thread), + (GstBinPrePostIterateFunction) callback_bin_post_iterate, + play->video_bin_mutex);*/ + + vis_video_thread_pad = gst_element_add_ghost_pad ( + vis_video_thread, + gst_element_get_pad (vis_video_queue, "sink"), + "sink"); + + g_hash_table_insert( play->other_elements, + "vis_video_thread_pad", + vis_video_thread_pad); + + gst_bin_add (GST_BIN(play->audio_sink), vis_video_thread); + + /* END VIS STUFF */ + + gst_bin_add (GST_BIN (work_thread), play->audio_sink); + + /* create video elements */ + play->video_sink = gst_element_factory_make ("fakesink", "fake_show"); + if (!play->video_sink) + { + gst_play_error_plugin (GST_PLAY_ERROR_FAKESINK, error); + return FALSE; + } + play->video_sink_element = NULL; + + video_queue = gst_element_factory_make ("queue", "video_queue"); + if (!video_queue) + { + gst_play_error_plugin (GST_PLAY_ERROR_QUEUE, error); + return FALSE; + } + g_hash_table_insert (play->other_elements, "video_queue", video_queue); + + colorspace = gst_element_factory_make ("colorspace", "colorspace"); + if (!colorspace) + { + gst_play_error_plugin (GST_PLAY_ERROR_COLORSPACE, error); + return FALSE; + } + g_hash_table_insert (play->other_elements, "colorspace", colorspace); + + video_bin = gst_thread_new ("video_thread"); + if (!video_bin) + { + gst_play_error_plugin (GST_PLAY_ERROR_THREAD, error); + return FALSE; + } + g_hash_table_insert (play->other_elements, "video_bin", video_bin); + + /* adding all that stuff to bin */ + gst_bin_add_many (GST_BIN (video_bin), video_queue, colorspace, + play->video_sink, NULL); + + gst_element_link_many (video_queue, colorspace, + play->video_sink, NULL); + + /* setting up iterate functions + gst_bin_set_pre_iterate_function ( + GST_BIN (video_bin), + (GstBinPrePostIterateFunction) callback_bin_pre_iterate, + play->video_bin_mutex); + gst_bin_set_post_iterate_function ( + GST_BIN (video_bin), + (GstBinPrePostIterateFunction) callback_bin_post_iterate, + play->video_bin_mutex);*/ + + gst_element_add_ghost_pad ( + video_bin, gst_element_get_pad (video_queue, "sink"), + "sink"); + + gst_bin_add (GST_BIN (work_thread), video_bin); + + return TRUE; +} + +static gboolean +gst_play_video_vis_set_audio ( GstPlay *play, + GstElement *audio_sink) +{ + GstElement *audio_bin, *vis_audio_sink, *vis_audio_queue; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (audio_sink != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY(play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (audio_sink), FALSE); + + audio_bin = g_hash_table_lookup ( play->other_elements, + "vis_audio_thread"); + vis_audio_sink = g_hash_table_lookup ( play->other_elements, + "vis_audio_sink"); + vis_audio_queue = g_hash_table_lookup ( play->other_elements, + "vis_audio_queue"); + + if (vis_audio_sink) + { + gst_element_unlink (vis_audio_queue, vis_audio_sink); + gst_bin_remove (GST_BIN (audio_bin), vis_audio_sink); + } + + gst_bin_add (GST_BIN (audio_bin), audio_sink); + gst_element_link (vis_audio_queue, audio_sink); + + g_hash_table_replace( play->other_elements, + "vis_audio_sink", + audio_sink); + + play->audio_sink_element = gst_play_get_sink_element ( + play, + audio_sink, + GST_PLAY_SINK_TYPE_AUDIO); + + if (play->audio_sink_element != NULL) { + g_signal_connect (G_OBJECT (play->audio_sink_element), "eos", + G_CALLBACK (callback_audio_sink_eos), play); + } + + return TRUE; +} + +static gboolean +gst_play_video_vis_set_video ( GstPlay *play, + GstElement *video_sink) +{ + GstElement *video_mate, *video_bin; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (video_sink != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY(play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (video_sink), FALSE); + + video_bin = g_hash_table_lookup(play->other_elements, "video_bin"); + video_mate = g_hash_table_lookup(play->other_elements, "colorspace"); + + if (play->video_sink) { + gst_element_unlink (video_mate, play->video_sink); + gst_bin_remove (GST_BIN (video_bin), play->video_sink); + } + play->video_sink = video_sink; + gst_bin_add (GST_BIN (video_bin), play->video_sink); + gst_element_link (video_mate, play->video_sink); + + play->video_sink_element = gst_play_get_sink_element ( + play, + video_sink, + GST_PLAY_SINK_TYPE_VIDEO); + + if (play->video_sink_element != NULL) { + g_signal_connect ( G_OBJECT (play->video_sink_element), + "have_xid", + G_CALLBACK (callback_video_have_xid), + play); + g_signal_connect ( G_OBJECT (play->video_sink_element), + "have_size", + G_CALLBACK (callback_video_have_size), + play); + g_object_set( G_OBJECT(play->video_sink_element), + "need_new_window", + TRUE, + "toplevel", + FALSE, NULL); + } + return TRUE; +} + +/** + * gst_play_set_visualisation_video_sink: + * @play: a #GstPlay. + * @video_sink: a #GstElement. + * + * Set @video_sink as the visualisation video sink element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_visualisation_video_sink ( GstPlay *play, + GstElement *video_sink) +{ + GstElement *video_mate, *video_bin, *vis_video_sink; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (video_sink != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY(play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (video_sink), FALSE); + + video_bin = g_hash_table_lookup(play->other_elements, "vis_video_thread"); + video_mate = g_hash_table_lookup(play->other_elements, "vis_colorspace"); + vis_video_sink = g_hash_table_lookup( play->other_elements, + "vis_video_sink"); + + if (vis_video_sink) { + gst_element_unlink (video_mate, vis_video_sink); + gst_bin_remove (GST_BIN (video_bin), vis_video_sink); + } + + gst_bin_add (GST_BIN (video_bin), video_sink); + gst_element_link (video_mate, video_sink); + + g_hash_table_replace( play->other_elements, + "vis_video_sink", + video_sink); + + play->visualisation_sink_element = gst_play_get_sink_element ( + play, + video_sink, + GST_PLAY_SINK_TYPE_VIDEO); + + if (play->visualisation_sink_element != NULL) { + g_signal_connect ( G_OBJECT (play->visualisation_sink_element), + "have_xid", + G_CALLBACK (callback_video_have_vis_xid), + play); + /*g_signal_connect ( G_OBJECT (play->visualisation_sink_element), + "have_size", + G_CALLBACK (callback_video_have_vis_size), + play);*/ + g_object_set( G_OBJECT(play->visualisation_sink_element), + "need_new_window", + TRUE, + "toplevel", + FALSE, NULL); + } + return TRUE; +} + +/** + * gst_play_set_visualisation_element: + * @play: a #GstPlay. + * @element: a #GstElement. + * + * Set @video_sink as the video sink element of @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_set_visualisation_element ( GstPlay *play, + GstElement *element) +{ + GstElement *video_queue, *video_colorspace; + GstElement *vis_element, *vis_video_bin; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (element != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY(play), FALSE); + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + vis_video_bin = g_hash_table_lookup ( play->other_elements, + "vis_video_thread"); + video_queue = g_hash_table_lookup ( play->other_elements, + "vis_video_queue"); + video_colorspace = g_hash_table_lookup ( play->other_elements, + "vis_colorspace"); + vis_element = g_hash_table_lookup ( play->other_elements, + "vis_element"); + if (vis_element) { + gst_element_unlink (video_queue, vis_element); + gst_element_unlink (vis_element, video_colorspace); + gst_bin_remove (GST_BIN (vis_video_bin), vis_element); + } + + gst_bin_add (GST_BIN (vis_video_bin), element); + gst_element_link_many (video_queue, element, video_colorspace, NULL); + + g_hash_table_replace( play->other_elements, + "vis_element", + element); + + return TRUE; +} + +/** + * gst_play_connect_visualisation: + * @play: a #GstPlay. + * @connect: a #gboolean indicating wether or not + * visualisation should be connected. + * + * Connect or disconnect visualisation bin in @play. + * + * Returns: TRUE if call succeeded. + */ +gboolean +gst_play_connect_visualisation ( GstPlay *play, + gboolean connect) +{ + GstPad *tee_vis_pad, *vis_video_thread_pad; + + g_return_val_if_fail (play != NULL, FALSE); + g_return_val_if_fail (GST_IS_PLAY(play), FALSE); + + tee_vis_pad = g_hash_table_lookup( play->other_elements, + "tee_vis_pad"); + vis_video_thread_pad = g_hash_table_lookup( play->other_elements, + "vis_video_thread_pad"); + + if (connect) { + gst_pad_link (tee_vis_pad, vis_video_thread_pad); + } + else { + gst_pad_unlink (tee_vis_pad, vis_video_thread_pad); + } + + return TRUE; +} + /* modelines */ /* vim:set ts=8:sw=8:noet */