[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    =?utf-8?q?=5Bphonon-gstreamer=5D_gstreamer=3A_Move_swaths_of_plu?=
From:       Trever Fischer <wm161 () wm161 ! net>
Date:       2011-03-01 14:39:26
Message-ID: 20110301143926.587A8A60CE () git ! kde ! org
[Download RAW message or body]

Git commit ae379e2c11a9c07bac311e57b2ca2e67e3040d80 by Trever Fischer.
Committed on 01/03/2011 at 15:34.
Pushed by tdfischer into branch 'master'.

Move swaths of plugin installation code to the PluginInstaller

Cleanup is probably needed. The mediaobject is still pretty freaking
huge; its hard to catch everything. Plugin installation still behaves as
previously (broken in places, but works for mp3s and rsndvdbin).

M  +40   -120  gstreamer/mediaobject.cpp     
M  +5    -9    gstreamer/mediaobject.h     
M  +145  -4    gstreamer/plugininstaller.cpp     
M  +35   -1    gstreamer/plugininstaller.h     

http://commits.kde.org/phonon-gstreamer/ae379e2c11a9c07bac311e57b2ca2e67e3040d80

diff --git a/gstreamer/mediaobject.cpp b/gstreamer/mediaobject.cpp
index 10a1038..05aa24b 100644
--- a/gstreamer/mediaobject.cpp
+++ b/gstreamer/mediaobject.cpp
@@ -87,6 +87,7 @@ MediaObject::MediaObject(Backend *backend, QObject *parent)
         , m_currentTitle(1)
         , m_pendingTitle(1)
         , m_installingPlugin(true)
+        , m_installer(new PluginInstaller(this))
 {
     qRegisterMetaType<GstCaps*>("GstCaps*");
     qRegisterMetaType<State>("State");
@@ -112,6 +113,10 @@ MediaObject::MediaObject(Backend *backend, QObject *parent)
         g_signal_connect(bus, "sync-message::warning", G_CALLBACK(cb_warning), \
                this);
         g_signal_connect(bus, "sync-message::error", G_CALLBACK(cb_error), this);
         connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick()));
+
+        connect(m_installer, SIGNAL(failure(const QString&)), this, \
SLOT(pluginInstallFailure(const QString&))); +        connect(m_installer, \
SIGNAL(started()), this, SLOT(pluginInstallStarted())); +        connect(m_installer, \
SIGNAL(success()), this, SLOT(pluginInstallComplete()));  }
     connect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
             this, SLOT(notifyStateChange(Phonon::State, Phonon::State)));
@@ -208,111 +213,6 @@ void MediaObject::cb_newpad (GstElement *decodebin,
     media->newPadAvailable(pad);
 }
 
-#ifdef PLUGIN_INSTALL_API
-void MediaObject::pluginInstallationResult(GstInstallPluginsReturn result)
-{
-    if (!m_installingPlugin) {
-        // Changed media while the installer was working, so we just do not care \
                what happened.
-        return;
-    }
-    bool wasInstalling = m_installingPlugin;
-    m_installingPlugin = false;
-    bool canPlay = (m_hasAudio || m_videoStreamFound);
-    Phonon::ErrorType error = canPlay ? Phonon::NormalError : Phonon::FatalError;
-    switch(result) {
-    case GST_INSTALL_PLUGINS_INVALID:
-        setError(QString(tr("Phonon attempted to install an invalid codec name.")));
-        break;
-    case GST_INSTALL_PLUGINS_CRASHED:
-        setError(QString(tr("The codec installer crashed.")), error);
-        break;
-    case GST_INSTALL_PLUGINS_NOT_FOUND:
-        setError(QString(tr("The required codec could not be found for \
                installation.")), error);
-        break;
-    case GST_INSTALL_PLUGINS_ERROR:
-        setError(QString(tr("An unspecified error occurred during codec \
                installation.")), error);
-        break;
-    case GST_INSTALL_PLUGINS_PARTIAL_SUCCESS:
-        setError(QString(tr("Not all codecs could be installed.")), error);
-        break;
-    case GST_INSTALL_PLUGINS_USER_ABORT:
-        setError(QString(tr("User aborted codec installation")), error);
-        break;
-    //These four should never ever be passed in.
-    //If they have, gstreamer has probably imploded in on itself.
-    case GST_INSTALL_PLUGINS_STARTED_OK:
-    case GST_INSTALL_PLUGINS_INTERNAL_FAILURE:
-    case GST_INSTALL_PLUGINS_HELPER_MISSING:
-    case GST_INSTALL_PLUGINS_INSTALL_IN_PROGRESS:
-    //But this one is OK.
-    case GST_INSTALL_PLUGINS_SUCCESS:
-        m_backend->logMessage("Updating registry");
-        if (gst_update_registry()) {
-            m_backend->logMessage("Registry updated failed");
-        }
-        if (wasInstalling) {
-            setSource(source());
-            play();
-        }
-        break;
-    }
-}
-
-void MediaObject::pluginInstallationDone(GstInstallPluginsReturn result, gpointer \
                userData)
