From 32f5b70f59e8b7e884de88378897bd6bc95643de Mon Sep 17 00:00:00 2001 From: Johanness Date: Tue, 19 May 2026 00:43:04 +0300 Subject: [PATCH] Avoid steady-state v210 double copy --- IVideoFeed.hpp | 12 +++++ MxlSdkFeed.cpp | 111 ++++++++++++++++++++++++++++++++++++++++ MxlSdkFeed.hpp | 5 ++ main.cpp | 136 +++++++++++++++++++++++++++++++++++-------------- 4 files changed, 227 insertions(+), 37 deletions(-) diff --git a/IVideoFeed.hpp b/IVideoFeed.hpp index dbeafa4..efed6cb 100644 --- a/IVideoFeed.hpp +++ b/IVideoFeed.hpp @@ -2,6 +2,7 @@ #include "VideoFrame.hpp" +#include #include #include @@ -52,6 +53,17 @@ public: virtual bool hasV210() const { return false; } virtual const uint8_t* v210Data() const { return nullptr; } + virtual bool supportsDirectV210Read() const { return false; } + virtual bool readV210FrameInto( + uint32_t frameCounter, + void* destination, + size_t destinationSize) + { + (void)frameCounter; + (void)destination; + (void)destinationSize; + return false; + } virtual uint32_t v210Width() const { return 0; } virtual uint32_t v210Height() const { return 0; } virtual uint32_t v210Stride() const { return 0; } diff --git a/MxlSdkFeed.cpp b/MxlSdkFeed.cpp index 8b25e76..a369db7 100644 --- a/MxlSdkFeed.cpp +++ b/MxlSdkFeed.cpp @@ -518,6 +518,105 @@ const VideoFrame& MxlSdkFeed::getFrame(uint32_t frameCounter) return mFrame; } +bool MxlSdkFeed::readV210FrameInto( + uint32_t frameCounter, + void* destination, + size_t destinationSize) +{ + (void)frameCounter; + + if (!mFlowOpened && !openFlow()) + { + return false; + } + + uint64_t index = mLastDisplayedIndex + 1; + const uint64_t currentIndex = mxlGetCurrentIndex(&mGrainRate); + + if (index > currentIndex) + { + return false; + } + + mxlGrainInfo grain{}; + grain.version = 2; + grain.size = sizeof(mxlGrainInfo); + + uint8_t* payload = nullptr; + + while (true) + { + mxlStatus status = mxlFlowReaderGetGrainNonBlocking( + mReader, + index, + &grain, + &payload); + + if (status == MXL_STATUS_OK) + { + break; + } + + if (status == MXL_ERR_OUT_OF_RANGE_TOO_EARLY) + { + return false; + } + + if (status == MXL_ERR_OUT_OF_RANGE_TOO_LATE) + { + mxlFlowRuntimeInfo runtimeInfo{}; + if (mxlFlowReaderGetRuntimeInfo(mReader, &runtimeInfo) != + MXL_STATUS_OK) + { + return false; + } + + if (runtimeInfo.headIndex == 0) + { + return false; + } + + index = runtimeInfo.headIndex - 1; + + if (index <= mLastDisplayedIndex) + { + return false; + } + + continue; + } + + if (status == MXL_ERR_FLOW_INVALID) + { + std::cerr << "MxlSdkFeed: flow invalidated, reconnecting" + << std::endl; + closeFlow(); + return false; + } + + std::cerr << "MxlSdkFeed: grain read error status=" + << static_cast(status) << std::endl; + return false; + } + + const size_t payloadSize = + static_cast(mSourceStride) * + static_cast(mSourceHeight); + + if (payload == nullptr || + destination == nullptr || + payloadSize == 0 || + destinationSize < payloadSize) + { + return false; + } + + std::memcpy(destination, payload, payloadSize); + mLastDisplayedIndex = index; + ++mFrameVersion; + return true; +} + FeedRuntimeStatus MxlSdkFeed::status() const { if (mFlowOpened && !mV210Payload.empty()) @@ -616,6 +715,7 @@ float MxlSdkFeed::srcAspectRatio() const bool MxlSdkFeed::hasV210() const { return mFlowOpened && !mV210Payload.empty(); } const uint8_t* MxlSdkFeed::v210Data() const { return mV210Payload.data(); } +bool MxlSdkFeed::supportsDirectV210Read() const { return mFlowOpened; } uint32_t MxlSdkFeed::v210Width() const { return mSourceWidth; } uint32_t MxlSdkFeed::v210Height() const { return mSourceHeight; } uint32_t MxlSdkFeed::v210Stride() const { return mSourceStride; } @@ -635,6 +735,17 @@ double MxlSdkFeed::frameRate() const { return 0.0; } float MxlSdkFeed::srcAspectRatio() const { return 16.0f / 9.0f; } bool MxlSdkFeed::hasV210() const { return false; } const uint8_t* MxlSdkFeed::v210Data() const { return nullptr; } +bool MxlSdkFeed::supportsDirectV210Read() const { return false; } +bool MxlSdkFeed::readV210FrameInto( + uint32_t frameCounter, + void* destination, + size_t destinationSize) +{ + (void)frameCounter; + (void)destination; + (void)destinationSize; + return false; +} uint32_t MxlSdkFeed::v210Width() const { return 0; } uint32_t MxlSdkFeed::v210Height() const { return 0; } uint32_t MxlSdkFeed::v210Stride() const { return 0; } diff --git a/MxlSdkFeed.hpp b/MxlSdkFeed.hpp index fbcfb41..1601f94 100644 --- a/MxlSdkFeed.hpp +++ b/MxlSdkFeed.hpp @@ -46,6 +46,11 @@ public: bool hasV210() const override; const uint8_t* v210Data() const override; + bool supportsDirectV210Read() const override; + bool readV210FrameInto( + uint32_t frameCounter, + void* destination, + size_t destinationSize) override; uint32_t v210Width() const override; uint32_t v210Height() const override; uint32_t v210Stride() const override; diff --git a/main.cpp b/main.cpp index c0601fa..471bc56 100644 --- a/main.cpp +++ b/main.cpp @@ -836,6 +836,7 @@ int main(int argc, char* argv[]) std::vector pendingFrames(feedCount); std::vector pendingVersions(feedCount); std::vector pendingUploadNeeded(feedCount); + std::vector postFenceDirectV210Read(feedCount); std::vector feedUploadCredits(feedCount, 1.0); uint64_t lastUploadPaceTicks = SDL_GetPerformanceCounter(); @@ -1353,6 +1354,11 @@ int main(int argc, char* argv[]) pendingUploadNeeded.end(), false ); + std::fill( + postFenceDirectV210Read.begin(), + postFenceDirectV210Read.end(), + false + ); const uint64_t uploadPaceTicks = SDL_GetPerformanceCounter(); @@ -1385,8 +1391,52 @@ int main(int argc, char* argv[]) } } + auto recordFeedVersionStats = + [&](uint32_t feedIndex, bool uploadNeeded) + { + if (!config.logPerf) + { + return; + } + + if (uploadNeeded) + { + ++feedPerfStats[feedIndex].updates; + + if (feeds[feedIndex]->hasGrainIndex()) + { + const uint64_t grain = + feeds[feedIndex]->grainIndex(); + + if (feedPerfStats[feedIndex].hasLastGrain && + grain > + feedPerfStats[feedIndex].lastGrain + 1) + { + feedPerfStats[feedIndex].skippedGrains += + grain - + feedPerfStats[feedIndex].lastGrain - + 1; + } + + feedPerfStats[feedIndex].lastGrain = grain; + feedPerfStats[feedIndex].hasLastGrain = true; + } + } + else + { + ++feedPerfStats[feedIndex].repeats; + } + }; + for (uint32_t i = 0; i < feedCount; ++i) { + if (v210FeedReady[i] && + feeds[i]->supportsDirectV210Read()) + { + postFenceDirectV210Read[i] = true; + continue; + } + perfSectionStartTicks = SDL_GetPerformanceCounter(); @@ -1405,33 +1455,7 @@ int main(int argc, char* argv[]) perfStats.feedReadTicks += elapsed; framePerf.feedReadTicks += elapsed; - if (uploadNeeded) - { - ++feedPerfStats[i].updates; - - if (feeds[i]->hasGrainIndex()) - { - const uint64_t grain = - feeds[i]->grainIndex(); - - if (feedPerfStats[i].hasLastGrain && - grain > - feedPerfStats[i].lastGrain + 1) - { - feedPerfStats[i].skippedGrains += - grain - - feedPerfStats[i].lastGrain - - 1; - } - - feedPerfStats[i].lastGrain = grain; - feedPerfStats[i].hasLastGrain = true; - } - } - else - { - ++feedPerfStats[i].repeats; - } + recordFeedVersionStats(i, uploadNeeded); } if (!uploadNeeded) @@ -1511,12 +1535,16 @@ int main(int argc, char* argv[]) const uint32_t i = (uploadStart + offset) % feedCount; - if (!pendingUploadNeeded[i]) + const bool directV210Read = + postFenceDirectV210Read[i]; + + if (!directV210Read && !pendingUploadNeeded[i]) { continue; } - const bool isV210 = feeds[i]->hasV210(); + const bool isV210 = + directV210Read || feeds[i]->hasV210(); if (config.paceUploads && isV210 && feeds[i]->hasFrameRate() && @@ -1543,7 +1571,7 @@ int main(int argc, char* argv[]) if (isV210) { - if (!v210FeedReady[i]) + if (!directV210Read && !v210FeedReady[i]) { v210Decoder.createFeedResources( ctx.physicalDevice(), @@ -1580,13 +1608,47 @@ int main(int argc, char* argv[]) << std::endl; } - std::memcpy( - v210Feeds[i].v210MappedData, - feeds[i]->v210Data(), - static_cast( - feeds[i]->v210Stride() - ) * feeds[i]->v210Height() - ); + if (directV210Read) + { + const size_t v210Bytes = + static_cast( + feeds[i]->v210Stride() + ) * + static_cast( + feeds[i]->v210Height() + ); + + const bool copied = + feeds[i]->readV210FrameInto( + frameCounter, + v210Feeds[i].v210MappedData, + v210Bytes + ); + const uint64_t version = + feeds[i]->frameVersion(); + const bool uploadNeeded = + copied && + uploadedVersions[i] != version; + + recordFeedVersionStats(i, uploadNeeded); + + if (!uploadNeeded) + { + continue; + } + + pendingVersions[i] = version; + } + else + { + std::memcpy( + v210Feeds[i].v210MappedData, + feeds[i]->v210Data(), + static_cast( + feeds[i]->v210Stride() + ) * feeds[i]->v210Height() + ); + } } else {