From 8ea9d9d21a5397d13363170bc74f323e6f8e218e Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 5 Nov 2006 09:23:47 +0000 Subject: [PATCH] Major performance improvements for the GstreamerPlayer: Lag for opening/starting files has been reduced by a multitude, for all filetypes except SMIL. This has been achieved by using GStreamer's decodebin autoplugger, instead of our (very slow) custom autoplugger. For SMIL we currently still need to use the old autoplugger, so I have implemented two different codepaths. For some hard numbers, this is an excerpt of a session with the new code: [GstreamerPlayer] BEGIN: virtual void LiveSupport::PlaylistExecutor::GstreamerPlayer::open(std::string) [GstreamerPlayer] Opening URL: file:var/test.mp3 [GstreamerPlayer] END__: virtual void LiveSupport::PlaylistExecutor::GstreamerPlayer::open(std::string) - Took 0.099144s [GstreamerPlayer] BEGIN: virtual void LiveSupport::PlaylistExecutor::GstreamerPlayer::start() [GstreamerPlayer] END__: virtual void LiveSupport::PlaylistExecutor::GstreamerPlayer::start() - Took 0.000105s Total execution time ~0.1s. Almost instant. Fixes #1904 --- .../playlistExecutor/src/GstreamerPlayer.cxx | 77 ++++++++++++++----- .../playlistExecutor/src/GstreamerPlayer.h | 11 +++ 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.cxx b/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.cxx index 9ad3dde89..006a37418 100644 --- a/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.cxx +++ b/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.cxx @@ -239,6 +239,31 @@ GstreamerPlayer :: eosEventHandler(GstElement * element, } +/*------------------------------------------------------------------------------ + * NewPad event handler. Links the decoder after decodebin's autoplugging. + *----------------------------------------------------------------------------*/ +void +GstreamerPlayer::newpadEventHandler(GstElement*, GstPad* pad, gboolean, gpointer self) throw () +{ + DEBUG_BLOCK + + GstreamerPlayer* const player = (GstreamerPlayer*) self; + GstPad* const audiopad = gst_element_get_pad(player->audioconvert, "sink"); + + if (GST_PAD_IS_LINKED(audiopad)) { + debug() << "audiopad is already linked. Unlinking old pad." << endl; + gst_pad_unlink(audiopad, GST_PAD_PEER(audiopad)); + } + + gst_pad_link(pad, audiopad); + + if (gst_element_get_parent(player->audiosink) == NULL) + gst_bin_add(GST_BIN(player->pipeline), player->audiosink); + + gst_bin_sync_children_state(GST_BIN(player->pipeline)); +} + + /*------------------------------------------------------------------------------ * Specify which file to play *----------------------------------------------------------------------------*/ @@ -270,31 +295,39 @@ GstreamerPlayer :: open(const std::string fileUrl) throw std::invalid_argument("badly formed URL or unsupported protocol"); } + const bool isSmil = fileUrl.substr(fileUrl.size()-5, fileUrl.size()) == ".smil" ? true : false; + filesrc = gst_element_factory_make("filesrc", "file-source"); gst_element_set(filesrc, "location", filePath.c_str(), NULL); - decoder = ls_gst_autoplug_plug_source(filesrc, "decoder", sinkCaps); - - if (!decoder) { - throw std::invalid_argument(std::string("can't open URL ") + fileUrl); - } - // converts between different audio formats (e.g. bitrate) audioconvert = gst_element_factory_make("audioconvert", NULL); // scale the sampling rate, if necessary audioscale = gst_element_factory_make("audioscale", NULL); - gst_bin_add_many(GST_BIN(pipeline), filesrc, - decoder, - audioconvert, - audioscale, - NULL); - gst_element_link_many(decoder, - audioconvert, - audioscale, - audiosink, - NULL); + // Using our custom autoplugger for SMIL + if (isSmil) { + debug() << "SMIL file detected. Using custom autoplugger." << endl; + decoder = ls_gst_autoplug_plug_source(filesrc, "decoder", sinkCaps); + gst_element_link(decoder,audioconvert); + if (gst_element_get_parent(audiosink) == NULL) + gst_bin_add(GST_BIN(pipeline), audiosink); + } + // Using GStreamer's decodebin autoplugger for everything else (it's much faster) + else { + decoder = gst_element_factory_make("decodebin", NULL); + gst_element_link(filesrc,decoder); + g_signal_connect(decoder, "new-decoded-pad", G_CALLBACK(newpadEventHandler), this); + } + + if (!decoder) { + throw std::invalid_argument(std::string("can't open URL ") + fileUrl); + } + + gst_bin_add_many(GST_BIN(pipeline), filesrc, decoder, audioconvert, audioscale, NULL); + + gst_element_link_many(audioconvert, audioscale, audiosink, NULL); // connect the eos signal handler g_signal_connect(decoder, "eos", G_CALLBACK(eosEventHandler), this); @@ -305,7 +338,6 @@ GstreamerPlayer :: open(const std::string fileUrl) // the audio device (as it might be blocked by an other process throw std::runtime_error("can't open audio device " + audioDevice); } - gst_bin_sync_children_state(GST_BIN(pipeline)); } @@ -472,6 +504,10 @@ GstreamerPlayer :: close(void) throw (std::logic_error) if (filesrc) { gst_bin_remove(GST_BIN(pipeline), filesrc); } + if (audiosink && gst_element_get_parent(audiosink) == GST_OBJECT(pipeline)) { + gst_object_ref(GST_OBJECT(audiosink)); + gst_bin_remove(GST_BIN(pipeline), audiosink); + } filesrc = 0; decoder = 0; @@ -518,7 +554,10 @@ GstreamerPlayer :: setAudioDevice(const std::string &deviceName) if (audioscale) { gst_element_unlink(audioscale, audiosink); } - gst_bin_remove(GST_BIN(pipeline), audiosink); + if ( gst_element_get_parent( audiosink ) == NULL ) + gst_object_unref(GST_OBJECT(audiosink)); + else + gst_bin_remove(GST_BIN(pipeline), audiosink); audiosink = 0; } @@ -536,8 +575,6 @@ GstreamerPlayer :: setAudioDevice(const std::string &deviceName) if (audioscale) { gst_element_link_filtered(audioscale, audiosink, sinkCaps); } - gst_bin_add(GST_BIN(pipeline), audiosink); - gst_bin_sync_children_state(GST_BIN(pipeline)); return true; } diff --git a/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.h b/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.h index 5d6976870..f851ae319 100644 --- a/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.h +++ b/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.h @@ -188,6 +188,16 @@ class GstreamerPlayer : virtual public Configurable, eosEventHandler(GstElement * element, gpointer self) throw (); + /** + * An newpad event handler, that will link the decoder after + * decodebin's autoplugging. + * + * @param element the element emitting the eos signal + * @param self a pointer to the associated GstreamerPlayer object. + */ + static void + newpadEventHandler(GstElement*, GstPad*, gboolean, gpointer self) throw(); + /** * Send the onStop event to all attached listeners. @@ -294,6 +304,7 @@ class GstreamerPlayer : virtual public Configurable, setAudioDevice(const std::string &deviceName) throw (); + /** * Specify which audio resource to play. * The file may be a playlist, referencing other files, which