#pragma once #include "call_camera_protocol.h" #include "debug_config.h" #include #ifdef Q_OS_WIN #include #else #include #include #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 m_file; #endif bool fail(const QString& error) { m_error = error; close(); return false; } bool map() { #ifdef Q_OS_WIN m_data = static_cast(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(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(); 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(name.utf16())); if (!m_mapping) return fail(QStringLiteral("OpenFileMapping error=%1").arg(GetLastError())); #else m_file = std::make_unique(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; } };