[Libreoffice-commits] core.git: avmedia/Library_avmediagst_0_10.mk avmedia/Library_avmediagst.mk avmedia/source

Stephan Bergmann sbergman at redhat.com
Wed May 20 05:42:09 PDT 2015


 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(-)

New commits:
commit 5f296f9b3e9f19a44e1a391b31a51a66b659050c
Author: Stephan Bergmann <sbergman at redhat.com>
Date:   Wed May 20 14:41:31 2015 +0200

    Fix reporting missing GStreamer plugins
    
    Change-Id: I99b5994b53a5768b4c0aa8dbd6f54b13b23b333a

diff --git a/avmedia/Library_avmediagst.mk b/avmedia/Library_avmediagst.mk
index 9eae219..a20a32b 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 d355076..10c10a0 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 eea5bb6..a6c1a87 100644
--- a/avmedia/source/gstreamer/gstplayer.cxx
+++ b/avmedia/source/gstreamer/gstplayer.cxx
@@ -19,14 +19,19 @@
 
 #include <sal/config.h>
 
+#include <algorithm>
+#include <cassert>
 #include <cstddef>
 #include <cstring>
+#include <map>
 #include <set>
+#include <vector>
 #include <math.h>
 
 #include <cppuhelper/supportsservice.hxx>
 
 #include <rtl/string.hxx>
+#include <salhelper/thread.hxx>
 #include <vcl/svapp.hxx>
 #include <vcl/syschild.hxx>
 #include <vcl/sysdata.hxx>
@@ -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<Player> 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<OString> reported_;
+    std::map<OString, std::set<rtl::Reference<Player>>> queued_;
+    rtl::Reference<MissingPluginInstallerThread> currentThread_;
+    std::vector<OString> currentDetails_;
+    std::set<rtl::Reference<Player>> 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<Player> 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<MissingPluginInstallerThread> join;
+    rtl::Reference<MissingPluginInstallerThread> 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<char *>(res.getStr()), nullptr};
-    gst_install_plugins_sync(args, nullptr);
+void eraseSource(std::set<rtl::Reference<Player>> & set, Player const * source)
+{
+    auto i = std::find_if(
+        set.begin(), set.end(),
+        [source](rtl::Reference<Player> const & el) {
+            return el.get() == source;
+        });
+    if (i != set.end()) {
+        set.erase(i);
+    }
+}
+
+void MissingPluginInstaller::detach(Player const * source) {
+    rtl::Reference<MissingPluginInstallerThread> 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<MissingPluginInstallerThread> 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<MissingPluginInstaller, TheMissingPluginInstaller>
 {};
 
+void MissingPluginInstallerThread::execute() {
+    MissingPluginInstaller & inst = TheMissingPluginInstaller::get();
+    for (;;) {
+        std::vector<OString> details;
+        {
+            osl::MutexGuard g(inst.mutex_);
+            assert(!inst.currentDetails_.empty());
+            details.swap(inst.currentDetails_);
+        }
+        std::vector<char *> args;
+        for (auto const & i: details) {
+            args.push_back(const_cast<char *>(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 ) {


More information about the Libreoffice-commits mailing list