diff --git a/io/exportthread.cpp b/io/exportthread.cpp index d09dc825e..93a6a8bc8 100644 --- a/io/exportthread.cpp +++ b/io/exportthread.cpp @@ -336,6 +336,7 @@ void ExportThread::run() { } panel_timeline->seek(start_frame); + panel_timeline->reset_all_audio(); QOpenGLFramebufferObject fbo(sequence->width, sequence->height, QOpenGLFramebufferObject::CombinedDepthStencil, GL_TEXTURE_RECTANGLE); fbo.bind(); diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp index 8a80af19d..8ef3e4148 100644 --- a/io/previewgenerator.cpp +++ b/io/previewgenerator.cpp @@ -55,7 +55,7 @@ void PreviewGenerator::parse_media() { ms->video_frame_rate = 0; } else { ms->infinite_length = false; - ms->video_frame_rate = av_q2d(fmt_ctx->streams[i]->avg_frame_rate)*0.5; + ms->video_frame_rate = av_q2d(fmt_ctx->streams[i]->avg_frame_rate); } ms->video_width = fmt_ctx->streams[i]->codecpar->width; ms->video_height = fmt_ctx->streams[i]->codecpar->height; diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 39a541fde..af1c7f84a 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -57,7 +57,8 @@ Timeline::Timeline(QWidget *parent) : zoomChanged(false), ui(new Ui::Timeline), last_frame(0), - creating(false) + creating(false), + queue_audio_reset(false) { default_track_height = (QGuiApplication::primaryScreen()->logicalDotsPerInch() / 96) * TRACK_DEFAULT_HEIGHT; @@ -144,8 +145,10 @@ void Timeline::next_cut() { void Timeline::reset_all_audio() { // reset all clip audio - audio_ibuffer_frame = sequence->playhead; if (sequence != NULL) { + audio_ibuffer_frame = sequence->playhead; + audio_ibuffer_timecode = (double) audio_ibuffer_frame / sequence->frame_rate; + for (int i=0;iclips.size();i++) { Clip* c = sequence->clips.at(i); if (c != NULL) { @@ -160,7 +163,7 @@ void Timeline::reset_all_audio() { void Timeline::seek(long p) { pause(); sequence->playhead = p; - reset_all_audio(); + queue_audio_reset = true; repaint_timeline(); } @@ -173,6 +176,10 @@ void Timeline::toggle_play() { } void Timeline::play() { + if (queue_audio_reset) { + reset_all_audio(); + queue_audio_reset = false; + } playhead_start = sequence->playhead; start_msecs = QDateTime::currentMSecsSinceEpoch(); playback_updater.start(); @@ -1081,7 +1088,23 @@ void Timeline::snap_to_clip(long* l, bool playhead_inclusive) { } } } - } + } +} + +void Timeline::set_marker() { + /* TODO make undoable */ + bool found = false; + for (int i=0;imarkers.size();i++) { + if (sequence->markers.at(i).frame == sequence->playhead) { + found = true; + break; + } + } + if (!found) { + Marker m; + m.frame = sequence->playhead; + sequence->markers.append(m); + } } void Timeline::toggle_links() { diff --git a/panels/timeline.h b/panels/timeline.h index f06f079e7..86173200f 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -103,6 +103,7 @@ public: int get_snap_range(); bool snap_to_point(long point, long* l); void snap_to_clip(long* l, bool playhead_inclusive); + void set_marker(); // playback functions void go_to_start(); @@ -180,6 +181,8 @@ public: bool creating; int creatingObject; + void reset_all_audio(); + Ui::Timeline *ui; public slots: void repaint_timeline(); @@ -216,7 +219,7 @@ private: void set_tool(int tool); long last_frame; QVector clip_clipboard; - void reset_all_audio(); + bool queue_audio_reset; int default_track_height; }; diff --git a/playback/audio.cpp b/playback/audio.cpp index 393eda2f8..a8f6428fd 100644 --- a/playback/audio.cpp +++ b/playback/audio.cpp @@ -22,6 +22,7 @@ QMutex audio_write_lock; qint8 audio_ibuffer[audio_ibuffer_size]; int audio_ibuffer_read = 0; long audio_ibuffer_frame = 0; +double audio_ibuffer_timecode = 0; AudioSenderThread* audio_thread; diff --git a/playback/audio.h b/playback/audio.h index e6c9bed78..5d57c20a4 100644 --- a/playback/audio.h +++ b/playback/audio.h @@ -39,6 +39,7 @@ extern QMutex audio_write_lock; extern qint8 audio_ibuffer[audio_ibuffer_size]; extern int audio_ibuffer_read; extern long audio_ibuffer_frame; +extern double audio_ibuffer_timecode; void clear_audio_ibuffer(); void init_audio(); diff --git a/playback/cacher.cpp b/playback/cacher.cpp index d5ab7feed..9cb4555d8 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -130,7 +130,7 @@ void cache_audio_worker(Clip* c, Clip* nest) { // apply any audio effects to the data if (nb_bytes == INT_MAX) nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast(frame->format), 1); if (new_frame) { - apply_audio_effects(c, (frame->pts * av_q2d(c->stream->time_base)), frame, nb_bytes); + apply_audio_effects(c, bytes_to_seconds(c->audio_buffer_write, 2, sequence->audio_frequency) + audio_ibuffer_timecode, frame, nb_bytes); } } break; diff --git a/project/undo.cpp b/project/undo.cpp index 2ad9ee96a..be3acf7b0 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -51,7 +51,8 @@ MoveClipAction::MoveClipAction(Clip *c, long iin, long iout, long iclip_in, int new_in(iin), new_out(iout), new_clip_in(iclip_in), - new_track(itrack) + new_track(itrack), + old_project_changed(project_changed) {} void MoveClipAction::undo() { @@ -59,6 +60,8 @@ void MoveClipAction::undo() { clip->timeline_out = old_out; clip->clip_in = old_clip_in; clip->track = old_track; + + project_changed = old_project_changed; } void MoveClipAction::redo() { @@ -71,11 +74,14 @@ void MoveClipAction::redo() { clip->timeline_out = new_out; clip->clip_in = new_clip_in; clip->track = new_track; + + project_changed = true; } DeleteClipAction::DeleteClipAction(Sequence* s, int clip) : seq(s), - index(clip) + index(clip), + old_project_changed(project_changed) {} DeleteClipAction::~DeleteClipAction() { @@ -91,6 +97,8 @@ void DeleteClipAction::undo() { for (int i=linkClipIndex.size()-1;i>=0;i--) { seq->clips.at(linkClipIndex.at(i))->linked.insert(linkLinkIndex.at(i), index); } + + project_changed = old_project_changed; } void DeleteClipAction::redo() { @@ -113,6 +121,8 @@ void DeleteClipAction::redo() { } } } + + project_changed = true; } ChangeSequenceAction::ChangeSequenceAction(Sequence* s) : @@ -132,13 +142,16 @@ SetTimelineInOutCommand::SetTimelineInOutCommand(Sequence *s, bool enabled, long seq(s), new_enabled(enabled), new_in(in), - new_out(out) + new_out(out), + old_project_changed(project_changed) {} void SetTimelineInOutCommand::undo() { seq->using_workarea = old_enabled; seq->workarea_in = old_in; seq->workarea_out = old_out; + + project_changed = old_project_changed; } void SetTimelineInOutCommand::redo() { @@ -149,13 +162,16 @@ void SetTimelineInOutCommand::redo() { seq->using_workarea = new_enabled; seq->workarea_in = new_in; seq->workarea_out = new_out; + + project_changed = true; } AddEffectCommand::AddEffectCommand(Clip* c, int ieffect) : clip(c), effect(ieffect), ref(NULL), - done(false) + done(false), + old_project_changed(project_changed) {} AddEffectCommand::~AddEffectCommand() { @@ -165,6 +181,7 @@ AddEffectCommand::~AddEffectCommand() { void AddEffectCommand::undo() { clip->effects.removeLast(); done = false; + project_changed = old_project_changed; } void AddEffectCommand::redo() { @@ -173,12 +190,14 @@ void AddEffectCommand::redo() { } clip->effects.append(ref); done = true; + project_changed = true; } AddTransitionCommand::AddTransitionCommand(Clip* c, int itransition, int itype) : clip(c), transition(itransition), - type(itype) + type(itype), + old_project_changed(project_changed) {} void AddTransitionCommand::undo() { @@ -189,6 +208,7 @@ void AddTransitionCommand::undo() { delete clip->closing_transition; clip->closing_transition = NULL; } + project_changed = old_project_changed; } void AddTransitionCommand::redo() { @@ -197,12 +217,14 @@ void AddTransitionCommand::redo() { } else { clip->closing_transition = create_transition(transition, clip); } + project_changed = true; } ModifyTransitionCommand::ModifyTransitionCommand(Clip* c, int itype, long ilength) : clip(c), type(itype), - new_length(ilength) + new_length(ilength), + old_project_changed(project_changed) {} void ModifyTransitionCommand::undo() { @@ -211,6 +233,7 @@ void ModifyTransitionCommand::undo() { } else { clip->closing_transition->length = old_length; } + project_changed = old_project_changed; } void ModifyTransitionCommand::redo() { @@ -221,12 +244,14 @@ void ModifyTransitionCommand::redo() { old_length = clip->closing_transition->length; clip->closing_transition->length = new_length; } + project_changed = true; } DeleteTransitionCommand::DeleteTransitionCommand(Clip* c, int itype) : clip(c), type(itype), - transition(NULL) + transition(NULL), + old_project_changed(project_changed) {} DeleteTransitionCommand::~DeleteTransitionCommand() { @@ -240,6 +265,7 @@ void DeleteTransitionCommand::undo() { clip->closing_transition = transition; } transition = NULL; + project_changed = old_project_changed; } void DeleteTransitionCommand::redo() { @@ -250,12 +276,14 @@ void DeleteTransitionCommand::redo() { transition = clip->closing_transition; clip->closing_transition = NULL; } + project_changed = true; } NewSequenceCommand::NewSequenceCommand(QTreeWidgetItem *s, QTreeWidgetItem* iparent) : seq(s), parent(iparent), - done(false) + done(false), + old_project_changed(project_changed) {} NewSequenceCommand::~NewSequenceCommand() { @@ -269,6 +297,7 @@ void NewSequenceCommand::undo() { parent->removeChild(seq); } done = false; + project_changed = old_project_changed; } void NewSequenceCommand::redo() { @@ -278,12 +307,14 @@ void NewSequenceCommand::redo() { parent->addChild(seq); } done = true; + project_changed = true; } AddMediaCommand::AddMediaCommand(QTreeWidgetItem* iitem, QTreeWidgetItem* iparent) : item(iitem), parent(iparent), - done(false) + done(false), + old_project_changed(project_changed) {} AddMediaCommand::~AddMediaCommand() { @@ -300,6 +331,7 @@ void AddMediaCommand::undo() { parent->removeChild(item); } done = false; + project_changed = old_project_changed; } void AddMediaCommand::redo() { @@ -309,10 +341,12 @@ void AddMediaCommand::redo() { parent->addChild(item); } done = true; + project_changed = true; } DeleteMediaCommand::DeleteMediaCommand(QTreeWidgetItem* i) : - item(i) + item(i), + old_project_changed(project_changed) {} DeleteMediaCommand::~DeleteMediaCommand() { @@ -326,6 +360,8 @@ void DeleteMediaCommand::undo() { } else { parent->addChild(item); } + + old_project_changed = project_changed; } void DeleteMediaCommand::redo() { @@ -336,12 +372,15 @@ void DeleteMediaCommand::redo() { } else { parent->removeChild(item); } + + project_changed = true; } RippleCommand::RippleCommand(Sequence *s, long ipoint, long ilength) : seq(s), point(ipoint), - length(ilength) + length(ilength), + old_project_changed(project_changed) {} void RippleCommand::undo() { @@ -350,6 +389,7 @@ void RippleCommand::undo() { c->timeline_in -= length; c->timeline_out -= length; } + project_changed = old_project_changed; } void RippleCommand::redo() { @@ -372,11 +412,13 @@ void RippleCommand::redo() { } } } + project_changed = true; } AddClipCommand::AddClipCommand(Sequence* s, QVector& add) : seq(s), - clips(add) + clips(add), + old_project_changed(project_changed) {} AddClipCommand::~AddClipCommand() { @@ -390,6 +432,7 @@ void AddClipCommand::undo() { delete seq->clips.last(); seq->clips.removeLast(); } + project_changed = old_project_changed; } void AddClipCommand::redo() { @@ -404,6 +447,7 @@ void AddClipCommand::redo() { } seq->clips.append(copy); } + project_changed = true; } /* diff --git a/project/undo.h b/project/undo.h index 4e7ef9103..1cdda6b5c 100644 --- a/project/undo.h +++ b/project/undo.h @@ -52,6 +52,8 @@ private: long old_out; long old_clip_in; int old_track; + + bool old_project_changed; }; class DeleteClipAction : public QUndoCommand { @@ -67,6 +69,8 @@ private: QVector linkClipIndex; QVector linkLinkIndex; + + bool old_project_changed; }; class ChangeSequenceAction : public QUndoCommand { @@ -90,6 +94,7 @@ private: int effect; Effect* ref; bool done; + bool old_project_changed; }; class AddTransitionCommand : public QUndoCommand { @@ -101,6 +106,7 @@ private: Clip* clip; int transition; int type; + bool old_project_changed; }; class ModifyTransitionCommand : public QUndoCommand { @@ -113,6 +119,7 @@ private: int type; long new_length; long old_length; + bool old_project_changed; }; class DeleteTransitionCommand : public QUndoCommand { @@ -125,6 +132,7 @@ private: Clip* clip; int type; Transition* transition; + bool old_project_changed; }; class SetTimelineInOutCommand : public QUndoCommand { @@ -142,6 +150,8 @@ private: bool new_enabled; long new_in; long new_out; + + bool old_project_changed; }; class NewSequenceCommand : public QUndoCommand { @@ -154,6 +164,7 @@ private: QTreeWidgetItem* seq; QTreeWidgetItem* parent; bool done; + bool old_project_changed; }; class AddMediaCommand : public QUndoCommand { @@ -166,6 +177,7 @@ private: QTreeWidgetItem* item; QTreeWidgetItem* parent; bool done; + bool old_project_changed; }; class DeleteMediaCommand : public QUndoCommand { @@ -177,6 +189,7 @@ public: private: QTreeWidgetItem* item; QTreeWidgetItem* parent; + bool old_project_changed; }; class RippleCommand : public QUndoCommand { @@ -190,6 +203,7 @@ private: long point; long length; QVector rippled; + bool old_project_changed; }; class AddClipCommand : public QUndoCommand { @@ -201,6 +215,7 @@ public: private: Sequence* seq; QVector clips; + bool old_project_changed; }; /*class TimelineAction : public QUndoCommand {