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.
This commit is contained in:
Wim Taymans 2008-12-10 17:39:32 +00:00
parent 1ab0f8da50
commit 1bfdc87815
2 changed files with 182 additions and 159 deletions

View file

@ -1,3 +1,17 @@
2008-12-10 Wim Taymans <wim.taymans@collabora.co.uk>
* 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 <wim.taymans@collabora.co.uk> 2008-12-10 Wim Taymans <wim.taymans@collabora.co.uk>
* ext/ogg/gstoggdemux.c: (gst_ogg_pad_class_init), * ext/ogg/gstoggdemux.c: (gst_ogg_pad_class_init),

View file

@ -170,8 +170,6 @@ static gboolean gst_play_sink_send_event (GstElement * element,
static GstStateChangeReturn gst_play_sink_change_state (GstElement * element, static GstStateChangeReturn gst_play_sink_change_state (GstElement * element,
GstStateChange transition); GstStateChange transition);
static GstElementClass *parent_class;
/* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */ /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */
static const GstElementDetails gst_play_sink_details = static const GstElementDetails gst_play_sink_details =
@ -180,31 +178,7 @@ GST_ELEMENT_DETAILS ("Player Sink",
"Autoplug and play media from an uri", "Autoplug and play media from an uri",
"Wim Taymans <wim.taymans@gmail.com>"); "Wim Taymans <wim.taymans@gmail.com>");
GType G_DEFINE_TYPE (GstPlaySink, gst_play_sink, GST_TYPE_BIN);
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;
}
static void static void
gst_play_sink_class_init (GstPlaySinkClass * klass) gst_play_sink_class_init (GstPlaySinkClass * klass)
@ -217,8 +191,6 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
gstelement_klass = (GstElementClass *) klass; gstelement_klass = (GstElementClass *) klass;
gstbin_klass = (GstBinClass *) 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->dispose = GST_DEBUG_FUNCPTR (gst_play_sink_dispose);
gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_sink_finalize); 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); g_free (playsink->font_desc);
playsink->font_desc = NULL; playsink->font_desc = NULL;
G_OBJECT_CLASS (parent_class)->dispose (object); G_OBJECT_CLASS (gst_play_sink_parent_class)->dispose (object);
} }
static void static void
@ -282,7 +254,7 @@ gst_play_sink_finalize (GObject * object)
g_mutex_free (playsink->lock); g_mutex_free (playsink->lock);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (gst_play_sink_parent_class)->finalize (object);
} }
void void
@ -636,6 +608,26 @@ gst_play_sink_find_property (GstPlaySink * playsink, GstElement * obj,
return result; 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 /* make the element (bin) that contains the elements needed to perform
* video display. * video display.
* *
@ -655,6 +647,7 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
GstPlayVideoChain *chain; GstPlayVideoChain *chain;
GstBin *bin; GstBin *bin;
GstPad *pad; GstPad *pad;
GstElement *prev, *elem;
chain = g_new0 (GstPlayVideoChain, 1); chain = g_new0 (GstPlayVideoChain, 1);
chain->chain.playsink = gst_object_ref (playsink); 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); GST_DEBUG_OBJECT (playsink, "making video chain %p", chain);
if (playsink->video_sink) { if (playsink->video_sink) {
chain->sink = gst_object_ref (playsink->video_sink); GST_DEBUG_OBJECT (playsink, "trying configured videosink");
} else { elem = gst_object_ref (playsink->video_sink);
chain->sink = gst_element_factory_make ("autovideosink", "videosink"); chain->sink = try_element (playsink, elem);
if (chain->sink == NULL) {
chain->sink = gst_element_factory_make ("xvimagesink", "videosink");
}
if (chain->sink == NULL)
goto no_sinks;
} }
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 /* 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 * 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); async);
g_object_set (chain->sink, "async", async, NULL); g_object_set (chain->sink, "async", async, NULL);
chain->async = async; chain->async = async;
} else } else {
GST_DEBUG_OBJECT (playsink, "no async property on the sink");
chain->async = TRUE; chain->async = TRUE;
}
/* create a bin to hold objects, as we create them we add them to this bin so /* 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 */ * 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_object_sink (bin);
gst_bin_add (bin, chain->sink); 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 /* decouple decoder from sink, this improves playback quite a lot since the
* decoder can continue while the sink blocks for synchronisation. We don't * 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 * 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, g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
"max-size-bytes", 0, "max-size-time", (gint64) 0, NULL); "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
gst_bin_add (bin, chain->queue); gst_bin_add (bin, chain->queue);
prev = chain->queue;
if (raw) { if (raw) {
gst_element_link_pads (chain->queue, "src", chain->conv, "sink"); GST_DEBUG_OBJECT (playsink, "creating ffmpegcolorspace");
gst_element_link_pads (chain->conv, "src", chain->scale, "sink"); chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
/* be more careful with the pad from the custom sink element, it might not if (chain->conv == NULL) {
* be named 'sink' */ post_missing_element_message (playsink, "ffmpegcolorspace");
if (!gst_element_link_pads (chain->scale, "src", chain->sink, NULL)) GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
goto link_failed; (_("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;
pad = gst_element_get_static_pad (chain->queue, "sink"); prev = chain->conv;
} else { }
if (!gst_element_link_pads (chain->queue, "src", chain->sink, NULL))
goto link_failed; GST_DEBUG_OBJECT (playsink, "creating videoscale");
pad = gst_element_get_static_pad (chain->queue, "sink"); 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); chain->sinkpad = gst_ghost_pad_new ("sink", pad);
gst_object_unref (pad); gst_object_unref (pad);
gst_element_add_pad (chain->chain.bin, chain->sinkpad); gst_element_add_pad (chain->chain.bin, chain->sinkpad);
return chain; return chain;
@ -743,24 +758,6 @@ no_sinks:
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
return NULL; 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: link_failed:
{ {
GST_ELEMENT_ERROR (playsink, CORE, PAD, GST_ELEMENT_ERROR (playsink, CORE, PAD,
@ -879,8 +876,9 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue)
{ {
GstPlayAudioChain *chain; GstPlayAudioChain *chain;
GstBin *bin; GstBin *bin;
gboolean res, have_volume; gboolean have_volume;
GstPad *pad; GstPad *pad;
GstElement *head, *prev, *elem;
chain = g_new0 (GstPlayAudioChain, 1); chain = g_new0 (GstPlayAudioChain, 1);
chain->chain.playsink = gst_object_ref (playsink); 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); GST_DEBUG_OBJECT (playsink, "making audio chain %p", chain);
if (playsink->audio_sink) { if (playsink->audio_sink) {
chain->sink = gst_object_ref (playsink->audio_sink); GST_DEBUG_OBJECT (playsink, "trying configured audiosink");
} else { elem = gst_object_ref (playsink->audio_sink);
chain->sink = gst_element_factory_make ("autoaudiosink", "audiosink"); chain->sink = try_element (playsink, elem);
if (chain->sink == NULL) {
chain->sink = gst_element_factory_make ("alsasink", "audiosink");
}
if (chain->sink == NULL)
goto no_sinks;
} }
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"); chain->chain.bin = gst_bin_new ("abin");
bin = GST_BIN_CAST (chain->chain.bin); bin = GST_BIN_CAST (chain->chain.bin);
gst_object_ref (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"); GST_DEBUG_OBJECT (playsink, "adding audio queue");
chain->queue = gst_element_factory_make ("queue", "aqueue"); chain->queue = gst_element_factory_make ("queue", "aqueue");
gst_bin_add (bin, chain->queue); 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 /* 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) { if (raw) {
chain->conv = gst_element_factory_make ("audioconvert", "aconv"); chain->conv = gst_element_factory_make ("audioconvert", "aconv");
if (chain->conv == NULL) if (chain->conv == NULL) {
goto no_audioconvert; post_missing_element_message (playsink, "audioconvert");
gst_bin_add (bin, chain->conv); 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"); chain->resample = gst_element_factory_make ("audioresample", "aresample");
if (chain->resample == NULL) if (chain->resample == NULL) {
goto no_audioresample; post_missing_element_message (playsink, "audioresample");
gst_bin_add (bin, chain->resample); GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink"); "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) { if (!have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) {
chain->volume = gst_element_factory_make ("volume", "volume"); chain->volume = gst_element_factory_make ("volume", "volume");
if (chain->volume == NULL) if (chain->volume == NULL) {
goto no_volume; 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;
have_volume = TRUE; /* volume also has the mute property */
chain->mute = gst_object_ref (chain->volume);
/* volume also has the mute property */ /* configure with the latest volume and mute */
chain->mute = gst_object_ref (chain->volume); 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);
/* configure with the latest volume and mute */ if (prev) {
g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL); if (!gst_element_link_pads (prev, "src", chain->volume, "sink"))
g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL); goto link_failed;
gst_bin_add (bin, chain->volume); } else {
head = chain->volume;
res &= }
gst_element_link_pads (chain->resample, "src", chain->volume, "sink"); prev = chain->volume;
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;
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");
} }
} }
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 */ /* post a warning if we have no way to configure the volume */
if (!have_volume) { if (!have_volume) {
GST_ELEMENT_WARNING (playsink, STREAM, NOT_IMPLEMENTED, GST_ELEMENT_WARNING (playsink, STREAM, NOT_IMPLEMENTED,
(_("No volume control found")), ("No volume control found")); (_("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); chain->sinkpad = gst_ghost_pad_new ("sink", pad);
gst_object_unref (pad); gst_object_unref (pad);
gst_element_add_pad (chain->chain.bin, chain->sinkpad); gst_element_add_pad (chain->chain.bin, chain->sinkpad);
@ -1003,33 +1034,6 @@ no_sinks:
free_chain ((GstPlayChain *) chain); free_chain ((GstPlayChain *) chain);
return NULL; 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: link_failed:
{ {
GST_ELEMENT_ERROR (playsink, CORE, PAD, GST_ELEMENT_ERROR (playsink, CORE, PAD,
@ -1175,7 +1179,8 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
/* figure out which components we need */ /* figure out which components we need */
if (flags & GST_PLAY_FLAG_TEXT && playsink->text_pad) { 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) if (!playsink->video_pad)
goto subs_but_no_video; 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); res = gst_play_sink_send_event_to_sink (GST_PLAY_SINK (element), event);
break; break;
default: default:
res = parent_class->send_event (element, event); res =
GST_ELEMENT_CLASS (gst_play_sink_parent_class)->send_event (element,
event);
break; break;
} }
return res; return res;
@ -1614,7 +1621,9 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
break; 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) if (ret == GST_STATE_CHANGE_FAILURE)
return ret; return ret;