diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 889450ada..98b5edda2 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -225,7 +225,7 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode) frame_container->set_width(frame->width); frame_container->set_height(frame->height); frame_container->set_format(static_cast(output_fmt_)); - frame_container->set_timestamp(olive::timestamp_to_time(target_ts, avstream_->time_base)); + frame_container->set_timestamp(Timecode::timestamp_to_time(target_ts, avstream_->time_base)); frame_container->allocate(); // Convert pixel format/linesize if necessary @@ -326,7 +326,7 @@ int64_t FFmpegDecoder::GetTimestampFromTime(const rational &time) } // Convert timecode to AVStream timebase - int64_t target_ts = olive::time_to_timestamp(time, avstream_->time_base); + int64_t target_ts = Timecode::time_to_timestamp(time, avstream_->time_base); // Find closest actual timebase in the file target_ts = GetClosestTimestampInIndex(target_ts); diff --git a/app/common/timecodefunctions.cpp b/app/common/timecodefunctions.cpp index 467a9412d..1717ee0b8 100644 --- a/app/common/timecodefunctions.cpp +++ b/app/common/timecodefunctions.cpp @@ -28,10 +28,10 @@ QString padded(int64_t arg, int padding) { return QStringLiteral("%1").arg(arg, padding, 10, QChar('0')); } -QString olive::timestamp_to_timecode(const int64_t ×tamp, - const rational& timebase, - const TimecodeDisplay& display, - bool show_plus_if_positive) +QString Timecode::timestamp_to_timecode(const int64_t ×tamp, + const rational& timebase, + const Display& display, + bool show_plus_if_positive) { if (timebase.isNull()) { return QString(); @@ -75,7 +75,7 @@ QString olive::timestamp_to_timecode(const int64_t ×tamp, int64_t frames, secs, mins, hours; int64_t f = qAbs(timestamp); - if (display == kTimecodeDropFrame && timebase.numerator() == 1001) { + if (display == kTimecodeDropFrame && TimebaseIsDropFrame(timebase)) { frame_token = ";"; /** @@ -129,7 +129,7 @@ QString olive::timestamp_to_timecode(const int64_t ×tamp, return QString(); } -int64_t olive::timecode_to_timestamp(const QString &timecode, const rational &timebase, const olive::TimecodeDisplay &display, bool* ok) +int64_t Timecode::timecode_to_timestamp(const QString &timecode, const rational &timebase, const Display &display, bool* ok) { double timebase_dbl = timebase.toDouble(); @@ -182,7 +182,7 @@ int64_t olive::timecode_to_timestamp(const QString &timecode, const rational &ti int64_t sec_count = (hours*3600 + mins*60 + secs); int64_t timestamp = sec_count*rounded_frame_rate + frames; - if (display == kTimecodeDropFrame && timebase.numerator() == 1001) { + if (display == kTimecodeDropFrame && TimebaseIsDropFrame(timebase)) { // Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate int64_t dropFrames = qRound64(frame_rate * (2.0/30.0)); @@ -231,22 +231,27 @@ err_fatal: return 0; } -rational olive::timestamp_to_time(const int64_t ×tamp, const rational &timebase) +rational Timecode::timestamp_to_time(const int64_t ×tamp, const rational &timebase) { return rational(timestamp) * timebase; } -int64_t olive::time_to_timestamp(const rational &time, const rational &timebase) +bool Timecode::TimebaseIsDropFrame(const rational &timebase) +{ + return (timebase.numerator() == 1001); +} + +int64_t Timecode::time_to_timestamp(const rational &time, const rational &timebase) { return time_to_timestamp(time.toDouble(), timebase); } -int64_t olive::time_to_timestamp(const double &time, const rational &timebase) +int64_t Timecode::time_to_timestamp(const double &time, const rational &timebase) { return qRound64(time * timebase.flipped().toDouble()); } -olive::TimecodeDisplay olive::CurrentTimecodeDisplay() +Timecode::Display Timecode::CurrentDisplay() { - return static_cast(Config::Current()["TimecodeDisplay"].toInt()); + return static_cast(Config::Current()["TimecodeDisplay"].toInt()); } diff --git a/app/common/timecodefunctions.h b/app/common/timecodefunctions.h index 393168a84..be26c63b7 100644 --- a/app/common/timecodefunctions.h +++ b/app/common/timecodefunctions.h @@ -25,30 +25,42 @@ #include "common/rational.h" -namespace olive { +/** + * @brief Functions for converting times/timecodes/timestamps + * + * Olive uses the following terminology through its code: + * + * `time` - time in seconds presented in a rational form + * `timebase` - the base time unit of an audio/video stream in seconds + * `timestamp` - an integer representation of a time in timebase units (in many cases is used like a frame number) + * `timecode` a user-friendly string representation of a time according to Timecode::Display + */ +class Timecode { +public: + enum Display { + kTimecodeDropFrame, + kTimecodeNonDropFrame, + kTimecodeSeconds, + kFrames, + kMilliseconds + }; + + static Display CurrentDisplay(); + + /** + * @brief Convert a timestamp (according to a rational timebase) to a user-friendly string representation + */ + static QString timestamp_to_timecode(const int64_t ×tamp, const rational& timebase, const Display &display, bool show_plus_if_positive = false); + + static int64_t timecode_to_timestamp(const QString& timecode, const rational& timebase, const Display& display, bool *ok = nullptr); + + static int64_t time_to_timestamp(const rational& time, const rational& timebase); + static int64_t time_to_timestamp(const double& time, const rational& timebase); + + static rational timestamp_to_time(const int64_t& timestamp, const rational& timebase); + + static bool TimebaseIsDropFrame(const rational& timebase); -enum TimecodeDisplay { - kTimecodeDropFrame, - kTimecodeNonDropFrame, - kTimecodeSeconds, - kFrames, - kMilliseconds }; -TimecodeDisplay CurrentTimecodeDisplay(); - -/** - * @brief Convert a timestamp (according to a rational timebase) to a user-friendly string representation - */ -QString timestamp_to_timecode(const int64_t ×tamp, const rational& timebase, const TimecodeDisplay& display, bool show_plus_if_positive = false); - -int64_t timecode_to_timestamp(const QString& timecode, const rational& timebase, const TimecodeDisplay& display, bool *ok = nullptr); - -int64_t time_to_timestamp(const rational& time, const rational& timebase); -int64_t time_to_timestamp(const double& time, const rational& timebase); - -rational timestamp_to_time(const int64_t& timestamp, const rational& timebase); - -} - #endif // TIMECODEFUNCTIONS_H diff --git a/app/config/config.cpp b/app/config/config.cpp index 0015bed93..8637106a9 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -49,7 +49,7 @@ Config &Config::Current() void Config::SetDefaults() { config_map_.clear(); - config_map_["TimecodeDisplay"] = olive::kTimecodeDropFrame; + config_map_["TimecodeDisplay"] = Timecode::kTimecodeDropFrame; config_map_["DefaultStillLength"] = QVariant::fromValue(rational(2)); config_map_["HoverFocus"] = false; config_map_["AudioScrubbing"] = true; diff --git a/app/dialog/speedduration/speedduration.cpp b/app/dialog/speedduration/speedduration.cpp index 3f3add0dc..1fb04f657 100644 --- a/app/dialog/speedduration/speedduration.cpp +++ b/app/dialog/speedduration/speedduration.cpp @@ -92,7 +92,7 @@ SpeedDurationDialog::SpeedDurationDialog(const rational& timebase, const QListaddWidget(duration_slider_, row, 1); if (same_duration) { - duration_slider_->SetValue(olive::time_to_timestamp(clips_.first()->length(), timebase_)); + duration_slider_->SetValue(Timecode::time_to_timestamp(clips_.first()->length(), timebase_)); } else { duration_slider_->SetTristate(); } @@ -149,7 +149,7 @@ void SpeedDurationDialog::accept() if (change_duration) { // Change the duration - int64_t current_duration = olive::time_to_timestamp(clip->length(), timebase_); + int64_t current_duration = Timecode::time_to_timestamp(clip->length(), timebase_); int64_t new_duration = current_duration; // Check if we're getting the duration value directly from the slider or calculating it from the speed @@ -168,7 +168,7 @@ void SpeedDurationDialog::accept() } if (new_duration != current_duration) { - new_clip_length = olive::timestamp_to_time(new_duration, timebase_); + new_clip_length = Timecode::timestamp_to_time(new_duration, timebase_); Block* next_block = clip->next(); // If "ripple clips" isn't checked, we need to calculate around the timeline as-is @@ -222,9 +222,9 @@ void SpeedDurationDialog::accept() } if (change_speed) { - int64_t new_clip_duration = olive::time_to_timestamp(new_clip_length, timebase_); + int64_t new_clip_duration = Timecode::time_to_timestamp(new_clip_length, timebase_); int64_t new_media_duration = qRound(static_cast(new_clip_duration) * new_speed); - rational new_media_length = olive::timestamp_to_time(new_media_duration, timebase_); + rational new_media_length = Timecode::timestamp_to_time(new_media_duration, timebase_); if (clip->is_reversed()) { new_media_length = -new_media_length; @@ -248,7 +248,7 @@ void SpeedDurationDialog::accept() double SpeedDurationDialog::GetUnadjustedLengthTimestamp(ClipBlock *clip) const { - double duration = static_cast(olive::time_to_timestamp(clip->length(), timebase_)); + double duration = static_cast(Timecode::time_to_timestamp(clip->length(), timebase_)); // Convert duration to non-speed adjusted duration duration *= clip->speed(); diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index ec33d94dc..7eb27ba70 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -162,19 +162,19 @@ QString Footage::duration() if (video_stream->timebase() != frame_rate_timebase) { // Convert from timebase to frame rate - rational duration_time = olive::timestamp_to_time(duration, video_stream->timebase()); - duration = olive::time_to_timestamp(duration_time, frame_rate_timebase); + rational duration_time = Timecode::timestamp_to_time(duration, video_stream->timebase()); + duration = Timecode::time_to_timestamp(duration_time, frame_rate_timebase); } - return olive::timestamp_to_timecode(duration, - frame_rate_timebase, - olive::CurrentTimecodeDisplay()); + return Timecode::timestamp_to_timecode(duration, + frame_rate_timebase, + Timecode::CurrentDisplay()); } else if (streams_.first()->type() == Stream::kAudio) { AudioStreamPtr audio_stream = std::static_pointer_cast(streams_.first()); - return olive::timestamp_to_timecode(streams_.first()->duration(), - streams_.first()->timebase(), - olive::CurrentTimecodeDisplay()); + return Timecode::timestamp_to_timecode(streams_.first()->duration(), + streams_.first()->timebase(), + Timecode::CurrentDisplay()); } return QString(); diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index a7872d3a4..b5debc99f 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -95,9 +95,9 @@ QString Sequence::duration() rational timeline_length = timeline_output_->length(); - int64_t timestamp = olive::time_to_timestamp(timeline_length, video_params_.time_base()); + int64_t timestamp = Timecode::time_to_timestamp(timeline_length, video_params_.time_base()); - return olive::timestamp_to_timecode(timestamp, video_params_.time_base(), olive::CurrentTimecodeDisplay()); + return Timecode::timestamp_to_timecode(timestamp, video_params_.time_base(), Timecode::CurrentDisplay()); } QString Sequence::rate() diff --git a/app/render/backend/videorenderbackend.cpp b/app/render/backend/videorenderbackend.cpp index dcc911955..0a9181b7b 100644 --- a/app/render/backend/videorenderbackend.cpp +++ b/app/render/backend/videorenderbackend.cpp @@ -56,8 +56,8 @@ void VideoRenderBackend::InvalidateCache(const rational &start_range, const rati << end_range_adj.toDouble(); // Snap start_range to timebase - int64_t timestamp = olive::time_to_timestamp(start_range_adj, params_.time_base()); - rational true_start = olive::timestamp_to_time(timestamp, params_.time_base()); + int64_t timestamp = Timecode::time_to_timestamp(start_range_adj, params_.time_base()); + rational true_start = Timecode::timestamp_to_time(timestamp, params_.time_base()); for (rational r=true_start;rtimebase()); + int64_t timestamp = Timecode::time_to_timestamp(time, keyframe_view_->timebase()); ruler_->SetTime(timestamp); keyframe_view_->SetTime(timestamp); @@ -160,7 +160,7 @@ void NodeParamView::UpdateItemTime(const rational &time) void NodeParamView::RulerTimeChanged(const int64_t ×tamp) { - rational time = olive::timestamp_to_time(timestamp, keyframe_view_->timebase()); + rational time = Timecode::timestamp_to_time(timestamp, keyframe_view_->timebase()); UpdateItemTime(time); } diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h index a33baf577..e4898a89f 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h @@ -18,7 +18,7 @@ public: private: void CreateWidgets(); - void SetInputValue(NodeInput* input, const QVariant& value); + void SetInputValue(const QVariant& value); NodeInput* input_; diff --git a/app/widget/playbackcontrols/playbackcontrols.cpp b/app/widget/playbackcontrols/playbackcontrols.cpp index 051bbe44d..da1538971 100644 --- a/app/widget/playbackcontrols/playbackcontrols.cpp +++ b/app/widget/playbackcontrols/playbackcontrols.cpp @@ -176,7 +176,7 @@ void PlaybackControls::SetTimeLabelInternal(QLabel* label, const int64_t& time) return; } - label->setText(olive::timestamp_to_timecode(time, - time_base_, - olive::CurrentTimecodeDisplay())); + label->setText(Timecode::timestamp_to_timecode(time, + time_base_, + Timecode::CurrentDisplay())); } diff --git a/app/widget/slider/timeslider.cpp b/app/widget/slider/timeslider.cpp index 9510e34bc..f5981fced 100644 --- a/app/widget/slider/timeslider.cpp +++ b/app/widget/slider/timeslider.cpp @@ -23,12 +23,12 @@ QString TimeSlider::ValueToString(const QVariant &v) return IntegerSlider::ValueToString(v); } - return olive::timestamp_to_timecode(v.toLongLong(), - timebase_, - olive::CurrentTimecodeDisplay()); + return Timecode::timestamp_to_timecode(v.toLongLong(), + timebase_, + Timecode::CurrentDisplay()); } QVariant TimeSlider::StringToValue(const QString &s, bool *ok) { - return olive::timecode_to_timestamp(s, timebase_, olive::CurrentTimecodeDisplay(), ok); + return Timecode::timecode_to_timestamp(s, timebase_, Timecode::CurrentDisplay(), ok); } diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 58e09b825..a33c4f72f 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -290,7 +290,7 @@ void TimelineWidget::GoToPrevCut() int64_t this_track_closest_cut = 0; foreach (Block* block, track->Blocks()) { - int64_t block_out_ts = olive::time_to_timestamp(block->out(), timebase()); + int64_t block_out_ts = Timecode::time_to_timestamp(block->out(), timebase()); if (block_out_ts < playhead_) { this_track_closest_cut = block_out_ts; @@ -314,14 +314,14 @@ void TimelineWidget::GoToNextCut() int64_t closest_cut = INT64_MAX; foreach (TrackOutput* track, timeline_node_->Tracks()) { - int64_t this_track_closest_cut = olive::time_to_timestamp(track->track_length(), timebase()); + int64_t this_track_closest_cut = Timecode::time_to_timestamp(track->track_length(), timebase()); if (this_track_closest_cut <= playhead_) { this_track_closest_cut = INT64_MAX; } foreach (Block* block, track->Blocks()) { - int64_t block_in_ts = olive::time_to_timestamp(block->in(), timebase()); + int64_t block_in_ts = Timecode::time_to_timestamp(block->in(), timebase()); if (block_in_ts > playhead_) { this_track_closest_cut = block_in_ts; @@ -339,7 +339,7 @@ void TimelineWidget::GoToNextCut() void TimelineWidget::SplitAtPlayhead() { - rational playhead_time = olive::timestamp_to_time(playhead_, timebase()); + rational playhead_time = Timecode::timestamp_to_time(playhead_, timebase()); QList selected_blocks = GetSelectedBlocks(); @@ -494,7 +494,7 @@ QList TimelineWidget::GetSelectedBlocks() void TimelineWidget::RippleEditTo(olive::timeline::MovementMode mode, bool insert_gaps) { - rational playhead_time = olive::timestamp_to_time(playhead_, timebase()); + rational playhead_time = Timecode::timestamp_to_time(playhead_, timebase()); rational closest_point_to_playhead; if (mode == olive::timeline::kTrimIn) { @@ -551,7 +551,7 @@ void TimelineWidget::RippleEditTo(olive::timeline::MovementMode mode, bool inser olive::undo_stack.pushIfHasChildren(command); if (mode == olive::timeline::kTrimIn && !insert_gaps) { - int64_t new_time = olive::time_to_timestamp(closest_point_to_playhead, timebase()); + int64_t new_time = Timecode::time_to_timestamp(closest_point_to_playhead, timebase()); SetTimeAndSignal(new_time); } diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index 128f3ba80..6e78a8d78 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -185,10 +185,10 @@ void TimelineWidget::ImportTool::DragMove(TimelineViewMouseEvent *event) } // Generate tooltip (showing earliest in point of imported clip) - int64_t earliest_timestamp = olive::time_to_timestamp(earliest_ghost, parent()->timebase()); - QString tooltip_text = olive::timestamp_to_timecode(earliest_timestamp, - parent()->timebase(), - olive::CurrentTimecodeDisplay()); + int64_t earliest_timestamp = Timecode::time_to_timestamp(earliest_ghost, parent()->timebase()); + QString tooltip_text = Timecode::timestamp_to_timecode(earliest_timestamp, + parent()->timebase(), + Timecode::CurrentDisplay()); // Force tooltip to update (otherwise the tooltip won't move as written in the documentation, and could get in the way // of the cursor) diff --git a/app/widget/timelinewidget/tool/pointer.cpp b/app/widget/timelinewidget/tool/pointer.cpp index 1481c7d03..41351de5e 100644 --- a/app/widget/timelinewidget/tool/pointer.cpp +++ b/app/widget/timelinewidget/tool/pointer.cpp @@ -326,11 +326,11 @@ void TimelineWidget::PointerTool::ProcessDrag(const TimelineCoordinate &mouse_po // Show tooltip // Generate tooltip (showing earliest in point of imported clip) - int64_t earliest_timestamp = olive::time_to_timestamp(time_movement, parent()->timebase()); - QString tooltip_text = olive::timestamp_to_timecode(earliest_timestamp, - parent()->timebase(), - olive::CurrentTimecodeDisplay(), - true); + int64_t earliest_timestamp = Timecode::time_to_timestamp(time_movement, parent()->timebase()); + QString tooltip_text = Timecode::timestamp_to_timecode(earliest_timestamp, + parent()->timebase(), + Timecode::CurrentDisplay(), + true); // Force tooltip to update (otherwise the tooltip won't move as written in the documentation, and could get in the way // of the cursor) diff --git a/app/widget/timelinewidget/tool/slip.cpp b/app/widget/timelinewidget/tool/slip.cpp index d00f5501c..2075998d4 100644 --- a/app/widget/timelinewidget/tool/slip.cpp +++ b/app/widget/timelinewidget/tool/slip.cpp @@ -51,11 +51,11 @@ void TimelineWidget::SlipTool::ProcessDrag(const TimelineCoordinate &mouse_pos) // Show tooltip // Generate tooltip (showing earliest in point of imported clip) - int64_t earliest_timestamp = olive::time_to_timestamp(time_movement, parent()->timebase()); - QString tooltip_text = olive::timestamp_to_timecode(earliest_timestamp, - parent()->timebase(), - olive::CurrentTimecodeDisplay(), - true); + int64_t earliest_timestamp = Timecode::time_to_timestamp(time_movement, parent()->timebase()); + QString tooltip_text = Timecode::timestamp_to_timecode(earliest_timestamp, + parent()->timebase(), + Timecode::CurrentDisplay(), + true); // Force tooltip to update (otherwise the tooltip won't move as written in the documentation, and could get in the way // of the cursor) QToolTip::hideText(); diff --git a/app/widget/timelinewidget/view/timelineviewbase.cpp b/app/widget/timelinewidget/view/timelineviewbase.cpp index e7d6b536f..eafe60d8b 100644 --- a/app/widget/timelinewidget/view/timelineviewbase.cpp +++ b/app/widget/timelinewidget/view/timelineviewbase.cpp @@ -89,7 +89,7 @@ bool TimelineViewBase::PlayheadMove(QMouseEvent *event) QPointF scene_pos = mapToScene(event->pos()); rational mouse_time = SceneToTime(scene_pos.x()); - int64_t target_ts = olive::time_to_timestamp(mouse_time, timebase()); + int64_t target_ts = Timecode::time_to_timestamp(mouse_time, timebase()); SetTime(target_ts); emit TimeChanged(target_ts); diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index 06bb27aee..156587c17 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -156,7 +156,7 @@ void TimeRuler::paintEvent(QPaintEvent *) if (text_visible_) { QFontMetrics fm = p.fontMetrics(); double width_of_second = scale_; - int average_text_width = QFontMetricsWidth(fm, olive::timestamp_to_timecode(0, timebase_, olive::CurrentTimecodeDisplay())); + int average_text_width = QFontMetricsWidth(fm, Timecode::timestamp_to_timecode(0, timebase_, Timecode::CurrentDisplay())); half_average_text_width = average_text_width/2; while (width_of_second * text_skip < average_text_width) { text_skip++; @@ -202,7 +202,8 @@ void TimeRuler::paintEvent(QPaintEvent *) // Try to draw text here if (text_visible_ && sec%text_skip == 0) { - QString timecode_string = olive::timestamp_to_timecode(sec, timebase_, olive::CurrentTimecodeDisplay()); + int64_t timestamp_here = Timecode::time_to_timestamp(rational(sec), timebase_); + QString timecode_string = Timecode::timestamp_to_timecode(timestamp_here, timebase_, Timecode::CurrentDisplay()); int text_x = i; diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 26ce5e63d..22aecb88e 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -105,7 +105,7 @@ const double &ViewerWidget::scale() const rational ViewerWidget::GetTime() const { - return olive::timestamp_to_time(ruler_->GetTime(), time_base_); + return Timecode::timestamp_to_time(ruler_->GetTime(), time_base_); } void ViewerWidget::SetScale(const double &scale_) @@ -330,7 +330,7 @@ void ViewerWidget::GoToEnd() if (viewer_node_ != nullptr) { Pause(); - SetTime(olive::time_to_timestamp(viewer_node_->Length(), time_base_)); + SetTime(Timecode::time_to_timestamp(viewer_node_->Length(), time_base_)); } } @@ -426,7 +426,7 @@ void ViewerWidget::SizeChangedSlot(int width, int height) void ViewerWidget::LengthChangedSlot(const rational &length) { - controls_->SetEndTime(olive::time_to_timestamp(length, time_base_)); + controls_->SetEndTime(Timecode::time_to_timestamp(length, time_base_)); } void ViewerWidget::resizeEvent(QResizeEvent *event)