Isolate video call camera capture from the GUI process
This commit is contained in:
1 parent
0b136ae2ab
commit
3e4d5d235f
13 files changed
+915
-115
No files matched your search
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
#include "call_camera_protocol.h"
|
||||
#include "debug_config.h"
|
||||
#include <QUuid>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <qt_windows.h>
|
||||
#else
|
||||
#include <QTemporaryFile>
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
// Владение пикселями задаётся FRAME/ACK. Закрытие mapping никогда не ждёт другой процесс.
|
||||
class CallCameraBuffer {
|
||||
QString m_name, m_error;
|
||||
uchar* m_data = nullptr;
|
||||
#ifdef Q_OS_WIN
|
||||
HANDLE m_mapping = nullptr;
|
||||
#else
|
||||
std::unique_ptr<QFile> m_file;
|
||||
#endif
|
||||
bool fail(const QString& error) { m_error = error; close(); return false; }
|
||||
bool map() {
|
||||
#ifdef Q_OS_WIN
|
||||
m_data = static_cast<uchar*>(MapViewOfFile(m_mapping, FILE_MAP_WRITE, 0, 0, CallCameraProtocol::FrameBytes));
|
||||
if (!m_data) return fail(QStringLiteral("MapViewOfFile error=%1").arg(GetLastError()));
|
||||
#else
|
||||
m_data = m_file->map(0, CallCameraProtocol::FrameBytes);
|
||||
if (!m_data) return fail(m_file->errorString());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
CallCameraBuffer() = default;
|
||||
CallCameraBuffer(const CallCameraBuffer&) = delete;
|
||||
CallCameraBuffer& operator=(const CallCameraBuffer&) = delete;
|
||||
~CallCameraBuffer() { close(); }
|
||||
bool create() {
|
||||
close();
|
||||
#ifdef Q_OS_WIN
|
||||
m_name = QStringLiteral("Local\\vibechat-camera-") + QUuid::createUuid().toString(QUuid::Id128);
|
||||
m_mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, CallCameraProtocol::FrameBytes,
|
||||
reinterpret_cast<const wchar_t*>(m_name.utf16()));
|
||||
const DWORD error = GetLastError();
|
||||
if (!m_mapping || error == ERROR_ALREADY_EXISTS) return fail(QStringLiteral("CreateFileMapping error=%1").arg(error));
|
||||
#else
|
||||
auto file = std::make_unique<QTemporaryFile>();
|
||||
if (!file->open() || !file->resize(CallCameraProtocol::FrameBytes)) return fail(file->errorString());
|
||||
m_name = file->fileName(); m_file = std::move(file);
|
||||
#endif
|
||||
return map();
|
||||
}
|
||||
bool attach(const QString& name) {
|
||||
close(); m_name = name;
|
||||
#ifdef Q_OS_WIN
|
||||
m_mapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, reinterpret_cast<const wchar_t*>(name.utf16()));
|
||||
if (!m_mapping) return fail(QStringLiteral("OpenFileMapping error=%1").arg(GetLastError()));
|
||||
#else
|
||||
m_file = std::make_unique<QFile>(name);
|
||||
if (!m_file->open(QIODevice::ReadWrite | QIODevice::ExistingOnly)) return fail(m_file->errorString());
|
||||
if (m_file->size() != CallCameraProtocol::FrameBytes) return fail(QStringLiteral("Invalid camera buffer size"));
|
||||
#endif
|
||||
return map();
|
||||
}
|
||||
void close() {
|
||||
#ifdef Q_OS_WIN
|
||||
if (m_data && !UnmapViewOfFile(m_data))
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CALL, "camera buffer unmap error=%lu", (unsigned long)GetLastError());
|
||||
if (m_mapping && !CloseHandle(m_mapping))
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CALL, "camera buffer close error=%lu", (unsigned long)GetLastError());
|
||||
m_mapping = nullptr;
|
||||
#else
|
||||
m_file.reset();
|
||||
#endif
|
||||
m_data = nullptr;
|
||||
}
|
||||
uchar* data() const { return m_data; }
|
||||
QString name() const { return m_name; }
|
||||
QString errorString() const { return m_error; }
|
||||
};
|
||||
Reference in new issue
Block a user