diff --git a/icons/icons.qrc b/icons/icons.qrc index 3fc0faaf0..3bbbc0ea9 100644 --- a/icons/icons.qrc +++ b/icons/icons.qrc @@ -30,5 +30,11 @@ slide.png slide-disabled.png throbber.png + magnet.png + magnet-disabled.png + zoomin.png + zoomin-disabled.png + zoomout.png + zoomout-disabled.png diff --git a/icons/magnet-disabled.png b/icons/magnet-disabled.png new file mode 100644 index 000000000..4f19588b2 Binary files /dev/null and b/icons/magnet-disabled.png differ diff --git a/icons/magnet.png b/icons/magnet.png new file mode 100644 index 000000000..d5fbf13a3 Binary files /dev/null and b/icons/magnet.png differ diff --git a/icons/zoomin-disabled.png b/icons/zoomin-disabled.png new file mode 100644 index 000000000..ad008a3f5 Binary files /dev/null and b/icons/zoomin-disabled.png differ diff --git a/icons/zoomin.png b/icons/zoomin.png new file mode 100644 index 000000000..cc49cdebf Binary files /dev/null and b/icons/zoomin.png differ diff --git a/icons/zoomout-disabled.png b/icons/zoomout-disabled.png new file mode 100644 index 000000000..a2b254cda Binary files /dev/null and b/icons/zoomout-disabled.png differ diff --git a/icons/zoomout.png b/icons/zoomout.png new file mode 100644 index 000000000..60a07a488 Binary files /dev/null and b/icons/zoomout.png differ diff --git a/main.cpp b/main.cpp index 61fc82cca..0634f98c9 100644 --- a/main.cpp +++ b/main.cpp @@ -12,7 +12,7 @@ int main(int argc, char *argv[]) // QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); - QApplication a(argc, argv); + QApplication a(argc, argv); MainWindow w; w.show(); diff --git a/mainwindow.cpp b/mainwindow.cpp index c5f4d7df3..53e6ce745 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -323,7 +323,15 @@ bool MainWindow::save_project() { bool MainWindow::can_close_project() { if (project_changed) { - int r = QMessageBox::question(this, "Unsaved Project", "This project has changed since it was last saved. Would you like to save it before closing?", QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes); + QMessageBox* m = new QMessageBox( + QMessageBox::Question, + "Unsaved Project", + "This project has changed since it was last saved. Would you like to save it before closing?", + QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, + this + ); + m->setWindowModality(Qt::WindowModal); + int r = m->exec(); if (r == QMessageBox::Yes) { return save_project(); } else if (r == QMessageBox::Cancel) { @@ -426,6 +434,10 @@ void MainWindow::on_actionCrash_triggered() // intentionally tries to crash the program - mostly used for debugging Timeline* temp = NULL; temp->snapped = true; + int* kek; + kek[5] = 69; + kek[99999] = 420; + delete temp; } } diff --git a/olive.pro b/olive.pro index 5b70bd5c5..682d07435 100644 --- a/olive.pro +++ b/olive.pro @@ -8,7 +8,7 @@ QT += core gui multimedia opengl greaterThan(QT_MAJOR_VERSION, 4): QT += widgets -TARGET = olive +TARGET = Olive TEMPLATE = app # The following define makes your compiler emit warnings if you use @@ -123,6 +123,7 @@ win32 { } mac { + LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lswscale -lswresample INCLUDEPATH = /usr/local/include } diff --git a/panels/timeline.cpp b/panels/timeline.cpp index ee53c4cac..9c7b3d03d 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -53,7 +53,8 @@ Timeline::Timeline(QWidget *parent) : ui->video_area->bottom_align = true; - ui->splitter->setOpaqueResize(false); + ui->video_area->container = ui->videoScrollArea; + ui->audio_area->container = ui->audioScrollArea; tool_buttons.append(ui->toolArrowButton); tool_buttons.append(ui->toolEditButton); diff --git a/panels/timeline.ui b/panels/timeline.ui index f486cb108..9df286d0c 100644 --- a/panels/timeline.ui +++ b/panels/timeline.ui @@ -6,8 +6,8 @@ 0 0 - 523 - 376 + 901 + 592 @@ -62,18 +62,6 @@ - - - 0 - 0 - - - - - 40 - 16777215 - - Pointer Tool (V) @@ -85,12 +73,6 @@ :/icons/arrow.png :/icons/arrow-disabled.png:/icons/arrow.png - - - 20 - 20 - - true @@ -98,12 +80,6 @@ - - - 40 - 16777215 - - Edit Tool (X) @@ -115,12 +91,6 @@ :/icons/beam.png :/icons/beam-disabled.png:/icons/beam.png - - - 20 - 20 - - true @@ -128,12 +98,6 @@ - - - 40 - 16777215 - - Ripple Tool (B) @@ -145,12 +109,6 @@ :/icons/ripple.png :/icons/ripple-disabled.png:/icons/ripple.png - - - 20 - 20 - - true @@ -158,12 +116,6 @@ - - - 40 - 16777215 - - Rolling Tool (N) @@ -175,12 +127,6 @@ :/icons/rolling.png :/icons/rolling-disabled.png:/icons/rolling.png - - - 20 - 20 - - true @@ -188,12 +134,6 @@ - - - 40 - 16777215 - - Razor Tool (C) @@ -205,12 +145,6 @@ :/icons/razor.png :/icons/razor-disabled.png:/icons/razor.png - - - 20 - 20 - - true @@ -218,12 +152,6 @@ - - - 40 - 16777215 - - Slip Tool (Y) @@ -236,12 +164,6 @@ :/icons/slip-disabled.png - - - 20 - 20 - - true @@ -249,12 +171,6 @@ - - - 40 - 16777215 - - Slide Tool (U) @@ -267,12 +183,6 @@ :/icons/slide-disabled.png - - - 20 - 20 - - true @@ -280,14 +190,14 @@ - - - 40 - 16777215 - - - S + + + + + :/icons/magnet.png + :/icons/magnet-disabled.png + true @@ -299,33 +209,33 @@ - - - 40 - 16777215 - - Zoom In (=) - + + + + + + :/icons/zoomin.png + :/icons/zoomin-disabled.png + - - - 40 - 16777215 - - Zoom Out (-) - - + + + + + :/icons/zoomout.png + :/icons/zoomout-disabled.png + @@ -348,7 +258,7 @@ - Qt::ScrollBarAlwaysOn + Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOn @@ -361,11 +271,11 @@ 0 0 - 408 - 327 + 819 + 551 - + 0 @@ -399,27 +309,101 @@ Qt::Vertical - - - - 0 - 0 - + + + QFrame::NoFrame - - Qt::ClickFocus + + Qt::ScrollBarAlwaysOn + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 802 + 266 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + + + - - - - 0 - 0 - + + + QFrame::NoFrame - - Qt::ClickFocus + + Qt::ScrollBarAlwaysOn + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 802 + 265 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::ClickFocus + + + + + diff --git a/panels/viewer.ui b/panels/viewer.ui index 7a748347c..f850d20c7 100644 --- a/panels/viewer.ui +++ b/panels/viewer.ui @@ -104,183 +104,48 @@ true - - - 0 - 0 - - - - - 36 - 0 - - - - - 16777215 - 16777215 - - - - - :/icons/prev.png :/icons/prev-disabled.png:/icons/prev.png - - - 14 - 14 - - - - - 0 - 0 - - - - - 36 - 0 - - - - - 16777215 - 16777215 - - - - - :/icons/rew.png :/icons/rew-disabled.png:/icons/rew.png - - - 14 - 14 - - - - - 0 - 0 - - - - - 36 - 0 - - - - - 16777215 - 16777215 - - - - - :/icons/play.png :/icons/play-disabled.png:/icons/play.png - - - 14 - 14 - - - - - 0 - 0 - - - - - 36 - 0 - - - - - 16777215 - 16777215 - - - - - :/icons/ff.png :/icons/ff-disabled.png - - - 14 - 14 - - - - - 0 - 0 - - - - - 36 - 0 - - - - - 16777215 - 16777215 - - - - - :/icons/next.png :/icons/next-disabled.png:/icons/next.png - - - 14 - 14 - - diff --git a/playback/cacher.cpp b/playback/cacher.cpp index d7e62a524..4ac960e83 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -180,21 +180,22 @@ void reset_cache(Clip* c, long target_frame) { if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { // seeks to nearest keyframe (target_frame represents internal clip frame) - av_seek_frame(c->formatCtx, ms->file_index, clip_frame_to_seconds(c, target_frame) / timebase, AVSEEK_FLAG_BACKWARD); + + av_seek_frame(c->formatCtx, ms->file_index, (int64_t) qFloor(clip_frame_to_seconds(c, target_frame) / timebase), AVSEEK_FLAG_BACKWARD); + qDebug() << target_frame; // play up to the frame we actually want long retrieved_frame = 0; AVFrame* temp = av_frame_alloc(); - do { + do { retrieve_next_frame(c, temp); if (retrieved_frame == 0) { - if (target_frame != 0) { - retrieved_frame = floor(temp->pts * timebase * av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, temp))); - } + if (target_frame != 0) retrieved_frame = floor(temp->pts * timebase * av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, temp))); } else { retrieved_frame++; } } while (retrieved_frame < target_frame); + av_frame_free(&temp); } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { // seek (target_frame represents timeline timecode in frames, not clip timecode) diff --git a/playback/playback.cpp b/playback/playback.cpp index 7097deaf4..578e6099c 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -75,7 +75,7 @@ void cache_clip(Clip* clip, long playhead, bool write_A, bool write_B, bool rese void get_clip_frame(Clip* c, long playhead) { if (c->open) { - long clip_time = seconds_to_clip_frame(c, playhead_to_seconds(c, playhead)); + long clip_time = refactor_frame_number(playhead - c->timeline_in + c->clip_in, c->sequence->frame_rate, av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, c->frame))); // do we need to update the texture? MediaStream* ms = static_cast(c->media)->get_stream_from_file_index(c->media_stream); @@ -139,15 +139,8 @@ void get_clip_frame(Clip* c, long playhead) { bool write_A = (!using_cache_A && !c->cache_A.unread); bool write_B = (!using_cache_B && !c->cache_B.unread); if (write_A || write_B) { - long playhead; - if (cache_needs_reset) { - // if we have no cache and need to seek, start us at the current playhead... - playhead = clip_time; - } else { - // ...otherwise start at the end of the current cache - playhead = cache_offset + c->cache_size; - } - cache_clip(c, playhead, write_A, write_B, cache_needs_reset, NULL); + // if we have no cache and need to seek, start us at the current playhead, otherwise start at the end of the current cache + cache_clip(c, (cache_needs_reset) ? clip_time : cache_offset + c->cache_size, write_A, write_B, cache_needs_reset, NULL); } c->lock.unlock(); } @@ -175,12 +168,12 @@ void get_clip_frame(Clip* c, long playhead) { } } -float playhead_to_seconds(Clip* c, long playhead) { +double playhead_to_seconds(Clip* c, long playhead) { // returns time in seconds return (qMax((long) 0, playhead - c->timeline_in) + c->clip_in)/c->sequence->frame_rate; } -long seconds_to_clip_frame(Clip* c, float seconds) { +long seconds_to_clip_frame(Clip* c, double seconds) { // returns time as frame number (according to clip's frame rate) if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { return floor(seconds*av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, c->frame))); @@ -190,9 +183,9 @@ long seconds_to_clip_frame(Clip* c, float seconds) { } } -float clip_frame_to_seconds(Clip* c, long clip_frame) { +double clip_frame_to_seconds(Clip* c, long clip_frame) { // returns frame number in decimal seconds - return (float) clip_frame / c->sequence->frame_rate; + return (double) clip_frame / av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, c->frame)); } int retrieve_next_frame(Clip* c, AVFrame* f) { diff --git a/playback/playback.h b/playback/playback.h index 25aa87c37..5acc5f359 100644 --- a/playback/playback.h +++ b/playback/playback.h @@ -19,9 +19,9 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache); void handle_media(Sequence* sequence, long playhead, bool multithreaded); void reset_cache(Clip* c, long target_frame); void get_clip_frame(Clip* c, long playhead); -float playhead_to_seconds(Clip* c, long playhead); -long seconds_to_clip_frame(Clip* c, float seconds); -float clip_frame_to_seconds(Clip* c, long clip_frame); +double playhead_to_seconds(Clip* c, long playhead); +long seconds_to_clip_frame(Clip* c, double seconds); +double clip_frame_to_seconds(Clip* c, long clip_frame); int retrieve_next_frame(Clip* c, AVFrame* f); void retrieve_next_frame_raw_data(Clip* c, AVFrame* output); bool is_clip_active(Clip* c, long playhead); diff --git a/project/clip.cpp b/project/clip.cpp index 6d6721984..65bea6ae2 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -91,7 +91,7 @@ void Clip::reset_audio() { audio_reset = true; frame_sample_index = 0; audio_buffer_write = 0; - reached_end = false; + reached_end = false; break; case MEDIA_TYPE_SEQUENCE: { diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 616146789..8c4381b82 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -1349,27 +1349,44 @@ int color_brightness(int r, int g, int b) { void TimelineWidget::redraw_clips() { // Draw clips if (sequence != NULL) { - int panel_width = panel_timeline->getScreenPointFromFrame(sequence->getEndFrame()) + 100; + // get widget width and height + int video_track_limit = 0; + int audio_track_limit = 0; + long end_frame = 0; + for (int i=0;iclip_count();i++) { + Clip* clip = sequence->get_clip(i); + if (clip != NULL) { + end_frame = qMax(end_frame, clip->timeline_out); + video_track_limit = qMin(video_track_limit, clip->track); + audio_track_limit = qMax(audio_track_limit, clip->track); + } + } + int panel_width = panel_timeline->getScreenPointFromFrame(end_frame) + 100; + int panel_height = 0; + if (bottom_align) { + for (int i=-1;i>=video_track_limit;i--) { + panel_height += panel_timeline->calculate_track_height(i, -1); + } + } else { + for (int i=0;i<=audio_track_limit;i++) { + panel_height += panel_timeline->calculate_track_height(i, -1); + } + } - if (minimumWidth() != panel_width || clip_pixmap.height() != height()) { + if (minimumWidth() != panel_width || /*clip_pixmap.height() != height() || */panel_height != minimumHeight()) { setMinimumWidth(panel_width); - clip_pixmap = QPixmap(qMax(width(), panel_width), height()); + container->setMinimumWidth(panel_width); + setMinimumHeight(panel_height); + clip_pixmap = QPixmap(qMax(width(), panel_width), qMax(height(), panel_height)); } clip_pixmap.fill(Qt::transparent); QPainter clip_painter(&clip_pixmap); - int video_track_limit = 0; - int audio_track_limit = 0; + QColor transition_color(255, 0, 0, 16); for (int i=0;iclip_count();i++) { Clip* clip = sequence->get_clip(i); - if (clip != NULL && is_track_visible(clip->track)) { - if (clip->track < 0 && clip->track < video_track_limit) { // video clip - video_track_limit = clip->track; - } else if (clip->track > audio_track_limit) { - audio_track_limit = clip->track; - } - + if (clip != NULL && is_track_visible(clip->track)) { QRect clip_rect(panel_timeline->getScreenPointFromFrame(clip->timeline_in), getScreenPointFromTrack(clip->track), clip->getLength() * panel_timeline->zoom, panel_timeline->calculate_track_height(clip->track, -1)); clip_painter.fillRect(clip_rect, QColor(clip->color_r, clip->color_g, clip->color_b)); @@ -1378,13 +1395,8 @@ void TimelineWidget::redraw_clips() { QRect text_rect(clip_rect.left() + CLIP_TEXT_PADDING, clip_rect.top() + CLIP_TEXT_PADDING, clip_rect.width() - CLIP_TEXT_PADDING - 1, clip_rect.height() - CLIP_TEXT_PADDING - 1); // draw clip transitions - for (char i=0;i<2;i++) { - Transition* t; - if (i == 0) { - t = clip->opening_transition; - } else { - t = clip->closing_transition; - } + for (int i=0;i<2;i++) { + Transition* t = (i == 0) ? clip->opening_transition : clip->closing_transition; if (t != NULL) { int transition_width = panel_timeline->getScreenPointFromFrame(t->length); int transition_height = clip_rect.height() * 0.6; @@ -1522,9 +1534,8 @@ void TimelineWidget::redraw_clips() { } } else { // only draw lines for audio tracks - for (int i=0;icalculate_track_height(i, -1); + for (int i=0;icalculate_track_height(i, -1); clip_painter.drawLine(0, line_y, rect().width(), line_y); } } diff --git a/ui/timelinewidget.h b/ui/timelinewidget.h index debc9506f..ed56c0faa 100644 --- a/ui/timelinewidget.h +++ b/ui/timelinewidget.h @@ -19,11 +19,13 @@ class TimelineAction; class TimelineWidget : public QWidget { Q_OBJECT public: - explicit TimelineWidget(QWidget *parent = 0); + explicit TimelineWidget(QWidget *parent = 0); bool bottom_align; void redraw_clips(); + + QWidget* container; protected: void paintEvent(QPaintEvent*); void resizeEvent(QResizeEvent*); @@ -60,8 +62,7 @@ private: int predicted_video_height; double predicted_new_frame_rate; int predicted_audio_freq; - int predicted_audio_layout; - + int predicted_audio_layout; signals: public slots: diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index b69881fae..8058a96e5 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -89,12 +89,10 @@ void ViewerWidget::paintEvent(QPaintEvent *e) { void ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { Sequence* s = sequence; - long playhead = panel_timeline->playhead; + long playhead = panel_timeline->playhead; + if (nest != NULL) { s = static_cast(nest->media); - -// qDebug() << "nested sequence was null:" << (s == NULL); - playhead += nest->clip_in - nest->timeline_in; playhead = refactor_frame_number(playhead, sequence->frame_rate, s->frame_rate); }