From 5f296f9b3e9f19a44e1a391b31a51a66b659050c Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Wed, 20 May 2015 14:41:31 +0200 Subject: Fix reporting missing GStreamer plugins Change-Id: I99b5994b53a5768b4c0aa8dbd6f54b13b23b333a --- avmedia/Library_avmediagst.mk | 1 + avmedia/Library_avmediagst_0_10.mk | 1 + avmedia/source/gstreamer/gstplayer.cxx | 224 +++++++++++++++++++++++++++++---- 3 files changed, 201 insertions(+), 25 deletions(-) diff --git a/avmedia/Library_avmediagst.mk b/avmedia/Library_avmediagst.mk index 9eae2190b79d..a20a32b6ac46 100644 --- a/avmedia/Library_avmediagst.mk +++ b/avmedia/Library_avmediagst.mk @@ -27,6 +27,7 @@ $(eval $(call gb_Library_use_libraries,avmediagst,\ cppu \ cppuhelper \ sal \ + salhelper \ tl \ vcl \ $(gb_UWINAPI) \ diff --git a/avmedia/Library_avmediagst_0_10.mk b/avmedia/Library_avmediagst_0_10.mk index d35507612caf..10c10a001296 100644 --- a/avmedia/Library_avmediagst_0_10.mk +++ b/avmedia/Library_avmediagst_0_10.mk @@ -29,6 +29,7 @@ $(eval $(call gb_Library_use_libraries,avmediagst_0_10,\ cppu \ cppuhelper \ sal \ + salhelper \ tl \ vcl \ $(gb_UWINAPI) \ diff --git a/avmedia/source/gstreamer/gstplayer.cxx b/avmedia/source/gstreamer/gstplayer.cxx index eea5bb66400b..a6c1a878253f 100644 --- a/avmedia/source/gstreamer/gstplayer.cxx +++ b/avmedia/source/gstreamer/gstplayer.cxx @@ -19,14 +19,19 @@ #include +#include +#include #include #include +#include #include +#include #include #include #include +#include #include #include #include @@ -66,46 +71,183 @@ namespace avmedia { namespace gstreamer { namespace { +class FlagGuard { +public: + explicit FlagGuard(bool & flag): flag_(flag) { flag_ = true; } + + ~FlagGuard() { flag_ = false; } + +private: + bool & flag_; +}; + +class MissingPluginInstallerThread: public salhelper::Thread { +public: + MissingPluginInstallerThread(): Thread("MissingPluginInstaller") {} + +private: + void execute() SAL_OVERRIDE; +}; + class MissingPluginInstaller { + friend MissingPluginInstallerThread; + public: - void report(GstMessage * message); + MissingPluginInstaller(): launchNewThread_(true), inCleanUp_(false) {} + + ~MissingPluginInstaller(); + + void report(rtl::Reference const & source, GstMessage * message); + + // Player::~Player calls Player::disposing calls + // MissingPluginInstaller::detach, so do not take Player by rtl::Reference + // here (which would bump its refcount back from 0 to 1): + void detach(Player const * source); private: - DECL_STATIC_LINK(MissingPluginInstaller, install, rtl_String *); + void processQueue(); + + DECL_STATIC_LINK( + MissingPluginInstaller, launchUi, MissingPluginInstallerThread *); + osl::Mutex mutex_; std::set reported_; + std::map>> queued_; + rtl::Reference currentThread_; + std::vector currentDetails_; + std::set> currentSources_; + bool launchNewThread_; + bool inCleanUp_; }; -void MissingPluginInstaller::report(GstMessage * message) { +MissingPluginInstaller::~MissingPluginInstaller() { + osl::MutexGuard g(mutex_); + SAL_WARN_IF(currentThread_.is(), "avmedia.gstreamer", "unjoined thread"); + inCleanUp_ = true; +} + +void MissingPluginInstaller::report( + rtl::Reference const & source, GstMessage * message) +{ // assert(gst_is_missing_plugin_message(message)); gchar * det = gst_missing_plugin_message_get_installer_detail(message); - if (det != nullptr) { - std::size_t len = std::strlen(det); - if (len <= sal_uInt32(SAL_MAX_INT32)) { - OString detStr(det, len); - if (reported_.insert(detStr).second) { - rtl_string_acquire(detStr.pData); - Application::PostUserEvent( - LINK(nullptr, MissingPluginInstaller, install), - detStr.pData); - } - } else { - SAL_WARN( - "avmedia.gstreamer", "detail string too long"); - } - g_free(det); - } else { + if (det == nullptr) { SAL_WARN( "avmedia.gstreamer", "gst_missing_plugin_message_get_installer_detail failed"); + return; + } + std::size_t len = std::strlen(det); + if (len > sal_uInt32(SAL_MAX_INT32)) { + SAL_WARN("avmedia.gstreamer", "detail string too long"); + g_free(det); + return; } + OString detStr(det, len); + g_free(det); + rtl::Reference join; + rtl::Reference launch; + { + osl::MutexGuard g(mutex_); + if (reported_.find(detStr) != reported_.end()) { + return; + } + auto & i = queued_[detStr]; + bool fresh = i.empty(); + i.insert(source); + if (!(fresh && launchNewThread_)) { + return; + } + join = currentThread_; + currentThread_ = new MissingPluginInstallerThread; + { + FlagGuard f(inCleanUp_); + currentSources_.clear(); + } + processQueue(); + launchNewThread_ = false; + launch = currentThread_; + } + if (join.is()) { + join->join(); + } + launch->acquire(); + Application::PostUserEvent( + LINK(this, MissingPluginInstaller, launchUi), launch.get()); } -IMPL_STATIC_LINK(MissingPluginInstaller, install, rtl_String *, data) { - OString res(data, SAL_NO_ACQUIRE); - gst_pb_utils_init(); // not thread safe - char * args[]{const_cast(res.getStr()), nullptr}; - gst_install_plugins_sync(args, nullptr); +void eraseSource(std::set> & set, Player const * source) +{ + auto i = std::find_if( + set.begin(), set.end(), + [source](rtl::Reference const & el) { + return el.get() == source; + }); + if (i != set.end()) { + set.erase(i); + } +} + +void MissingPluginInstaller::detach(Player const * source) { + rtl::Reference join; + { + osl::MutexGuard g(mutex_); + if (inCleanUp_) { + // Guard against ~MissingPluginInstaller with erroneously un-joined + // currentThread_ (thus non-empty currentSources_) calling + // destructor of currentSources_, calling ~Player, calling here, + // which would use currentSources_ while it is already being + // destroyed: + return; + } + for (auto i = queued_.begin(); i != queued_.end();) { + eraseSource(i->second, source); + if (i->second.empty()) { + i = queued_.erase(i); + } else { + ++i; + } + } + if (currentThread_.is()) { + assert(!currentSources_.empty()); + eraseSource(currentSources_, source); + if (currentSources_.empty()) { + join = currentThread_; + currentThread_.clear(); + launchNewThread_ = true; + } + } + } + if (join.is()) { + // missing cancelability of gst_install_plugins_sync + join->join(); + } +} + +void MissingPluginInstaller::processQueue() { + assert(!queued_.empty()); + assert(currentDetails_.empty()); + for (auto i = queued_.begin(); i != queued_.end(); ++i) { + reported_.insert(i->first); + currentDetails_.push_back(i->first); + currentSources_.insert(i->second.begin(), i->second.end()); + } + queued_.clear(); +} + +IMPL_STATIC_LINK( + MissingPluginInstaller, launchUi, MissingPluginInstallerThread *, thread) +{ + rtl::Reference ref(thread, SAL_NO_ACQUIRE); + gst_pb_utils_init(); + // not thread safe; hopefully fine to consistently call from our event + // loop (which is the only reason to have this + // Application::PostUserEvent diversion, in case + // MissingPluginInstaller::report might be called from outside our event + // loop), and hopefully fine to call gst_is_missing_plugin_message and + // gst_missing_plugin_message_get_installer_detail before calling + // gst_pb_utils_init + ref->launch(); return 0; } @@ -113,6 +255,32 @@ struct TheMissingPluginInstaller: public rtl::Static {}; +void MissingPluginInstallerThread::execute() { + MissingPluginInstaller & inst = TheMissingPluginInstaller::get(); + for (;;) { + std::vector details; + { + osl::MutexGuard g(inst.mutex_); + assert(!inst.currentDetails_.empty()); + details.swap(inst.currentDetails_); + } + std::vector args; + for (auto const & i: details) { + args.push_back(const_cast(i.getStr())); + } + args.push_back(nullptr); + gst_install_plugins_sync(args.data(), nullptr); + { + osl::MutexGuard g(inst.mutex_); + if (inst.queued_.empty() || inst.launchNewThread_) { + inst.launchNewThread_ = true; + break; + } + inst.processQueue(); + } + } +} + } // - Player - @@ -166,6 +334,8 @@ Player::~Player() void SAL_CALL Player::disposing() { + TheMissingPluginInstaller::get().detach(this); + ::osl::MutexGuard aGuard(m_aMutex); stop(); @@ -387,7 +557,11 @@ GstBusSyncReply Player::processSyncMessage( GstMessage *message ) } #endif } else if (gst_is_missing_plugin_message(message)) { - TheMissingPluginInstaller::get().report(message); + TheMissingPluginInstaller::get().report(this, message); + if( mnWidth == 0 ) { + // an error occurred, set condition so that OOo thread doesn't wait for us + maSizeCondition.set(); + } } else if( GST_MESSAGE_TYPE( message ) == GST_MESSAGE_ERROR ) { DBG( "Error !\n" ); if( mnWidth == 0 ) { -- cgit n> LibreOffice 核心代码仓库文档基金会
summaryrefslogtreecommitdiff
AgeCommit message (Expand)Author
2016-03-15vcl: move graph.[hx]xx to graphic.[hc]xxChris Sherlock