Преамбула
Все нижеизложенное приводится в контексте 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 <QAbstractVideoSurface> #include <QVideoSurfaceFormat> 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 <QtQml/qqml.h> #include <QApplication> #include <QScreen> #include <QDesktopWidget> void DesktopVideoProducer::registerQmlType() { //Регистрируем наш класс в составе пакета DesktopVideoProducer, //под версией 0.1, под именем DesktopVideoProducer. //Нижележащая строчка является подсказкой для парсера типов QtCreator, //и она не обязательна. // @uri DesktopVideoProducer qmlRegisterType<DesktopVideoProducer>( "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 <QApplication> #include <QQmlApplicationEngine> #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.
ссылка на оригинал статьи http://habrahabr.ru/post/229747/
Добавить комментарий