implemented core UI caching feedback functionality
Not a perfect implementation yet, but this shows UI feedback on what frames are cached and which ones aren't.
This commit is contained in:
@@ -58,6 +58,11 @@ TimeRange TimeRange::CombineWith(const TimeRange &a) const
|
||||
return Combine(a, *this);
|
||||
}
|
||||
|
||||
bool TimeRange::Contains(const TimeRange &a) const
|
||||
{
|
||||
return (a.in() >= in() && a.out() <= out());
|
||||
}
|
||||
|
||||
bool TimeRange::Overlap(const TimeRange &a, const TimeRange &b)
|
||||
{
|
||||
return !(a.out() < b.in() || a.in() > b.out());
|
||||
@@ -85,3 +90,43 @@ uint qHash(const TimeRange &r, uint seed)
|
||||
{
|
||||
return qHash(r.in(), seed) ^ qHash(r.out(), seed);
|
||||
}
|
||||
|
||||
void TimeRangeList::InsertTimeRange(const TimeRange &range)
|
||||
{
|
||||
for (int i=0;i<size();i++) {
|
||||
const TimeRange& compare = at(i);
|
||||
|
||||
if (TimeRange::Overlap(range, compare)) {
|
||||
replace(i, TimeRange::Combine(range, compare));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
append(range);
|
||||
}
|
||||
|
||||
void TimeRangeList::RemoveTimeRange(const TimeRange &range)
|
||||
{
|
||||
for (int i=0;i<size();i++) {
|
||||
const TimeRange& compare = at(i);
|
||||
|
||||
if (range.Contains(compare)) {
|
||||
// This element is entirely encompassed in this range, remove it
|
||||
removeAt(i);
|
||||
i--;
|
||||
} else if (compare.Contains(range)) {
|
||||
// The remove range is within this element, only choice is to split the element into two
|
||||
TimeRange first(compare.in(), range.in());
|
||||
TimeRange last(range.out(), compare.out());
|
||||
|
||||
replace(i, first);
|
||||
append(last);
|
||||
} else if (compare.in() < range.in() && compare.out() > range.in()) {
|
||||
// This element's out point overlaps the range's in, we'll trim it
|
||||
(*this)[i].set_out(range.in());
|
||||
} else if (compare.in() < range.out() && compare.out() > range.out()) {
|
||||
// This element's in point overlaps the range's out, we'll trim it
|
||||
(*this)[i].set_in(range.out());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
|
||||
bool OverlapsWith(const TimeRange& a) const;
|
||||
TimeRange CombineWith(const TimeRange& a) const;
|
||||
bool Contains(const TimeRange& a) const;
|
||||
|
||||
static bool Overlap(const TimeRange& a, const TimeRange& b);
|
||||
static TimeRange Combine(const TimeRange &a, const TimeRange &b);
|
||||
@@ -34,4 +35,14 @@ private:
|
||||
|
||||
uint qHash(const TimeRange& r, uint seed);
|
||||
|
||||
class TimeRangeList : public QList<TimeRange> {
|
||||
public:
|
||||
TimeRangeList() = default;
|
||||
|
||||
void InsertTimeRange(const TimeRange& range);
|
||||
|
||||
void RemoveTimeRange(const TimeRange& range);
|
||||
|
||||
};
|
||||
|
||||
#endif // TIMERANGE_H
|
||||
|
||||
@@ -39,10 +39,7 @@ void AudioRenderBackend::InvalidateCache(const rational &start_range, const rati
|
||||
rational end_range_adj = qMin(GetSequenceLength(), end_range);
|
||||
|
||||
// Add the range to the list
|
||||
cache_queue_.append(TimeRange(start_range_adj, end_range_adj));
|
||||
|
||||
// Remove any overlaps so we don't render the same thing twice
|
||||
ValidateRanges();
|
||||
cache_queue_.InsertTimeRange(TimeRange(start_range_adj, end_range_adj));
|
||||
|
||||
// Queue value update
|
||||
QueueValueUpdate();
|
||||
@@ -87,26 +84,6 @@ NodeInput *AudioRenderBackend::GetDependentInput()
|
||||
return viewer_node()->samples_input();
|
||||
}
|
||||
|
||||
void AudioRenderBackend::ValidateRanges()
|
||||
{
|
||||
for (int i=0;i<cache_queue_.size();i++) {
|
||||
const TimeRange& range1 = cache_queue_.at(i);
|
||||
|
||||
for (int j=0;j<cache_queue_.size();j++) {
|
||||
const TimeRange& range2 = cache_queue_.at(j);
|
||||
|
||||
if (TimeRange::Overlap(range1, range2) && i != j) {
|
||||
// Combine with the first range
|
||||
cache_queue_[i] = TimeRange::Combine(range1, range2);
|
||||
|
||||
// Remove the second range
|
||||
cache_queue_.removeAt(j);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString AudioRenderBackend::CachePathName()
|
||||
{
|
||||
QDir this_cache_dir = QDir(GetMediaCacheLocation()).filePath(cache_id());
|
||||
|
||||
@@ -42,8 +42,6 @@ protected:
|
||||
virtual bool CanRender() override;
|
||||
|
||||
private:
|
||||
void ValidateRanges();
|
||||
|
||||
AudioRenderingParams params_;
|
||||
|
||||
};
|
||||
|
||||
@@ -141,7 +141,7 @@ void OpenGLBackend::DecompileInternal()
|
||||
shader_cache_.Clear();
|
||||
}
|
||||
|
||||
void OpenGLBackend::EmitCachedFrameReady(const QList<rational> ×, const QVariant &value)
|
||||
void OpenGLBackend::EmitCachedFrameReady(const QList<rational> ×, const QVariant &value, qint64 job_time)
|
||||
{
|
||||
OpenGLTextureCache::ReferencePtr ref = value.value<OpenGLTextureCache::ReferencePtr>();
|
||||
OpenGLTexturePtr tex;
|
||||
@@ -153,7 +153,7 @@ void OpenGLBackend::EmitCachedFrameReady(const QList<rational> ×, const QVa
|
||||
}
|
||||
|
||||
foreach (const rational& t, times) {
|
||||
emit CachedFrameReady(t, QVariant::fromValue(tex));
|
||||
emit CachedFrameReady(t, QVariant::fromValue(tex), job_time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ protected:
|
||||
|
||||
virtual void DecompileInternal() override;
|
||||
|
||||
virtual void EmitCachedFrameReady(const QList<rational> ×, const QVariant& value) override;
|
||||
virtual void EmitCachedFrameReady(const QList<rational> ×, const QVariant& value, qint64 job_time) override;
|
||||
|
||||
private:
|
||||
OpenGLTexturePtr CopyTexture(OpenGLTexturePtr input);
|
||||
|
||||
@@ -90,7 +90,7 @@ protected:
|
||||
bool WorkerIsBusy(RenderWorker* worker) const;
|
||||
void SetWorkerBusyState(RenderWorker* worker, bool busy);
|
||||
|
||||
QList<TimeRange> cache_queue_;
|
||||
TimeRangeList cache_queue_;
|
||||
|
||||
QVector<RenderWorker*> processors_;
|
||||
|
||||
|
||||
@@ -159,6 +159,13 @@ void VideoRenderBackend::SetExportMode(bool enabled)
|
||||
export_mode_ = enabled;
|
||||
}
|
||||
|
||||
bool VideoRenderBackend::IsRendered(const rational &time) const
|
||||
{
|
||||
TimeRange range(time, time);
|
||||
|
||||
return !TimeIsQueued(range) && !render_job_info_.contains(range);
|
||||
}
|
||||
|
||||
bool VideoRenderBackend::GenerateCacheIDInternal(QCryptographicHash& hash)
|
||||
{
|
||||
if (!params_.is_valid()) {
|
||||
@@ -250,7 +257,7 @@ bool VideoRenderBackend::CanRender()
|
||||
void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value)
|
||||
{
|
||||
if (last_time_requested_ == path.in() || frame_cache_.TimeToHash(last_time_requested_) == hash) {
|
||||
EmitCachedFrameReady({last_time_requested_}, value);
|
||||
EmitCachedFrameReady({last_time_requested_}, value, job_time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +265,13 @@ void VideoRenderBackend::ThreadCompletedDownload(NodeDependency dep, qint64 job_
|
||||
{
|
||||
SetWorkerBusyState(static_cast<RenderWorker*>(sender()), false);
|
||||
|
||||
SetFrameHash(dep, hash, job_time);
|
||||
if (SetFrameHash(dep, hash, job_time)) {
|
||||
QList<rational> hashes_with_time = frame_cache()->FramesWithHash(hash);
|
||||
|
||||
foreach (const rational& t, hashes_with_time) {
|
||||
emit CachedTimeReady(t, job_time);
|
||||
}
|
||||
}
|
||||
|
||||
// Queue up a new frame for this worker
|
||||
CacheNext();
|
||||
@@ -269,9 +282,8 @@ void VideoRenderBackend::ThreadSkippedFrame(NodeDependency dep, qint64 job_time,
|
||||
SetWorkerBusyState(static_cast<RenderWorker*>(sender()), false);
|
||||
|
||||
if (SetFrameHash(dep, hash, job_time)
|
||||
&& last_time_requested_ == dep.in()
|
||||
&& frame_cache_.HasHash(hash)) {
|
||||
emit CachedTimeReady(dep.in());
|
||||
emit CachedTimeReady(dep.in(), job_time);
|
||||
}
|
||||
|
||||
// Queue up a new frame for this worker
|
||||
@@ -282,9 +294,8 @@ void VideoRenderBackend::ThreadHashAlreadyExists(NodeDependency dep, qint64 job_
|
||||
{
|
||||
SetWorkerBusyState(static_cast<RenderWorker*>(sender()), false);
|
||||
|
||||
if (SetFrameHash(dep, hash, job_time)
|
||||
&& dep.in() == last_time_requested_) {
|
||||
emit CachedTimeReady(dep.in());
|
||||
if (SetFrameHash(dep, hash, job_time)) {
|
||||
emit CachedTimeReady(dep.in(), job_time);
|
||||
}
|
||||
|
||||
// Queue up a new frame for this worker
|
||||
|
||||
@@ -55,6 +55,8 @@ public:
|
||||
|
||||
void SetExportMode(bool enabled);
|
||||
|
||||
bool IsRendered(const rational& time) const;
|
||||
|
||||
public slots:
|
||||
virtual void InvalidateCache(const rational &start_range, const rational &end_range) override;
|
||||
|
||||
@@ -97,13 +99,13 @@ protected:
|
||||
|
||||
virtual void ConnectWorkerToThis(RenderWorker* processor) override;
|
||||
|
||||
virtual void EmitCachedFrameReady(const QList<rational> ×, const QVariant& value) = 0;
|
||||
virtual void EmitCachedFrameReady(const QList<rational> ×, const QVariant& value, qint64 job_time) = 0;
|
||||
|
||||
bool export_mode_;
|
||||
|
||||
signals:
|
||||
void CachedFrameReady(const rational& time, QVariant value);
|
||||
void CachedTimeReady(const rational& time);
|
||||
void CachedFrameReady(const rational& time, QVariant value, qint64 job_time);
|
||||
void CachedTimeReady(const rational& time, qint64 job_time);
|
||||
|
||||
private:
|
||||
bool TimeIsQueued(const TimeRange &time) const;
|
||||
|
||||
@@ -81,6 +81,21 @@ void VideoRenderFrameCache::RemoveHashFromCurrentlyCaching(const QByteArray &has
|
||||
currently_caching_lock_.unlock();
|
||||
}
|
||||
|
||||
QList<rational> VideoRenderFrameCache::FramesWithHash(const QByteArray &hash)
|
||||
{
|
||||
QList<rational> times;
|
||||
|
||||
QMap<rational, QByteArray>::const_iterator iterator;
|
||||
|
||||
for (iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) {
|
||||
if (iterator.value() == hash) {
|
||||
times.append(iterator.key());
|
||||
}
|
||||
}
|
||||
|
||||
return times;
|
||||
}
|
||||
|
||||
QString VideoRenderFrameCache::CachePathName(const QByteArray &hash) const
|
||||
{
|
||||
QDir this_cache_dir = QDir(GetMediaCacheLocation()).filePath(cache_id_);
|
||||
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
|
||||
void RemoveHashFromCurrentlyCaching(const QByteArray& hash);
|
||||
|
||||
QList<rational> FramesWithHash(const QByteArray& hash);
|
||||
|
||||
private:
|
||||
QMap<rational, QByteArray> time_hash_map_;
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ protected:
|
||||
double scale_;
|
||||
|
||||
private:
|
||||
|
||||
rational timebase_;
|
||||
|
||||
double timebase_dbl_;
|
||||
|
||||
};
|
||||
|
||||
#endif // TIMELINESCALEDOBJECT_H
|
||||
|
||||
@@ -32,7 +32,7 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
|
||||
connect(timecode_label_, SIGNAL(ValueChanged(int64_t)), this, SLOT(UpdateInternalTime(const int64_t&)));
|
||||
ruler_and_time_layout->addWidget(timecode_label_);
|
||||
|
||||
ruler_ = new TimeRuler(true);
|
||||
ruler_ = new TimeRuler(true, true);
|
||||
connect(ruler_, SIGNAL(TimeChanged(const int64_t&)), this, SIGNAL(TimeChanged(const int64_t&)));
|
||||
connect(ruler_, SIGNAL(TimeChanged(const int64_t&)), this, SLOT(UpdateInternalTime(const int64_t&)));
|
||||
ruler_and_time_layout->addWidget(ruler_);
|
||||
@@ -60,7 +60,6 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
|
||||
tools_.replace(::Tool::kRazor, std::make_shared<RazorTool>(this));
|
||||
tools_.replace(::Tool::kSlip, std::make_shared<SlipTool>(this));
|
||||
tools_.replace(::Tool::kSlide, std::make_shared<SlideTool>(this));
|
||||
// tools_.replace(::Tool::kHand, std::make_shared<HandTool>(this));
|
||||
tools_.replace(::Tool::kZoom, std::make_shared<ZoomTool>(this));
|
||||
tools_.replace(::Tool::kTransition, std::make_shared<TransitionTool>(this));
|
||||
//tools_.replace(::Tool::kRecord, new PointerTool(this)); FIXME: Implement
|
||||
|
||||
@@ -14,6 +14,7 @@ TimelineViewBase::TimelineViewBase(QWidget *parent) :
|
||||
playhead_(0),
|
||||
playhead_scene_left_(-1),
|
||||
playhead_scene_right_(-1),
|
||||
dragging_hand_(false),
|
||||
limit_y_axis_(false)
|
||||
{
|
||||
setScene(&scene_);
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
#include "config/config.h"
|
||||
#include "core.h"
|
||||
|
||||
TimeRuler::TimeRuler(bool text_visible, QWidget* parent) :
|
||||
TimeRuler::TimeRuler(bool text_visible, bool cache_status_visible, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
scroll_(0),
|
||||
text_visible_(text_visible),
|
||||
centered_text_(true),
|
||||
scale_(1.0),
|
||||
time_(0),
|
||||
snapping_(false)
|
||||
show_cache_status_(cache_status_visible)
|
||||
{
|
||||
QFontMetrics fm = fontMetrics();
|
||||
|
||||
@@ -44,6 +45,7 @@ TimeRuler::TimeRuler(bool text_visible, QWidget* parent) :
|
||||
|
||||
// Text height is used to calculate widget height
|
||||
text_height_ = fm.height();
|
||||
cache_status_height_ = text_height_ / 4;
|
||||
|
||||
// Get the "minimum" space allowed between two line markers on the ruler (in screen pixels)
|
||||
// Mediocre but reliable way of scaling UI objects by font/DPI size
|
||||
@@ -53,22 +55,7 @@ TimeRuler::TimeRuler(bool text_visible, QWidget* parent) :
|
||||
playhead_width_ = minimum_gap_between_lines_;
|
||||
|
||||
// Text visibility affects height, so we set that here
|
||||
SetTextVisible(text_visible);
|
||||
}
|
||||
|
||||
void TimeRuler::SetTextVisible(bool e)
|
||||
{
|
||||
text_visible_ = e;
|
||||
|
||||
// Text visibility affects height, if text is visible the widget doubles in height with the top half for text and
|
||||
// the bottom half for ruler markings
|
||||
if (text_visible_) {
|
||||
setMinimumHeight(text_height_ * 2);
|
||||
} else {
|
||||
setMinimumHeight(text_height_);
|
||||
}
|
||||
|
||||
update();
|
||||
UpdateHeight();
|
||||
}
|
||||
|
||||
const double &TimeRuler::scale()
|
||||
@@ -94,16 +81,20 @@ void TimeRuler::SetTimebase(const rational &r)
|
||||
update();
|
||||
}
|
||||
|
||||
void TimeRuler::SetSnapping(bool snapping)
|
||||
{
|
||||
snapping_ = snapping;
|
||||
}
|
||||
|
||||
const int64_t &TimeRuler::GetTime()
|
||||
{
|
||||
return time_;
|
||||
}
|
||||
|
||||
void TimeRuler::SetCacheStatusLength(const rational &length)
|
||||
{
|
||||
cache_length_ = length;
|
||||
|
||||
dirty_cache_ranges_.RemoveTimeRange(TimeRange(length, RATIONAL_MAX));
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void TimeRuler::SetTime(const int64_t &r)
|
||||
{
|
||||
time_ = r;
|
||||
@@ -118,6 +109,20 @@ void TimeRuler::SetScroll(int s)
|
||||
update();
|
||||
}
|
||||
|
||||
void TimeRuler::CacheInvalidatedRange(const rational& in, const rational& out)
|
||||
{
|
||||
dirty_cache_ranges_.InsertTimeRange(TimeRange(in, out));
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void TimeRuler::CacheTimeReady(const rational &time)
|
||||
{
|
||||
dirty_cache_ranges_.RemoveTimeRange(TimeRange(time, time + timebase_));
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void TimeRuler::paintEvent(QPaintEvent *)
|
||||
{
|
||||
// Nothing to paint if the timebase is invalid
|
||||
@@ -198,11 +203,16 @@ void TimeRuler::paintEvent(QPaintEvent *)
|
||||
|
||||
// Calculate line dimensions
|
||||
QFontMetrics fm = p.fontMetrics();
|
||||
int line_bottom = height();
|
||||
|
||||
if (show_cache_status_) {
|
||||
line_bottom -= cache_status_height_;
|
||||
}
|
||||
|
||||
int long_height = fm.height();
|
||||
int short_height = long_height/2;
|
||||
int long_y = height() - long_height;
|
||||
int short_y = height() - short_height;
|
||||
int line_bottom = height();
|
||||
int long_y = line_bottom - long_height;
|
||||
int short_y = line_bottom - short_height;
|
||||
|
||||
// Draw long lines
|
||||
int last_long_unit = -1;
|
||||
@@ -267,12 +277,34 @@ void TimeRuler::paintEvent(QPaintEvent *)
|
||||
}
|
||||
}
|
||||
|
||||
// If cache status is enabled
|
||||
if (show_cache_status_) {
|
||||
int cache_screen_length = qMin(TimeToScreen(cache_length_), width());
|
||||
|
||||
if (cache_screen_length > 0) {
|
||||
int cache_y = height() - cache_status_height_;
|
||||
|
||||
p.fillRect(0, cache_y, cache_screen_length , cache_status_height_, Qt::green);
|
||||
|
||||
foreach (const TimeRange& range, dirty_cache_ranges_) {
|
||||
int range_left = TimeToScreen(range.in());
|
||||
int range_right = TimeToScreen(range.out());
|
||||
|
||||
if (range_left >= width() || range_right < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p.fillRect(qMax(0, range_left), cache_y, qMin(width(), range_right) - range_left, cache_status_height_, Qt::red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the playhead if it's on screen at the moment
|
||||
int playhead_pos = qFloor(static_cast<double>(time_) * scale_ * timebase_dbl_) - scroll_;
|
||||
int playhead_pos = UnitToScreen(time_);
|
||||
if (playhead_pos + playhead_width_ >= 0 && playhead_pos - playhead_width_ < width()) {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(style_.PlayheadColor());
|
||||
DrawPlayhead(&p, playhead_pos, height());
|
||||
DrawPlayhead(&p, playhead_pos, line_bottom);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +349,16 @@ int64_t TimeRuler::ScreenToUnit(int screen)
|
||||
return qFloor(ScreenToUnitFloat(screen));
|
||||
}
|
||||
|
||||
int TimeRuler::UnitToScreen(int64_t unit)
|
||||
{
|
||||
return qFloor(static_cast<double>(unit) * scale_ * timebase_dbl_) - scroll_;
|
||||
}
|
||||
|
||||
int TimeRuler::TimeToScreen(const rational &time)
|
||||
{
|
||||
return qFloor(time.toDouble() * scale_) - scroll_;
|
||||
}
|
||||
|
||||
void TimeRuler::SeekToScreenPoint(int screen)
|
||||
{
|
||||
int64_t timestamp = qMax(0, qRound(ScreenToUnitFloat(screen)));
|
||||
@@ -325,3 +367,18 @@ void TimeRuler::SeekToScreenPoint(int screen)
|
||||
|
||||
emit TimeChanged(timestamp);
|
||||
}
|
||||
|
||||
void TimeRuler::UpdateHeight()
|
||||
{
|
||||
int height = text_height_;
|
||||
|
||||
if (text_visible_) {
|
||||
height += text_height_;
|
||||
}
|
||||
|
||||
if (show_cache_status_) {
|
||||
height += cache_status_height_;
|
||||
}
|
||||
|
||||
setFixedHeight(height);
|
||||
}
|
||||
|
||||
@@ -25,15 +25,14 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "common/timerange.h"
|
||||
#include "widget/timelinewidget/view/timelineplayhead.h"
|
||||
|
||||
class TimeRuler : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TimeRuler(bool text_visible = true, QWidget* parent = nullptr);
|
||||
|
||||
void SetTextVisible(bool e);
|
||||
TimeRuler(bool text_visible = true, bool cache_status_visible = false, QWidget* parent = nullptr);
|
||||
|
||||
const double& scale();
|
||||
void SetScale(const double& d);
|
||||
@@ -42,8 +41,6 @@ public:
|
||||
|
||||
void SetCenteredText(bool c);
|
||||
|
||||
void SetSnapping(bool snapping);
|
||||
|
||||
const int64_t& GetTime();
|
||||
|
||||
public slots:
|
||||
@@ -51,6 +48,12 @@ public slots:
|
||||
|
||||
void SetScroll(int s);
|
||||
|
||||
void CacheInvalidatedRange(const rational& in, const rational& out);
|
||||
|
||||
void CacheTimeReady(const rational& time);
|
||||
|
||||
void SetCacheStatusLength(const rational& length);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent* e) override;
|
||||
|
||||
@@ -64,14 +67,7 @@ signals:
|
||||
void TimeChanged(int64_t);
|
||||
|
||||
private:
|
||||
enum Component {
|
||||
kNone,
|
||||
kDay,
|
||||
kHour,
|
||||
kMinute,
|
||||
kSecond,
|
||||
kFrame
|
||||
};
|
||||
void UpdateHeight();
|
||||
|
||||
void DrawPlayhead(QPainter* p, int x, int y);
|
||||
|
||||
@@ -79,10 +75,16 @@ private:
|
||||
|
||||
int64_t ScreenToUnit(int screen);
|
||||
|
||||
int UnitToScreen(int64_t unit);
|
||||
|
||||
int TimeToScreen(const rational& time);
|
||||
|
||||
void SeekToScreenPoint(int screen);
|
||||
|
||||
int text_height_;
|
||||
|
||||
int cache_status_height_;
|
||||
|
||||
int minimum_gap_between_lines_;
|
||||
|
||||
int playhead_width_;
|
||||
@@ -105,7 +107,11 @@ private:
|
||||
|
||||
TimelinePlayhead style_;
|
||||
|
||||
bool snapping_;
|
||||
bool show_cache_status_;
|
||||
|
||||
rational cache_length_;
|
||||
|
||||
TimeRangeList dirty_cache_ranges_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
||||
sizer_->SetWidget(gl_widget_);
|
||||
|
||||
// Create time ruler
|
||||
ruler_ = new TimeRuler(false);
|
||||
ruler_ = new TimeRuler(false, true);
|
||||
layout->addWidget(ruler_);
|
||||
connect(ruler_, SIGNAL(TimeChanged(int64_t)), this, SLOT(RulerTimeChange(int64_t)));
|
||||
|
||||
@@ -79,8 +79,9 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
||||
|
||||
// Start background renderers
|
||||
video_renderer_ = new OpenGLBackend(this);
|
||||
connect(video_renderer_, SIGNAL(CachedFrameReady(const rational&, QVariant)), this, SLOT(RendererCachedFrame(const rational&, QVariant)));
|
||||
connect(video_renderer_, SIGNAL(CachedTimeReady(const rational&)), this, SLOT(RendererCachedTime(const rational&)));
|
||||
connect(video_renderer_, &VideoRenderBackend::CachedFrameReady, this, &ViewerWidget::RendererCachedFrame);
|
||||
connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, this, &ViewerWidget::RendererCachedTime);
|
||||
connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, ruler_, &TimeRuler::CacheTimeReady);
|
||||
audio_renderer_ = new AudioBackend(this);
|
||||
}
|
||||
|
||||
@@ -138,9 +139,11 @@ void ViewerWidget::ConnectViewerNode(ViewerOutput *node, ColorManager* color_man
|
||||
if (viewer_node_ != nullptr) {
|
||||
SetTimebase(0);
|
||||
|
||||
disconnect(viewer_node_, SIGNAL(TimebaseChanged(const rational&)), this, SLOT(SetTimebase(const rational&)));
|
||||
disconnect(viewer_node_, SIGNAL(SizeChanged(int, int)), this, SLOT(SizeChangedSlot(int, int)));
|
||||
disconnect(viewer_node_, SIGNAL(LengthChanged(const rational&)), this, SLOT(LengthChangedSlot(const rational&)));
|
||||
disconnect(viewer_node_, &ViewerOutput::TimebaseChanged, this, &ViewerWidget::SetTimebase);
|
||||
disconnect(viewer_node_, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot);
|
||||
disconnect(viewer_node_, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot);
|
||||
disconnect(viewer_node_, &ViewerOutput::LengthChanged, ruler_, &TimeRuler::SetCacheStatusLength);
|
||||
disconnect(viewer_node_, &ViewerOutput::VideoChangedBetween, ruler_, &TimeRuler::CacheInvalidatedRange);
|
||||
|
||||
// Effectively disables the viewer and clears the state
|
||||
SizeChangedSlot(0, 0);
|
||||
@@ -159,9 +162,11 @@ void ViewerWidget::ConnectViewerNode(ViewerOutput *node, ColorManager* color_man
|
||||
if (viewer_node_ != nullptr) {
|
||||
SetTimebase(viewer_node_->video_params().time_base());
|
||||
|
||||
connect(viewer_node_, SIGNAL(TimebaseChanged(const rational&)), this, SLOT(SetTimebase(const rational&)));
|
||||
connect(viewer_node_, SIGNAL(SizeChanged(int, int)), this, SLOT(SizeChangedSlot(int, int)));
|
||||
connect(viewer_node_, SIGNAL(LengthChanged(const rational&)), this, SLOT(LengthChangedSlot(const rational&)));
|
||||
connect(viewer_node_, &ViewerOutput::TimebaseChanged, this, &ViewerWidget::SetTimebase);
|
||||
connect(viewer_node_, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot);
|
||||
connect(viewer_node_, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot);
|
||||
connect(viewer_node_, &ViewerOutput::LengthChanged, ruler_, &TimeRuler::SetCacheStatusLength);
|
||||
connect(viewer_node_, &ViewerOutput::VideoChangedBetween, ruler_, &TimeRuler::CacheInvalidatedRange);
|
||||
|
||||
SizeChangedSlot(viewer_node_->video_params().width(), viewer_node_->video_params().height());
|
||||
LengthChangedSlot(viewer_node_->Length());
|
||||
@@ -407,16 +412,18 @@ void ViewerWidget::PlaybackTimerUpdate()
|
||||
SetTime(current_time);
|
||||
}
|
||||
|
||||
void ViewerWidget::RendererCachedFrame(const rational &time, QVariant value)
|
||||
void ViewerWidget::RendererCachedFrame(const rational &time, QVariant value, qint64 job_time)
|
||||
{
|
||||
if (GetTime() == time) {
|
||||
SetTexture(value.value<OpenGLTexturePtr>());
|
||||
|
||||
frame_cache_job_time_ = job_time;
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerWidget::RendererCachedTime(const rational &time)
|
||||
void ViewerWidget::RendererCachedTime(const rational &time, qint64 job_time)
|
||||
{
|
||||
if (GetTime() == time) {
|
||||
if (GetTime() == time && job_time > frame_cache_job_time_) {
|
||||
UpdateTextureFromNode(GetTime());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,13 +171,15 @@ private:
|
||||
|
||||
int playback_speed_;
|
||||
|
||||
qint64 frame_cache_job_time_;
|
||||
|
||||
private slots:
|
||||
void RulerTimeChange(int64_t);
|
||||
|
||||
void PlaybackTimerUpdate();
|
||||
|
||||
void RendererCachedFrame(const rational& time, QVariant value);
|
||||
void RendererCachedTime(const rational& time);
|
||||
void RendererCachedFrame(const rational& time, QVariant value, qint64 job_time);
|
||||
void RendererCachedTime(const rational& time, qint64 job_time);
|
||||
|
||||
void SizeChangedSlot(int width, int height);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user