Files
utun2/tools/chatgui/src/call_camera_buffer.h
T

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; }
};