-{
-    QPointer<MediaObject> *that = static_cast<QPointer<MediaObject>*>(userData);
-    if (*that) {
-        qRegisterMetaType<GstInstallPluginsReturn>("GstInstallPluginsReturn");
-        QMetaObject::invokeMethod(*that, "pluginInstallationResult", \
                Qt::QueuedConnection, Q_ARG(GstInstallPluginsReturn, result));
-    }
-}
-#endif // PLUGIN_INSTALL_API
-
-void MediaObject::installMissingCodecs()
-{
-    if (m_missingCodecs.size() > 0) {
-        bool canPlay = (m_hasAudio || m_videoStreamFound);
-        Phonon::ErrorType error = canPlay ? Phonon::NormalError : \
                Phonon::FatalError;
-#ifdef PLUGIN_INSTALL_API
-        GstInstallPluginsContext *ctx = gst_install_plugins_context_new();
-        QWidget *activeWindow = QApplication::activeWindow();
-        if (activeWindow) {
-            gst_install_plugins_context_set_xid(ctx, \
                static_cast<int>(activeWindow->winId()));
-        }
-        gchar *details[2];
-        QByteArray missingCodec = m_missingCodecs.first().toLocal8Bit();
-        details[0] = missingCodec.data();
-        details[1] = NULL;
-        GstInstallPluginsReturn status;
-
-        status = gst_install_plugins_async(details, ctx, pluginInstallationDone, new \
                QPointer<MediaObject>(this));
-        gst_install_plugins_context_free(ctx);
-
-        if (status != GST_INSTALL_PLUGINS_STARTED_OK) {
-            if (status == GST_INSTALL_PLUGINS_HELPER_MISSING)
-                setError(QString(tr("Missing codec helper script assistant.")), \
                Phonon::FatalError);
-            else
-                setError(QString(tr("Plugin codec installation failed for plugin: \
                %1"))
-                        .arg(m_missingCodecs[0].split('|')[3]), error);
-        } else {
-            m_installingPlugin = true;
-            setState(Phonon::LoadingState);
-        }
-        m_missingCodecs.clear();
-#else
-        QString codecs = m_missingCodecs.join(", ");
-
-        if (error == Phonon::NormalError && m_hasVideo && !m_videoStreamFound) {
-            m_hasVideo = false;
-            emit hasVideoChanged(false);
-        }
-        setError(QString(tr("A required GStreamer plugin is missing. You need to \
install the following plugin(s) to play this content: %0"), "", \
                codecs.size()).arg(codecs), error);
-        m_missingCodecs.clear();
-#endif
-    }
-}
-
-
 void MediaObject::cb_unknown_type (GstElement *decodebin, GstPad *pad, GstCaps \
*caps, gpointer data)  {
     Q_UNUSED(decodebin);
@@ -320,8 +220,7 @@ void MediaObject::cb_unknown_type (GstElement *decodebin, GstPad \
*pad, GstCaps *  MediaObject *media = static_cast<MediaObject*>(data);
     Q_ASSERT(media);
 
-    media->addMissingCodecName(PluginInstaller::buildInstallationString(caps, \
                PluginInstaller::Codec));
-
+    media->m_installer->addPlugin(caps, PluginInstaller::Codec);
 }
 
 static void notifyVideoCaps(GObject *obj, GParamSpec *, gpointer data)
@@ -461,26 +360,20 @@ bool MediaObject::createPipefromDVD(const MediaSource &source)
     // video output stream. The audio and video streams are then funneled into
     // the audioGraph and videoGraph bins by way of connectAudio and decodebin,
     // respectively.
-
+    
+    m_installer->addPlugin("rsndvdbin", PluginInstaller::Element);
+    m_installer->addPlugin("dvdspu", PluginInstaller::Element);
+    if (m_installer->checkInstalledPlugins() != PluginInstaller::Installed)
+        return false;
     m_datasource = gst_bin_new(NULL);
     gst_bin_add(GST_BIN(m_pipeline), m_datasource);
 
     GstElement *dvdsrc = gst_element_factory_make("rsndvdbin", NULL);
-    if (!dvdsrc) {
-        addMissingCodecName( PluginInstaller::buildInstallationString("rsndvdbin", \
                PluginInstaller::Element) );
-        installMissingCodecs();
-        return false;
-    }
 
     // Check for the dvdspu element from gst-plugins-bad before continuing.
     // Fedora keeps rsndvdbin and dvdspu in separate packages for some reason.
     GstElement *spu = gst_element_factory_make("dvdspu", NULL);
 
-    if (!spu) {
-        addMissingCodecName( PluginInstaller::buildInstallationString("dvdspu", \
                PluginInstaller::Element) );
-        installMissingCodecs();
-        return false;
-    }
     gst_bin_add(GST_BIN(m_datasource), dvdsrc);
 
     QByteArray mediaDevice = QFile::encodeName(source.deviceName());
@@ -1114,7 +1007,7 @@ void MediaObject::setSource(const MediaSource &source)
     m_source = source;
     emit currentSourceChanged(m_source);
     m_previousTickTime = -1;
-    m_missingCodecs.clear();
+    m_installer->reset();
 
     // Go into to loading state
     changeState(Phonon::LoadingState);
@@ -1488,7 +1381,7 @@ void MediaObject::handleErrorMessage(GstMessage *gstMessage)
         }
     } else if ((err->domain == GST_CORE_ERROR && err->code == \
                GST_CORE_ERROR_MISSING_PLUGIN)
             || (err->domain == GST_STREAM_ERROR && err->code == \
                GST_STREAM_ERROR_CODEC_NOT_FOUND)) {
-        installMissingCodecs();
+        m_installer->checkInstalledPlugins();
     } else if (!(err->domain == GST_STREAM_ERROR && m_installingPlugin)) {
         setError(err->message, Phonon::FatalError);
     }
