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:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ private:
|
||||
|
||||
VideoRenderFrameCache frame_cache_;
|
||||
|
||||
TimeRangeList missing_cache_;
|
||||
TimeRangeList invalidated_;
|
||||
|
||||
rational last_time_requested_;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user