mirror of
https://github.com/niellun/FastCarPlay.git
synced 2026-06-07 09:38:25 +02:00
Optimise and refactor protocol, better logging, optimise rendering, double buffering.
This commit is contained in:
@@ -1,31 +0,0 @@
|
||||
#ifndef SRC_STRUCT_AUDIO_CHUNK
|
||||
#define SRC_STRUCT_AUDIO_CHUNK
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
class AudioChunk
|
||||
{
|
||||
public:
|
||||
AudioChunk(uint16_t size)
|
||||
: data(nullptr), size(size)
|
||||
{
|
||||
if (size > 0)
|
||||
data = static_cast<uint8_t *>(malloc(size));
|
||||
}
|
||||
|
||||
~AudioChunk()
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
// Deleted copy constructor/assignment
|
||||
AudioChunk(const AudioChunk &) = delete;
|
||||
AudioChunk &operator=(const AudioChunk &) = delete;
|
||||
|
||||
uint8_t *data;
|
||||
uint16_t size;
|
||||
};
|
||||
|
||||
#endif /* SRC_STRUCT_AUDIO_CHUNK */
|
||||
@@ -1,189 +0,0 @@
|
||||
#ifndef SRC_STRUCT_COMMAND
|
||||
#define SRC_STRUCT_COMMAND
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
|
||||
#include "helper/functions.h"
|
||||
#include "helper/protocol_const.h"
|
||||
#include "struct/audio_chunk.h"
|
||||
#include "struct/multitouch.h"
|
||||
|
||||
class Command
|
||||
{
|
||||
public:
|
||||
Command(const Command &) = delete;
|
||||
Command &operator=(const Command &) = delete;
|
||||
|
||||
Command(int cmd, bool encrypt = true, uint32_t size = 0)
|
||||
: command(cmd), encryption(encrypt), length(size), data(nullptr)
|
||||
{
|
||||
if (size > 0)
|
||||
data = static_cast<uint8_t *>(malloc(size));
|
||||
}
|
||||
|
||||
Command(int cmd, uint32_t value, bool encrypt = true)
|
||||
: Command(cmd, encrypt, 4)
|
||||
{
|
||||
write_uint32_le(data, value);
|
||||
}
|
||||
|
||||
Command(int cmd, bool encrypt, uint8_t *buffer, uint32_t size)
|
||||
: command(cmd), encryption(encrypt), length(size), data(buffer)
|
||||
{
|
||||
}
|
||||
|
||||
~Command()
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
free(data);
|
||||
data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> Init(int width, int height, int fps)
|
||||
{
|
||||
std::unique_ptr<Command> result(new Command(CMD_OPEN, true, 28));
|
||||
write_uint32_le(result->data + 0, width);
|
||||
write_uint32_le(result->data + 4, height);
|
||||
write_uint32_le(result->data + 8, fps);
|
||||
write_uint32_le(result->data + 12, 5);
|
||||
write_uint32_le(result->data + 16, 49152);
|
||||
write_uint32_le(result->data + 20, 2);
|
||||
write_uint32_le(result->data + 24, 2);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> File(const char *filename, const uint8_t *data, uint32_t length)
|
||||
{
|
||||
// filename is assumed null‑terminated, so strlen + 1 to include the '\0'
|
||||
uint32_t fn_len = strlen(filename) + 1;
|
||||
|
||||
// Total buffer size: 4 (fn_len) + fn_len + 4 (content_len) + content_len
|
||||
std::unique_ptr<Command> result(new Command(CMD_SEND_FILE, true, 4 + fn_len + 4 + length));
|
||||
uint8_t *buf = result->data;
|
||||
|
||||
// 1) filename length (LE)
|
||||
write_uint32_le(buf, fn_len);
|
||||
buf += 4;
|
||||
|
||||
// 2) filename bytes (including the '\0')
|
||||
std::memcpy(buf, filename, fn_len);
|
||||
buf += fn_len;
|
||||
|
||||
// 3) content length (LE)
|
||||
write_uint32_le(buf, length);
|
||||
buf += 4;
|
||||
|
||||
// 4) content bytes
|
||||
if (length > 0 && data)
|
||||
std::memcpy(buf, data, length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> File(const char *filename, const char *value)
|
||||
{
|
||||
uint32_t len = std::strlen(value);
|
||||
if (len > 16)
|
||||
throw std::invalid_argument("String too long (max 16 bytes)");
|
||||
// note: we send only the ASCII bytes, no trailing '\0'
|
||||
return File(filename, reinterpret_cast<const uint8_t *>(value), len);
|
||||
}
|
||||
|
||||
// overload for a single 32‑bit integer
|
||||
static std::unique_ptr<Command> File(const char *filename, int value)
|
||||
{
|
||||
uint8_t buffer[4];
|
||||
write_uint32_le(buffer, value);
|
||||
return File(filename, buffer, 4);
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> Control(uint32_t value, bool encrypt = false)
|
||||
{
|
||||
return std::unique_ptr<Command>(new Command(CMD_CONTROL, value, encrypt));
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> Encryption(uint32_t seed)
|
||||
{
|
||||
return std::unique_ptr<Command>(new Command(CMD_ENCRYPTION, seed, false));
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> String(uint32_t cmd, const char *str, bool encrypt = true)
|
||||
{
|
||||
uint32_t length = std::strlen(str);
|
||||
std::unique_ptr<Command> result(new Command(cmd, encrypt, length));
|
||||
if (length > 0)
|
||||
std::memcpy(result->data, str, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static std::unique_ptr<Command> String(uint32_t cmd, const char *format, Args... args)
|
||||
{
|
||||
char buffer[512];
|
||||
std::snprintf(buffer, sizeof(buffer), format, args...);
|
||||
return String(cmd, buffer);
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> Touch(uint32_t action, float x, float y)
|
||||
{
|
||||
std::unique_ptr<Command> result(new Command(CMD_TOUCH, false, 16));
|
||||
write_uint32_le(result->data, action);
|
||||
write_uint32_le(result->data + 4, int(10000 * x));
|
||||
write_uint32_le(result->data + 8, int(10000 * y));
|
||||
write_uint32_le(result->data + 12, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> Click(float x, float y, bool down)
|
||||
{
|
||||
return Touch(down ? 14 : 16, x, y);
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> Move(float x, float y)
|
||||
{
|
||||
return Touch(15, x, y);
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> Audio(std::unique_ptr<AudioChunk> chunk)
|
||||
{
|
||||
std::unique_ptr<Command> result(new Command(CMD_AUDIO_DATA, false, chunk->data, chunk->size));
|
||||
chunk->data = nullptr;
|
||||
write_uint32_le(result->data, 5);
|
||||
write_uint32_le(result->data + 4, 0);
|
||||
write_uint32_le(result->data + 8, 3);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Command> MultiTouch(const Multitouch &touches)
|
||||
{
|
||||
int count = touches.size();
|
||||
if (count == 0)
|
||||
return nullptr;
|
||||
|
||||
std::unique_ptr<Command> result(new Command(CMD_MULTI_TOUCH, false, sizeof(Multitouch::Touch) * count));
|
||||
uint8_t *buf = result->data;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
const Multitouch::Touch &t = touches[i];
|
||||
write_float_le(buf + 0, t.x);
|
||||
write_float_le(buf + 4, t.y);
|
||||
write_uint32_le(buf + 8, static_cast<uint32_t>(t.state));
|
||||
write_uint32_le(buf + 12, static_cast<uint32_t>(t.id));
|
||||
buf += 16;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int command;
|
||||
bool encryption;
|
||||
uint32_t length;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
#endif /* SRC_STRUCT_COMMAND */
|
||||
@@ -1,152 +0,0 @@
|
||||
#ifndef SRC_STRUCT_MESSAGE
|
||||
#define SRC_STRUCT_MESSAGE
|
||||
|
||||
#include "libavcodec/defs.h"
|
||||
#include "helper/protocol_const.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "aes_cipher.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Header
|
||||
{
|
||||
uint32_t magic;
|
||||
int32_t length;
|
||||
uint32_t type;
|
||||
uint32_t typecheck;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class Message
|
||||
{
|
||||
public:
|
||||
Message() : _header({0, 0, 0, 0}), _data(nullptr), _offset(0), _headerLegth(0), _dataLength(0), _valid(false), _ready(false)
|
||||
{
|
||||
}
|
||||
|
||||
Message(uint8_t *data, uint32_t length, uint32_t offset)
|
||||
: _header({0, static_cast<int32_t>(length), 0, 0}),
|
||||
_data(data),
|
||||
_offset(offset <= length ? offset : length),
|
||||
_headerLegth(sizeof(Header)),
|
||||
_dataLength(length),
|
||||
_valid(true),
|
||||
_ready(true)
|
||||
{
|
||||
}
|
||||
|
||||
~Message()
|
||||
{
|
||||
if (_data)
|
||||
{
|
||||
free(_data);
|
||||
_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t parse(uint8_t *data, uint32_t data_length)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
if (_headerLegth != sizeof(Header))
|
||||
{
|
||||
uint8_t copy = sizeof(Header) - _headerLegth;
|
||||
if (copy > data_length)
|
||||
copy = data_length;
|
||||
memcpy(reinterpret_cast<uint8_t *>(&_header) + _headerLegth, data, copy);
|
||||
_headerLegth += copy;
|
||||
result += copy;
|
||||
|
||||
if (_headerLegth != sizeof(Header))
|
||||
return result;
|
||||
|
||||
if ((_header.magic != MAGIC && _header.magic != MAGIC_ENC) || _header.length < 0)
|
||||
{
|
||||
_ready = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_header.length == 0)
|
||||
{
|
||||
_ready = true;
|
||||
_valid = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (_data == nullptr)
|
||||
{
|
||||
uint32_t padding = _header.type == CMD_VIDEO_DATA ? AV_INPUT_BUFFER_PADDING_SIZE : 0;
|
||||
_data = (uint8_t *)malloc(_header.length + padding);
|
||||
if (_data)
|
||||
{
|
||||
_valid = true;
|
||||
if (padding > 0)
|
||||
std::fill(_data + _header.length, _data + _header.length + padding, 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t copy = _header.length - _dataLength;
|
||||
if (copy > data_length - result)
|
||||
copy = data_length - result;
|
||||
if (_valid)
|
||||
memcpy(_data + _dataLength, data + result, copy);
|
||||
_dataLength += copy;
|
||||
result += copy;
|
||||
|
||||
_ready = _dataLength >= static_cast<uint32_t>(_header.length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int getInt(uint32_t offset) const
|
||||
{
|
||||
int result = 0;
|
||||
if (_data && _dataLength - sizeof(int) >= offset)
|
||||
memcpy(&result, _data + offset, sizeof(int));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ready() const { return _ready; }
|
||||
|
||||
bool valid() const { return _valid; }
|
||||
|
||||
bool setOffset(uint32_t offset)
|
||||
{
|
||||
if (offset >= _dataLength)
|
||||
return false;
|
||||
_offset = offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool encrypted() const { return _header.magic == MAGIC_ENC; }
|
||||
|
||||
bool decrypt(AESCipher *cipher)
|
||||
{
|
||||
if (!cipher)
|
||||
return false;
|
||||
return cipher->Decrypt(_data, _dataLength);
|
||||
}
|
||||
|
||||
uint8_t *data() const { return _data + _offset; }
|
||||
uint32_t length() const { return _dataLength - _offset; }
|
||||
uint32_t type() const { return _header.type; }
|
||||
|
||||
private:
|
||||
bool hasHeader() const { return _headerLegth == sizeof(Header); }
|
||||
|
||||
Header _header;
|
||||
uint8_t *_data;
|
||||
uint32_t _offset;
|
||||
|
||||
u_int8_t _headerLegth;
|
||||
uint32_t _dataLength;
|
||||
bool _valid;
|
||||
bool _ready;
|
||||
};
|
||||
|
||||
#endif /* SRC_STRUCT_MESSAGE */
|
||||
@@ -0,0 +1,153 @@
|
||||
#include "struct/usb_buffer.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
DataSlot::DataSlot()
|
||||
: ready(false), offset(0), length(0), size(0), data(nullptr), _cv(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
DataSlot::~DataSlot()
|
||||
{
|
||||
size = 0;
|
||||
if (data)
|
||||
{
|
||||
free(data);
|
||||
data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DataSlot::init(uint32_t slotSize, std::condition_variable *condition)
|
||||
{
|
||||
ready.store(false);
|
||||
offset = 0;
|
||||
length = 0;
|
||||
size = slotSize;
|
||||
data = static_cast<uint8_t *>(malloc(size));
|
||||
_cv = condition;
|
||||
}
|
||||
|
||||
void DataSlot::reset()
|
||||
{
|
||||
ready.store(false);
|
||||
offset = 0;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
void DataSlot::commit(size_t dataSize)
|
||||
{
|
||||
length = dataSize;
|
||||
offset = 0;
|
||||
ready.store(true);
|
||||
|
||||
if (_cv)
|
||||
_cv->notify_one();
|
||||
}
|
||||
|
||||
bool DataSlot::consume(size_t dataSize)
|
||||
{
|
||||
offset += dataSize;
|
||||
if (offset < length)
|
||||
return false;
|
||||
ready.store(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t DataSlot::remain() const
|
||||
{
|
||||
return length > offset ? length - offset : 0;
|
||||
}
|
||||
|
||||
UsbBuffer::UsbBuffer(uint16_t slotCount, uint32_t slotSize)
|
||||
: _slots(nullptr), _size(slotCount), _writeSlot(0), _readSlot(0)
|
||||
{
|
||||
if (slotCount == 0 || slotSize == 0)
|
||||
throw std::invalid_argument("Number of slots and slot size must be greater than 0");
|
||||
|
||||
_slots = new DataSlot[_size];
|
||||
|
||||
for (uint16_t i = 0; i < _size; i++)
|
||||
{
|
||||
_slots[i].init(slotSize, &_cv);
|
||||
}
|
||||
}
|
||||
|
||||
UsbBuffer::~UsbBuffer()
|
||||
{
|
||||
_cv.notify_all();
|
||||
if (_slots)
|
||||
{
|
||||
delete[] _slots;
|
||||
}
|
||||
}
|
||||
|
||||
DataSlot *UsbBuffer::get()
|
||||
{
|
||||
if (_slots[_writeSlot].ready.load())
|
||||
return nullptr;
|
||||
DataSlot *slot = &(_slots[_writeSlot]);
|
||||
_writeSlot++;
|
||||
if (_writeSlot >= _size)
|
||||
_writeSlot = 0;
|
||||
return slot;
|
||||
}
|
||||
|
||||
bool UsbBuffer::read(uint8_t *dst, uint32_t length, std::atomic<bool> &active)
|
||||
{
|
||||
if (length == 0)
|
||||
return true;
|
||||
|
||||
size_t done = 0;
|
||||
while (length > 0)
|
||||
{
|
||||
while (!_slots[_readSlot].ready.load())
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_cv.wait(lock, [&]()
|
||||
{ return !active.load() || _slots[_readSlot].ready.load(); });
|
||||
if (!active.load())
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t copy = _slots[_readSlot].remain();
|
||||
if (copy > length)
|
||||
copy = length;
|
||||
if (dst != nullptr)
|
||||
std::memcpy(dst + done, _slots[_readSlot].data + _slots[_readSlot].offset, copy);
|
||||
if (_slots[_readSlot].consume(copy))
|
||||
{
|
||||
_readSlot++;
|
||||
if (_readSlot >= _size)
|
||||
_readSlot = 0;
|
||||
}
|
||||
done += copy;
|
||||
length -= copy;
|
||||
}
|
||||
|
||||
return active.load();
|
||||
}
|
||||
|
||||
void UsbBuffer::reset()
|
||||
{
|
||||
_readSlot = 0;
|
||||
_writeSlot = 0;
|
||||
for (uint16_t i = 0; i < _size; i++)
|
||||
{
|
||||
_slots[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
void UsbBuffer::notify()
|
||||
{
|
||||
_cv.notify_all();
|
||||
}
|
||||
|
||||
int UsbBuffer::count() const
|
||||
{
|
||||
int result = _writeSlot - _readSlot;
|
||||
if (result < 0)
|
||||
result += _size;
|
||||
return result;
|
||||
}
|
||||
+21
-160
@@ -4,69 +4,22 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
|
||||
class DataSlot
|
||||
{
|
||||
public:
|
||||
DataSlot()
|
||||
: ready(false), offset(0), length(0), size(0), data(nullptr), _cv(nullptr)
|
||||
{
|
||||
}
|
||||
DataSlot();
|
||||
~DataSlot();
|
||||
|
||||
~DataSlot()
|
||||
{
|
||||
size = 0;
|
||||
if (data)
|
||||
{
|
||||
free(data);
|
||||
data = nullptr;
|
||||
}
|
||||
}
|
||||
void init(uint32_t slotSize, std::condition_variable *condition);
|
||||
void reset();
|
||||
void commit(size_t dataSize);
|
||||
bool consume(size_t dataSize);
|
||||
size_t remain() const;
|
||||
|
||||
void init(uint32_t slotSize, std::condition_variable *condition)
|
||||
{
|
||||
ready = false;
|
||||
offset = 0;
|
||||
length = 0;
|
||||
size = slotSize;
|
||||
data = static_cast<uint8_t *>(malloc(size));
|
||||
_cv = condition;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
ready = false;
|
||||
offset = 0;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
void commit(size_t dataSize)
|
||||
{
|
||||
length = dataSize;
|
||||
offset = 0;
|
||||
ready = true;
|
||||
|
||||
if (_cv)
|
||||
_cv->notify_one();
|
||||
}
|
||||
|
||||
bool consume(size_t dataSize)
|
||||
{
|
||||
offset += dataSize;
|
||||
if (offset < length)
|
||||
return false;
|
||||
ready = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t remain() const { return length > offset ? length - offset : 0; }
|
||||
|
||||
bool ready;
|
||||
std::atomic<bool> ready;
|
||||
size_t offset;
|
||||
size_t length;
|
||||
size_t size;
|
||||
@@ -79,119 +32,27 @@ private:
|
||||
class UsbBuffer
|
||||
{
|
||||
public:
|
||||
UsbBuffer(uint16_t slotCount, size_t slotSize)
|
||||
: _active(true), _size(slotCount)
|
||||
{
|
||||
if (slotCount == 0 || slotSize == 0)
|
||||
throw std::invalid_argument("[UsbBuffer] Number of slots and slot size must be greater than 0");
|
||||
|
||||
_slots = new DataSlot[_size];
|
||||
|
||||
for (uint16_t i = 0; i < _size; i++)
|
||||
{
|
||||
_slots[i].init(slotSize, &_cvReady);
|
||||
}
|
||||
}
|
||||
UsbBuffer(uint16_t slotCount, uint32_t slotSize);
|
||||
~UsbBuffer();
|
||||
|
||||
UsbBuffer(const UsbBuffer &) = delete;
|
||||
UsbBuffer &operator=(const UsbBuffer &) = delete;
|
||||
|
||||
~UsbBuffer()
|
||||
{
|
||||
stop();
|
||||
if (_slots)
|
||||
{
|
||||
delete[] _slots;
|
||||
}
|
||||
}
|
||||
DataSlot *get();
|
||||
bool read(uint8_t *dst, uint32_t length, std::atomic<bool> &active);
|
||||
|
||||
void start()
|
||||
{
|
||||
_readSlot = 0;
|
||||
_writeSlot = 0;
|
||||
for (uint16_t i = 0; i < _size; i++)
|
||||
{
|
||||
_slots[i].reset();
|
||||
}
|
||||
_active = true;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
_active = false;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_cvReady.notify_all();
|
||||
}
|
||||
|
||||
DataSlot *get()
|
||||
{
|
||||
if (!_active || _slots[_writeSlot].ready)
|
||||
throw std::runtime_error("[UsbBuffer] No free slots available");
|
||||
DataSlot *slot = &(_slots[_writeSlot]);
|
||||
_writeSlot++;
|
||||
if (_writeSlot >= _size)
|
||||
_writeSlot = 0;
|
||||
return slot;
|
||||
}
|
||||
|
||||
bool read(uint8_t *dst, size_t length)
|
||||
{
|
||||
if (length == 0)
|
||||
return true;
|
||||
|
||||
if (dst == nullptr)
|
||||
throw std::invalid_argument("[UsbBuffer] Read destination is null");
|
||||
|
||||
size_t done = 0;
|
||||
while (length > 0)
|
||||
{
|
||||
if (!_active)
|
||||
return false;
|
||||
|
||||
while (!_slots[_readSlot].ready)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_cvReady.wait(lock, [&]()
|
||||
{ return !_active || _slots[_readSlot].ready; });
|
||||
if (!_active)
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t copy = _slots[_readSlot].remain();
|
||||
if (copy > length)
|
||||
copy = length;
|
||||
std::memcpy(dst + done, _slots[_readSlot].data + _slots[_readSlot].offset, copy);
|
||||
if (_slots[_readSlot].consume(copy))
|
||||
{
|
||||
_readSlot++;
|
||||
if (_readSlot >= _size)
|
||||
_readSlot = 0;
|
||||
}
|
||||
done += copy;
|
||||
length -= copy;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int count() const {
|
||||
int result = _writeSlot - _readSlot;
|
||||
if(result<0)
|
||||
result += _size;
|
||||
return result;
|
||||
}
|
||||
void reset();
|
||||
void notify();
|
||||
int count() const;
|
||||
|
||||
private:
|
||||
mutable std::mutex _mutex;
|
||||
std::condition_variable _cvReady;
|
||||
std::mutex _mutex;
|
||||
std::condition_variable _cv;
|
||||
|
||||
std::atomic<bool> _active;
|
||||
|
||||
uint16_t _writeSlot = 0;
|
||||
uint16_t _readSlot = 0;
|
||||
|
||||
DataSlot *_slots = nullptr;
|
||||
uint16_t _size = 0;
|
||||
DataSlot *_slots;
|
||||
uint16_t _size;
|
||||
uint16_t _writeSlot;
|
||||
uint16_t _readSlot;
|
||||
};
|
||||
|
||||
#endif /* SRC_STRUCT_USB_BUFFER */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SRC_STRUCT_VIDEO_BUFFER
|
||||
#define SRC_STRUCT_VIDEO_BUFFER
|
||||
#ifndef SRC_STRUCT_VIDER_BUFFER2
|
||||
#define SRC_STRUCT_VIDER_BUFFER2
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -9,7 +9,7 @@ extern "C"
|
||||
#include <atomic>
|
||||
#include <stdexcept>
|
||||
|
||||
#define BUFFER_VIDEO_FRAMES 3
|
||||
#define BUFFER_VIDEO_FRAMES 4
|
||||
|
||||
class VideoBuffer
|
||||
{
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
VideoBuffer()
|
||||
{
|
||||
_writing.store(0);
|
||||
_oldest.store(-1);
|
||||
_reading.store(-1);
|
||||
_latest.store(-1);
|
||||
for (uint8_t i = 0; i < BUFFER_VIDEO_FRAMES; ++i)
|
||||
@@ -52,10 +53,15 @@ public:
|
||||
|
||||
bool latest(AVFrame **frame, uint32_t *id)
|
||||
{
|
||||
_reading.store(_latest.load());
|
||||
_reading.store(_oldest.load());
|
||||
int index = _reading.load();
|
||||
if (index < 0)
|
||||
return false;
|
||||
{
|
||||
_reading.store(_latest.load());
|
||||
index = _reading.load();
|
||||
if (index < 0)
|
||||
return false;
|
||||
}
|
||||
*frame = _frames[index];
|
||||
*id = _ids[index];
|
||||
return true;
|
||||
@@ -63,13 +69,15 @@ public:
|
||||
|
||||
void consume()
|
||||
{
|
||||
if(_oldest.load() == _reading.load())
|
||||
_oldest.store(-1);
|
||||
_reading.store(-1);
|
||||
}
|
||||
|
||||
AVFrame *write(uint32_t id)
|
||||
{
|
||||
int index = _writing.load();
|
||||
while (index == _reading.load() || index == _latest.load())
|
||||
while (index == _reading.load() || index == _latest.load() || index == _oldest.load())
|
||||
{
|
||||
index = (index + 1) % BUFFER_VIDEO_FRAMES;
|
||||
}
|
||||
@@ -80,17 +88,20 @@ public:
|
||||
|
||||
void commit()
|
||||
{
|
||||
_oldest.store(_latest.load());
|
||||
_latest.store(_writing.load());
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
_writing.store(0);
|
||||
_oldest.store(-1);
|
||||
_reading.store(-1);
|
||||
_latest.store(-1);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<int8_t> _oldest;
|
||||
std::atomic<int8_t> _latest;
|
||||
std::atomic<int8_t> _reading;
|
||||
std::atomic<int8_t> _writing;
|
||||
@@ -98,4 +109,4 @@ private:
|
||||
uint32_t _ids[BUFFER_VIDEO_FRAMES];
|
||||
};
|
||||
|
||||
#endif /* SRC_STRUCT_VIDEO_BUFFER */
|
||||
#endif /* SRC_STRUCT_VIDER_BUFFER2 */
|
||||
|
||||
Reference in New Issue
Block a user