@@ -2037,6 +1930,33 @@ void MediaObject::setTrack(int title)
     }
 }
 
+void MediaObject::pluginInstallComplete()
+{
+    if (!m_installingPlugin)
+        return;
+
+    bool wasInstalling = m_installingPlugin;
+    m_installingPlugin = false;
+    if (wasInstalling) {
+        setSource(source());
+        play();
+    }
+}
+
+void MediaObject::pluginInstallStarted()
+{
+    setState(Phonon::LoadingState);
+    m_installingPlugin = true;
+}
+
+void MediaObject::pluginInstallFailure(const QString &msg)
+{
+    m_installingPlugin = false;
+    bool canPlay = (m_hasAudio || m_videoStreamFound);
+    Phonon::ErrorType error = canPlay ? Phonon::NormalError : Phonon::FatalError;
+    setError(msg, error);
+}
+
 } // ns Gstreamer
 } // ns Phonon
 
diff --git a/gstreamer/mediaobject.h b/gstreamer/mediaobject.h
index 0b88431..044a1ff 100644
--- a/gstreamer/mediaobject.h
+++ b/gstreamer/mediaobject.h
@@ -46,6 +46,7 @@ class VideoWidget;
 class AudioPath;
 class VideoPath;
 class AudioOutput;
+class PluginInstaller;
 
 class MediaObject : public QObject, public MediaObjectInterface
 #ifndef QT_NO_PHONON_MEDIACONTROLLER
