Updated plugins to use new plugin architecture

Changed QMediaPluginLoader to use QFactoryLoader instead of QPluginLoader
and used metadata to get keys.
Removed QAudioPluginLoader and changed audio classes to use instead use
QMediaPluginLoader.
The plugins must include the Q_PLUGIN_METADATA macro, and no longer use
the Q_PLUGIN_EXPORT/Q_PLUGIN_EXPORT2 macros.
A json file has been added for each plugin which can contain metadata
which is available to the plugin loader before the plugin is actually
loaded, and is used to read the keys for the plugin, e.g. supported
services.
QFactoryInterface will be deprecated and has been removed from all
plugins.

Change-Id: I035b82f9c9c65717bebf704d560ea8f891df21da
Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
Reviewed-by: Dmytro Poplavskiy <dmytro.poplavskiy@nokia.com>
This commit is contained in:
Jonas Rabbe
2012-03-14 13:02:32 +10:00
committed by Qt by Nokia
parent 61c09d1614
commit a8ba6e3c7f
61 changed files with 630 additions and 745 deletions

View File

@@ -41,191 +41,105 @@
#include "qmediapluginloader_p.h"
#include <QtCore/qcoreapplication.h>
#include <QtCore/qpluginloader.h>
#include <QtCore/qdir.h>
#include <QtCore/qdebug.h>
#include <QtCore/qjsonarray.h>
#include <private/qfactoryloader_p.h>
#include "qmediaserviceproviderplugin.h"
#if defined(Q_OS_MAC)
# include <CoreFoundation/CoreFoundation.h>
#endif
QT_BEGIN_NAMESPACE
typedef QMap<QString,QObjectList> ObjectListMap;
Q_GLOBAL_STATIC(ObjectListMap, staticMediaPlugins);
QMediaPluginLoader::QMediaPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity):
QMediaPluginLoader::QMediaPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity caseSensitivity):
m_iid(iid)
{
m_location = QString::fromLatin1("/%1").arg(location);
load();
m_factoryLoader = new QFactoryLoader(m_iid, m_location, caseSensitivity);
loadMetadata();
}
QMediaPluginLoader::~QMediaPluginLoader()
{
delete m_factoryLoader;
}
QStringList QMediaPluginLoader::keys() const
{
return m_instances.keys();
return m_metadata.keys();
}
QObject* QMediaPluginLoader::instance(QString const &key)
{
return m_instances.value(key).value(0);
if (!m_metadata.contains(key))
return 0;
int idx = m_metadata.value(key).first().value(QStringLiteral("index")).toDouble();
if (idx < 0)
return 0;
return m_factoryLoader->instance(idx);
}
QList<QObject*> QMediaPluginLoader::instances(QString const &key)
{
return m_instances.value(key);
}
if (!m_metadata.contains(key))
return QList<QObject*>();
//to be used for testing purposes only
void QMediaPluginLoader::setStaticPlugins(const QString &location, const QObjectList& objects)
{
staticMediaPlugins()->insert(QString::fromLatin1("/%1").arg(location), objects);
}
QList<QObject *> objects;
foreach (QJsonObject jsonobj, m_metadata.value(key)) {
int idx = jsonobj.value(QStringLiteral("index")).toDouble();
if (idx < 0)
continue;
QStringList QMediaPluginLoader::availablePlugins() const
{
QStringList paths;
QStringList plugins;
#if defined(Q_OS_MAC)
QString imageSuffix(qgetenv("DYLD_IMAGE_SUFFIX"));
// Bundle plugin directory
CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle != 0) {
CFURLRef baseUrl = CFBundleCopyBundleURL(mainBundle);
CFURLRef pluginUrlPart = CFBundleCopyBuiltInPlugInsURL(mainBundle);
CFStringRef pluginPathPart = CFURLCopyFileSystemPath(pluginUrlPart, kCFURLPOSIXPathStyle);
CFURLRef pluginUrl = CFURLCreateCopyAppendingPathComponent(0, baseUrl, pluginPathPart, true);
CFStringRef pluginPath = CFURLCopyFileSystemPath(pluginUrl, kCFURLPOSIXPathStyle);
CFIndex length = CFStringGetLength(pluginPath);
UniChar buffer[length];
CFStringGetCharacters(pluginPath, CFRangeMake(0, length), buffer);
paths << QString(reinterpret_cast<const QChar *>(buffer), length);
CFRelease(pluginPath);
CFRelease(pluginUrl);
CFRelease(pluginPathPart);
CFRelease(pluginUrlPart);
CFRelease(baseUrl);
}
#endif
// Qt paths
paths << QCoreApplication::libraryPaths();
foreach (const QString &path, paths) {
QDir typeDir(path + m_location);
foreach (const QString &file, typeDir.entryList(QDir::Files, QDir::Name)) {
#if defined(Q_OS_MAC)
if (!imageSuffix.isEmpty()) { // Only add appropriate images
if (file.lastIndexOf(imageSuffix, -6) == -1)
continue;
} else {
int foundSuffix = file.lastIndexOf(QLatin1String("_debug.dylib"));
if (foundSuffix == -1) {
foundSuffix = file.lastIndexOf(QLatin1String("_profile.dylib"));
}
if (foundSuffix != -1) {
/*
If this is a "special" version of the plugin, prefer the release
version, where available.
Avoids warnings like:
objc[23101]: Class TransparentQTMovieView is implemented in both
libqqt7engine_debug.dylib and libqqt7engine.dylib. One of the two
will be used. Which one is undefined.
Note, this code relies on QDir::Name sorting!
*/
QString preferred =
typeDir.absoluteFilePath(file.left(foundSuffix) + QLatin1String(".dylib"));
if (plugins.contains(preferred)) {
continue;
}
}
}
#elif defined(Q_OS_UNIX)
// Ignore separate debug files
if (file.endsWith(QLatin1String(".debug")))
continue;
#elif defined(Q_OS_WIN)
// Ignore non-dlls
if (!file.endsWith(QLatin1String(".dll"), Qt::CaseInsensitive))
continue;
#endif
plugins << typeDir.absoluteFilePath(file);
QObject *object = m_factoryLoader->instance(idx);
if (!objects.contains(object)) {
objects.append(object);
}
}
return plugins;
return objects;
}
void QMediaPluginLoader::load()
void QMediaPluginLoader::loadMetadata()
{
if (!m_instances.isEmpty())
return;
#if !defined QT_NO_DEBUG
const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0;
#endif
if (staticMediaPlugins() && staticMediaPlugins()->contains(m_location)) {
foreach(QObject *o, staticMediaPlugins()->value(m_location)) {
if (o != 0 && o->qt_metacast(m_iid) != 0) {
QFactoryInterface* p = qobject_cast<QFactoryInterface*>(o);
if (p != 0) {
foreach (QString const &key, p->keys())
m_instances[key].append(o);
}
}
}
} else {
QSet<QString> loadedPlugins;
#if !defined QT_NO_DEBUG
if (showDebug)
qDebug() << "QMediaPluginLoader: loading metadata for iid " << m_iid << " at location " << m_location;
#endif
foreach (const QString &plugin, availablePlugins()) {
QString fileName = QFileInfo(plugin).fileName();
//don't try to load plugin with the same name if it's already loaded
if (loadedPlugins.contains(fileName)) {
if (!m_metadata.isEmpty()) {
#if !defined QT_NO_DEBUG
if (showDebug)
qDebug() << "QMediaPluginLoader: already loaded metadata, returning";
#endif
return;
}
QList<QJsonObject> meta = m_factoryLoader->metaData();
for (int i = 0; i < meta.size(); i++) {
QJsonObject jsonobj = meta.at(i).value(QStringLiteral("MetaData")).toObject();
jsonobj.insert(QStringLiteral("index"), i);
#if !defined QT_NO_DEBUG
if (showDebug)
qDebug() << "QMediaPluginLoader: Inserted index " << i << " into metadata: " << jsonobj;
#endif
QJsonArray arr = jsonobj.value(QStringLiteral("Keys")).toArray();
foreach (QJsonValue value, arr) {
QString key = value.toString();
if (!m_metadata.contains(key)) {
#if !defined QT_NO_DEBUG
if (showDebug)
qDebug() << "Skip loading plugin" << plugin;
qDebug() << "QMediaPluginLoader: Inserting new list for key: " << key;
#endif
continue;
m_metadata.insert(key, QList<QJsonObject>());
}
QPluginLoader loader(plugin);
QObject *o = loader.instance();
if (o != 0 && o->qt_metacast(m_iid) != 0) {
QFactoryInterface* p = qobject_cast<QFactoryInterface*>(o);
if (p != 0) {
foreach (const QString &key, p->keys())
m_instances[key].append(o);
loadedPlugins.insert(fileName);
#if !defined QT_NO_DEBUG
if (showDebug)
qDebug() << "Loaded plugin" << plugin << "services:" << p->keys();
#endif
}
continue;
} else {
#if !defined QT_NO_DEBUG
if (showDebug)
qWarning() << "QMediaPluginLoader: Failed to load plugin: " << plugin << loader.errorString();
#endif
}
loader.unload();
m_metadata[key].append(jsonobj);
}
}
}