mirror of
https://github.com/niellun/FastCarPlay.git
synced 2026-06-07 09:38:25 +02:00
Initial commit. Version 0.1
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
#include "raw_queue.h"
|
||||
|
||||
RawQueue::RawQueue(uint16_t capacity)
|
||||
: _buffer(capacity), _head(0), _tail(0), _size(0), _capacity(capacity)
|
||||
{
|
||||
}
|
||||
|
||||
RawQueue::~RawQueue()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
bool RawQueue::push(uint8_t *data, int offset, int size)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (_size == _buffer.size())
|
||||
{
|
||||
free(data);
|
||||
return false; // queue full
|
||||
}
|
||||
|
||||
_buffer[_tail] = RawEntry{data, offset, size};
|
||||
_tail = (_tail + 1) % _capacity;
|
||||
_size++;
|
||||
|
||||
_condition.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
RawEntry RawQueue::wait(const std::atomic<bool> &reading)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_condition.wait(lock, [&]
|
||||
{ return !reading.load() || _size > 0; });
|
||||
|
||||
if (!reading || _size == 0)
|
||||
return RawEntry{nullptr, 0, 0};
|
||||
|
||||
RawEntry entry = _buffer[_head];
|
||||
_head = (_head + 1) % _capacity;
|
||||
_size--;
|
||||
return entry;
|
||||
}
|
||||
|
||||
void RawQueue::clear()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
// Free any remaining buffers
|
||||
while (_size > 0)
|
||||
{
|
||||
RawEntry &e = _buffer[_head];
|
||||
if (e.data)
|
||||
{
|
||||
free(e.data);
|
||||
e.data = nullptr;
|
||||
}
|
||||
_head = (_head + 1) % _capacity;
|
||||
_size--;
|
||||
}
|
||||
|
||||
// Reset indices
|
||||
_head = _tail = 0;
|
||||
}
|
||||
|
||||
void RawQueue::notify()
|
||||
{
|
||||
_condition.notify_all();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef SRC_RAW_QUEUE
|
||||
#define SRC_RAW_QUEUE
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
struct RawEntry
|
||||
{
|
||||
uint8_t *data;
|
||||
int offset;
|
||||
int size;
|
||||
};
|
||||
|
||||
// Single entry: raw buffer pointer + metadata
|
||||
class RawQueue
|
||||
{
|
||||
public:
|
||||
RawQueue(uint16_t capacity = 256);
|
||||
~RawQueue();
|
||||
|
||||
// Non-blocking push: returns false if full
|
||||
bool push(uint8_t *data, int offset, int size);
|
||||
|
||||
// Blocks until an entry is available or reader_active == false
|
||||
RawEntry wait(const std::atomic<bool> &reading);
|
||||
|
||||
// Clears the queue and frees any pending buffers
|
||||
void clear();
|
||||
|
||||
// Unlock queus
|
||||
void notify();
|
||||
|
||||
private:
|
||||
std::vector<RawEntry> _buffer;
|
||||
uint16_t _head;
|
||||
uint16_t _tail;
|
||||
uint16_t _size;
|
||||
uint16_t _capacity;
|
||||
std::mutex _mutex;
|
||||
std::condition_variable _condition;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
#include "video_buffer.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <libavutil/imgutils.h>
|
||||
}
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
VideoBuffer::VideoBuffer()
|
||||
: _width(0), _height(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Allocate two YUV420P frames for double buffering and initialize to black
|
||||
Error VideoBuffer::allocate(uint16_t width, uint16_t height)
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
deallocate();
|
||||
reset();
|
||||
|
||||
Error e;
|
||||
for (uint8_t i = 0; i < BUFFER_VIDEO_FRAMES; ++i)
|
||||
{
|
||||
// Allocate AVFrame
|
||||
_frames[i] = av_frame_alloc();
|
||||
if (e.null(_frames[i], "Failed to allocate AVFrame"))
|
||||
break;
|
||||
_frames[i]->format = AV_PIX_FMT_YUV420P;
|
||||
_frames[i]->width = width;
|
||||
_frames[i]->height = height;
|
||||
// Allocate data buffer with 32 byte allingment
|
||||
if (e.avFail(av_frame_get_buffer(_frames[i], 32), "Failed to allocate AVFrame buffer"))
|
||||
break;
|
||||
// Set Y plane to black (0)
|
||||
memset(_frames[i]->data[0], 0, _frames[i]->linesize[0] * height);
|
||||
// Set U plane to 128 (neutral)
|
||||
memset(_frames[i]->data[1], 128, _frames[i]->linesize[1] * (height / 2));
|
||||
// Set V plane to 128 (neutral)
|
||||
memset(_frames[i]->data[2], 128, _frames[i]->linesize[2] * (height / 2));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
VideoBuffer::~VideoBuffer()
|
||||
{
|
||||
deallocate();
|
||||
}
|
||||
|
||||
void VideoBuffer::deallocate()
|
||||
{
|
||||
for (uint8_t i = 0; i < BUFFER_VIDEO_FRAMES; ++i)
|
||||
{
|
||||
if (_frames[i])
|
||||
{
|
||||
// Free the frame itself
|
||||
av_frame_free(&_frames[i]);
|
||||
// Clear
|
||||
_frames[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VideoBuffer::getLatest(AVFrame **frame, uint32_t *id)
|
||||
{
|
||||
_reading.store(_latest.load());
|
||||
int index = _reading.load();
|
||||
if (index < 0)
|
||||
return false;
|
||||
*frame = _frames[index];
|
||||
*id = _ids[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoBuffer::consumeLatest()
|
||||
{
|
||||
_reading.store(-1);
|
||||
}
|
||||
|
||||
const AVFrame *VideoBuffer::writeFrame(uint32_t id)
|
||||
{
|
||||
int index = _writing.load();
|
||||
while (index == _reading.load() || index == _latest.load())
|
||||
{
|
||||
index = (index + 1) % BUFFER_VIDEO_FRAMES;
|
||||
}
|
||||
_writing.store(index);
|
||||
_ids[index] = id;
|
||||
return _frames[index];
|
||||
}
|
||||
|
||||
void VideoBuffer::commitFrame()
|
||||
{
|
||||
_latest.store(_writing.load());
|
||||
}
|
||||
|
||||
void VideoBuffer::reset()
|
||||
{
|
||||
_writing.store(0);
|
||||
_reading.store(-1);
|
||||
_latest.store(-1);
|
||||
for (uint8_t i = 0; i < BUFFER_VIDEO_FRAMES; i++)
|
||||
{
|
||||
_ids[i] = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef SRC_VIDEO_BUFFER
|
||||
#define SRC_VIDEO_BUFFER
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <libavutil/frame.h> // For AVFrame
|
||||
}
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "helper/error.h"
|
||||
|
||||
#define BUFFER_VIDEO_FRAMES 3
|
||||
|
||||
class VideoBuffer
|
||||
{
|
||||
public:
|
||||
VideoBuffer();
|
||||
~VideoBuffer();
|
||||
|
||||
Error allocate(uint16_t width, uint16_t height);
|
||||
uint16_t width() const { return _width; };
|
||||
uint16_t height() const { return _height; };
|
||||
void reset();
|
||||
bool getLatest(AVFrame **frame, uint32_t *id);
|
||||
void consumeLatest();
|
||||
const AVFrame *writeFrame(uint32_t id);
|
||||
void commitFrame();
|
||||
|
||||
private:
|
||||
void deallocate();
|
||||
|
||||
uint16_t _width;
|
||||
uint16_t _height;
|
||||
std::atomic<int8_t> _latest;
|
||||
std::atomic<int8_t> _reading;
|
||||
std::atomic<int8_t> _writing;
|
||||
AVFrame *_frames[BUFFER_VIDEO_FRAMES] = {nullptr, nullptr, nullptr};
|
||||
uint32_t _ids[BUFFER_VIDEO_FRAMES];
|
||||
};
|
||||
|
||||
#endif /* SRC_VIDEO_BUFFER */
|
||||
Reference in New Issue
Block a user