fix: use mxlSleepUntil delivery deadline pattern for grain timing

Match the mxl-gst-sink pattern: sleep until the next grain's delivery
deadline using mxlSleepUntil, then read with a short 5ms timeout.
Uses 2-grain read delay (40ms at 50fps) for buffering headroom.

Previous approach of mxlSleepForNs + 20ms GetGrain timeout caused the
passthrough to fall behind: each iteration took ~25ms (poll+sleep+read),
missing grains and perpetually chasing headIndex via realign.
This commit is contained in:
Johanness
2026-05-26 22:46:33 +03:00
parent 2c712592dd
commit 503023f3e5
2 changed files with 30 additions and 21 deletions
+28 -20
View File
@@ -25,9 +25,14 @@ void PassthroughNode::on_add_reader(const std::string& port_id, mxlFlowReader re
mxlFlowReaderGetConfigInfo(*reader_, &config);
grain_rate_ = config.common.grainRate;
realign();
spdlog::info("Passthrough: reader added on video_in, grain_rate={}/{}, read_index={}",
grain_rate_.numerator, grain_rate_.denominator, read_index_);
auto now = mxlGetTime();
auto current_index = mxlTimestampToIndex(&grain_rate_, now);
read_index_ = current_index - READ_DELAY_GRAINS;
delivery_deadline_ = mxlIndexToTimestamp(&grain_rate_, read_index_ + 1);
aligned_ = true;
spdlog::info("Passthrough: reader added, grain_rate={}/{}, read_index={}, delay={} grains",
grain_rate_.numerator, grain_rate_.denominator, read_index_, READ_DELAY_GRAINS);
}
}
@@ -45,32 +50,32 @@ void PassthroughNode::on_remove_reader(const std::string& port_id) {
}
}
void PassthroughNode::realign() {
auto now = mxlGetTime();
auto current_index = mxlTimestampToIndex(&grain_rate_, now);
constexpr int64_t read_delay_grains = 1;
read_index_ = current_index - read_delay_grains;
aligned_ = true;
}
void PassthroughNode::process() {
if (!reader_ || !writer_ || !aligned_) {
return;
}
auto wait_ns = mxlGetNsUntilIndex(read_index_, &grain_rate_);
if (wait_ns > 0 && wait_ns < 500000000ULL) {
mxlSleepForNs(wait_ns);
auto now = mxlGetTime();
if (delivery_deadline_ > now) {
auto sleep_ns = delivery_deadline_ - now;
if (sleep_ns < 500000000ULL) {
mxlSleepUntil(delivery_deadline_);
}
}
mxlGrainInfo grain_info{};
uint8_t* payload = nullptr;
auto status = mxlFlowReaderGetGrain(*reader_, read_index_, 20000000ULL, &grain_info, &payload);
auto status = mxlFlowReaderGetGrain(*reader_, read_index_, 5000000ULL, &grain_info, &payload);
if (status != MXL_STATUS_OK) {
if (status == MXL_ERR_OUT_OF_RANGE_TOO_LATE || status == MXL_ERR_OUT_OF_RANGE_TOO_EARLY) {
spdlog::warn("Passthrough: index {} out of range ({}), realigning", read_index_, static_cast<int>(status));
realign();
auto old_index = read_index_;
now = mxlGetTime();
auto current_index = mxlTimestampToIndex(&grain_rate_, now);
read_index_ = current_index - READ_DELAY_GRAINS;
delivery_deadline_ = mxlIndexToTimestamp(&grain_rate_, read_index_ + 1);
spdlog::warn("Passthrough: index {} out of range ({}), realigned to {}",
old_index, static_cast<int>(status), read_index_);
}
return;
}
@@ -79,8 +84,10 @@ void PassthroughNode::process() {
uint8_t* out_payload = nullptr;
status = mxlFlowWriterOpenGrain(*writer_, grain_info.index, &out_grain, &out_payload);
if (status != MXL_STATUS_OK) {
spdlog::warn("Passthrough: failed to open output grain at index {}: {}", grain_info.index, static_cast<int>(status));
read_index_ = grain_info.index + 1;
spdlog::warn("Passthrough: failed to open output grain at index {}: {}",
grain_info.index, static_cast<int>(status));
read_index_++;
delivery_deadline_ = mxlIndexToTimestamp(&grain_rate_, read_index_ + 1);
return;
}
@@ -91,7 +98,8 @@ void PassthroughNode::process() {
out_grain.flags = grain_info.flags;
mxlFlowWriterCommitGrain(*writer_, &out_grain);
read_index_ = grain_info.index + 1;
read_index_++;
delivery_deadline_ = mxlIndexToTimestamp(&grain_rate_, read_index_ + 1);
grains_processed_++;
if (grains_processed_ <= 5 || grains_processed_ % 50 == 0) {
+2 -1
View File
@@ -33,12 +33,13 @@ public:
nlohmann::json status() const override;
private:
void realign();
static constexpr int64_t READ_DELAY_GRAINS = 2;
std::optional<mxlFlowReader> reader_;
std::optional<mxlFlowWriter> writer_;
mxlRational grain_rate_{50, 1};
uint64_t read_index_ = 0;
uint64_t delivery_deadline_ = 0;
uint64_t grains_processed_ = 0;
bool aligned_ = false;
};