#pragma once #include #include #include #include namespace CallCameraProtocol { enum Type : quint8 { Configure = 1, Quit, Ack, Devices, Frame, Stage, Error, Buffer }; constexpr quint32 FrameBytes = 1920 * 1080 * 4; constexpr quint32 MaxPacket = 65536; // Full HD в обеих ориентациях; чётные размеры необходимы для YUV420. inline bool validSize(int width, int height) { return width >= 16 && height >= 16 && width <= 1920 && height <= 1920 && (width <= 1080 || height <= 1080) && !(width % 2) && !(height % 2); } // Только команды и метаданные. Пиксели — в mapping с владением Frame -> Ack, без shared mutex. inline QByteArray packet(Type type, quint64 generation, const std::function& write = {}) { QByteArray result; QDataStream out(&result, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_15); out << quint32(0) << quint8(type) << generation; if (write) write(out); out.device()->seek(0); out << quint32(result.size() - 4); return result; } class Reader { QByteArray pending; quint32 length = 0; public: bool read(QLocalSocket& socket, const std::function& consume) { while (socket.bytesAvailable()) { const qsizetype wanted = length ? length : 4; pending += socket.read(wanted - pending.size()); if (pending.size() != wanted) return true; QDataStream in(pending); in.setVersion(QDataStream::Qt_5_15); if (!length) { in >> length; pending.clear(); if (length < 9 || length > MaxPacket) return false; } else { quint8 type; quint64 generation; in >> type >> generation; bool valid = consume(type, generation, in) && in.status() == QDataStream::Ok && in.atEnd(); pending.clear(); length = 0; if (!valid) return false; } } return true; } }; }