From a285f10e6a2fecf9eb53e93a75308092620886c6 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 13 Oct 2018 13:08:20 +1100 Subject: [PATCH] several improvements --- dialogs/newsequencedialog.cpp | 15 +++++++++++- dialogs/speeddialog.cpp | 17 ++------------ effects/effect.cpp | 1 + icons/folder.png | Bin 0 -> 1506 bytes icons/icons.qrc | 2 ++ icons/sequence.png | Bin 0 -> 1598 bytes mainwindow.cpp | 11 +++++---- panels/effectcontrols.cpp | 8 ++----- panels/panels.cpp | 1 + panels/panels.h | 1 + panels/project.cpp | 10 ++++++-- panels/timeline.cpp | 11 ++++++++- panels/viewer.cpp | 7 ++---- panels/viewer.ui | 12 ++++++++++ playback/cacher.cpp | 43 ++++++++++++++++++++++++++++++---- playback/playback.cpp | 14 +++++++++-- project/clip.cpp | 26 ++++++++++++++++++++ project/clip.h | 2 ++ project/undo.cpp | 3 +++ ui/keyframeview.cpp | 1 - ui/labelslider.cpp | 2 +- ui/sourcetable.cpp | 4 ++++ ui/timelineheader.cpp | 40 ++++++++++++++++++++----------- ui/timelineheader.h | 5 ++++ 24 files changed, 179 insertions(+), 57 deletions(-) create mode 100644 icons/folder.png create mode 100644 icons/sequence.png diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index 5adbef49c..1d36e1101 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -90,6 +90,10 @@ void NewSequenceDialog::on_buttonBox_accepted() { panel_project->new_sequence(ca, s, true, NULL); undo_stack.push(ca); } else { + ComboAction* ca = new ComboAction(); + + double multiplier = ui->frame_rate_combobox->currentData().toDouble() / existing_sequence->frame_rate; + EditSequenceCommand* esc = new EditSequenceCommand(existing_item, existing_sequence); esc->name = ui->lineEdit->text(); esc->width = ui->width_numeric->value(); @@ -97,7 +101,16 @@ void NewSequenceDialog::on_buttonBox_accepted() { esc->frame_rate = ui->frame_rate_combobox->currentData().toDouble(); esc->audio_frequency = ui->audio_frequency_combobox->currentData().toInt(); esc->audio_layout = AV_CH_LAYOUT_STEREO; - undo_stack.push(esc); + ca->append(esc); + + for (int i=0;iclips.size();i++) { + Clip* c = existing_sequence->clips.at(i); + if (c != NULL) { + c->refactor_frame_rate(ca, multiplier, true); + } + } + + undo_stack.push(ca); } } diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index 4f48baf2d..9d2739516 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -315,21 +315,8 @@ void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, lo ep = qMin(ep, c->timeline_out); lr = qMax(lr, proposed_out - c->timeline_out); ca->append(new MoveClipAction(c, c->timeline_in, proposed_out, c->clip_in * multiplier, c->track)); - for (int i=0;ieffects.size();i++) { - Effect* e = c->effects.at(i); - for (int j=0;jrow_count();j++) { - EffectRow* r = e->row(j); - for (int k=0;kkeyframe_times.size();k++) { - long new_pos = r->keyframe_times.at(k) * c->speed / speed; - qDebug() << "old key" << r->keyframe_times.at(k) << "new key" << new_pos; - KeyframeMove* km = new KeyframeMove(); - km->movement = new_pos - r->keyframe_times.at(k); - km->rows.append(r); - km->keyframes.append(k); - ca->append(km); - } - } - } + + c->refactor_frame_rate(ca, multiplier, false); Selection sel; sel.in = c->timeline_in; diff --git a/effects/effect.cpp b/effects/effect.cpp index 75bf981c3..1814bce08 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -116,6 +116,7 @@ Effect::Effect(Clip* c, int t, int i) : ui = new QWidget(); ui_layout = new QGridLayout(); + ui_layout->setSpacing(4); ui->setLayout(ui_layout); container->setContents(ui); } diff --git a/icons/folder.png b/icons/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..8b51987b4091c97ec7fd22823a4652fae35d1766 GIT binary patch literal 1506 zcmbtTi8C8`6#mJf>ZrPdA#rQnH^q|1k<@)v)s@PsI@+X&IGPAqb+uDPD4}|YRkSG8 z*44D6Ydf}BRH?H~+g-QOQR3Rz+1dRA_RYNS`{vE}X5P$uFW1}CRYFur6aXNB!#ep2 zn0}BVFabteJ#ZAzVG=ed0RS;R_K%OeH<}!dx3|A9PnCyIlu~4KXty)2XOv|egqq3oXB-n0C;LDfIT$g8 z;GQqb5C_g7|yIj20t+y9lIK+ni{sjKzGTF^Zw28Ci$Q*h|RP$)qh z3T0q@lm6C12RaE`U?!*wJThLm7-xY8%1EH0BYn=Ny5wfwWwY6tgi|!%x|5{H%ea_J z&6!bQ@iZSa%_jmEBPuYD91#{oSm};5{CjV|9b5w%AbgyW)29m;5tI5s!~}*lG&s&U zqy=RF281ERfMNhf9b?}Exq4rmh~O%QBHR=Mji(9H1ks3cPGUyTEt|p=wRL5Aw~`|z z!40Vm4;#L}*B`HGrV=EhW`4WdJH%bfGP}7BDb*O0zvQtDxAV30OUX*sSv$P$@u_q! zT>p+n6J{`AHP5?lP;xFzO73RYy}5hgz1q3Tx#2f!3yO>Ew3$W*2Go-^?x#aHNQvlt@XkSE!K;Q5i{@ z!M}j*@6h?2T(ld5k`*FOReUR}rVuSBClxAXW|rhN$$+&vO;tDXt`=K7uo|{8)i*V3 z`EowIKXRaDpi%d||K_7J9h&ut0pl#u-8Y4Gp%&MkgpvIgke2fnqvll?nX!6t4im?w z0!FCqflnHn_m`bmxE7uLN+pM-Rq^X(yDi-VxLawd-CLRLd?)#*hFfj=30qxEwR+FS z%RwE)uFqF5vfM3+<1vpfZXcs!sLT{7)= z=Os7SM$NEY3iYiAE10q}GUL~s{_)&2p;>3UDzf`%O3EsEFL;Zh@Pj$kba!WdA#-KU z0Zyyr5Az4s_S1m`kTmC)tc4052Svd8dH|5BC3q+X09*S4{u2PQF#z*;08ZQjK!I2o z&UFC*;)HWT`zKE`$fRV;GNJkkAFow73C-vfPAqgs&c`X-aMT-DzY_rBw8feN8iX(< z(r`p`aaN2Lr6vSB>InWX(48ThWpNw#A+y1c!7gOhI*48bnbi%VW72YX7O0Y<6ra6DThEp@I?h!LA!tNE8Cg!=EO{XxsFxm3K z4F*4ES=S7hWOshu9=*{vN;dj$od>EK@j@85<=c+bHoCS5ZV%v`J)It%#Ap5m(i3g^ literal 0 HcmV?d00001 diff --git a/icons/icons.qrc b/icons/icons.qrc index 64b3fc6f8..a65c87c34 100644 --- a/icons/icons.qrc +++ b/icons/icons.qrc @@ -41,5 +41,7 @@ add-button.png add-button-disabled.png clock.png + sequence.png + folder.png diff --git a/icons/sequence.png b/icons/sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..b09483a06d8237fc5ed9b462b60c859d977453b7 GIT binary patch literal 1598 zcmZ`&eKga19R4yZ%_Jd{%6p_CFXi<%Yg^f5TQkWuEDI4vS)$D5cPZ4V6k#!x5=tU< zTh{7&ONF9aBJW9*msCQtJKb~tx##pb=kq+zdCuqg{P8{CPb!tXLlvtF4 z!5}x<;h$PzQ6F|YV=MRNGa3|P7(qS*gAQ@ALA!$Ex2Gl*78e&Mu}EB6>9(k#Xku7o zWm1U$LGCUrcUK@W3?U!xSiVGF{uh3%gwNDHb%7hfyq1_lCz{OQ$|~wxm93TBEG^8T zr6w>4K#Gt81j7NGA?~-o6jLrC*{FIQKa{(U_og1!N){q8R}#bb$#%?$Gnm$0<({=X z%eOqf{CfG!Yjo$8$^@2LNbj@4y65#%$+l;w6)zaQS{3Or4tJrsc*Z3kF`ZgA?J;c#dlA1KLw@a80`Sa&EknSo5uY0)&$4%O09_fxmEJxu9_lxpyAFW($WIluXueY>L# z+QznOI5^;GP-|6dh1qNR_Zxde#$_>HodSfkIiu8X^U2%(9M3VmEu))X+6f~v4{Qv_ zyxH*9t0Uo__w9;G**IQ6tTL75t;T$sM4rl#R*74Q*+=8Wvq{D2_*Hi-XKT=hW@|GI z%E%SbJ|cGQyOapQ&MoZDuv-!H%ggfSV@2bRBCBv21UVk(t_#Ji=N_vkj(NUsF&0WW z+!usT?mH@s{iU%9Egk~j*olr_PjTYF-X2z^>AWyVydo}clC$7D8>_w5F2P3nV{|NO zq8|h2=FPRwwNA+rfhth5o6DN=lOK*g%Z=s%K)i|kpdbKdWpe%i0A~{bqf7vtvH{R$ zX9U!52SBlah{w{8y!qH&d%$zACU5G!zk6YU8&-)B(`IS%(xlJuZfaQ~t_-r|x_-DK zAm8JRcVm^-R*%ru;>W1DuUB(JQS7@NDfI z7-0>azoQ45X1j|-Qfr*1w$o;K_{Ed;22{7OqO zR&DqsJs<41=Ju)f1RK^!HNoWB#-+#JX>7%7Yd=r~IJC_{-jfk{O_961wZhH%BaM12 z#QK3Q3LLO=#wWGfpI$XXKSO{ug%3Z}P!fw9g41rvpFjLyE!1xRqFT5T3}=T<4km563C%!7SCfRxsH<*Il?y$j*XEC2(gi&E<;6%2EFXfFEaA>hmZuFl($?OTc2_`Sgfy8I4?CZRvn7(T}2Ymd_yXfVKCku}QMP+^0fJX4)29)PF zl6Iz?%v-d60bin#bWQ-bx9K8KP+H+C2jxV)wuovOJRNOTq4BHO;=WIWnHhM|_~5+s szvziXy*>;z3jXh+pWFTq1(bnSpi-h*#oUSMl>ci$B#`kpwlS0b0Zv$>H~;_u literal 0 HcmV?d00001 diff --git a/mainwindow.cpp b/mainwindow.cpp index fcee3bfc8..8d257b451 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -56,6 +56,7 @@ void MainWindow::setup_layout() { addDockWidget(Qt::TopDockWidgetArea, panel_project); addDockWidget(Qt::TopDockWidgetArea, panel_effect_controls); + tabifyDockWidget(panel_effect_controls, panel_footage_viewer); addDockWidget(Qt::TopDockWidgetArea, panel_sequence_viewer); addDockWidget(Qt::BottomDockWidgetArea, panel_timeline); @@ -103,6 +104,7 @@ MainWindow::MainWindow(QWidget *parent) : panel_project = new Project(this); panel_effect_controls = new EffectControls(this); panel_sequence_viewer = new Viewer(this); + panel_footage_viewer = new Viewer(this); panel_timeline = new Timeline(this); setup_layout(); @@ -174,8 +176,9 @@ MainWindow::~MainWindow() { delete panel_project; delete panel_effect_controls; + delete panel_timeline; delete panel_sequence_viewer; - delete panel_timeline; + delete panel_footage_viewer; } void MainWindow::on_action_Import_triggered() @@ -698,16 +701,16 @@ void MainWindow::on_actionRipple_to_Out_Point_triggered() void MainWindow::on_actionSet_In_Point_triggered() { - if (panel_timeline->focused()) panel_timeline->set_in_point(); + if (panel_timeline->focused() || panel_sequence_viewer->hasFocus()) panel_timeline->set_in_point(); } void MainWindow::on_actionSet_Out_Point_triggered() { - if (panel_timeline->focused()) panel_timeline->set_out_point(); + if (panel_timeline->focused() || panel_sequence_viewer->hasFocus()) panel_timeline->set_out_point(); } void MainWindow::on_actionClear_In_Out_triggered() { - if (panel_timeline->focused() && sequence->using_workarea) { + if ((panel_timeline->focused() || panel_sequence_viewer->hasFocus()) && sequence->using_workarea) { undo_stack.push(new SetTimelineInOutCommand(sequence, false, 0, 0)); panel_timeline->repaint_timeline(false); } diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index dbee21d26..b06019806 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -59,11 +59,7 @@ bool EffectControls::keyframe_focus() { } void EffectControls::set_zoom(bool in) { - if (in) { - zoom *= 2; - } else { - zoom *= 0.5; - } + zoom *= (in) ? 2 : 0.5; update_keyframes(); } @@ -94,7 +90,7 @@ void EffectControls::menu_select(QAction* q) { } void EffectControls::update_keyframes() { - if (ui->headers->isVisible()) ui->headers->update_zoom(zoom); + ui->headers->update_zoom(zoom); ui->keyframeView->update(); } diff --git a/panels/panels.cpp b/panels/panels.cpp index 5c96d840e..c597121b1 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -3,4 +3,5 @@ Project* panel_project = 0; EffectControls* panel_effect_controls = 0; Viewer* panel_sequence_viewer = 0; +Viewer* panel_footage_viewer = 0; Timeline* panel_timeline = 0; diff --git a/panels/panels.h b/panels/panels.h index 020a39217..680e291d2 100644 --- a/panels/panels.h +++ b/panels/panels.h @@ -9,6 +9,7 @@ class Timeline; extern Project* panel_project; extern EffectControls* panel_effect_controls; extern Viewer* panel_sequence_viewer; +extern Viewer* panel_footage_viewer; extern Timeline* panel_timeline; #endif // PANELS_H diff --git a/panels/project.cpp b/panels/project.cpp index d87b7eee2..6a20612a3 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -165,9 +165,13 @@ void Project::open_properties() { default: { // fall back to renaming - QString new_name = QInputDialog::getText(this, "Rename '" + item->text(0) + "'", "Enter new name:"); + QString new_name = QInputDialog::getText(this, "Rename '" + item->text(0) + "'", "Enter new name:", QLineEdit::Normal, item->text(0)); if (!new_name.isEmpty()) { - item->setText(0, new_name); + MediaRename* mr = new MediaRename(); + mr->from = item->text(0); + mr->item = item; + mr->to = new_name; + undo_stack.push(mr); } } } @@ -220,6 +224,7 @@ QTreeWidgetItem* Project::new_folder(QString name) { QTreeWidgetItem* item = new_item(); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); item->setText(0, (name.isEmpty()) ? "New Folder" : name); + item->setIcon(0, QIcon(":/icons/folder.png")); set_item_to_folder(item); return item; } @@ -576,6 +581,7 @@ void set_sequence_of_tree(QTreeWidgetItem* item, Sequence* s) { + "\nFrame Rate: " + QString::number(s->frame_rate) + "\nAudio Frequency: " + QString::number(s->audio_frequency) + "\nAudio Layout: " + get_channel_layout_name(av_get_channel_layout_nb_channels(s->audio_layout), s->audio_layout)); + item->setIcon(0, QIcon(":/icons/sequence.png")); } int get_type_from_tree(QTreeWidgetItem* item) { diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 376815764..df5a855c7 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -307,7 +307,9 @@ void Timeline::repaint_timeline(bool changed) { panel_effect_controls->update_keyframes(); if (sequence != NULL) { - panel_timeline->ui->horizontalScrollBar->setMaximum(qMax(0, getScreenPointFromFrame(panel_timeline->zoom, sequence->getEndFrame()) + 100 - ui->editAreas->width())); + long sequenceEndFrame = sequence->getEndFrame(); + + panel_timeline->ui->horizontalScrollBar->setMaximum(qMax(0, getScreenPointFromFrame(panel_timeline->zoom, sequenceEndFrame) + 100 - ui->editAreas->width())); if (last_frame != sequence->playhead) { panel_sequence_viewer->viewer_widget->update(); @@ -324,6 +326,13 @@ void Timeline::repaint_timeline(bool changed) { } panel_sequence_viewer->update_playhead_timecode(sequence->playhead); + + + if (sequenceEndFrame > 0) { + panel_sequence_viewer->ui->headers->update_zoom((double) panel_sequence_viewer->ui->headers->width() / (double) sequenceEndFrame); + } else { + panel_sequence_viewer->ui->headers->update_zoom(1); + } } } diff --git a/panels/viewer.cpp b/panels/viewer.cpp index f4acb535c..b2132d7a4 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -22,6 +22,7 @@ Viewer::Viewer(QWidget *parent) : ui(new Ui::Viewer) { ui->setupUi(this); + ui->headers->show_text(false); ui->glViewerPane->child = ui->openGLWidget; viewer_widget = ui->openGLWidget; update_media(MEDIA_TYPE_SEQUENCE, NULL); @@ -111,11 +112,7 @@ void Viewer::update_playhead_timecode(long p) { } void Viewer::update_end_timecode() { - if (sequence == NULL) { - ui->endTimecode->setText(frame_to_timecode(0, config.timecode_view, 30)); - } else { - ui->endTimecode->setText(frame_to_timecode(sequence->getEndFrame(), config.timecode_view, sequence->frame_rate)); - } + ui->endTimecode->setText((sequence == NULL) ? frame_to_timecode(0, config.timecode_view, 30) : frame_to_timecode(sequence->getEndFrame(), config.timecode_view, sequence->frame_rate)); } void Viewer::update_media(int type, void* media) { diff --git a/panels/viewer.ui b/panels/viewer.ui index 534322a67..111812803 100644 --- a/panels/viewer.ui +++ b/panels/viewer.ui @@ -38,6 +38,9 @@ 0 + + 0 + @@ -58,6 +61,9 @@ + + + @@ -233,6 +239,12 @@ QLabel
ui/labelslider.h
+ + TimelineHeader + QWidget +
ui/timelineheader.h
+ 1 +
diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 81788c116..a2d2834e3 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -26,6 +26,9 @@ extern "C" { #include #include +// temp debug shit +//#define AUDIOWARNINGS + int dest_format = AV_PIX_FMT_RGBA; double bytes_to_seconds(int nb_bytes, int nb_channels, int sample_rate) { @@ -97,9 +100,11 @@ void cache_audio_worker(Clip* c, Clip* nest) { avcodec_flush_buffers(c->codecCtx); int64_t backtrack_seek = qMax(c->rev_target - static_cast(av_q2d(av_inv_q(c->stream->time_base))), static_cast(0)); av_seek_frame(c->formatCtx, c->stream->index, backtrack_seek, AVSEEK_FLAG_BACKWARD); +#ifdef AUDIOWARNINGS if (backtrack_seek == 0) { qDebug() << "backtracked to 0"; } +#endif } do { @@ -120,7 +125,9 @@ void cache_audio_worker(Clip* c, Clip* nest) { if (!c->reverse) { c->reached_end = true; } else { +#ifdef AUDIOWARNINGS qDebug() << "reached EOF"; +#endif } } else { qDebug() << "[WARNING] Raw audio frame data could not be retrieved." << ret; @@ -136,7 +143,9 @@ void cache_audio_worker(Clip* c, Clip* nest) { c->reached_end = true; break; } else { +#ifdef AUDIOWARNINGS qDebug() << "reached EOF"; +#endif if (!c->reverse) break; } } @@ -146,19 +155,25 @@ void cache_audio_worker(Clip* c, Clip* nest) { AVFrame* rev_frame = c->cache_A.frames[1]; if (ret != AVERROR_EOF) { if (loop == 2) { +#ifdef AUDIOWARNINGS qDebug() << "starting rev_frame"; +#endif rev_frame->nb_samples = 0; rev_frame->pts = c->frame->pkt_pts; } int offset = rev_frame->nb_samples * av_get_bytes_per_sample(static_cast(rev_frame->format)) * rev_frame->channels; +#ifdef AUDIOWARNINGS qDebug() << "offset 1:" << offset; qDebug() << "retrieved samples:" << frame->nb_samples << "size:" << (frame->nb_samples * av_get_bytes_per_sample(static_cast(frame->format)) * frame->channels); +#endif memcpy( rev_frame->data[0]+offset, frame->data[0], (frame->nb_samples * av_get_bytes_per_sample(static_cast(frame->format)) * frame->channels) ); +#ifdef AUDIOWARNINGS qDebug() << "pts:" << c->frame->pts << "dur:" << c->frame->pkt_duration << "rev_target:" << c->rev_target << "offset:" << offset << "limit:" << rev_frame->linesize[0]; +#endif } rev_frame->nb_samples += frame->nb_samples; @@ -173,9 +188,13 @@ void cache_audio_worker(Clip* c, Clip* nest) { rev_frame->nb_samples -= cutoff; }*/ +#ifdef AUDIOWARNINGS qDebug() << "pre cutoff deets::: rev_frame.pts:" << rev_frame->pts << "rev_frame.nb_samples" << rev_frame->nb_samples << "rev_target:" << c->rev_target; +#endif rev_frame->nb_samples = qRound(static_cast(c->rev_target - rev_frame->pts) / c->stream->codecpar->sample_rate * sequence->audio_frequency); +#ifdef AUDIOWARNINGS qDebug() << "post cutoff deets::" << rev_frame->nb_samples; +#endif int frame_size = rev_frame->nb_samples * rev_frame->channels * av_get_bytes_per_sample(static_cast(rev_frame->format)); int half_frame_size = frame_size >> 1; @@ -203,7 +222,9 @@ void cache_audio_worker(Clip* c, Clip* nest) { loop++; +#ifdef AUDIOWARNINGS qDebug() << "loop" << loop; +#endif } else { frame->pts = c->frame->pts; break; @@ -228,15 +249,19 @@ void cache_audio_worker(Clip* c, Clip* nest) { // get precise sample offset for the elected clip_in from this audio frame double target_sts = playhead_to_seconds(c, c->audio_target_frame); double frame_sts = (frame->pts * timebase); - int nb_samples = qRound((target_sts - frame_sts)*c->sequence->audio_frequency); - qDebug() << "fsts:" << frame_sts << "tsts:" << target_sts << "nbs:" << nb_samples << "nbb:" << nb_bytes << "rev_targetToSec:" << (c->rev_target * timebase); + int nb_samples = qRound((target_sts - frame_sts)*c->sequence->audio_frequency); c->frame_sample_index = nb_samples * 4; +#ifdef AUDIOWARNINGS + qDebug() << "fsts:" << frame_sts << "tsts:" << target_sts << "nbs:" << nb_samples << "nbb:" << nb_bytes << "rev_targetToSec:" << (c->rev_target * timebase); qDebug() << "fsi-calc:" << c->frame_sample_index; +#endif if (c->reverse) c->frame_sample_index = nb_bytes - c->frame_sample_index; c->audio_just_reset = false; } +#ifdef AUDIOWARNINGS qDebug() << "fsi-post-post:" << c->frame_sample_index; +#endif if (c->audio_buffer_write == 0) c->audio_buffer_write = get_buffer_offset_from_frame(qMax(timeline_in, c->audio_target_frame)); @@ -255,7 +280,9 @@ void cache_audio_worker(Clip* c, Clip* nest) { if (c->reverse) frame = c->cache_A.frames[1]; +#ifdef AUDIOWARNINGS qDebug() << "j" << c->frame_sample_index << nb_bytes; +#endif // apply any audio effects to the data if (nb_bytes == INT_MAX) nb_bytes = frame->nb_samples * av_get_bytes_per_sample(static_cast(frame->format)) * frame->channels; @@ -290,7 +317,6 @@ void cache_audio_worker(Clip* c, Clip* nest) { if (frame->nb_samples == 0) { break; } else { - qDebug() << "re:" << c->reached_end; long buffer_timeline_out = get_buffer_offset_from_frame(timeline_out); audio_write_lock.lock(); while (c->frame_sample_index < nb_bytes @@ -308,7 +334,9 @@ void cache_audio_worker(Clip* c, Clip* nest) { c->audio_buffer_write+=2; c->frame_sample_index+=2; } +#ifdef AUDIOWARNINGS if (c->audio_buffer_write >= buffer_timeline_out) qDebug() << "timeline out at fsi" << c->frame_sample_index << "of frame ts" << c->frame->pts; +#endif audio_write_lock.unlock(); if (c->frame_sample_index == nb_bytes) { @@ -318,7 +346,7 @@ void cache_audio_worker(Clip* c, Clip* nest) { break; } - qDebug() << "ended" << c->frame_sample_index << nb_bytes; +// qDebug() << "ended" << c->frame_sample_index << nb_bytes; } if (c->reached_end) { frame->nb_samples = 0; @@ -386,6 +414,8 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) { break; } } else { + qDebug() << "retrieved PTS:" << cache->frames[i]->pts << c->stream->time_base.num << "/" << c->stream->time_base.den; + cache->written = true; i++; cache->write_count = i; @@ -412,6 +442,7 @@ void reset_cache(Clip* c, long target_frame) { switch (c->media_type) { case MEDIA_TYPE_FOOTAGE: { + c->reached_end = false; MediaStream* ms = static_cast(c->media)->get_stream_from_file_index(c->track < 0, c->media_stream); if (!ms->infinite_length) { // flush ffmpeg codecs @@ -445,7 +476,7 @@ void reset_cache(Clip* c, long target_frame) { av_frame_unref(temp); av_frame_free(&temp); } else { - av_seek_frame(c->formatCtx, ms->file_index, 0, AVSEEK_FLAG_BACKWARD); + av_seek_frame(c->formatCtx, ms->file_index, c->stream->start_time, AVSEEK_FLAG_BACKWARD); } } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { // seek (target_frame represents timeline timecode in frames, not clip timecode) @@ -453,7 +484,9 @@ void reset_cache(Clip* c, long target_frame) { if (c->reverse) { c->rev_target = timestamp; timestamp -= av_q2d(av_inv_q(c->stream->time_base)); +#ifdef AUDIOWARNINGS qDebug() << "seeking to" << timestamp << "(originally" << c->rev_target << ")"; +#endif } av_seek_frame(c->formatCtx, ms->file_index, timestamp, AVSEEK_FLAG_BACKWARD); c->audio_target_frame = target_frame; diff --git a/playback/playback.cpp b/playback/playback.cpp index 40c91beeb..9b6959e7a 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -9,6 +9,7 @@ #include "panels/timeline.h" #include "panels/viewer.h" #include "effects/effect.h" +#include "panels/effectcontrols.h" extern "C" { #include @@ -281,8 +282,16 @@ int retrieve_next_frame(Clip* c, AVFrame* f) { return send_ret; } } else { - if (read_ret != AVERROR_EOF) qDebug() << "[ERROR] Could not read frame." << read_ret; - return read_ret; // skips trying to find a frame at all + if (read_ret == AVERROR_EOF) { + int send_ret = avcodec_send_packet(c->codecCtx, NULL); + if (send_ret < 0) { + qDebug() << "[ERROR] Failed to send packet to decoder." << send_ret; + return send_ret; + } + } else { + qDebug() << "[ERROR] Could not read frame." << read_ret; + return read_ret; // skips trying to find a frame at all + } } } if (receive_ret < 0) { @@ -302,6 +311,7 @@ bool is_clip_active(Clip* c, long playhead) { void set_sequence(Sequence* s) { closeActiveClips(sequence, true); + panel_effect_controls->clear_effects(true); sequence = s; panel_timeline->update_sequence(); panel_sequence_viewer->update_media(MEDIA_TYPE_SEQUENCE, sequence); diff --git a/project/clip.cpp b/project/clip.cpp index 0da9553cd..ade8eea7d 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -9,6 +9,7 @@ #include "panels/project.h" #include "project/sequence.h" #include "panels/timeline.h" +#include "undo.h" #include @@ -259,3 +260,28 @@ int Clip::getHeight() { } return 0; } + +void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points) { + if (change_timeline_points) { + ca->append(new MoveClipAction(this, + qRound((double) timeline_in * multiplier), + qRound((double) timeline_out * multiplier), + qRound((double) clip_in * multiplier), + track)); + } + + for (int i=0;irow_count();j++) { + EffectRow* r = e->row(j); + for (int k=0;kkeyframe_times.size();k++) { + long new_pos = r->keyframe_times.at(k) * multiplier; + KeyframeMove* km = new KeyframeMove(); + km->movement = new_pos - r->keyframe_times.at(k); + km->rows.append(r); + km->keyframes.append(k); + ca->append(km); + } + } + } +} diff --git a/project/clip.h b/project/clip.h index 13af3822e..7d009e356 100644 --- a/project/clip.h +++ b/project/clip.h @@ -12,6 +12,7 @@ class Cacher; class Effect; class Transition; class QOpenGLFramebufferObject; +class ComboAction; struct Sequence; struct Media; struct MediaStream; @@ -78,6 +79,7 @@ struct Clip bool reverse; long calculated_length; int skip_type; + void refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points); // other variables (should be "duplicated" in copy()) QList effects; diff --git a/project/undo.cpp b/project/undo.cpp index 8b36e9cc0..0bdbc2d83 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -1572,6 +1572,9 @@ void EditSequenceCommand::redo() { } void EditSequenceCommand::update() { + // update name + item->setText(0, seq->name); + // update tooltip set_sequence_of_tree(item, seq); diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index dbd0dc102..184c306ea 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -150,7 +150,6 @@ void KeyframeView::draw_keyframe(QPainter &p, int x, int y, bool darker) { p.setPen(QColor(0, 0, 0)); p.setBrush(QColor(color, color, color)); p.drawPolygon(points, KEYFRAME_POINT_COUNT); - qDebug() << "drew key at" << x << y; } void KeyframeView::mousePressEvent(QMouseEvent *event) { diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 155bef818..9e34c55c0 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -75,7 +75,7 @@ double LabelSlider::value() { } void LabelSlider::set_default_value(double v) { - if (internal_value == default_value) set = false; // TODO: CONTROVERSIAL - may be undesirable behaviour + // if (internal_value == default_value) set = false; TODO: CONTROVERSIAL - disabled bc may lead undesirable behaviour default_value = v; if (!set) { diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp index 6d18b1ca0..f0ca732b9 100644 --- a/ui/sourcetable.cpp +++ b/ui/sourcetable.cpp @@ -7,6 +7,7 @@ #include "panels/panels.h" #include "playback/playback.h" #include "project/undo.h" +#include "mainwindow.h" #include #include @@ -33,6 +34,9 @@ void SourceTable::show_context_menu() { if (selectedItems().size() == 0) { QAction* import_action = menu.addAction("Import..."); connect(import_action, SIGNAL(triggered(bool)), panel_project, SLOT(import_dialog())); + + QAction* new_folder_action = menu.addAction("New Folder..."); + connect(new_folder_action, SIGNAL(triggered(bool)), mainWindow, SLOT(on_actionFolder_triggered())); } else { if (selectedItems().size() == 1) { // replace footage diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index 472c69d94..6471cc7c9 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -30,10 +30,11 @@ TimelineHeader::TimelineHeader(QWidget *parent) : dragging_markers(false), scroll(0) { + height_actual = fm.height(); setCursor(Qt::ArrowCursor); setMouseTracking(true); - setFixedHeight(fm.height()*2); setFocusPolicy(Qt::ClickFocus); + show_text(true); } void TimelineHeader::set_scroll(int s) { @@ -85,6 +86,16 @@ void TimelineHeader::set_out_point(long new_out) { panel_timeline->repaint_timeline(false); } +void TimelineHeader::show_text(bool enable) { + text_enabled = enable; + if (enable) { + setFixedHeight(height_actual*2); + } else { + setFixedHeight(height_actual); + } + update(); +} + void TimelineHeader::mousePressEvent(QMouseEvent* event) { if (resizing_workarea) { sequence_end = sequence->getEndFrame(); @@ -137,7 +148,7 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) { if (dragging) { if (resizing_workarea) { long frame = getHeaderFrameFromScreenPoint(event->pos().x()); - panel_timeline->snap_to_timeline(&frame, true, true, false); + if (snapping) panel_timeline->snap_to_timeline(&frame, true, true, false); if (resizing_workarea_in) { temp_workarea_in = qMax(qMin(temp_workarea_out-1, frame), 0L); @@ -152,7 +163,7 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) { // snap markers for (int i=0;isnap_to_timeline(&fm, true, false, true)) { + if (snapping && panel_timeline->snap_to_timeline(&fm, true, false, true)) { frame_movement = fm - selected_marker_original_times.at(i); break; } @@ -179,7 +190,7 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) { } else { resizing_workarea = false; unsetCursor(); - if (sequence->using_workarea) { + if (sequence != NULL && sequence->using_workarea) { long min_frame = getHeaderFrameFromScreenPoint(event->pos().x() - CLICK_RANGE) - 1; long max_frame = getHeaderFrameFromScreenPoint(event->pos().x() + CLICK_RANGE) + 1; if (sequence->workarea_in > min_frame && sequence->workarea_in < max_frame) { @@ -198,7 +209,7 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) { } } -void TimelineHeader::mouseReleaseEvent(QMouseEvent* event) { +void TimelineHeader::mouseReleaseEvent(QMouseEvent*) { dragging = false; if (resizing_workarea) { undo_stack.push(new SetTimelineInOutCommand(sequence, true, temp_workarea_in, temp_workarea_out)); @@ -248,9 +259,9 @@ void TimelineHeader::delete_markers() { } void TimelineHeader::paintEvent(QPaintEvent*) { - if (sequence != NULL) { + if (sequence != NULL && zoom > 0) { QPainter p(this); - int yoff = height()/2; + int yoff = (text_enabled) ? height()/2 : 0; double interval = sequence->frame_rate; int textWidth = 0; @@ -278,14 +289,15 @@ void TimelineHeader::paintEvent(QPaintEvent*) { if (lineX > width()) break; if (next_lineX > 0 && lineX > lastLineX+LINE_MIN_PADDING) { // draw text - if (lineX-textWidth > lastTextBoundary) { + if (text_enabled && lineX-textWidth > lastTextBoundary) { p.setPen(Qt::white); QString timecode = frame_to_timecode(frame + in_visible, config.timecode_view, sequence->frame_rate); - textWidth = fm.width(timecode)>>1; - if (lineX + textWidth > 0) { - int text_x = qMax(lineX-textWidth, 0); - lastTextBoundary = text_x+textWidth+textWidth; - p.drawText(QRect(text_x, 0, lastTextBoundary, yoff), timecode); + int fullTextWidth = fm.width(timecode); + textWidth = fullTextWidth>>1; + int text_x = lineX-textWidth; + lastTextBoundary = lineX+textWidth; + if (lastTextBoundary >= 0) { + p.drawText(QRect(text_x, 0, fullTextWidth, yoff), timecode); } } @@ -351,5 +363,5 @@ void TimelineHeader::paintEvent(QPaintEvent*) { path.lineTo(in_x+PLAYHEAD_SIZE, yoff); path.lineTo(start); p.fillPath(path, Qt::red); - } + } } diff --git a/ui/timelineheader.h b/ui/timelineheader.h index ad3b733b2..2540d8552 100644 --- a/ui/timelineheader.h +++ b/ui/timelineheader.h @@ -15,6 +15,8 @@ public: bool snapping; + void show_text(bool enable); + void update_zoom(double z); void delete_markers(); @@ -57,6 +59,9 @@ private: int scroll; + int height_actual; + bool text_enabled; + signals: };