From 12cfe650b9948aa10be6cad5756598b1f678b9a8 Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 14 Dec 2006 11:59:00 +0000 Subject: [PATCH] Improvement for the preloading system: Now it is possible to abort running Preloader instances. This helps greatly with the Live Mode, when items are reshuffled before playing. Took a bit longer than expected, since it was more complicated to implement than I had originally thought. On the upside, I've learned more tricks about GStreamer, which is a good thing (tm). Fixes #2087 --- .../src/minimal-audio-smil.c | 59 ++++++++++++++++--- .../src/minimal-audio-smil.h | 3 + .../playlistExecutor/src/GstreamerPlayer.cxx | 19 +++++- .../playlistExecutor/src/GstreamerPlayer.h | 6 ++ 4 files changed, 77 insertions(+), 10 deletions(-) diff --git a/campcaster/src/modules/gstreamerElements/src/minimal-audio-smil.c b/campcaster/src/modules/gstreamerElements/src/minimal-audio-smil.c index 7e1462c75..228745053 100644 --- a/campcaster/src/modules/gstreamerElements/src/minimal-audio-smil.c +++ b/campcaster/src/modules/gstreamerElements/src/minimal-audio-smil.c @@ -51,6 +51,13 @@ /* =================================================== local data structures */ + +enum { + ARG_0, + ARG_ABORT +}; + + /** * ElementFactory information */ @@ -89,6 +96,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ( "rate = (int) [ 8000, 96000 ]")); + /* ================================================ local constants & macros */ #define NSEC_PER_SEC_FLOAT 1000000000.0 @@ -122,6 +130,10 @@ GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, /* =============================================== local function prototypes */ +static void +livesupport_minimal_audio_smil_set_property( GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec ); + + /** * Read the sink stream into memory, using a oneshotreader element. * @@ -272,6 +284,29 @@ livesupport_minimal_audio_smil_class_init( /* ============================================================= module code */ +static void +livesupport_minimal_audio_smil_set_property( GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec ) +{ + LivesupportMinimalAudioSmil* smil; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(LIVESUPPORT_IS_MINIMAL_AUDIO_SMIL(object)); + + smil = LIVESUPPORT_MINIMAL_AUDIO_SMIL(object); + + switch ( prop_id ) + { + case ARG_ABORT: + smil->myclass->abort = g_value_get_pointer (value); + printf("SETTING ABORT POINTER: %d\n", smil->myclass->abort); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID ( object, prop_id, pspec ); + break; + } +} + /*------------------------------------------------------------------------------ * Read the sink stream into memory, using a oneshotreader element. *----------------------------------------------------------------------------*/ @@ -351,7 +386,7 @@ handle_animate_element(LivesupportMinimalAudioSmil * smil, /* handle the attributes */ for (attr = ((xmlElement*)animate)->attributes; - attr; + attr && !(*smil->myclass->abort); attr = (xmlAttribute*) attr->next) { xmlNode * node; @@ -509,7 +544,7 @@ handle_audio_element(LivesupportMinimalAudioSmil * smil, /* handle the attributes */ for (attr = ((xmlElement*)audio)->attributes; - attr; + attr && !(*smil->myclass->abort); attr = (xmlAttribute*) attr->next) { xmlNode * node; @@ -584,7 +619,7 @@ handle_audio_element(LivesupportMinimalAudioSmil * smil, /* now handle the possible animate elements inside this audio element */ element = pplay; - for (ix = 0, node = audio->children; node; node = node->next, ++ix) { + for (ix = 0, node = audio->children; node && !(*smil->myclass->abort); node = node->next, ++ix) { if (node->type == XML_ELEMENT_NODE) { GstElement * elem = 0; @@ -658,7 +693,7 @@ handle_par_element(LivesupportMinimalAudioSmil * smil, g_value_unset(&gvalue); - for (index = 0, node = par->children; node; node = node->next, ++index) { + for (index = 0, node = par->children; node && !(*smil->myclass->abort); node = node->next, ++index) { if (node->type == XML_ELEMENT_NODE) { GstElement * element = 0; @@ -731,7 +766,7 @@ process_smil_file(LivesupportMinimalAudioSmil * smil) return FALSE; } - for (node = node->children; node; node = node->next) { + for (node = node->children; node && !(*smil->myclass->abort); node = node->next) { if (node->type == XML_ELEMENT_NODE) { GstElement * element = 0; @@ -838,6 +873,10 @@ livesupport_minimal_audio_smil_dispose(GObject * object) static void livesupport_minimal_audio_smil_init(LivesupportMinimalAudioSmil * smil) { + printf("INIT().\n"); + + smil->myclass = (LivesupportMinimalAudioSmilClass*) G_OBJECT_GET_CLASS(smil); + GValue gvalue = { 0 }; GstPad * oneshotReaderSink; @@ -913,6 +952,8 @@ static void livesupport_minimal_audio_smil_class_init( LivesupportMinimalAudioSmilClass * klass) { + printf("CLASS_INIT().\n"); + GObjectClass * gobject_class; GstElementClass * gstelement_class; @@ -920,9 +961,13 @@ livesupport_minimal_audio_smil_class_init( gstelement_class = (GstElementClass *) klass; parent_class = (GstBinClass*)g_type_class_ref(GST_TYPE_BIN); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ABORT, g_param_spec_pointer + ("abort", "abort", "abort", (GParamFlags)G_PARAM_WRITABLE)); + gobject_class->dispose = livesupport_minimal_audio_smil_dispose; - gstelement_class->change_state = - livesupport_minimal_audio_smil_change_state; + gobject_class->set_property = livesupport_minimal_audio_smil_set_property; + gstelement_class->change_state = livesupport_minimal_audio_smil_change_state; + /* check for the libxml version */ LIBXML_TEST_VERSION diff --git a/campcaster/src/modules/gstreamerElements/src/minimal-audio-smil.h b/campcaster/src/modules/gstreamerElements/src/minimal-audio-smil.h index c958a6553..3047e662b 100644 --- a/campcaster/src/modules/gstreamerElements/src/minimal-audio-smil.h +++ b/campcaster/src/modules/gstreamerElements/src/minimal-audio-smil.h @@ -80,6 +80,7 @@ typedef struct _LivesupportMinimalAudioSmilClass * The MinimalAudioSmil object structure. */ struct _LivesupportMinimalAudioSmil { + LivesupportMinimalAudioSmilClass* myclass; GstBin parent; GstPad * sinkpad; @@ -99,6 +100,8 @@ struct _LivesupportMinimalAudioSmil { */ struct _LivesupportMinimalAudioSmilClass { GstBinClass parent_class; + + gboolean* abort; }; diff --git a/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.cxx b/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.cxx index be912ab6c..19578f550 100644 --- a/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.cxx +++ b/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.cxx @@ -644,6 +644,8 @@ Preloader::Preloader(GstreamerPlayer* player, const std::string url) throw() , m_fileUrl(url) { DEBUG_FUNC_INFO + + player->m_stopPreloader = false; } @@ -688,6 +690,7 @@ void Preloader::run() throw() gst_element_set(p->m_preloadFilesrc, "location", filePath.c_str(), NULL); p->m_preloadDecoder = gst_element_factory_make("minimalaudiosmil", NULL); + gst_element_set(p->m_preloadDecoder, "abort", &p->m_stopPreloader, NULL); GstElement* pipe = gst_pipeline_new("pipe"); GstElement* fakesink = gst_element_factory_make("fakesink", "fakesink"); @@ -697,13 +700,20 @@ void Preloader::run() throw() gst_element_set_state(pipe, GST_STATE_PLAYING); gint64 position = 0LL; - while (position == 0LL && gst_bin_iterate(GST_BIN(pipe))) { + while (position == 0LL && !p->m_stopPreloader && gst_bin_iterate(GST_BIN(pipe))) { GstFormat format = GST_FORMAT_DEFAULT; gst_element_query(fakesink, GST_QUERY_POSITION, &format, &position); } gst_element_set_state(pipe, GST_STATE_PAUSED); + if (p->m_stopPreloader) { + debug() << "Aborting preloader, per request." << endl; + g_object_unref(G_OBJECT(p->m_preloadFilesrc)); + g_object_unref(G_OBJECT(p->m_preloadDecoder)); + return; + } + g_object_ref(G_OBJECT(p->m_preloadFilesrc)); g_object_ref(G_OBJECT(p->m_preloadDecoder)); gst_bin_remove_many(GST_BIN(pipe), p->m_preloadFilesrc, p->m_preloadDecoder, NULL); @@ -720,8 +730,11 @@ void Preloader::signal(int) throw() {} -// TODO This should be implemented by adding a "abort" property to the minimalaudiosmil element. void Preloader::stop() throw() -{} +{ + DEBUG_FUNC_INFO + + m_player->m_stopPreloader = true; +} diff --git a/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.h b/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.h index 709ba47ec..28ebeb618 100644 --- a/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.h +++ b/campcaster/src/modules/playlistExecutor/src/GstreamerPlayer.h @@ -170,6 +170,12 @@ class GstreamerPlayer : virtual public Configurable, */ Ptr::Ref m_preloadThread; + /** + * Flag that indicates that the preloader should abort. + */ + + gboolean m_stopPreloader; + /** * The type for the vector of listeners. * Just a shorthand notation, to make reference to the type