@@ -163,7 +164,6 @@ public:
     static gboolean cb_warning(GstBus *bus, GstMessage *msg, gpointer data);
     static gboolean cb_error(GstBus *bus, GstMessage *msg, gpointer data);
 
-    void addMissingCodecName(const QString &codec) { m_missingCodecs.append(codec); \
}  void invalidateGraph();
 
     static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, \
gpointer data); @@ -233,15 +233,14 @@ protected:
     }
 
 private Q_SLOTS:
-    void installMissingCodecs();
     void getStreamInfo();
     void emitTick();
     void beginPlay();
     void setVideoCaps(GstCaps *caps);
     void notifyStateChange(Phonon::State newstate, Phonon::State oldstate);
-#ifdef PLUGIN_INSTALL_API
-    void pluginInstallationResult(GstInstallPluginsReturn result);
-#endif // PLUGIN_INSTALL_API
+    void pluginInstallComplete();
+    void pluginInstallFailure(const QString &msg);
+    void pluginInstallStarted();
 
 private:
     // GStreamer specific :
@@ -258,9 +257,6 @@ private:
     void _iface_setCurrentTitle(int title);
     void setTrack(int title);
 
-    // Plugin API callback
-    static void pluginInstallationDone(GstInstallPluginsReturn result, gpointer \
                userData);
-
     bool m_resumeState;
     State m_oldState;
     quint64 m_oldPos;
@@ -305,13 +301,13 @@ private:
     GstElement *m_videoGraph;
     int m_previousTickTime;
     bool m_resetNeeded;
-    QStringList m_missingCodecs;
     QMultiMap<QString, QString> m_metaData;
     bool m_autoplayTitles;
     int m_availableTitles;
     int m_currentTitle;
     int m_pendingTitle;
     bool m_installingPlugin;
+    PluginInstaller *m_installer;
 };
 }
 } //namespace Phonon::Gstreamer
diff --git a/gstreamer/plugininstaller.cpp b/gstreamer/plugininstaller.cpp
index f716729..5cac431 100644
--- a/gstreamer/plugininstaller.cpp
+++ b/gstreamer/plugininstaller.cpp
@@ -16,8 +16,14 @@
 */
 
 #include "plugininstaller.h"
+#include <gst/gst.h>
 #include <QtCore/QCoreApplication>
+#include <QtGui/QApplication>
+#include <QtGui/QWidget>
 #include <QtCore/QLibrary>
+#include <QtCore/QPointer>
+#include <QtCore/QMetaType>
+#include <QtCore/QDebug>
 
 QT_BEGIN_NAMESPACE
 
@@ -83,8 +89,7 @@ QString PluginInstaller::description(const GstCaps *caps, \
PluginType type)  g_free (pluginDesc);
         return pluginStr;
     }
-    GstStructure *str = gst_caps_get_structure (caps, 0);
-    return QString::fromUtf8(gst_structure_get_name (str));;
+    return getCapType(caps);
 }
 
 QString PluginInstaller::description(const gchar *name, PluginType type)
@@ -129,12 +134,11 @@ QString PluginInstaller::buildInstallationString(const GstCaps \
*caps, PluginType  return 0;
     }
 
-    GstStructure *str = gst_caps_get_structure(caps, 0);
     return QString("gstreamer|0.10|%0|%1|%2-%3")
         .arg( qApp->applicationName() )
         .arg( description(caps, type) )
         .arg( descType )
-        .arg( QString::fromUtf8(gst_structure_get_name(str)) );
+        .arg( getCapType(caps) );
 }
 
 QString PluginInstaller::buildInstallationString(const gchar *name, PluginType type)
