Qt Multimedia::QMediaPlayer框架源码分析
2017-09-15 23:05
337 查看
经过分析Qt Multimedia的QMediaPlayer播放器源码,发现了Qt是如何加载那些解码插件的。如果要实现自己的解码插件,让QMediaPlayer自动加载自己开发的解码插件,那么某些音视频文件在没有安装解码器的系统上也能正常播放。
首先,看看QMediaPlayer是如何工作的。以UML序列图表示:
Created with Raphaël 2.1.0ClientClientQMediaPlayerQMediaPlayerQMediaServiceProviderPluginQMediaServiceProviderPluginQMediaServiceQMediaServiceQMediaPlayerControlQMediaPlayerControlFFmpegFFmpeg传入一个音频文件或一个播放列表请求播放服务factory创建一个媒体服务product请求播放控制正在播放音频与解码器通信进行解码音频文件
QMediaPlayer调用的是QMediaPlayerControl的接口,其中QMediaPlayerControl是一个抽象类,所有接口需要自己实现。
QMediaServiceProviderPlugin是一个Qt插件,派生自QMediaServiceProviderFactoryInterface抽象接口,从它派生可生成一个“.dll”或“.a”类型的插件。然后发现,QMediaServiceProviderPlugin和QMediaService其实就是一个抽象工厂模式。QMediaService 的工作就是请求一系列不同功能的播放控制插件(解码、声音输出、声音输入等),如QAudioOutputControl、QAodioInputControl、QAudioDecoderControl、QMetaDataReaderControl、QMetaDataWriterControl等等。
而这个插件又是如何被加载并实例化的呢?
Created with Raphaël 2.1.0QMediaPlayerQMediaPlayerQMediaServiceProviderQMediaServiceProviderQMediaPluginLoaderQMediaPluginLoaderQFactoryLoaderQFactoryLoaderQLibraryQLibraryPluginPlugincall:requestService()=0implement:QPluginServiceProvidercall:instances()check plugin jsoncall:loadPlugin()call:instance()
1.QMediaPlayer
调用了QMediaServiceProvider的抽象接口requestService()。派生QPluginServiceProvider并实现了QMediaServiceProvider的接口。在defaultServiceProvider()函数中实例化一个QPluginServiceProvider对象。
2.QMediaServiceProvider
派生的子类QPluginServiceProvider实现了requestService函数。
代码片段中的loader()是:
mediaservice是Qt加载多媒体插件的路径,即QT_DIR/plugins/mediaservice
3.QMediaPluginLoader
调用instances()成员函数。
这里检查重复加载以及验证插件合法性,key是插件接口中的IID:
Q_PLUGIN_METADATA(IID “org.qt-project.qt.mediaserviceproviderfactory/5.0” FILE “wmf.json”)
4.QFactoryLoader
该类是Qt base的类,调用成员函数instance()。QLibraryPrivate是QLibrary的d指针。
5.QLibrary
调用loadPlugin()函数从本地(QT_DIR/plugins/mediaservice)加载dll插件并instance()实例化插件。
分析先到这,下次更新一篇如何实现一个基于FFmpeg实现的Qt插件。
首先,看看QMediaPlayer是如何工作的。以UML序列图表示:
Created with Raphaël 2.1.0ClientClientQMediaPlayerQMediaPlayerQMediaServiceProviderPluginQMediaServiceProviderPluginQMediaServiceQMediaServiceQMediaPlayerControlQMediaPlayerControlFFmpegFFmpeg传入一个音频文件或一个播放列表请求播放服务factory创建一个媒体服务product请求播放控制正在播放音频与解码器通信进行解码音频文件
QMediaPlayer调用的是QMediaPlayerControl的接口,其中QMediaPlayerControl是一个抽象类,所有接口需要自己实现。
QMediaServiceProviderPlugin是一个Qt插件,派生自QMediaServiceProviderFactoryInterface抽象接口,从它派生可生成一个“.dll”或“.a”类型的插件。然后发现,QMediaServiceProviderPlugin和QMediaService其实就是一个抽象工厂模式。QMediaService 的工作就是请求一系列不同功能的播放控制插件(解码、声音输出、声音输入等),如QAudioOutputControl、QAodioInputControl、QAudioDecoderControl、QMetaDataReaderControl、QMetaDataWriterControl等等。
而这个插件又是如何被加载并实例化的呢?
Created with Raphaël 2.1.0QMediaPlayerQMediaPlayerQMediaServiceProviderQMediaServiceProviderQMediaPluginLoaderQMediaPluginLoaderQFactoryLoaderQFactoryLoaderQLibraryQLibraryPluginPlugincall:requestService()=0implement:QPluginServiceProvidercall:instances()check plugin jsoncall:loadPlugin()call:instance()
1.QMediaPlayer
调用了QMediaServiceProvider的抽象接口requestService()。派生QPluginServiceProvider并实现了QMediaServiceProvider的接口。在defaultServiceProvider()函数中实例化一个QPluginServiceProvider对象。
//QMediaPlayer构造函数中调用playerService() static QMediaService *playerService(QMediaPlayer::Flags flags) { QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); if (flags) { QMediaServiceProviderHint::Features features = 0; if (flags & QMediaPlayer::LowLatency) features |= QMediaServiceProviderHint::LowLatencyPlayback; if (flags & QMediaPlayer::StreamPlayback) features |= QMediaServiceProviderHint::StreamPlayback; if (flags & QMediaPlayer::VideoSurface) features |= QMediaServiceProviderHint::VideoSurface; return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER, QMediaServiceProviderHint(features)); } else return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER); }
2.QMediaServiceProvider
派生的子类QPluginServiceProvider实现了requestService函数。
class QPluginServiceProvider : public QMediaServiceProvider { //... QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) { QString key(QLatin1String(type.constData())); QList<QMediaServiceProviderPlugin *>plugins; const auto instances = loader()->instances(key); for (QObject *obj : instances) { QMediaServiceProviderPlugin *plugin = qobject_cast<QMediaServiceProviderPlugin*>(obj); if (plugin) plugins << plugin; } //...
代码片段中的loader()是:
Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, loader, (QMediaServiceProviderFactoryInterface_iid, QLatin1String("mediaservice"), Qt::CaseInsensitive))
mediaservice是Qt加载多媒体插件的路径,即QT_DIR/plugins/mediaservice
3.QMediaPluginLoader
调用instances()成员函数。
// QFactoryLoader m_factoryLoader; QList<QObject*> QMediaPluginLoader::instances(QString const &key) { if (!m_metadata.contains(key)) return QList<QObject*>(); QList<QObject *> objects; const auto list = m_metadata.value(key); for (const QJsonObject &jsonobj : list) { int idx = jsonobj.value(QStringLiteral("index")).toDouble(); if (idx < 0) continue; QObject *object = m_factoryLoader->instance(idx); if (!objects.contains(object)) { objects.append(object); } } return objects; }
这里检查重复加载以及验证插件合法性,key是插件接口中的IID:
Q_PLUGIN_METADATA(IID “org.qt-project.qt.mediaserviceproviderfactory/5.0” FILE “wmf.json”)
4.QFactoryLoader
该类是Qt base的类,调用成员函数instance()。QLibraryPrivate是QLibrary的d指针。
QObject *QFactoryLoader::instance(int index) const { Q_D(const QFactoryLoader); if (index < 0) return 0; #ifndef QT_NO_LIBRARY if (index < d->libraryList.size()) { QLibraryPrivate *library = d->libraryList.at(index); if (library->instance || library->loadPlugin()) { if (!library->inst) library->inst = library->instance(); QObject *obj = library->inst.data(); if (obj) { if (!obj->parent()) obj->moveToThread(QCoreApplicationPrivate::mainThread()); return obj; } } return 0; } index -= d->libraryList.size(); #endif // ... }
5.QLibrary
调用loadPlugin()函数从本地(QT_DIR/plugins/mediaservice)加载dll插件并instance()实例化插件。
分析先到这,下次更新一篇如何实现一个基于FFmpeg实现的Qt插件。
相关文章推荐
- Cocos2d-x:整体框架源码分析以及启动过程原理(win32)
- Qt仿Android带特效的数字时钟源码分析(滑动,翻页,旋转效果)
- Phalcon框架启动流程(部分源码)分析
- 缓存框架Guava Cache部分源码分析 推荐
- Linux驱动修炼之道-SPI驱动框架源码分析(中)
- java源码分析之集合框架 LinkedList 04
- MINA框架源码分析(四)
- Qt源码分析之信号和槽机制
- 集合框架源码分析五之LinkedHashMap,LinkedHashSet
- 网络通讯框架-Volley源码分析(2)
- j2ee页面静态化方案encache web cache框架源码分析2
- 【JDK集合框架源码分析】-集合框架概述
- RankLib源码分析(一):主框架
- Okhttp 框架使用和源码分析
- Alluxio源码分析:RPC框架浅析(一)
- Java 集合框架源码分析(五)——Vector
- android2.3 View视图框架源码分析之一:android是如何创建一个view的?
- Volley(四) Volley框架(从源码角度分析)
- Android-FixBug热修复框架的使用及源码分析(不发版修复bug)
- ⑤NuPlayer播放框架之GenericSource源码分析