80 lines
3.1 KiB
C++
80 lines
3.1 KiB
C++
#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; }
|
|
};
|