diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index ba35fc5f1..aba335bed 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -13,6 +13,8 @@ #include "project/sequence.h" #include "io/media.h" #include "playback/playback.h" +#include "panels/panels.h" +#include "panels/timeline.h" SpeedDialog::SpeedDialog(QWidget *parent) : QDialog(parent) { QVBoxLayout* main_layout = new QVBoxLayout(); @@ -79,32 +81,38 @@ void SpeedDialog::run() { // get "default" frame rate" if (enable_frame_rate) { // check if frame rate is equal to default - if (!qIsNaN(default_frame_rate) && media_frame_rate != default_frame_rate) { + if (!qIsNaN(default_frame_rate) && !qFuzzyCompare(media_frame_rate, default_frame_rate)) { default_frame_rate = NAN; } + if (!qIsNaN(current_frame_rate) && !qFuzzyCompare(c->frame_rate, current_frame_rate)) { + current_frame_rate = NAN; + } } else { default_frame_rate = media_frame_rate; + current_frame_rate = c->frame_rate; } enable_frame_rate = true; } else { clip_percent = c->frame_rate; - - if (i > 0) { - if (!qIsNaN(default_percent) && c->frame_rate != default_percent) { - default_percent = NAN; - } - } else { - default_percent = c->frame_rate; - } } // get default length + long clip_default_length = qRound(c->getLength() * clip_percent); if (i == 0) { current_length = c->getLength(); - default_length = qRound(c->getLength() * clip_percent); - } else if (current_length != -1 && c->getLength() != current_length) { - current_length = -1; + default_length = clip_default_length; + current_percent = clip_percent; + } else { + if (current_length != -1 && c->getLength() != current_length) { + current_length = -1; + } + if (default_length != -1 && clip_default_length != default_length) { + default_length = -1; + } + if (!qIsNaN(current_percent) && !qFuzzyCompare(clip_percent, current_percent)) { + current_percent = NAN; + } } } @@ -113,17 +121,18 @@ void SpeedDialog::run() { frame_rate->set_value(current_frame_rate, false); percent->set_value(current_percent, false); duration->set_default_value(default_length); + duration->set_value(current_length, false); exec(); } void SpeedDialog::percent_update() { frame_rate->set_value(default_frame_rate * percent->value(), false); - duration->set_value(clips.at(0)->getLength() / percent->value(), false); + duration->set_value(default_length / percent->value(), false); } void SpeedDialog::duration_update() { - double pc = clips.at(0)->getLength() / duration->value(); + double pc = default_length / duration->value(); frame_rate->set_value(default_frame_rate * pc, false); percent->set_value(pc, false); } @@ -132,18 +141,27 @@ void SpeedDialog::frame_rate_update() { double fr = (frame_rate->value()); double pc = (fr / default_frame_rate); percent->set_value(pc, false); - duration->set_value(clips.at(0)->getLength() / pc, false); + duration->set_value(default_length / pc, false); } void SpeedDialog::accept() { for (int i=0;itrack < 0) { - c->frame_rate = frame_rate->value(); - } else { - c->frame_rate = percent->value(); - } close_clip(c); + if (c->track < 0) { + if (!qIsNaN(frame_rate->value())) { + // TODO add validators + c->timeline_out = c->timeline_in + (c->getLength() * (c->frame_rate / frame_rate->value())); + c->frame_rate = frame_rate->value(); + } + } else { + if (!qIsNaN(percent->value())) { + c->timeline_out = c->timeline_in + (c->getLength() * (c->frame_rate / percent->value())); + c->frame_rate = percent->value(); + } + } + c->recalculateMaxLength(); } + panel_timeline->redraw_all_clips(true); QDialog::accept(); } diff --git a/effects/effect.cpp b/effects/effect.cpp index 2dbd256de..e1453f7b6 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -737,7 +737,6 @@ void EffectField::uiElementChange() { parent_row->set_keyframe_now(enableKeyframes); } else if (enableKeyframes) { // set undo - qDebug() << "h"; undo_stack.push(new EffectFieldUndo(this)); } emit changed(); diff --git a/effects/video/texteffect.cpp b/effects/video/texteffect.cpp index 57a2f0175..c8bcd92be 100644 --- a/effects/video/texteffect.cpp +++ b/effects/video/texteffect.cpp @@ -73,7 +73,7 @@ TextEffect::TextEffect(Clip *c) : shadow_softness->set_double_default_value(5); shadow_distance->set_double_default_value(5); shadow_opacity->set_double_default_value(80); - outline_width->set_double_default_value(2); + outline_width->set_double_default_value(20); outline_enable(false); shadow_enable(false); @@ -245,12 +245,11 @@ void TextEffect::redraw(double timecode) { } path.addText(text_x, text_y, font, lines.at(i)); - } - - p.setPen(Qt::NoPen); + } // draw shadow if (shadow_bool->get_bool_value(timecode)) { + p.setPen(Qt::NoPen); int shadow_offset = shadow_distance->get_double_value(timecode); QPainterPath shadow_path(path); @@ -271,9 +270,12 @@ void TextEffect::redraw(double timecode) { QPen outline(outline_color->get_color_value(timecode)); outline.setWidth(outline_width_val); p.setPen(outline); + p.setBrush(Qt::NoBrush); + p.drawPath(path); } // draw "master" text + p.setPen(Qt::NoPen); p.setBrush(set_color_button->get_color_value(timecode)); p.drawPath(path); } diff --git a/icons/olive.ico b/icons/olive.ico index b4252d44b..193fa5989 100644 Binary files a/icons/olive.ico and b/icons/olive.ico differ diff --git a/mainwindow.cpp b/mainwindow.cpp index 12c735858..8d7495494 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -45,7 +45,7 @@ QMainWindow* mainWindow; QTimer autorecovery_timer; QString config_dir; -QString appName = "Olive (September 2018 | Alpha)"; +QString appName = "Olive (October 2018 | Alpha)"; bool demoNoticeShown = false; void MainWindow::setup_layout() { @@ -383,7 +383,7 @@ bool MainWindow::can_close_project() { void MainWindow::updateTitle(const QString& url) { project_url = url; - setWindowTitle(appName + " - " + ((project_url.isEmpty()) ? "" : project_url)); + setWindowTitle(appName + " - " + ((project_url.isEmpty()) ? "" : project_url) + "[*]"); } void MainWindow::closeEvent(QCloseEvent *e) { diff --git a/panels/project.cpp b/panels/project.cpp index eb89f18ce..29385bd8c 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -1030,7 +1030,7 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int stream.writeAttribute("id", QString::number(ms->file_index)); stream.writeAttribute("width", QString::number(ms->video_width)); stream.writeAttribute("height", QString::number(ms->video_height)); - stream.writeAttribute("framerate", QString::number(ms->video_frame_rate)); + stream.writeAttribute("framerate", QString::number(ms->video_frame_rate, 'f', 10)); stream.writeAttribute("infinite", QString::number(ms->infinite_length)); stream.writeEndElement(); } @@ -1057,7 +1057,7 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int stream.writeAttribute("name", s->name); stream.writeAttribute("width", QString::number(s->width)); stream.writeAttribute("height", QString::number(s->height)); - stream.writeAttribute("framerate", QString::number(s->frame_rate)); + stream.writeAttribute("framerate", QString::number(s->frame_rate, 'f', 10)); stream.writeAttribute("afreq", QString::number(s->audio_frequency)); stream.writeAttribute("alayout", QString::number(s->audio_layout)); if (s == sequence) { @@ -1089,7 +1089,7 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int stream.writeAttribute("autoscale", QString::number(c->autoscale)); - stream.writeAttribute("framerate", QString::number(c->frame_rate)); + stream.writeAttribute("framerate", QString::number(c->frame_rate, 'f', 10)); stream.writeAttribute("type", QString::number(c->media_type)); switch (c->media_type) { diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 5c3e71f55..e4764ac58 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -25,6 +25,11 @@ Viewer::Viewer(QWidget *parent) : viewer_widget = ui->openGLWidget; update_sequence(); + ui->currentTimecode->set_display_type(LABELSLIDER_FRAMENUMBER); + ui->currentTimecode->set_default_value(NAN); + ui->currentTimecode->set_value(0, false); + connect(ui->currentTimecode, SIGNAL(valueChanged()), this, SLOT(update_playhead())); + update_playhead_timecode(0); update_end_timecode(); } @@ -81,6 +86,8 @@ QString frame_to_timecode(long f, int view, double frame_rate) { token = ";"; } else { + // non-drop timecode + int int_fps = qRound(frame_rate); hours = f/ (3600 * int_fps); mins = f / (60*int_fps) % 60; @@ -99,7 +106,7 @@ bool frame_rate_is_droppable(float rate) { } void Viewer::update_playhead_timecode(long p) { - ui->currentTimecode->setText(frame_to_timecode(p, config.timecode_view, (sequence != NULL) ? sequence->frame_rate : 30)); + ui->currentTimecode->set_value(p, false); } void Viewer::update_end_timecode() { @@ -124,11 +131,7 @@ void Viewer::update_sequence() { init_audio(); if (!null_sequence) { - if (frame_rate_is_droppable(sequence->frame_rate)) { - config.timecode_view = TIMECODE_DROP; - } else { - config.timecode_view = TIMECODE_NONDROP; - } + config.timecode_view = (frame_rate_is_droppable(sequence->frame_rate)) ? TIMECODE_DROP : TIMECODE_NONDROP; update_playhead_timecode(sequence->playhead); update_end_timecode(); @@ -167,13 +170,13 @@ void Viewer::on_pushButton_4_clicked() void Viewer::on_pushButton_3_clicked() { - panel_timeline->toggle_play(); + panel_timeline->toggle_play(); +} + +void Viewer::update_playhead() { + panel_timeline->seek(ui->currentTimecode->value()); } void Viewer::set_playpause_icon(bool play) { - if (play) { - ui->pushButton_3->setIcon(QIcon(":/icons/play.png")); - } else { - ui->pushButton_3->setIcon(QIcon(":/icons/pause.png")); - } + ui->pushButton_3->setIcon(QIcon((play) ? ":/icons/play.png" : ":/icons/pause.png")); } diff --git a/panels/viewer.h b/panels/viewer.h index 085cb11fb..5335a1a57 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -40,6 +40,8 @@ private slots: void on_pushButton_4_clicked(); void on_pushButton_3_clicked(); + + void update_playhead(); }; #endif // VIEWER_H diff --git a/panels/viewer.ui b/panels/viewer.ui index 3511ef03a..534322a67 100644 --- a/panels/viewer.ui +++ b/panels/viewer.ui @@ -98,7 +98,7 @@ 0 - + 0 @@ -228,6 +228,11 @@
ui/viewercontainer.h
1 + + LabelSlider + QLabel +
ui/labelslider.h
+
diff --git a/playback/cacher.cpp b/playback/cacher.cpp index e0f4b9f07..e6ee7088f 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -206,7 +206,7 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) { int i = 0; - double fr_ratio = qRound((c->sequence->frame_rate / c->frame_rate)*100)*0.01; +// double fr_ratio = c->sequence->frame_rate / c->frame_rate; /* old swscale solution if (!c->reached_end) { @@ -231,17 +231,20 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) { if (ret >= 0) { // optimization: mathematically determine based on the sequence and clips' frame rates whether this frame will actually be shown - double timeline_frame = (i+cache->offset) * fr_ratio; + // note: is not actually much faster and currently leads to crashes, may remove in the future +// int proposed_frame = qFloor((i+cache->offset) * fr_ratio); - if (qFloor(timeline_frame) == timeline_frame) { +// if (proposed_frame != c->last_cached_frame) { if ((ret = av_buffersrc_add_frame_flags(c->buffersrc_ctx, c->frame, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0) { qDebug() << "[ERROR] Could not feed filtergraph -" << ret; error = true; break; +// } else { +// c->last_cached_frame = proposed_frame; } - } else { - i++; - } +// } else { +// i++; +// } } else { if (ret == AVERROR_EOF) { c->reached_end = true; @@ -306,6 +309,8 @@ void reset_cache(Clip* c, long target_frame) { } while (retrieved_frame < target_frame); av_frame_free(&temp); + + c->last_cached_frame = -1; } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { // seek (target_frame represents timeline timecode in frames, not clip timecode) swr_drop_output(c->swr_ctx, swr_get_out_samples(c->swr_ctx, 0)); @@ -367,7 +372,7 @@ void open_clip_worker(Clip* clip) { AVDictionary* opts = NULL; - // decoding optimization configuration + // optimized decoding settings if (clip->stream->codecpar->codec_id != AV_CODEC_ID_PNG && clip->stream->codecpar->codec_id != AV_CODEC_ID_APNG && clip->stream->codecpar->codec_id != AV_CODEC_ID_TIFF && diff --git a/playback/playback.cpp b/playback/playback.cpp index cd8cb1051..c87d5243e 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -36,12 +36,7 @@ void open_clip(Clip* clip, bool multithreaded) { // maybe keep cacher instance in memory while clip exists for performance? clip->cacher = new Cacher(clip); QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater())); - - if (clip->track < 0) { - clip->cacher->start(QThread::LowPriority); - } else { - clip->cacher->start(QThread::TimeCriticalPriority); - } + clip->cacher->start((clip->track < 0) ? QThread::LowPriority : QThread::TimeCriticalPriority); } } else { clip->finished_opening = false; @@ -114,11 +109,6 @@ bool get_clip_frame(Clip* c, long playhead) { // do we need to update the texture? MediaStream* ms = static_cast(c->media)->get_stream_from_file_index(c->track < 0, c->media_stream); - // backwards compatibilty code - if (c->frame_rate == 0) { - c->frame_rate = ms->video_frame_rate; - } - long sequence_clip_time = playhead - c->timeline_in + c->clip_in; long clip_time = refactor_frame_number(sequence_clip_time, c->sequence->frame_rate, c->frame_rate); @@ -286,7 +276,10 @@ void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) { // output->pts = c->frame->best_effort_timestamp; } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { output->pts = c->frame->pts; - ret = swr_convert_frame(c->swr_ctx, output, c->frame); + ret = swr_convert_frame(c->swr_ctx, output, c->frame); + + + if (ret < 0) { qDebug() << "[ERROR] Failed to resample audio." << ret; } @@ -303,7 +296,7 @@ bool is_clip_active(Clip* c, long playhead) { return c->enabled && c->timeline_in < playhead + ceil(c->sequence->frame_rate) && c->timeline_out > playhead - && playhead - c->timeline_in + c->clip_in < c->getMediaLength(c->sequence->frame_rate); + && playhead - c->timeline_in + c->clip_in < c->getMaximumLength(); } void set_sequence(Sequence* s) { diff --git a/project/clip.cpp b/project/clip.cpp index 0e6c4935a..72e06dddf 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -124,7 +124,9 @@ void Clip::refresh() { // reinitializes all effects... just in case for (int i=0;irefresh(); - } + } + + recalculateMaxLength(); } Clip::~Clip() { @@ -168,28 +170,39 @@ long Clip::getLength() { return timeline_out - timeline_in; } -long Clip::getMediaLength(double framerate) { - switch (media_type) { - case MEDIA_TYPE_FOOTAGE: - { - Media* m = static_cast(media); - if (m->get_stream_from_file_index(track < 0, media_stream)->infinite_length) { - return LONG_MAX; - } else { - return m->get_length_in_frames(framerate); - } - } - break; - case MEDIA_TYPE_SEQUENCE: - { - Sequence* s = static_cast(media); - return refactor_frame_number(s->getEndFrame(), s->frame_rate, framerate); +void Clip::recalculateMaxLength() { + double fr = this->sequence->frame_rate; + + if (track < 0) { + fr *= (getMediaFrameRate()/frame_rate); + } else { + fr /= frame_rate; + } + + switch (media_type) { + case MEDIA_TYPE_FOOTAGE: + { + Media* m = static_cast(media); + if (m->get_stream_from_file_index(track < 0, media_stream)->infinite_length) { + calculated_length = LONG_MAX; + } else { + calculated_length = m->get_length_in_frames(fr); + } + } + break; + case MEDIA_TYPE_SEQUENCE: + { + Sequence* s = static_cast(media); + calculated_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, fr); } case MEDIA_TYPE_SOLID: case MEDIA_TYPE_TONE: - return LONG_MAX; + calculated_length = LONG_MAX; } - return 0; +} + +long Clip::getMaximumLength() { + return calculated_length; } double Clip::getMediaFrameRate() { diff --git a/project/clip.h b/project/clip.h index 51e9186bc..15d26dfde 100644 --- a/project/clip.h +++ b/project/clip.h @@ -63,7 +63,8 @@ struct Clip quint8 color_g; quint8 color_b; long getLength(); - long getMediaLength(double framerate); + long getMaximumLength(); + void recalculateMaxLength(); double getMediaFrameRate(); void* media; // attached media int media_type; @@ -71,6 +72,7 @@ struct Clip int getWidth(); int getHeight(); double frame_rate; + long calculated_length; // other variables (should be "duplicated" in copy()) QList effects; @@ -101,6 +103,7 @@ struct Clip ClipCache cache_B; QMutex lock; QMutex open_lock; + int last_cached_frame; // converters/filters AVFilterGraph* filter_graph; @@ -115,7 +118,7 @@ struct Clip bool autoscale; // audio playback variables - SwrContext* swr_ctx; +// SwrContext* swr_ctx; int frame_sample_index; int audio_buffer_write; bool audio_reset; diff --git a/ui/fontcombobox.cpp b/ui/fontcombobox.cpp index 6528c4dd8..5c2c98e19 100644 --- a/ui/fontcombobox.cpp +++ b/ui/fontcombobox.cpp @@ -15,7 +15,6 @@ const QString& FontCombobox::getPreviousValue() { } void FontCombobox::updateInternals() { - qDebug() << "h"; previousValue = value; value = currentText(); } diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index ac2ef918a..6e24bd9fa 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -10,6 +10,7 @@ #include LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) { + decimal_places = 1; drag_start = false; drag_proc = false; min_enabled = false; @@ -21,7 +22,6 @@ LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) { set_value(0, false); set = false; display_type = LABELSLIDER_NORMAL; - decimal_places = 1; } void LabelSlider::set_display_type(int type) { @@ -57,7 +57,7 @@ QString LabelSlider::valueToString(double v) { return "---"; } else { switch (display_type) { - case LABELSLIDER_FRAMENUMBER: return frame_to_timecode(v, config.timecode_view, sequence->frame_rate); + case LABELSLIDER_FRAMENUMBER: return frame_to_timecode(v, config.timecode_view, (sequence != NULL) ? sequence->frame_rate : 30); case LABELSLIDER_PERCENT: return QString::number((v*100), 'f', decimal_places) + "%"; } return QString::number(v, 'f', decimal_places); @@ -97,7 +97,7 @@ double LabelSlider::get_drag_start_value() { void LabelSlider::mousePressEvent(QMouseEvent *ev) { drag_start_value = internal_value; if (ev->modifiers() & Qt::AltModifier) { - if (internal_value != default_value) { + if (internal_value != default_value && !qIsNaN(default_value)) { previous_value = internal_value; set_value(default_value, true); } @@ -115,11 +115,7 @@ void LabelSlider::mouseMoveEvent(QMouseEvent*) { if (drag_start) { drag_proc = true; int diff = (cursor().pos().x()-drag_start_x) + (drag_start_y-cursor().pos().y()); - if (display_type == LABELSLIDER_PERCENT) { - set_value(internal_value + (diff*0.01), true); - } else { - set_value(internal_value + diff, true); - } + set_value(internal_value + ((display_type == LABELSLIDER_PERCENT) ? (diff*0.01) : diff), true); cursor().setPos(drag_start_x, drag_start_y); } } @@ -133,7 +129,16 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) { previous_value = drag_start_value; emit valueChanged(); } else { - double d = QInputDialog::getDouble(this, "Set Value", "New value:", internal_value); + double d = QInputDialog::getDouble( + this, + "Set Value", + "New value:", + (display_type == LABELSLIDER_PERCENT) ? internal_value * 100 : internal_value, + (min_enabled) ? min_value : INT_MIN, + (max_enabled) ? max_value : INT_MAX, + decimal_places + ); + if (display_type == LABELSLIDER_PERCENT) d *= 0.01; if (d != internal_value) { previous_value = internal_value; set_value(d, true); diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 3ff64b526..7fdfe57dd 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -348,9 +348,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) { c->color_g = 128; c->color_b = 192; } - if (c->track < 0) { - c->frame_rate = m->get_stream_from_file_index(true, c->media_stream)->video_frame_rate; - } + c->frame_rate = (c->track < 0) ? m->get_stream_from_file_index(true, c->media_stream)->video_frame_rate : 1.0; c->name = m->name; } else if (c->media_type == MEDIA_TYPE_SEQUENCE) { // sequence (red?ish?) @@ -359,7 +357,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) { c->color_b = 128; Sequence* media = static_cast(c->media); - c->frame_rate = media->frame_rate; + c->frame_rate = (c->track < 0) ? media->frame_rate : 1.0; c->name = media->name; } @@ -621,13 +619,12 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { c->color_b = 64; c->track = g.track; - if (c->track < 0) c->frame_rate = sequence->frame_rate; + c->frame_rate = (c->track < 0) ? sequence->frame_rate : 1.0; QVector add; add.append(c); ca->append(new AddClipCommand(sequence, add)); -// int clipIndex = sequence->clips.size(); if (c->track < 0) { // default video effects (before custom effects) c->effects.append(create_effect(VIDEO_TRANSFORM_EFFECT, c)); @@ -933,15 +930,7 @@ void TimelineWidget::init_ghosts() { } // used for trim ops - switch (c->media_type) { - case MEDIA_TYPE_FOOTAGE: - g.media_length = static_cast(c->media)->get_length_in_frames(sequence->frame_rate); - break; - case MEDIA_TYPE_SEQUENCE: - Sequence* s = static_cast(c->media); - g.media_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, sequence->frame_rate); - break; - } + g.media_length = c->getMaximumLength(); } for (int i=0;iselections.size();i++) { Selection& s = sequence->selections[i]; @@ -1710,18 +1699,10 @@ void TimelineWidget::redraw_clips() { draw_checkerboard = true; } else if (ms->preview_done) { // draw thumbnail/waveform - long media_length = m->get_length_in_frames(clip->sequence->frame_rate); - int waveform_limit; - - if (!ms->infinite_length) { - waveform_limit = qMin(clip_rect.width(), panel_timeline->getTimelineScreenPointFromFrame(media_length - clip->clip_in)); - if (waveform_limit < clip_rect.width()) { - draw_checkerboard = true; - if (waveform_limit > 0) checkerboard_rect.setLeft(checkerboard_rect.left() + waveform_limit); - } - } + long media_length = clip->getMaximumLength(); if (clip->track < 0) { + // draw thumbnail int space_for_thumb = clip_rect.width(); if (clip->opening_transition != NULL) { int ot_width = panel_timeline->getTimelineScreenPointFromFrame(clip->opening_transition->length); @@ -1739,13 +1720,21 @@ void TimelineWidget::redraw_clips() { clip_painter.drawImage(thumb_rect, ms->video_preview); } } else if (clip_rect.height() > TRACK_MIN_HEIGHT) { + int waveform_limit = qMin(clip_rect.width(), panel_timeline->getTimelineScreenPointFromFrame(media_length - clip->clip_in)); + + if (waveform_limit < clip_rect.width()) { + draw_checkerboard = true; + if (waveform_limit > 0) checkerboard_rect.setLeft(checkerboard_rect.left() + waveform_limit); + } + + // draw waveform clip_painter.setPen(QColor(80, 80, 80)); int divider = ms->audio_channels*2; int channel_height = clip_rect.height()/ms->audio_channels; for (int i=0;iclip_in + ((double) i/panel_timeline->zoom))/media_length) * ms->audio_preview.size())/divider)*divider; + int waveform_index = qFloor((((clip->clip_in + ((double) (i*clip->frame_rate)/panel_timeline->zoom))/media_length) * ms->audio_preview.size())/divider)*divider; int rectified_height = 0; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 9308d3153..24984a5f7 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -176,19 +176,27 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { QVector current_clips; for (int i=0;iclips.size();i++) { - Clip* c = s->clips.at(i); + Clip* c = s->clips.at(i); // if clip starts within one second and/or hasn't finished yet if (c != NULL && !(nest != NULL && !same_sign(c->track, nest->track))) { bool clip_is_active = false; + // backwards compatibilty + if (c->frame_rate == 0 && c->track >= 0) { + c->frame_rate = 1.0; + } + switch (c->media_type) { case MEDIA_TYPE_FOOTAGE: { Media* m = static_cast(c->media); if (m->ready) { - if (m->get_stream_from_file_index(c->track < 0, c->media_stream) != NULL - && is_clip_active(c, playhead)) { + MediaStream* ms = m->get_stream_from_file_index(c->track < 0, c->media_stream); + if (ms != NULL && is_clip_active(c, playhead)) { + // backwards compatibility + if (c->frame_rate == 0 && c->track < 0) c->frame_rate = ms->video_frame_rate; + // if thread is already working, we don't want to touch this, // but we also don't want to hang the UI thread if (!c->open) { @@ -204,8 +212,13 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { } break; case MEDIA_TYPE_SEQUENCE: + // backwards compatibility + if (c->frame_rate == 0 == c->track < 0) c->frame_rate = static_cast(c->media)->frame_rate; case MEDIA_TYPE_SOLID: case MEDIA_TYPE_TONE: + // backwards compatibility + if (c->frame_rate == 0 && c->track < 0) c->frame_rate = s->frame_rate; + if (is_clip_active(c, playhead)) { if (!c->open) open_clip(c, !rendering); clip_is_active = true;