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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user