Skip to content

Commit

Permalink
Cancel requests by ID
Browse files Browse the repository at this point in the history
  • Loading branch information
darbyjohnston committed Mar 11, 2024
1 parent 531d86c commit 556afde
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 60 deletions.
2 changes: 1 addition & 1 deletion lib/tlBakeApp/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ namespace tl
_render->begin(_renderSize);
_render->setOCIOOptions(_options.ocioOptions);
_render->setLUTOptions(_options.lutOptions);
const auto videoData = _timeline->getVideo(_inputTime).get();
const auto videoData = _timeline->getVideo(_inputTime).future.get();
_render->drawVideo(
{ videoData },
{ math::Box2i(0, 0, _renderSize.w, _renderSize.h) });
Expand Down
19 changes: 16 additions & 3 deletions lib/tlTimeline/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,23 @@ namespace tl
// Clear requests.
if (clearRequests)
{
p.timeline->cancelRequests();
for (const auto& i : p.thread.compare)
std::vector<std::vector<uint64_t> > ids;
ids.resize(1 + p.thread.compare.size());
for (const auto& i : p.thread.videoDataRequests)
{
i->cancelRequests();
for (size_t j = 0; j < i.second.size() && j < ids.size(); ++j)
{
ids[j].push_back(i.second[j].id);
}
}
for (const auto& i : p.thread.audioDataRequests)
{
ids[0].push_back(i.second.id);
}
p.timeline->cancelRequests(ids[0]);
for (size_t i = 0; i < p.thread.compare.size(); ++i)
{
p.thread.compare[i]->cancelRequests(ids[i + 1]);
}
p.thread.videoDataRequests.clear();
p.thread.audioDataRequests.clear();
Expand Down
12 changes: 6 additions & 6 deletions lib/tlTimeline/PlayerPrivate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,8 @@ namespace tl
videoDataRequestIt != videoDataRequestsIt->second.end();
++videoDataRequestIt)
{
ready &= videoDataRequestIt->valid() &&
videoDataRequestIt->wait_for(std::chrono::seconds(0)) == std::future_status::ready;
ready &= videoDataRequestIt->future.valid() &&
videoDataRequestIt->future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
if (ready)
{
Expand All @@ -397,7 +397,7 @@ namespace tl
videoDataRequestIt != videoDataRequestsIt->second.end();
++videoDataRequestIt)
{
auto data = videoDataRequestIt->get();
auto data = videoDataRequestIt->future.get();
data.time = time;
thread.videoDataCache[data.time].push_back(data);
}
Expand All @@ -413,10 +413,10 @@ namespace tl
auto audioDataRequestsIt = thread.audioDataRequests.begin();
while (audioDataRequestsIt != thread.audioDataRequests.end())
{
if (audioDataRequestsIt->second.valid() &&
audioDataRequestsIt->second.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
if (audioDataRequestsIt->second.future.valid() &&
audioDataRequestsIt->second.future.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
auto audioData = audioDataRequestsIt->second.get();
auto audioData = audioDataRequestsIt->second.future.get();
audioData.seconds = audioDataRequestsIt->first;
{
std::unique_lock<std::mutex> lock(audioMutex.mutex);
Expand Down
4 changes: 2 additions & 2 deletions lib/tlTimeline/PlayerPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,12 @@ namespace tl
CacheDirection cacheDirection = CacheDirection::Forward;
PlayerCacheOptions cacheOptions;

std::map<otime::RationalTime, std::vector<std::future<VideoData> > > videoDataRequests;
std::map<otime::RationalTime, std::vector<VideoRequest> > videoDataRequests;
std::map<otime::RationalTime, std::vector<VideoData> > videoDataCache;
#if defined(TLRENDER_AUDIO)
std::unique_ptr<RtAudio> rtAudio;
#endif // TLRENDER_AUDIO
std::map<int64_t, std::future<AudioData> > audioDataRequests;
std::map<int64_t, AudioRequest> audioDataRequests;
std::chrono::steady_clock::time_point cacheTimer;
std::chrono::steady_clock::time_point logTimer;
std::atomic<bool> running;
Expand Down
60 changes: 42 additions & 18 deletions lib/tlTimeline/Timeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,15 +251,19 @@ namespace tl
return _p->ioInfo;
}

std::future<VideoData> Timeline::getVideo(
VideoRequest Timeline::getVideo(
const otime::RationalTime& time,
const io::Options& options)
{
TLRENDER_P();
(p.requestId)++;
auto request = std::make_shared<Private::VideoRequest>();
request->id = p.requestId;
request->time = time;
request->options = options;
auto future = request->promise.get_future();
VideoRequest out;
out.id = p.requestId;
out.future = request->promise.get_future();
bool valid = false;
{
std::unique_lock<std::mutex> lock(p.mutex.mutex);
Expand All @@ -277,18 +281,22 @@ namespace tl
{
request->promise.set_value(VideoData());
}
return future;
return out;
}

std::future<AudioData> Timeline::getAudio(
AudioRequest Timeline::getAudio(
double seconds,
const io::Options& options)
{
TLRENDER_P();
(p.requestId)++;
auto request = std::make_shared<Private::AudioRequest>();
request->id = p.requestId;
request->seconds = seconds;
request->options = options;
auto future = request->promise.get_future();
AudioRequest out;
out.id = p.requestId;
out.future = request->promise.get_future();
bool valid = false;
{
std::unique_lock<std::mutex> lock(p.mutex.mutex);
Expand All @@ -306,26 +314,42 @@ namespace tl
{
request->promise.set_value(AudioData());
}
return future;
return out;
}

void Timeline::cancelRequests()
void Timeline::cancelRequests(const std::vector<uint64_t>& ids)
{
TLRENDER_P();
std::list<std::shared_ptr<Private::VideoRequest> > videoRequests;
std::list<std::shared_ptr<Private::AudioRequest> > audioRequests;
{
std::unique_lock<std::mutex> lock(p.mutex.mutex);
videoRequests = std::move(p.mutex.videoRequests);
audioRequests = std::move(p.mutex.audioRequests);
}
for (auto& request : videoRequests)
std::unique_lock<std::mutex> lock(p.mutex.mutex);
{
request->promise.set_value(VideoData());
auto i = p.mutex.videoRequests.begin();
while (i != p.mutex.videoRequests.end())
{
const auto j = std::find(ids.begin(), ids.end(), (*i)->id);
if (j != ids.end())
{
i = p.mutex.videoRequests.erase(i);
}
else
{
++i;
}
}
}
for (auto& request : audioRequests)
{
request->promise.set_value(AudioData());
auto i = p.mutex.audioRequests.begin();
while (i != p.mutex.audioRequests.end())
{
const auto j = std::find(ids.begin(), ids.end(), (*i)->id);
if (j != ids.end())
{
i = p.mutex.audioRequests.erase(i);
}
else
{
++i;
}
}
}
}

Expand Down
22 changes: 17 additions & 5 deletions lib/tlTimeline/Timeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ namespace tl
const std::shared_ptr<system::Context>&,
const Options& = Options());

//! Video request.
struct VideoRequest
{
uint64_t id = 0;
std::future<VideoData> future;
};

//! Audio request.
struct AudioRequest
{
uint64_t id = 0;
std::future<AudioData> future;
};

//! Timeline.
class Timeline : public std::enable_shared_from_this<Timeline>
{
Expand Down Expand Up @@ -159,19 +173,17 @@ namespace tl
///@{

//! Get video data.
std::future<VideoData> getVideo(
VideoRequest getVideo(
const otime::RationalTime&,
const io::Options& = io::Options());

//! Get audio data.
std::future<AudioData> getAudio(
AudioRequest getAudio(
double seconds,
const io::Options& = io::Options());

//! Cancel requests.
//!
//! \todo Change this to cancel only specific requests.
void cancelRequests();
void cancelRequests(const std::vector<uint64_t>&);

///@}

Expand Down
3 changes: 3 additions & 0 deletions lib/tlTimeline/TimelinePrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ namespace tl
memory::LRUCache<std::string, std::shared_ptr<io::IRead> > readCache;
otime::TimeRange timeRange = time::invalidTimeRange;
io::Info ioInfo;
uint64_t requestId = 0;

struct VideoLayerData
{
Expand All @@ -74,6 +75,7 @@ namespace tl
VideoRequest() {};
VideoRequest(VideoRequest&&) = default;

uint64_t id = 0;
otime::RationalTime time = time::invalidTime;
io::Options options;
std::promise<VideoData> promise;
Expand All @@ -95,6 +97,7 @@ namespace tl
AudioRequest() {};
AudioRequest(AudioRequest&&) = default;

uint64_t id = 0;
double seconds = -1.0;
io::Options options;
std::promise<AudioData> promise;
Expand Down
59 changes: 34 additions & 25 deletions tests/tlTimelineTest/TimelineTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,80 +134,89 @@ namespace tl
// Get video from the timeline.
const otime::TimeRange& timeRange = timeline->getTimeRange();
std::vector<timeline::VideoData> videoData;
std::vector<std::future<timeline::VideoData> > videoFutures;
std::vector<timeline::VideoRequest> videoRequests;
for (size_t i = 0; i < static_cast<size_t>(timeRange.duration().value()); ++i)
{
videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0)));
videoRequests.push_back(timeline->getVideo(otime::RationalTime(i, 24.0)));
}
io::Options ioOptions;
ioOptions["Layer"] = "1";
for (size_t i = 0; i < static_cast<size_t>(timeRange.duration().value()); ++i)
{
videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0), ioOptions));
videoRequests.push_back(timeline->getVideo(otime::RationalTime(i, 24.0), ioOptions));
}
while (videoData.size() < static_cast<size_t>(timeRange.duration().value()) * 2)
{
auto i = videoFutures.begin();
while (i != videoFutures.end())
auto i = videoRequests.begin();
while (i != videoRequests.end())
{
if (i->valid() &&
i->wait_for(std::chrono::seconds(0)) == std::future_status::ready)
if (i->future.valid() &&
i->future.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
videoData.push_back(i->get());
i = videoFutures.erase(i);
videoData.push_back(i->future.get());
i = videoRequests.erase(i);
}
else
{
++i;
}
}
}
TLRENDER_ASSERT(videoFutures.empty());
TLRENDER_ASSERT(videoRequests.empty());

// Get audio from the timeline.
std::vector<timeline::AudioData> audioData;
std::vector<std::future<timeline::AudioData> > audioFutures;
std::vector<timeline::AudioRequest> audioRequests;
for (size_t i = 0; i < static_cast<size_t>(timeRange.duration().rescaled_to(1.0).value()); ++i)
{
audioFutures.push_back(timeline->getAudio(i));
audioRequests.push_back(timeline->getAudio(i));
}
while (audioData.size() < static_cast<size_t>(timeRange.duration().rescaled_to(1.0).value()))
{
auto i = audioFutures.begin();
while (i != audioFutures.end())
auto i = audioRequests.begin();
while (i != audioRequests.end())
{
if (i->valid() &&
i->wait_for(std::chrono::seconds(0)) == std::future_status::ready)
if (i->future.valid() &&
i->future.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
audioData.push_back(i->get());
i = audioFutures.erase(i);
audioData.push_back(i->future.get());
i = audioRequests.erase(i);
}
else
{
++i;
}
}
}
TLRENDER_ASSERT(audioFutures.empty());
TLRENDER_ASSERT(audioRequests.empty());

// Cancel requests.
videoData.clear();
videoFutures.clear();
videoRequests.clear();
audioData.clear();
audioFutures.clear();
audioRequests.clear();
for (size_t i = 0; i < static_cast<size_t>(timeRange.duration().value()); ++i)
{
videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0)));
videoRequests.push_back(timeline->getVideo(otime::RationalTime(i, 24.0)));
}
for (size_t i = 0; i < static_cast<size_t>(timeRange.duration().value()); ++i)
{
videoFutures.push_back(timeline->getVideo(otime::RationalTime(i, 24.0), ioOptions));
videoRequests.push_back(timeline->getVideo(otime::RationalTime(i, 24.0), ioOptions));
}
for (size_t i = 0; i < static_cast<size_t>(timeRange.duration().rescaled_to(1.0).value()); ++i)
{
audioFutures.push_back(timeline->getAudio(i));
audioRequests.push_back(timeline->getAudio(i));
}
timeline->cancelRequests();
std::vector<uint64_t> ids;
for (const auto& i : videoRequests)
{
ids.push_back(i.id);
}
for (const auto& i : audioRequests)
{
ids.push_back(i.id);
}
timeline->cancelRequests(ids);
}

void TimelineTest::_separateAudio()
Expand Down

0 comments on commit 556afde

Please sign in to comment.