From kde-commits Tue Mar 01 14:39:26 2011 From: Trever Fischer Date: Tue, 01 Mar 2011 14:39:26 +0000 To: kde-commits Subject: =?utf-8?q?=5Bphonon-gstreamer=5D_gstreamer=3A_Move_swaths_of_plu?= Message-Id: <20110301143926.587A8A60CE () git ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=129899040803573 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*"); qRegisterMetaType("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 *that = static_cast*>(userData); - if (*that) { - qRegisterMetaType("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(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(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(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 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 #include +#include +#include #include +#include +#include +#include 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(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(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 *that = static_cast*>(data); + if (*that) { + qRegisterMetaType("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 #include +#include +#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 m_pluginList; + QHash m_capList; static bool init(); static bool s_ready; static Ptr_gst_pb_utils_init p_gst_pb_utils_init;