Удаленное управление компьютером по сети: Формирование видео-потока

Структура Qt-проекта на C++

В прошлый раз мы в целом продумали архитектуру приложения, схожего с TeamViewer. Эта часть посвящена разработке библиотеки, которая поможет нам формировать видео-поток происходящего на экране.

Изначально планировалось, что модуль будет называться InputRecorder. Но у меня произошло небольшое переосмысление задачи, поэтому было решено сосредоточиться на записи экрана, и не примешивать сюда события мыши и клавиатуры. Соответствующей библиотеке дадим имя DesktopRecorder.

Скриншоты в Qt

Видео-поток с экрана представляет собой всего лишь последовательность скриншотов, транслируемых с определенной частотой.

Сделать скриншот в Qt сверх-просто:

Представленная функция получает скриншот с экрана по умолчанию (принципиально на многоэкранных системах), и работает одинаково хорошо в Linux и Windows. Теперь можно было бы добавить запуск этой функции по таймеру, и просто генерировать поток кадров. Но это еще не все. Нам хотелось бы иметь возможность захватывать не только содержимое экрана, но и курсор. Получившая реализация этим похвастаться не может.

Дополняем скриншот курсором мыши

Чтобы получить скриншот с курсором мыши, придется прибегнуть к специфичным API конкретных платформ. В Linux для этого подойдет расширение X11 — XFixes, а в Windows — функции Win32 API: GetCursorInfo() и GetIconInfo().

Для передачи информации о курсоре определим структуру:

Она хранит изображение иконки, которая используется в качестве графического представления курсора, а также позицию левого верхнего угла, где курсор должен быть отрисован на скриншоте.

Тогда интерфейс функции получения курсора довольно прост:

Функция получения курсора в Linux

Для Linux реализация получилась несколько проще, поэтому начнем с нее:

Функция получения курсора в Windows

Теперь версия функции для Windows:

На самом деле, эти функции могут работать несколько нестабильно при каких-то особых ситуациях. Но в большинстве случаев их поведение нас устроит.

Все вместе: Класс DesktopRecorder

Теперь посмотрим на все это вместе. Заголовочный файл desktoprecorder.h:

Действие функций-членов, сигналов и слотов класса должно быть понятно из их названий. Однако стоит отметить следующую особенность: необходимость захвата курсора мыши определяется полем m_cursorCaptureEnabled. Если эта переменная имеет значение true, то курсор будет отображен на скриншоте, полученном с помощью makeScreenShot(), иначе — не будет.

Далее переходим к файлу реализации desktoprecorder.cpp:

То, что следует за #ifdef Q_OS_LINUX относится к Linux-версии, а то, что находится после #elif defined Q_OS_WIN32 — к Windows. Компилятор просто проигнорирует строки кода, которые не соответствуют текущей операционной системе.

Похожая ситуация наблюдается и в pro-файле библиотеки DesktopRecorder:

Для разных ОС — разные библиотеки.

Сам видео-поток представляет собой всего лишь последовательность скриншотов, отправляемых по событиям таймера QTimer.

Демонстрационный пример

Проверим, что все работает. Создадим тестовое приложение DesktopRecorderDemo, которое использует возможности нашей библиотеки. Заголовочный файл desktoprecorderdemo.h:

Реализация в desktoprecorderdemo.cpp:

Получилось довольно лаконично. Это объясняется использованием Qt Designer для формирования ui-формы виджета.

Выводы

Видео-трансляция у нас есть. Следующий шаг — организовать ее передачу по сети. Это и станет темой следующей части…

Исходники

Также они доступны на github: https://github.com/itnotesblog/RemoteControlDemo под тэгом v.0.1.1.

Сборка проекта проверялась под Linux и Windows с Qt 4.8.4 и компиляторами gcc и msvc.2010 соответственно.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий