File decoder_cache.hpp
File List > plugins > semantic_python > decoder_cache.hpp
Go to the documentation of this file
#pragma once
#include "illixr/data_format/semantics.hpp"
#include "illixr/switchboard.hpp"
#include
#include
#include
#include
#include
#include
namespace ILLIXR::decode {
// ---------------------------------------------------------------------------
// decoded_frame_cache
//
// Ring buffer storing decoded RGB frames alongside their frame numbers.
// Sized to match the switchboard topic history depth (256).
//
// Written by the decode callback (switchboard thread).
// Read by latest() (Python thread).
// Protected by a mutex.
//
// Each slot owns a std::vector that holds a copy of the pinned
// host RGB buffer. The copy is necessary because NvdecDecoder reuses its
// pinned buffer on each decode() call.
// ---------------------------------------------------------------------------
class decoded_frame_cache {
public:
static constexpr size_t CAPACITY = 256;
struct Entry {
std::vector<uint8_t> rgb; // packed RGB uint8, H*W*3 bytes
int32_t frame_number = -1;
int32_t width = 0;
int32_t height = 0;
bool valid = false;
};
// Store a decoded RGB frame. Copies from the pinned host pointer.
void store(int32_t frame_number, int32_t w, int32_t h, const uint8_t* rgb_data) {
std::lock_guard<std::mutex> lock(mutex_);
Entry& slot = entries_[next_slot_];
slot.frame_number = frame_number;
slot.width = w;
slot.height = h;
const auto nbytes = static_cast<size_t>(w * h * 3);
slot.rgb.resize(nbytes);
std::memcpy(slot.rgb.data(), rgb_data, nbytes);
slot.valid = true;
next_slot_ = (next_slot_ + 1) % CAPACITY;
}
// Return a copy of the most recently stored entry, taken under the lock.
// Returns nullopt if no frame has been stored yet.
std::optional<Entry> latest() const {
std::lock_guard<std::mutex> lock(mutex_);
int32_t best_fn = -1;
const Entry* best = nullptr;
for (const auto& e : entries_) {
if (e.valid && e.frame_number > best_fn) {
best_fn = e.frame_number;
best = &e;
}
}
if (best == nullptr)
return std::nullopt;
return *best; // copy made while lock is held
}
private:
mutable std::mutex mutex_;
std::array<Entry, CAPACITY> entries_;
size_t next_slot_ = 0;
};
// ---------------------------------------------------------------------------
// semantic_metadata_cache
//
// Ring buffer storing each semantic_frame (depth, poses, intrinsics, etc.),
// keyed by frame_number. Holds a switchboard::ptr to the frame itself rather
// than copying individual fields out, so the frame's other data stays alive
// and zero-copy-accessible for as long as the slot is valid.
//
// decode lags arrival by a variable amount (see nvdec_decoder::decode), so
// the frame most recently decoded is not the frame most recently arrived.
// This cache lets get() look up the arrival-time data (depth/pose/etc.)
// for whichever frame_number the decoder actually finished decoding,
// rather than assuming the two arrive together.
//
// Written by on_semantic_data() (switchboard thread), at arrival, before
// the decode call. Read by find() (Python thread).
// Protected by a mutex.
// ---------------------------------------------------------------------------
class semantic_metadata_cache {
public:
static constexpr size_t CAPACITY = 256;
struct Entry {
switchboard::ptr<const data_format::semantic_frame> data;
int32_t frame_number = -1;
bool valid = false;
};
// Store a frame's metadata, keyed by frame_number.
void store(int32_t frame_number, const switchboard::ptr<const data_format::semantic_frame>& frame) {
std::lock_guard<std::mutex> lock(mutex_);
Entry& slot = entries_[next_slot_];
slot.data = frame;
slot.frame_number = frame_number;
slot.valid = true;
next_slot_ = (next_slot_ + 1) % CAPACITY;
}
// Return a copy of the entry matching frame_number, taken under the lock.
// Returns nullopt if not found (evicted or not yet arrived).
std::optional<Entry> find(int32_t frame_number) const {
std::lock_guard<std::mutex> lock(mutex_);
for (const auto& e : entries_) {
if (e.valid && e.frame_number == frame_number)
return e; // copy made while lock is held
}
return std::nullopt;
}
private:
mutable std::mutex mutex_;
std::array<Entry, CAPACITY> entries_;
size_t next_slot_ = 0;
};
} // namespace ILLIXR::decode