@@ -154,7 +158,144 @@ QString PluginInstaller::buildInstallationString(const gchar \
                *name, PluginType t
         .arg( name );
 }
 
+PluginInstaller::PluginInstaller(QObject *parent)
+    : QObject(parent)
+{
+}
+
+void PluginInstaller::addPlugin(const QString &name, PluginType type)
+{
+    m_pluginList.insert(name, type);
+}
+
+void PluginInstaller::addPlugin(const GstCaps *caps, PluginType type)
+{
+    m_capList.insert(gst_caps_copy(caps), type);
+}
+
+#ifdef PLUGIN_INSTALL_API
+void PluginInstaller::run()
+{
+    GstInstallPluginsContext *ctx = gst_install_plugins_context_new();
+    QWidget *activeWindow = QApplication::activeWindow();
+    if (activeWindow) {
+        gst_install_plugins_context_set_xid(ctx, \
static_cast<int>(activeWindow->winId())); +    }
+    gchar *details[m_pluginList.size()+m_capList.size()+1];
+    int i = 0;
+    foreach(QString plugin, m_pluginList.keys()) {
+        details[i] = strdup(buildInstallationString(plugin.toLocal8Bit().data(), \
m_pluginList[plugin]).toLocal8Bit().data()); +        i++;
+    }
+    foreach(GstCaps *caps, m_capList.keys()) {
+        details[i] = strdup(buildInstallationString(caps, \
m_capList[caps]).toLocal8Bit().data()); +        i++;
+    }
+    details[i] = NULL;
+
+    GstInstallPluginsReturn status;
+    status = gst_install_plugins_async(details, ctx, pluginInstallationDone, new \
QPointer<PluginInstaller>(this)); +    gst_install_plugins_context_free(ctx);
+    if (status != GST_INSTALL_PLUGINS_STARTED_OK) {
+        if (status == GST_INSTALL_PLUGINS_HELPER_MISSING)
+            emit failure(tr("Missing codec helper script assistant."));
+        else
+            emit failure(tr("Plugin codec installation failed."));
+    } else {
+        emit started();
+    }
+    for(i;i>0;i--)
+        free(details[i]);
+    reset();
+}
+
+void PluginInstaller::pluginInstallationDone(GstInstallPluginsReturn result, \
gpointer data) +{
+    QPointer<PluginInstaller> *that = static_cast<QPointer<PluginInstaller>*>(data);
+    if (*that) {
+        qRegisterMetaType<GstInstallPluginsReturn>("GstInstallPluginsReturn");
+        (*that)->pluginInstallationResult(result);
+    }
+}
+
+void PluginInstaller::pluginInstallationResult(GstInstallPluginsReturn result)
+{
+    switch(result) {
+        case GST_INSTALL_PLUGINS_INVALID:
+            emit failure(tr("Phonon attempted to install an invalid codec name."));
+            break;
+        case GST_INSTALL_PLUGINS_CRASHED:
+            emit failure(tr("The codec installer crashed."));
+            break;
+        case GST_INSTALL_PLUGINS_NOT_FOUND:
+            emit failure(tr("The required codec could not be found for \
installation.")); +            break;
+        case GST_INSTALL_PLUGINS_ERROR:
+            emit failure(tr("An unspecified error occurred during codec \
installation.")); +            break;
+        case GST_INSTALL_PLUGINS_PARTIAL_SUCCESS:
+            emit failure(tr("Not all codecs could be installed."));
+            break;
+        case GST_INSTALL_PLUGINS_USER_ABORT:
+            emit failure(tr("User aborted codec installation"));
+            break;
+        //These four should never ever be passed in.
+        //If they have, gstreamer has probably imploded in on itself.
+        case GST_INSTALL_PLUGINS_STARTED_OK:
+        case GST_INSTALL_PLUGINS_INTERNAL_FAILURE:
+        case GST_INSTALL_PLUGINS_HELPER_MISSING:
+        case GST_INSTALL_PLUGINS_INSTALL_IN_PROGRESS:
+        //But this one is OK.
+        case GST_INSTALL_PLUGINS_SUCCESS:
+            if (!gst_update_registry()) {
+                emit failure(tr("Could not update plugin registry after update."));
+            } else {
+                emit success();
+            }
+            break;
+    }
+}
+#endif
+
+PluginInstaller::InstallStatus PluginInstaller::checkInstalledPlugins()
+{
+    bool allFound = true;
+    foreach(QString plugin, m_pluginList.keys()) {
+        if (!gst_default_registry_check_feature_version(plugin.toLocal8Bit().data(), \
0, 10, 0)) { +            allFound = false;
+            break;
+        }
+    }
+    if (!allFound || m_capList.size() > 0) {
+#ifdef PLUGIN_INSTALL_API
+        run();
+        return Installing;
+#else
+        return Missing;
+#endif
+    } else {
+        return Installed;
+    }
+}
+
+QString PluginInstaller::getCapType(const GstCaps *caps)
+{
+    GstStructure *str = gst_caps_get_structure (caps, 0);
+    return QString::fromUtf8(gst_structure_get_name (str));;
+}
+
+void PluginInstaller::reset()
+{
+    foreach(GstCaps *caps, m_capList.keys()) {
+        gst_caps_unref(caps);
+    }
+    m_capList.clear();
+    m_pluginList.clear();
+}
+
 } // ns Gstreamer
 } // ns Phonon
 
 QT_END_NAMESPACE
