51 lines
4.7 KiB
C++
51 lines
4.7 KiB
C++
/* GUI-обёртка камеры: автоматически запускает отдельный процесс для опроса устройств, захвата и конвертации.
|
||
* Создавать/вызывать/уничтожать в GUI-потоке при работающем Qt event loop; аппаратные вызовы не выполняются в GUI.
|
||
* configure меняет поколение, старые кадры отбрасываются. Внешний main должен обработать --call-camera-worker
|
||
* через call_camera_worker_main до обычной инициализации приложения. */
|
||
#pragma once
|
||
#include <QObject>
|
||
#include <QImage>
|
||
#include <QList>
|
||
#include "stream_video_modes.h"
|
||
|
||
/* Снимок устройства от camera worker; содержит только аппаратные размеры, допустимые для видеозвонка. */
|
||
struct CallCameraDevice {
|
||
QString name; // Отображаемое имя устройства.
|
||
QByteArray id; // Непрозрачный идентификатор Qt backend.
|
||
QList<StreamVideoMode> modes; // Чётные размеры до 1920x1080 в обеих ориентациях; FPS передачи 1..60, capture может быть быстрее.
|
||
};
|
||
using CallCameraDevices = QList<CallCameraDevice>;
|
||
constexpr qint64 CallCameraMaxFrameAgeUs = 250000; // Предел возраста кадра в микросекундах при конвертации и приёме GUI.
|
||
|
||
class CallCameraCapture : public QObject {
|
||
Q_OBJECT
|
||
public:
|
||
/* Создаёт сессию и откладывает запуск worker до event loop; без configure только опрашивает устройства. */
|
||
explicit CallCameraCapture(QObject* parent = nullptr);
|
||
/* Отвязывает GUI-владельца и запрашивает асинхронный Quit; сессия сама дождётся выхода/убьёт зависший worker. */
|
||
~CallCameraCapture() override;
|
||
/* enabled включает/выключает захват; device — точный id из devicesChanged, пустой id не выбирает камеру автоматически.
|
||
* width/height должны пройти CallCameraProtocol::validSize, fps=1..60 — предел выдачи, не команда драйверу.
|
||
* Параметры проверяются и при enabled=false; повтор тех же параметров без ошибки ничего не меняет.
|
||
* Смена конфигурации асинхронна; после failed явный configure(true, ...) допускает перезапуск процесса. */
|
||
void configure(bool enabled, const QByteArray& device = {}, int width = 640, int height = 480, int fps = 30);
|
||
signals:
|
||
/* Полный список устройств/режимов после опроса и при изменениях backend, независимо от enabled. */
|
||
void devicesChanged(const CallCameraDevices& devices);
|
||
/* Текущий свежий RGB32-кадр в собственной CPU-памяти GUI; image можно сохранить копированием QImage.
|
||
* pts — монотонное время захвата в микросекундах (шкала call_video_playout_now_us), correction — накопленное
|
||
* уменьшение опережения исходных PTS. Ack worker отправлен до сигнала, mapping больше не удерживается. */
|
||
void frameReady(const QImage& image, qint64 pts, qint64 correction);
|
||
/* Ошибка запуска/IPC/драйвера/параметров или watchdog: процесс останавливается, захват отключается.
|
||
* Watchdog: отсутствие прогресса/свежих кадров около 5 с, остановка — около 1.5 с, проверка каждые 250 мс. */
|
||
void failed(const QString& error);
|
||
private:
|
||
struct Session;
|
||
Session* m; // Независимый QObject с QPointer на владельца; после shutdown живёт до завершения worker/event loop.
|
||
};
|
||
|
||
/* Entry point дочернего процесса: argc=3, argv[2] — endpoint, создаёт QGuiApplication и запускает worker event loop.
|
||
* Вызывается до обычной инициализации приложения, конфига, БД и single-instance lock.
|
||
* Возвращает код event loop; без HAVE_STREAM_CAPTURE или с неверным argc — 2. */
|
||
int call_camera_worker_main(int argc, char** argv);
|