52 lines
2.1 KiB
C++
52 lines
2.1 KiB
C++
#pragma once
|
|
#include <QDataStream>
|
|
#include <QLocalSocket>
|
|
#include <QByteArray>
|
|
#include <functional>
|
|
|
|
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<void(QDataStream&)>& 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<bool(quint8, quint64, QDataStream&)>& 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;
|
|
}
|
|
};
|
|
}
|