+
+#include "moc_plugininstaller.cpp"
diff --git a/gstreamer/plugininstaller.h b/gstreamer/plugininstaller.h
index e2a1191..d79e17d 100644
--- a/gstreamer/plugininstaller.h
+++ b/gstreamer/plugininstaller.h
@@ -19,7 +19,11 @@
 #define Phonon_GSTREAMER_PLUGININSTALLER_H
 
 #include "common.h"
+#include <QtCore/QObject>
 #include <gst/gstcaps.h>
+#include <gst/pbutils/install-plugins.h>
+#include "phonon-config-gstreamer.h"
+
 
 QT_BEGIN_NAMESPACE
 
@@ -40,7 +44,8 @@ typedef gchar* (*Ptr_gst_pb_utils_get_codec_description)(const \
                GstCaps *);
  * A class to help with installing missing gstreamer plugins
  */
 
-class PluginInstaller {
+class PluginInstaller : public QObject {
+    Q_OBJECT
     public: 
         enum PluginType {
             Source,
@@ -51,19 +56,48 @@ class PluginInstaller {
             Codec
         };
 
+        enum InstallStatus {
+            Idle,
+            Installed,
+            Installing,
+            Missing
+        };
+
+        PluginInstaller(QObject *parent = 0);
+
+        void addPlugin(const QString &name, PluginType type);
+        void addPlugin(const GstCaps *caps, PluginType type);
+
+        InstallStatus checkInstalledPlugins();
+#ifdef PLUGIN_INSTALL_API
+        static void pluginInstallationDone(GstInstallPluginsReturn result, gpointer \
data); +        void pluginInstallationResult(GstInstallPluginsReturn result);
+        void run();
+#endif
+        void reset();
+
         /**
          * Returns the translated, user-friendly string that describes a plugin
          */
         static QString description(const gchar *name, PluginType type);
         static QString description(const GstCaps *caps, PluginType type);
 
+        static QString getCapType(const GstCaps *caps);
+
         /**
          * Builds a string suitable for passing to gst_install_plugins_*
          */
         static QString buildInstallationString(const gchar *name, PluginType type);
         static QString buildInstallationString(const GstCaps *caps, PluginType \
type);  
+    Q_SIGNALS:
+        void started();
+        void success();
+        void failure(const QString &message);
+
     private:
+        QHash<QString, PluginType> m_pluginList;
+        QHash<GstCaps *, PluginType> m_capList;
         static bool init();
         static bool s_ready;
         static Ptr_gst_pb_utils_init p_gst_pb_utils_init;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic