video renderer will always render frames closest to the playhead first

A few commits ago, the render behavior was changed to only render within a
user-specified range of the playhead. This works well, but it would still
render from the start of the range (usually before the playhead) to the end,
meaning it couldn't keep up with the playhead as well as it should. This
commit prioritizes frames close to the playhead and renders outwards to
address this.
This commit is contained in:
itsmattkc
2020-01-12 01:14:56 +11:00
parent 0823c84fb2
commit 1c5d55012b
3 changed files with 53 additions and 17 deletions
+8 -4
View File
@@ -202,7 +202,8 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
DiskManager::instance()->Accessed(compressed_frame.fileName());
// Read data
QByteArray frame_loader = qUncompress(compressed_frame.readAll());
//QByteArray frame_loader = qUncompress(compressed_frame.readAll());
QByteArray frame_loader = compressed_frame.readAll();
// Frame was valid, now we convert it to a native Olive frame
FramePtr frame_container = Frame::Create();
@@ -277,8 +278,11 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
QFile save_frame(GetIndexFilename().append(QString::number(frame_->pts)));
if (save_frame.open(QFile::WriteOnly)) {
QByteArray compressed = qCompress(reinterpret_cast<const uchar*>(output_frame->data()), output_frame->allocated_size());
save_frame.write(compressed);
// FIXME: This compression is really slow
//QByteArray compressed = qCompress(reinterpret_cast<const uchar*>(output_frame->data()), output_frame->allocated_size());
//save_frame.write(compressed);
save_frame.write(output_frame->data(), output_frame->allocated_size());
save_frame.close();
DiskManager::instance()->CreatedFile(save_frame.fileName(), QByteArray());
@@ -374,7 +378,7 @@ int64_t FFmpegDecoder::GetTimestampFromTime(const rational &time)
return -1;
}
// Convert timecode to AVStream timebase
// Get rough approximation of what the timestamp would be in this timebase
int64_t target_ts = Timecode::time_to_timestamp(time, avstream_->time_base);
// Adjust target by stream's start time
+44 -12
View File
@@ -155,7 +155,7 @@ void VideoRenderBackend::InvalidateCacheInternal(const rational &start_range, co
{
TimeRange invalidated(start_range, end_range);
missing_cache_.InsertTimeRange(invalidated);
invalidated_.InsertTimeRange(invalidated);
emit RangeInvalidated(invalidated);
@@ -226,26 +226,58 @@ bool VideoRenderBackend::CanRender()
TimeRange VideoRenderBackend::PopNextFrameFromQueue()
{
TimeRange range = cache_queue_.first();
// Try to find the frame that's closest to the last time requested (the playhead)
// Snap the range to a single discrete frame
rational snapped_in = Timecode::snap_time_to_timebase(range.in(), params_.time_base());
// Set up playhead frame range to see if the queue contains this frame precisely
TimeRange test_range(last_time_requested_, last_time_requested_ + params_.time_base());
// Check if the range starts earlier, in which case we should render that frame instead
if (range.in() < snapped_in) {
snapped_in -= params_.time_base();
// Use this variable to find the closest frame in the range
rational closest_time = -1;
for (int i=0;i<cache_queue_.size();i++) {
const TimeRange& range_here = cache_queue_.at(i);
if (range_here.Contains(test_range)) {
closest_time = -1;
break;
}
rational compare_in = range_here.in();
rational compare_out = range_here.out() - params_.time_base();
if (closest_time < 0 || qAbs(compare_in - last_time_requested_) < qAbs(closest_time - last_time_requested_)) {
closest_time = compare_in;
}
if (closest_time < 0 || qAbs(compare_out - last_time_requested_) < qAbs(closest_time - last_time_requested_)) {
closest_time = compare_out;
}
}
TimeRange frame_range(snapped_in, snapped_in + params_.time_base());
TimeRange frame_range;
if (closest_time == -1) {
frame_range = test_range;
} else {
// Snap the range to a single discrete frame
rational snapped_in = Timecode::snap_time_to_timebase(closest_time, params_.time_base());
// Check if the range starts earlier, in which case we should render that frame instead
if (closest_time < snapped_in) {
frame_range = TimeRange(snapped_in - params_.time_base(), snapped_in);
} else {
frame_range = TimeRange(snapped_in, snapped_in + params_.time_base());
}
}
// Remove this particular frame from the queue
cache_queue_.RemoveTimeRange(frame_range);
// Remove this particular frame from missing frames
missing_cache_.RemoveTimeRange(frame_range);
invalidated_.RemoveTimeRange(frame_range);
// Return the snapped frame
return TimeRange(snapped_in, snapped_in);
return TimeRange(frame_range.in(), frame_range.in());
}
void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value)
@@ -321,7 +353,7 @@ void VideoRenderBackend::FrameRemovedFromDiskCache(const QByteArray &hash)
foreach (const rational& frame, deleted_frames) {
TimeRange invalidated(frame, frame+params_.time_base());
missing_cache_.InsertTimeRange(invalidated);
invalidated_.InsertTimeRange(invalidated);
emit RangeInvalidated(invalidated);
}
@@ -357,7 +389,7 @@ void VideoRenderBackend::Requeue()
TimeRange queueable_range(last_time_requested_ - Config::Current()["DiskCacheBehind"].value<rational>(),
last_time_requested_ + Config::Current()["DiskCacheAhead"].value<rational>());
cache_queue_ = missing_cache_.Intersects(queueable_range);
cache_queue_ = invalidated_.Intersects(queueable_range);
CacheNext();
}
+1 -1
View File
@@ -128,7 +128,7 @@ private:
VideoRenderFrameCache frame_cache_;
TimeRangeList missing_cache_;
TimeRangeList invalidated_;
rational last_time_requested_;