[Из песочницы] Простой спрособ подключения произвольного видеоисточника в Qml
Преамбула Все нижеизложенное приводится в контексте Qt версии 5.3.1 (как наиболее актуальной на данный момент), но имеет смысл в контексте любой версии ветки 5.x, а возможно даже 4.8.x (не проверял за ненадобностью).Операционная система — Windows, среда разработки — QtCreator 3.1.2 в связке с MinGW и gcc 4.8.2 От использования других платформ/IDE/компиляторов суть не меняется.
В качестве иточника видеоданных был выбран самый простой из доступных вариантов, а именно — рабочий стол. Т.е. приложение будет отображать копию всего что происходит на рабочем столе. В многомониторных конфигурациях, в качестве источника, будем использовать основной экран.
Итак, приступим В качестве отправной точки можно почитать документацию: «Video Overview: Working with Low Level Video Frames».Несколько тезисов, которые необходимо почерпнуть из этой статьи:
Источник видеоданных должен являться потомком QObject; Он должен объявлять property videoSurface типа QAbstractVideoSurface*; Он должен вызывать QAbstractVideoSurface: start, с передачей QVideoSurfaceFormat, перед началом воспроизведения; Он должен вызывать QAbstractVideoSurface: present, с передачей QVideoFrame, для отображения каждого кадра; Он должен вызывать QAbstractVideoSurface: stop, по завершении воспроизведения ролика. Пишем код Создаем новый проект «Qt Quick Application». Важно выбрать именно этот тип тип приложения, поскольку в дальнейшем мы будем создавать Qml компоненту с использованием C++.Далее создаем класс, потомок QObject, и начинаем его расширять.
Посколку то, что получилось в итоге, достаточно просто и немногословно, не буду лить много воды, а просто приведу код, с некоторыми комментариями:
DesktopVideoProducer.h:
#pragma once
#include
class DesktopVideoProducer: public QObject { Q_OBJECT public: //Для того чтобы класс был доступен для использования в Qml его необходимо регистрировать static void registerQmlType ();
explicit DesktopVideoProducer (QObject *parent = 0); ~DesktopVideoProducer ();
//то самое property, упомянутое выше Q_PROPERTY (QAbstractVideoSurface* videoSurface READ videoSurface WRITE setVideoSurface)
QAbstractVideoSurface* videoSurface () const; void setVideoSurface (QAbstractVideoSurface* s);
protected: void timerEvent (QTimerEvent*);
private: void closeSurface ();
private: QAbstractVideoSurface* _surface; QVideoSurfaceFormat _format; }; DesktopVideoProducer.cpp: #include «DesktopVideoProducer.h»
#include
#include
void DesktopVideoProducer: registerQmlType ()
{
//Регистрируем наш класс в составе пакета DesktopVideoProducer,
//под версией 0.1, под именем DesktopVideoProducer.
//Нижележащая строчка является подсказкой для парсера типов QtCreator,
//и она не обязательна.
// @uri DesktopVideoProducer
qmlRegisterType
DesktopVideoProducer: DesktopVideoProducer (QObject *parent) : QObject (parent), _surface (0) { startTimer (1000 / 15); //15 fps }
DesktopVideoProducer::~DesktopVideoProducer () { closeSurface (); }
QAbstractVideoSurface* DesktopVideoProducer: videoSurface () const { return _surface; }
void DesktopVideoProducer: setVideoSurface (QAbstractVideoSurface* s) { closeSurface (); _surface = s; }
void DesktopVideoProducer: closeSurface () { if (_surface && _surface→isActive ()) _surface→stop (); }
void DesktopVideoProducer: timerEvent (QTimerEvent*) { if (!_surface) return;
QScreen* screen = QGuiApplication: primaryScreen (); QDesktopWidget* desktop = QApplication: desktop ();
if (! screen || ! desktop) return;
//Получим screenshot и преобразуем в экземпляр класса подходящий для QVideoFrame QPixmap screenPixmap = screen→grabWindow (desktop→screen ()→winId ()); QImage screenImage = screenPixmap.toImage (); QVideoFrame: PixelFormat pixelFormat = QVideoFrame: pixelFormatFromImageFormat (screenImage.format ());
//если формат кадра по какой-то причине поменялся (или это первый кадр)- //выполним повторную (первичную) инициализацию surface if (screenPixmap.size () != _format.frameSize () || pixelFormat!= _format.pixelFormat ()) { closeSurface (); _format = QVideoSurfaceFormat (screenPixmap.size (), pixelFormat); _surface→start (_format); }
//передадим полученный кадр на отрисовку _surface→present (QVideoFrame (screenImage)); } main.qml: import QtQuick 2.2 import QtQuick.Window 2.1 import QtMultimedia 5.0 import DesktopVideoProducer 0.1
Window { visible: true width: 360 height: 360
DesktopVideoProducer { id: videoProducer; }
VideoOutput { anchors.fill: parent; source: videoProducer; } } main.cpp:
#include
#include«DesktopVideoProducer.h»
int main (int argc, char *argv[]) { //зарегистрируем DesktopVideoProducer для использования в Qml DesktopVideoProducer: registerQmlType ();
//для возможности вызова QApplication: desktop () QGuiApplication недостаточно //QGuiApplication app (argc, argv); QApplication app (argc, argv);
QQmlApplicationEngine engine; engine.load (QUrl (QStringLiteral («qrc:///main.qml»)));
return app.exec (); } P.S.: Полный проект доступен для скачивания с GitHub.