[Из песочницы] Простой спрособ подключения произвольного видеоисточника в 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 #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 #include #include

void DesktopVideoProducer: registerQmlType () { //Регистрируем наш класс в составе пакета DesktopVideoProducer, //под версией 0.1, под именем DesktopVideoProducer. //Нижележащая строчка является подсказкой для парсера типов QtCreator, //и она не обязательна. // @uri DesktopVideoProducer qmlRegisterType( «DesktopVideoProducer», 0, 1, «DesktopVideoProducer»); }

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

#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.

© Habrahabr.ru