From 1bfdc8781557bd7a45a2a22d5f8424008e9ab050 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Dec 2008 17:39:32 +0000 Subject: [PATCH] gst/playback/gstplaysink.c: Use G_DEFINE_TYPE. Original commit message from CVS: * gst/playback/gstplaysink.c: (gst_play_sink_class_init), (gst_play_sink_dispose), (gst_play_sink_finalize), (try_element), (gen_video_chain), (gen_audio_chain), (gst_play_sink_reconfigure), (gst_play_sink_send_event), (gst_play_sink_change_state): Use G_DEFINE_TYPE. Try to set the selected sink to READY before using it. This will allow for detection of incompatible formats sooner. Don't cause a fatal error when conversion elements are missing but post a missing-element message and a warning instead because things might still link and run fine. Simplyfy the construction of audio and video sink chains. --- ChangeLog | 14 ++ gst/playback/gstplaysink.c | 331 +++++++++++++++++++++++---------------------- 2 files changed, 184 insertions(+), 161 deletions(-) diff --git a/ChangeLog b/ChangeLog index 74f5827..fdbdb1c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2008-12-10 Wim Taymans + * gst/playback/gstplaysink.c: (gst_play_sink_class_init), + (gst_play_sink_dispose), (gst_play_sink_finalize), (try_element), + (gen_video_chain), (gen_audio_chain), (gst_play_sink_reconfigure), + (gst_play_sink_send_event), (gst_play_sink_change_state): + Use G_DEFINE_TYPE. + Try to set the selected sink to READY before using it. This will allow + for detection of incompatible formats sooner. + Don't cause a fatal error when conversion elements are missing but post + a missing-element message and a warning instead because things might + still link and run fine. + Simplyfy the construction of audio and video sink chains. + +2008-12-10 Wim Taymans + * ext/ogg/gstoggdemux.c: (gst_ogg_pad_class_init), (gst_ogg_pad_dispose), (gst_ogg_pad_finalize): Use G_DEFINE_TYPE for the OggPad to get some threadsafe type diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index acc4234..4008b17 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -170,8 +170,6 @@ static gboolean gst_play_sink_send_event (GstElement * element, static GstStateChangeReturn gst_play_sink_change_state (GstElement * element, GstStateChange transition); -static GstElementClass *parent_class; - /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */ static const GstElementDetails gst_play_sink_details = @@ -180,31 +178,7 @@ GST_ELEMENT_DETAILS ("Player Sink", "Autoplug and play media from an uri", "Wim Taymans "); -GType -gst_play_sink_get_type (void) -{ - static GType gst_play_sink_type = 0; - - if (!gst_play_sink_type) { - static const GTypeInfo gst_play_sink_info = { - sizeof (GstPlaySinkClass), - NULL, - NULL, - (GClassInitFunc) gst_play_sink_class_init, - NULL, - NULL, - sizeof (GstPlaySink), - 0, - (GInstanceInitFunc) gst_play_sink_init, - NULL - }; - - gst_play_sink_type = g_type_register_static (GST_TYPE_BIN, - "GstPlaySink", &gst_play_sink_info, 0); - } - - return gst_play_sink_type; -} +G_DEFINE_TYPE (GstPlaySink, gst_play_sink, GST_TYPE_BIN); static void gst_play_sink_class_init (GstPlaySinkClass * klass) @@ -217,8 +191,6 @@ gst_play_sink_class_init (GstPlaySinkClass * klass) gstelement_klass = (GstElementClass *) klass; gstbin_klass = (GstBinClass *) klass; - parent_class = g_type_class_peek_parent (klass); - gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_sink_dispose); gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_sink_finalize); @@ -270,7 +242,7 @@ gst_play_sink_dispose (GObject * object) g_free (playsink->font_desc); playsink->font_desc = NULL; - G_OBJECT_CLASS (parent_class)->dispose (object); + G_OBJECT_CLASS (gst_play_sink_parent_class)->dispose (object); } static void @@ -282,7 +254,7 @@ gst_play_sink_finalize (GObject * object) g_mutex_free (playsink->lock); - G_OBJECT_CLASS (parent_class)->finalize (object); + G_OBJECT_CLASS (gst_play_sink_parent_class)->finalize (object); } void @@ -636,6 +608,26 @@ gst_play_sink_find_property (GstPlaySink * playsink, GstElement * obj, return result; } +/* try to change the state of an element. This function returns the element when + * the state change could be performed. When this function returns NULL an error + * occured and the element is unreffed. */ +static GstElement * +try_element (GstPlaySink * playsink, GstElement * element) +{ + GstStateChangeReturn ret; + + if (element) { + ret = gst_element_set_state (element, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_DEBUG_OBJECT (playsink, "failed state change.."); + gst_element_set_state (element, GST_STATE_NULL); + gst_object_unref (element); + element = NULL; + } + } + return element; +} + /* make the element (bin) that contains the elements needed to perform * video display. * @@ -655,6 +647,7 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) GstPlayVideoChain *chain; GstBin *bin; GstPad *pad; + GstElement *prev, *elem; chain = g_new0 (GstPlayVideoChain, 1); chain->chain.playsink = gst_object_ref (playsink); @@ -662,15 +655,22 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) GST_DEBUG_OBJECT (playsink, "making video chain %p", chain); if (playsink->video_sink) { - chain->sink = gst_object_ref (playsink->video_sink); - } else { - chain->sink = gst_element_factory_make ("autovideosink", "videosink"); - if (chain->sink == NULL) { - chain->sink = gst_element_factory_make ("xvimagesink", "videosink"); - } - if (chain->sink == NULL) - goto no_sinks; + GST_DEBUG_OBJECT (playsink, "trying configured videosink"); + elem = gst_object_ref (playsink->video_sink); + chain->sink = try_element (playsink, elem); + } + if (chain->sink == NULL) { + GST_DEBUG_OBJECT (playsink, "trying autovideosink"); + elem = gst_element_factory_make ("autovideosink", "videosink"); + chain->sink = try_element (playsink, elem); + } + if (chain->sink == NULL) { + GST_DEBUG_OBJECT (playsink, "trying xvimagesink"); + elem = gst_element_factory_make ("xvimagesink", "videosink"); + chain->sink = try_element (playsink, elem); } + if (chain->sink == NULL) + goto no_sinks; /* if we can disable async behaviour of the sink, we can avoid adding a * queue for the audio chain. We can't use the deep property here because the @@ -680,8 +680,10 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) async); g_object_set (chain->sink, "async", async, NULL); chain->async = async; - } else + } else { + GST_DEBUG_OBJECT (playsink, "no async property on the sink"); chain->async = TRUE; + } /* create a bin to hold objects, as we create them we add them to this bin so * that when something goes wrong we only need to unref the bin */ @@ -691,18 +693,6 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) gst_object_sink (bin); gst_bin_add (bin, chain->sink); - if (raw) { - chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv"); - if (chain->conv == NULL) - goto no_colorspace; - gst_bin_add (bin, chain->conv); - - chain->scale = gst_element_factory_make ("videoscale", "vscale"); - if (chain->scale == NULL) - goto no_videoscale; - gst_bin_add (bin, chain->scale); - } - /* decouple decoder from sink, this improves playback quite a lot since the * decoder can continue while the sink blocks for synchronisation. We don't * need a lot of buffers as this consumes a lot of memory and we don't want @@ -711,24 +701,49 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3, "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL); gst_bin_add (bin, chain->queue); + prev = chain->queue; if (raw) { - gst_element_link_pads (chain->queue, "src", chain->conv, "sink"); - gst_element_link_pads (chain->conv, "src", chain->scale, "sink"); - /* be more careful with the pad from the custom sink element, it might not - * be named 'sink' */ - if (!gst_element_link_pads (chain->scale, "src", chain->sink, NULL)) - goto link_failed; - - pad = gst_element_get_static_pad (chain->queue, "sink"); - } else { - if (!gst_element_link_pads (chain->queue, "src", chain->sink, NULL)) - goto link_failed; - pad = gst_element_get_static_pad (chain->queue, "sink"); + GST_DEBUG_OBJECT (playsink, "creating ffmpegcolorspace"); + chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv"); + if (chain->conv == NULL) { + post_missing_element_message (playsink, "ffmpegcolorspace"); + GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, + (_("Missing element '%s' - check your GStreamer installation."), + "ffmpegcolorspace"), (NULL)); + } else { + gst_bin_add (bin, chain->conv); + if (!gst_element_link_pads (prev, "src", chain->conv, "sink")) + goto link_failed; + + prev = chain->conv; + } + + GST_DEBUG_OBJECT (playsink, "creating videoscale"); + chain->scale = gst_element_factory_make ("videoscale", "vscale"); + if (chain->scale == NULL) { + post_missing_element_message (playsink, "videoscale"); + GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, + (_("Missing element '%s' - check your GStreamer installation."), + "videoscale"), ("possibly a liboil version mismatch?")); + } else { + gst_bin_add (bin, chain->scale); + if (!gst_element_link_pads (prev, "src", chain->scale, "sink")) + goto link_failed; + + prev = chain->scale; + } } + /* be more careful with the pad from the custom sink element, it might not + * be named 'sink' */ + if (!gst_element_link_pads (prev, "src", chain->sink, NULL)) + goto link_failed; + + pad = gst_element_get_static_pad (chain->queue, "sink"); chain->sinkpad = gst_ghost_pad_new ("sink", pad); gst_object_unref (pad); + gst_element_add_pad (chain->chain.bin, chain->sinkpad); return chain; @@ -743,24 +758,6 @@ no_sinks: free_chain ((GstPlayChain *) chain); return NULL; } -no_colorspace: - { - post_missing_element_message (playsink, "ffmpegcolorspace"); - GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, - (_("Missing element '%s' - check your GStreamer installation."), - "ffmpegcolorspace"), (NULL)); - free_chain ((GstPlayChain *) chain); - return NULL; - } -no_videoscale: - { - post_missing_element_message (playsink, "videoscale"); - GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, - (_("Missing element '%s' - check your GStreamer installation."), - "videoscale"), ("possibly a liboil version mismatch?")); - free_chain ((GstPlayChain *) chain); - return NULL; - } link_failed: { GST_ELEMENT_ERROR (playsink, CORE, PAD, @@ -879,8 +876,9 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue) { GstPlayAudioChain *chain; GstBin *bin; - gboolean res, have_volume; + gboolean have_volume; GstPad *pad; + GstElement *head, *prev, *elem; chain = g_new0 (GstPlayAudioChain, 1); chain->chain.playsink = gst_object_ref (playsink); @@ -888,15 +886,24 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue) GST_DEBUG_OBJECT (playsink, "making audio chain %p", chain); if (playsink->audio_sink) { - chain->sink = gst_object_ref (playsink->audio_sink); - } else { - chain->sink = gst_element_factory_make ("autoaudiosink", "audiosink"); - if (chain->sink == NULL) { - chain->sink = gst_element_factory_make ("alsasink", "audiosink"); - } - if (chain->sink == NULL) - goto no_sinks; + GST_DEBUG_OBJECT (playsink, "trying configured audiosink"); + elem = gst_object_ref (playsink->audio_sink); + chain->sink = try_element (playsink, elem); + } + if (chain->sink == NULL) { + GST_DEBUG_OBJECT (playsink, "trying autoaudiosink"); + elem = gst_element_factory_make ("autoaudiosink", "audiosink"); + chain->sink = try_element (playsink, elem); + } + if (chain->sink == NULL) { + GST_DEBUG_OBJECT (playsink, "trying alsasink"); + elem = gst_element_factory_make ("alsasink", "audiosink"); + chain->sink = try_element (playsink, elem); } + if (chain->sink == NULL) + goto no_sinks; + + chain->chain.bin = gst_bin_new ("abin"); bin = GST_BIN_CAST (chain->chain.bin); gst_object_ref (bin); @@ -909,6 +916,10 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue) GST_DEBUG_OBJECT (playsink, "adding audio queue"); chain->queue = gst_element_factory_make ("queue", "aqueue"); gst_bin_add (bin, chain->queue); + prev = head = chain->queue; + } else { + head = chain->sink; + prev = NULL; } /* check if the sink has the volume property, if it does we don't need to @@ -934,60 +945,80 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue) if (raw) { chain->conv = gst_element_factory_make ("audioconvert", "aconv"); - if (chain->conv == NULL) - goto no_audioconvert; - gst_bin_add (bin, chain->conv); + if (chain->conv == NULL) { + post_missing_element_message (playsink, "audioconvert"); + GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, + (_("Missing element '%s' - check your GStreamer installation."), + "audioconvert"), ("possibly a liboil version mismatch?")); + } else { + gst_bin_add (bin, chain->conv); + if (prev) { + if (!gst_element_link_pads (prev, "src", chain->conv, "sink")) + goto link_failed; + } else { + head = chain->conv; + } + prev = chain->conv; + } chain->resample = gst_element_factory_make ("audioresample", "aresample"); - if (chain->resample == NULL) - goto no_audioresample; - gst_bin_add (bin, chain->resample); - - res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink"); + if (chain->resample == NULL) { + post_missing_element_message (playsink, "audioresample"); + GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, + (_("Missing element '%s' - check your GStreamer installation."), + "audioresample"), ("possibly a liboil version mismatch?")); + } else { + gst_bin_add (bin, chain->resample); + if (prev) { + if (!gst_element_link_pads (prev, "src", chain->resample, "sink")) + goto link_failed; + } else { + head = chain->resample; + } + prev = chain->resample; + } if (!have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) { chain->volume = gst_element_factory_make ("volume", "volume"); - if (chain->volume == NULL) - goto no_volume; - - have_volume = TRUE; - - /* volume also has the mute property */ - chain->mute = gst_object_ref (chain->volume); - - /* configure with the latest volume and mute */ - g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL); - g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL); - gst_bin_add (bin, chain->volume); + if (chain->volume == NULL) { + post_missing_element_message (playsink, "volume"); + GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, + (_("Missing element '%s' - check your GStreamer installation."), + "volume"), ("possibly a liboil version mismatch?")); + } else { + have_volume = TRUE; - res &= - gst_element_link_pads (chain->resample, "src", chain->volume, "sink"); - res &= gst_element_link_pads (chain->volume, "src", chain->sink, NULL); - } else { - res &= gst_element_link_pads (chain->resample, "src", chain->sink, NULL); - } - if (!res) - goto link_failed; + /* volume also has the mute property */ + chain->mute = gst_object_ref (chain->volume); - if (queue) { - res = gst_element_link_pads (chain->queue, "src", chain->conv, "sink"); - pad = gst_element_get_static_pad (chain->queue, "sink"); - } else { - pad = gst_element_get_static_pad (chain->conv, "sink"); - } - } else { - if (queue) { - res = gst_element_link_pads (chain->queue, "src", chain->sink, "sink"); - pad = gst_element_get_static_pad (chain->queue, "sink"); - } else { - pad = gst_element_get_static_pad (chain->sink, "sink"); + /* configure with the latest volume and mute */ + g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, + NULL); + g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL); + gst_bin_add (bin, chain->volume); + + if (prev) { + if (!gst_element_link_pads (prev, "src", chain->volume, "sink")) + goto link_failed; + } else { + head = chain->volume; + } + prev = chain->volume; + } } } + + if (!gst_element_link_pads (prev, "src", chain->sink, NULL)) + goto link_failed; + /* post a warning if we have no way to configure the volume */ if (!have_volume) { GST_ELEMENT_WARNING (playsink, STREAM, NOT_IMPLEMENTED, (_("No volume control found")), ("No volume control found")); } + + /* and ghost the sinkpad of the headmost element */ + pad = gst_element_get_static_pad (head, "sink"); chain->sinkpad = gst_ghost_pad_new ("sink", pad); gst_object_unref (pad); gst_element_add_pad (chain->chain.bin, chain->sinkpad); @@ -1003,33 +1034,6 @@ no_sinks: free_chain ((GstPlayChain *) chain); return NULL; } -no_audioconvert: - { - post_missing_element_message (playsink, "audioconvert"); - GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, - (_("Missing element '%s' - check your GStreamer installation."), - "audioconvert"), ("possibly a liboil version mismatch?")); - free_chain ((GstPlayChain *) chain); - return NULL; - } -no_audioresample: - { - post_missing_element_message (playsink, "audioresample"); - GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, - (_("Missing element '%s' - check your GStreamer installation."), - "audioresample"), ("possibly a liboil version mismatch?")); - free_chain ((GstPlayChain *) chain); - return NULL; - } -no_volume: - { - post_missing_element_message (playsink, "volume"); - GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, - (_("Missing element '%s' - check your GStreamer installation."), - "volume"), ("possibly a liboil version mismatch?")); - free_chain ((GstPlayChain *) chain); - return NULL; - } link_failed: { GST_ELEMENT_ERROR (playsink, CORE, PAD, @@ -1175,7 +1179,8 @@ gst_play_sink_reconfigure (GstPlaySink * playsink) /* figure out which components we need */ if (flags & GST_PLAY_FLAG_TEXT && playsink->text_pad) { - /* we need video too */ + /* we have a text_pad and we need text rendering, in this case we need a + * video_pad to combine the video with the text */ if (!playsink->video_pad) goto subs_but_no_video; @@ -1593,7 +1598,9 @@ gst_play_sink_send_event (GstElement * element, GstEvent * event) res = gst_play_sink_send_event_to_sink (GST_PLAY_SINK (element), event); break; default: - res = parent_class->send_event (element, event); + res = + GST_ELEMENT_CLASS (gst_play_sink_parent_class)->send_event (element, + event); break; } return res; @@ -1614,7 +1621,9 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) break; } - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + ret = + GST_ELEMENT_CLASS (gst_play_sink_parent_class)->change_state (element, + transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; -- 2.7.4