From 083f7daf1896f4303845164c2088e9f4459c7b37 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 6 Jul 2018 23:58:21 +0100 Subject: [PATCH] refactored clip references and improved audio hotfix --- .gitignore | 1 + io/exportthread.cpp | 3 +- olive.pro.user | 654 ++++++++++++++++++-------------------- panels/effectcontrols.cpp | 14 +- panels/effectcontrols.h | 4 +- panels/project.cpp | 23 +- panels/timeline.cpp | 141 ++++---- panels/timeline.h | 6 +- playback/audio.cpp | 3 +- playback/playback.cpp | 5 +- project/clip.cpp | 1 - project/clip.h | 2 +- project/effect.cpp | 11 +- project/effect.h | 1 + project/sequence.cpp | 17 +- project/sequence.h | 4 +- ui/timelinewidget.cpp | 122 ++++--- 17 files changed, 531 insertions(+), 481 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..a91ab86c3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +olive.pro.* diff --git a/io/exportthread.cpp b/io/exportthread.cpp index df4208f3b..b07da9e0e 100644 --- a/io/exportthread.cpp +++ b/io/exportthread.cpp @@ -189,7 +189,8 @@ void ExportThread::run() { acodec_ctx->channels = av_get_channel_layout_nb_channels(acodec_ctx->channel_layout); acodec_ctx->sample_fmt = acodec->sample_fmts[0]; acodec_ctx->bit_rate = audio_bitrate * 1000; - acodec_ctx->time_base = (AVRational){1, audio_sampling_rate}; + acodec_ctx->time_base.num = 1; + acodec_ctx->time_base.den = audio_sampling_rate; if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) { acodec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; diff --git a/olive.pro.user b/olive.pro.user index a9eed8832..1bd70650a 100644 --- a/olive.pro.user +++ b/olive.pro.user @@ -1,336 +1,318 @@ - - - - - - EnvironmentId - {0973e18b-ea93-4e4c-8225-598cb1e91b00} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - - ProjectExplorer.Project.Target.0 - - Desktop Qt 5.5.1 clang 64bit - Desktop Qt 5.5.1 clang 64bit - qt.55.clang_64_kit - 0 - 0 - 0 - - /Users/matt/build-olive-Desktop_Qt_5_5_1_clang_64bit-Debug - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Debug - Debug - Qt4ProjectManager.Qt4BuildConfiguration - 2 - true - - - /Users/matt/build-olive-Desktop_Qt_5_5_1_clang_64bit-Release - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Release - Release - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - - /Users/matt/build-olive-Desktop_Qt_5_5_1_clang_64bit-Profile - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - true - false - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Profile - Profile - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - 3 - - - 0 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy Configuration - - ProjectExplorer.DefaultDeployConfiguration - - 1 - - - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - 2 - - olive - - Qt4ProjectManager.Qt4RunConfiguration:/Users/matt/olive/olive.pro - true - - olive.pro - false - - /Users/matt/build-olive-Desktop_Qt_5_5_1_clang_64bit-Debug/olive.app/Contents/MacOS - 3768 - false - true - false - false - true - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 18 - - - Version - 18 - - + + + + + + EnvironmentId + {3af06612-75ce-48d7-b444-7dc372f1566d} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop Qt 5.11.0 MSVC2017 64bit + Desktop Qt 5.11.0 MSVC2017 64bit + qt.qt5.5110.win64_msvc2017_64_kit + 0 + 0 + 0 + + C:/Users/Matt/Desktop/build-olive-Desktop_Qt_5_11_0_MSVC2017_64bit-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + C:/Users/Matt/Desktop/build-olive-Desktop_Qt_5_11_0_MSVC2017_64bit-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + C:/Users/Matt/Desktop/build-olive-Desktop_Qt_5_11_0_MSVC2017_64bit-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy Configuration + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + olive + + Qt4ProjectManager.Qt4RunConfiguration:C:/Users/Matt/Desktop/olive/olive.pro + true + + olive.pro + false + + C:/Users/Matt/Desktop/build-olive-Desktop_Qt_5_11_0_MSVC2017_64bit-Debug + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 77bc89a4a..1ffff3062 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -9,7 +9,7 @@ #include "project/clip.h" #include "project/effect.h" #include "ui/collapsiblewidget.h" - +#include "project/sequence.h" EffectControls::EffectControls(QWidget *parent) : QDockWidget(parent), @@ -27,7 +27,7 @@ EffectControls::~EffectControls() void EffectControls::menu_select(QAction* q) { for (int i=0;iget_clip(selected_clips.at(i)); if ((clip->track < 0 && video_menu) || (clip->track >= 0 && !video_menu)) { clip->effects.append(create_effect(q->data().toInt(), clip)); } @@ -83,7 +83,7 @@ void EffectControls::clear_effects(bool clear_cache) { void EffectControls::deselect_all_effects(QWidget* sender) { QVector delete_effects; for (int i=0;iget_clip(selected_clips.at(i)); for (int j=0;jeffects.size();j++) { if (c->effects.at(j)->container != sender) { c->effects.at(j)->container->header_click(false, false); @@ -95,7 +95,7 @@ void EffectControls::deselect_all_effects(QWidget* sender) { void EffectControls::load_effects() { // load in new clips for (int i=0;iget_clip(selected_clips.at(i)); if (c->track < 0) { ui->vcontainer->setVisible(true); } else { @@ -119,7 +119,7 @@ void EffectControls::delete_clips() { // load in new clips QVector delete_effects; for (int i=0;iget_clip(selected_clips.at(i)); for (int j=0;jeffects.size();j++) { Effect* effect = c->effects.at(j); if (effect->container->selected) { @@ -141,7 +141,7 @@ void EffectControls::reload_clips() { load_effects(); } -void EffectControls::set_clips(QVector& clips) { +void EffectControls::set_clips(QVector& clips) { clear_effects(true); // replace clip vector @@ -163,7 +163,7 @@ void EffectControls::on_add_audio_effect_button_clicked() bool EffectControls::is_focused() { if (this->hasFocus()) return true; for (int i=0;iget_clip(selected_clips.at(i)); if (c != NULL) { for (int j=0;jeffects.size();j++) { if (c->effects.at(j)->container->is_focused()) { diff --git a/panels/effectcontrols.h b/panels/effectcontrols.h index 31e9d52d6..64d1b92a0 100644 --- a/panels/effectcontrols.h +++ b/panels/effectcontrols.h @@ -18,7 +18,7 @@ public: explicit EffectControls(QWidget *parent = 0); ~EffectControls(); // void set_clip(Clip* c); - void set_clips(QVector& clips); + void set_clips(QVector& clips); void clear_effects(bool clear_cache); void delete_clips(); bool is_focused(); @@ -34,7 +34,7 @@ private slots: private: Ui::EffectControls *ui; - QVector selected_clips; + QVector selected_clips; void show_menu(bool video); void load_effects(); void reload_clips(); diff --git a/panels/project.cpp b/panels/project.cpp index 8713ff184..654be2b48 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -110,6 +110,7 @@ Media* Project::import_file(QString file) { strcpy(filename, ba.data()); Media* m = NULL; + AVFormatContext* pFormatCtx = NULL; int errCode = avformat_open_input(&pFormatCtx, filename, NULL, NULL); if(errCode != 0) { @@ -128,6 +129,7 @@ Media* Project::import_file(QString file) { m = new Media(); m->type = MEDIA_TYPE_FOOTAGE; m->url = file; + m->name = file.mid(file.lastIndexOf('/')+1); // detect video/audio streams in file for (int i=0;i<(int)pFormatCtx->nb_streams;i++) { @@ -151,7 +153,6 @@ Media* Project::import_file(QString file) { } } } - m->name = file.mid(file.lastIndexOf('/')+1); m->length = pFormatCtx->duration; QTreeWidgetItem* item = new QTreeWidgetItem(); @@ -354,7 +355,6 @@ void Project::load_project() { int temp_media_id; Sequence* temp_seq; Clip* temp_clip; - int temp_clip_id; int state = LOAD_STATE_IDLE; while (!stream.atEnd()) { @@ -401,18 +401,20 @@ void Project::load_project() { // correct IDs in linked clips for (int j=0;jlinked.size();j++) { + bool found = false; for (int k=0;kclip_count();k++) { - if (temp_seq->get_clip(k)->id == clip->linked.at(j)) { + if (temp_seq->get_clip(k)->load_id == clip->linked.at(j)) { clip->linked[j] = k; + found = true; break; } } + if (!found) { + clip->linked.removeAt(j); + qDebug() << "[WARNING] Discarded link from loaded file - this should NEVER happen"; + } } } - for (int i=0;iclip_count();i++) { - // correct actual IDs - temp_seq->get_clip(i)->id = i; - } new_sequence(temp_seq); state = LOAD_STATE_IDLE; @@ -445,7 +447,6 @@ void Project::load_project() { case LOAD_STATE_CLIP: if (stream.isEndElement() && stream.name() == "clip") { temp_seq->add_clip(temp_clip); - temp_clip->id = temp_clip_id; // uses loaded ID (corrects later) state = LOAD_STATE_SEQUENCE; } else if (stream.isStartElement()) { if (stream.name() == "name") { @@ -453,7 +454,7 @@ void Project::load_project() { temp_clip->name = stream.text().toString(); } else if (stream.name() == "id") { stream.readNext(); - temp_clip_id = stream.text().toInt(); + temp_clip->load_id = stream.text().toInt(); } else if (stream.name() == "clipin") { stream.readNext(); temp_clip->clip_in = stream.text().toInt(); @@ -552,7 +553,7 @@ void Project::save_project() { if (m->type == MEDIA_TYPE_FOOTAGE) { m->save_id = i; stream.writeStartElement("footage"); - stream.writeAttribute("id", QString::number(m->save_id)); + stream.writeAttribute("id", QString::number(i)); stream.writeTextElement("name", m->name); stream.writeTextElement("url", m->url); stream.writeEndElement(); @@ -578,7 +579,7 @@ void Project::save_project() { Clip* c = s->get_clip(i); if (c != NULL) { stream.writeStartElement("clip"); - stream.writeTextElement("id", QString::number(c->id)); + stream.writeTextElement("id", QString::number(i)); stream.writeTextElement("name", c->name); stream.writeTextElement("clipin", QString::number(c->clip_in)); stream.writeTextElement("in", QString::number(c->timeline_in)); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 93526c52e..0c3c5fb68 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -268,7 +268,11 @@ void Timeline::select_all() { selections.clear(); for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - if (c != NULL) selections.append((Selection){c->timeline_in, c->timeline_out, c->track}); + Selection s; + s.in = c->timeline_in; + s.out = c->timeline_out; + s.track = c->track; + if (c != NULL) selections.append(s); } repaint_timeline(); } @@ -442,32 +446,36 @@ void Timeline::on_snappingButton_toggled(bool checked) snapping = checked; } -void Timeline::split_clip_and_relink(Clip* clip, long frame, bool relink) { - QVector pre_clips; - QVector post_clips; +void Timeline::split_clip_and_relink(int clip, long frame, bool relink) { + Clip* c = sequence->get_clip(clip); + if (c != NULL) { + QVector pre_clips; + QVector post_clips; - Clip* post = sequence->split_clip(clip, frame); + int post = sequence->split_clip(clip, frame); - // if alt is not down, split clips links too - if (post != NULL && relink) { - pre_clips.append(clip); - post_clips.append(post); + // if alt is not down, split clips links too + if (post > -1 && relink) { + pre_clips.append(clip); + post_clips.append(post); - bool original_clip_is_selected = is_clip_selected(clip); + bool original_clip_is_selected = is_clip_selected(c); - // find linked clips of old clip - for (int i=0;ilinked.size();i++) { - Clip* link = sequence->get_clip(clip->linked.at(i)); - if (original_clip_is_selected != !is_clip_selected(link)) { - Clip* s = sequence->split_clip(link, frame); - if (s != NULL) { - pre_clips.append(link); - post_clips.append(s); + // find linked clips of old clip + for (int i=0;ilinked.size();i++) { + int l = c->linked.at(i); + Clip* link = sequence->get_clip(l); + if (original_clip_is_selected != !is_clip_selected(link)) { + int s = sequence->split_clip(l, frame); + if (s > -1) { + pre_clips.append(l); + post_clips.append(s); + } } } - } - relink_clips_using_ids(pre_clips, post_clips); + relink_clips_using_ids(pre_clips, post_clips); + } } } @@ -504,8 +512,8 @@ void Timeline::clean_up_selections(QVector& areas) { void Timeline::delete_areas_and_relink(QVector& areas) { clean_up_selections(areas); - QVector pre_clips; - QVector post_clips; + QVector pre_clips; + QVector post_clips; for (int i=0;i& areas) { post->timeline_in = s.out; post->clip_in = c->clip_in + c->getLength() + (s.out - s.in); - pre_clips.append(c); - post_clips.append(post); - - sequence->add_clip(post); + pre_clips.append(j); + post_clips.append(sequence->add_clip(post)); } else if (c->timeline_in < s.in && c->timeline_out > s.in) { // only out point is in deletion area c->timeline_out = s.in; @@ -582,6 +588,8 @@ void Timeline::copy(bool del) { copied = true; } + copied_clip->load_id = i; + clip_clipboard.append(copied_clip); } } @@ -599,17 +607,17 @@ void Timeline::copy(bool del) { } } -void Timeline::relink_clips_using_ids(QVector& old_clips, QVector& new_clips) { +void Timeline::relink_clips_using_ids(QVector& old_clips, QVector& new_clips) { // relink pasted clips for (int i=0;iget_clip(old_clips.at(i)); + Clip* nc = sequence->get_clip(new_clips.at(i)); for (int j=0;jlinked.size();j++) { for (int k=0;kid == oc->linked.at(j)) { - nc->linked.append(new_clips.at(k)->id); + if (old_clips.at(k) == oc->linked.at(j)) { + nc->linked.append(new_clips.at(k)); } } } @@ -618,27 +626,50 @@ void Timeline::relink_clips_using_ids(QVector& old_clips, QVector& void Timeline::paste() { if (clip_clipboard.size() > 0) { + // create copies and delete areas that we'll be pasting to QVector delete_areas; - for (int i=0;itimeline_in + playhead, c->timeline_out + playhead, c->track}); - } - delete_areas_and_relink(delete_areas); - + QVector pasted_clips; + QVector pasted_clip_ids; long paste_end = 0; - QVector added_clips; for (int i=0;icopy(); cc->timeline_in += playhead; cc->timeline_out += playhead; + cc->track = c->track; if (cc->timeline_out > paste_end) paste_end = cc->timeline_out; cc->sequence = sequence; - added_clips.append(cc); - sequence->add_clip(cc); + pasted_clips.append(cc); + + Selection s; + s.in = cc->timeline_in; + s.out = cc->timeline_out; + s.track = c->track; + delete_areas.append(s); + } + delete_areas_and_relink(delete_areas); + + // add copies to the sequence (added afterwards to avoid + for (int i=0;iadd_clip(pasted_clips.at(i))); } - relink_clips_using_ids(clip_clipboard, added_clips); + // ADAPT + for (int i=0;ilinked.size();j++) { + for (int k=0;kload_id == oc->linked.at(j)) { + pasted_clips.at(i)->linked.append(pasted_clip_ids.at(k)); + } + } + } + } + // ADAPT redraw_all_clips(true); @@ -652,8 +683,8 @@ bool Timeline::split_selection() { bool split = false; // temporary relinking vectors - QVector pre_splits; - QVector post_splits; + QVector pre_splits; + QVector post_splits; // find clips within selection and split for (int j=0;jclip_count();j++) { @@ -662,15 +693,15 @@ bool Timeline::split_selection() { for (int i=0;itrack) { - Clip* post_a = sequence->split_clip(clip, s.in); - Clip* post_b = sequence->split_clip(clip, s.out); + int post_a = sequence->split_clip(j, s.in); + int post_b = sequence->split_clip(j, s.out); - if (post_a != NULL) { - pre_splits.append(clip); + if (post_a != -1) { + pre_splits.append(j); post_splits.append(post_a); } - if (post_b != NULL) { - pre_splits.append(clip); + if (post_b != -1) { + pre_splits.append(j); post_splits.append(post_b); } @@ -691,14 +722,14 @@ void Timeline::split_at_playhead() { if (selections.size() > 0) { // see if whole clips are selected - QVector pre_clips; - QVector post_clips; + QVector pre_clips; + QVector post_clips; for (int j=0;jclip_count();j++) { Clip* clip = sequence->get_clip(j); if (clip != NULL && is_clip_selected(clip)) { - Clip* s = sequence->split_clip(clip, playhead); - if (s != NULL) { - pre_clips.append(clip); + int s = sequence->split_clip(j, playhead); + if (s != -1) { + pre_clips.append(j); post_clips.append(s); split_selected = true; } @@ -720,7 +751,7 @@ void Timeline::split_at_playhead() { Clip* c = sequence->get_clip(j); if (c != NULL) { // always relinks - split_clip_and_relink(sequence->get_clip(j), playhead, true); + split_clip_and_relink(j, playhead, true); split_selected = true; } } diff --git a/panels/timeline.h b/panels/timeline.h index 16e0d02e9..943b75234 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -16,7 +16,7 @@ struct Media; struct MediaStream; struct Ghost { - Clip* clip; + int clip; long in; long out; int track; @@ -67,10 +67,10 @@ public: void deselect(); bool split_selection(); void split_at_playhead(); - void split_clip_and_relink(Clip* clip, long frame, bool relink); + void split_clip_and_relink(int clip, long frame, bool relink); void clean_up_selections(QVector& areas); void delete_areas_and_relink(QVector& areas); - void relink_clips_using_ids(QVector& old_clips, QVector& new_clips); + void relink_clips_using_ids(QVector& old_clips, QVector& new_clips); void update_sequence(); void increase_track_height(); void decrease_track_height(); diff --git a/playback/audio.cpp b/playback/audio.cpp index 3d6373096..80fb17d73 100644 --- a/playback/audio.cpp +++ b/playback/audio.cpp @@ -3,6 +3,7 @@ #include "project/sequence.h" #include +#include #include extern "C" { @@ -56,7 +57,7 @@ void clear_audio_ibuffer() { int get_buffer_offset_from_frame(long frame) { if (frame >= audio_ibuffer_frame) { - return av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(sequence->audio_layout), qRound(((frame-audio_ibuffer_frame)/sequence->frame_rate)*sequence->audio_frequency), AV_SAMPLE_FMT_S16, 1); + return av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(sequence->audio_layout), qFloor(((frame-audio_ibuffer_frame)/sequence->frame_rate)*sequence->audio_frequency), AV_SAMPLE_FMT_S16, 1); } else { qDebug() << "[WARNING] get_buffer_offset_from_frame called incorrectly"; return 0; diff --git a/playback/playback.cpp b/playback/playback.cpp index 998f84173..81a586e82 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -191,10 +191,9 @@ long seconds_to_clip_frame(Clip* c, float seconds) { float clip_frame_to_seconds(Clip* c, long clip_frame) { // returns frame number as seconds (decimal) if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - return (double) clip_frame / av_q2d(c->stream->avg_frame_rate); + return (double) clip_frame / av_q2d(c->stream->avg_frame_rate); } else { - qDebug() << "[ERROR] clip_frame_to_seconds only works on video streams"; - return 0; + return (double) clip_frame / c->sequence->frame_rate; } } diff --git a/project/clip.cpp b/project/clip.cpp index 2a8a75f83..e99da404c 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -30,7 +30,6 @@ Clip* Clip::copy() { Clip* copy = new Clip(); copy->enabled = enabled; - copy->id = id; copy->name = QString(name); copy->clip_in = clip_in; copy->timeline_in = timeline_in; diff --git a/project/clip.h b/project/clip.h index b1e94797f..a41bac0dd 100644 --- a/project/clip.h +++ b/project/clip.h @@ -40,7 +40,7 @@ struct Clip // timeline variables bool enabled; - int id; + int load_id; QString name; long get_timeline_in_with_transition(); long get_timeline_out_with_transition(); diff --git a/project/effect.cpp b/project/effect.cpp index a12ffe039..cf5c22007 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -33,8 +33,13 @@ bool Effect::is_enabled() { } Effect* Effect::copy(Clip*) {return NULL;} -void Effect::load(QXmlStreamReader*) {} -void Effect::save(QXmlStreamWriter*) {} - +void Effect::load(QXmlStreamReader* stream) {} +void Effect::save(QXmlStreamWriter* stream) {} +/*void Effect::import_values(float* val, int count) { + qDebug() << "[ERROR] import_values MUST be overridden"; +} +void Effect::export_values(float* val, int* count) { + qDebug() << "[ERROR] export_values MUST be overridden"; +}*/ void Effect::process_gl(int*, int*) {} void Effect::process_audio(uint8_t*, int) {} diff --git a/project/effect.h b/project/effect.h index f47495383..85d052879 100644 --- a/project/effect.h +++ b/project/effect.h @@ -27,6 +27,7 @@ public: bool is_enabled(); virtual Effect* copy(Clip* c); + virtual void load(QXmlStreamReader* stream); virtual void save(QXmlStreamWriter* stream); diff --git a/project/sequence.cpp b/project/sequence.cpp index 203fcf17a..8a26281d5 100644 --- a/project/sequence.cpp +++ b/project/sequence.cpp @@ -36,9 +36,9 @@ Sequence* Sequence::copy() { return s; } -void Sequence::add_clip(Clip* c) { - c->id = clip_count(); +int Sequence::add_clip(Clip* c) { clips.append(c); + return clip_count() - 1; } int Sequence::clip_count() { @@ -55,7 +55,7 @@ void Sequence::delete_clip(int i) { Clip* c = get_clip(j); if (c != NULL) { for (int k=0;klinked.size();k++) { - if (c->linked[k] == clips[i]->id) { + if (c->linked[k] == i) { c->linked.removeAt(k); break; } @@ -100,8 +100,9 @@ void Sequence::get_track_limits(int* video_tracks, int* audio_tracks) { //} -Clip* Sequence::split_clip(Clip* pre, long frame) { - if (pre->timeline_in < frame && pre->timeline_out > frame) { // guard against attempts to split at in/out points +int Sequence::split_clip(int p, long frame) { + Clip* pre = get_clip(p); + if (pre != NULL && pre->timeline_in < frame && pre->timeline_out > frame) { // guard against attempts to split at in/out points Clip* post = pre->copy(); pre->timeline_out = frame; @@ -122,11 +123,9 @@ Clip* Sequence::split_clip(Clip* pre, long frame) { pre->opening_transition->length = pre_length; } - add_clip(post); - - return post; + return add_clip(post); } - return NULL; + return -1; } void Sequence::undo_add_current() { diff --git a/project/sequence.h b/project/sequence.h index 58a481994..8f39ec1ed 100644 --- a/project/sequence.h +++ b/project/sequence.h @@ -13,11 +13,11 @@ public: ~Sequence(); Sequence* copy(); QString name; - void add_clip(Clip* c); + int add_clip(Clip* c); int clip_count(); Clip* get_clip(int i); void delete_clip(int i); - Clip* split_clip(Clip* pre, long frame); + int split_clip(int pre, long frame); void get_track_limits(int* video_tracks, int* audio_tracks); long getEndFrame(); int width; diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 4e9dcd4fd..1dc04d7d2 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -104,13 +104,17 @@ void TimelineWidget::dropEvent(QDropEvent* event) { if (panel_timeline->importing) { event->accept(); - QVector added_clips; + QVector added_clips; // delete areas before adding QVector delete_areas; for (int i=0;ighosts.size();i++) { const Ghost& g = panel_timeline->ghosts.at(i); - delete_areas.append((Selection){g.in, g.out, g.track}); + Selection s; + s.in = g.in; + s.out = g.out; + s.track = g.track; + delete_areas.append(s); } panel_timeline->delete_areas_and_relink(delete_areas); @@ -140,17 +144,16 @@ void TimelineWidget::dropEvent(QDropEvent* event) { c->effects.append(create_effect(AUDIO_PAN_EFFECT, c)); } - sequence->add_clip(c); - added_clips.append(c); + added_clips.append(sequence->add_clip(c)); } // link clips from the same media for (int i=0;iget_clip(added_clips.at(i)); for (int j=0;jget_clip(added_clips.at(j)); if (c != cc && c->media == cc->media) { - c->linked.append(cc->id); + c->linked.append(j); } } } @@ -171,7 +174,11 @@ void TimelineWidget::mouseDoubleClickEvent(QMouseEvent *event) { if (clip_index >= 0) { Clip* clip = sequence->get_clip(clip_index); if (!(event->modifiers() & Qt::ShiftModifier)) panel_timeline->selections.clear(); - panel_timeline->selections.append((Selection){clip->timeline_in, clip->timeline_out, clip->track}); + Selection s; + s.in = clip->timeline_in; + s.out = clip->timeline_out; + s.track = clip->track; + panel_timeline->selections.append(s); panel_timeline->repaint_timeline(); } } @@ -222,7 +229,11 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { Clip* clip = sequence->get_clip(clip_index); if (clip != NULL) { - panel_timeline->selections.append((Selection){clip->timeline_in, clip->timeline_out, clip->track}); + Selection s; + s.in = clip->timeline_in; + s.out = clip->timeline_out; + s.track = clip->track; + panel_timeline->selections.append(s); if (panel_timeline->select_also_seeks) { panel_timeline->seek(clip->timeline_in); @@ -233,7 +244,11 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { for (int i=0;ilinked.size();i++) { Clip* link = sequence->get_clip(c->linked.at(i)); if (!panel_timeline->is_clip_selected(link)) { - panel_timeline->selections.append((Selection){link->timeline_in, link->timeline_out, link->track}); + Selection ss; + ss.in = link->timeline_in; + ss.out = link->timeline_out; + ss.track = link->track; + panel_timeline->selections.append(ss); } } } @@ -259,10 +274,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { case TIMELINE_TOOL_RAZOR: { if (clip_index >= 0) { - Clip* clip = sequence->get_clip(clip_index); - if (clip != NULL) { - panel_timeline->split_clip_and_relink(clip, panel_timeline->drag_frame_start, !(event->modifiers() & Qt::AltModifier)); - } + panel_timeline->split_clip_and_relink(clip_index, panel_timeline->drag_frame_start, !(event->modifiers() & Qt::AltModifier)); } panel_timeline->splitting = true; panel_timeline->redraw_all_clips(true); @@ -279,19 +291,24 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { if (panel_timeline->moving_proc) { if (event->modifiers() & Qt::AltModifier) { // if holding alt, duplicate rather than move // duplicate clips - QVector old_clips; QVector copy_clips; + QVector old_clips; + QVector new_clips; QVector delete_areas; for (int i=0;ighosts.size();i++) { const Ghost& g = panel_timeline->ghosts.at(i); if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) { - Clip* c = g.clip->copy(); + Clip* c = sequence->get_clip(g.clip)->copy(); c->timeline_in = g.in; c->timeline_out = g.out; c->track = g.track; - delete_areas.append((Selection){g.in, g.out, g.track}); + Selection s; + s.in = g.in; + s.out = g.out; + s.track = g.track; + delete_areas.append(s); old_clips.append(g.clip); copy_clips.append(c); @@ -301,17 +318,17 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { panel_timeline->delete_areas_and_relink(delete_areas); for (int i=0;iadd_clip(copy_clips.at(i)); + new_clips.append(sequence->add_clip(copy_clips.at(i))); } // relink duplicated clips - panel_timeline->relink_clips_using_ids(old_clips, copy_clips); + panel_timeline->relink_clips_using_ids(old_clips, new_clips); } } else { // move clips // TODO can we do this better than 3 consecutive for loops? for (int i=0;ighosts.size();i++) { // step 1 - set clips that are moving to "undeletable" (to avoid step 2 deleting any part of them) - panel_timeline->ghosts[i].clip->undeletable = true; + sequence->get_clip(panel_timeline->ghosts[i].clip)->undeletable = true; } // step 2 - delete areas QVector delete_areas; @@ -321,7 +338,11 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { // step 2 - delete anything that exists in area that clip is moving to // note: ripples are non-destructive so this is pointer-tool exclusive - delete_areas.append((Selection){g.in, g.out, g.track}); + Selection s; + s.in = g.in; + s.out = g.out; + s.track = g.track; + delete_areas.append(s); } } panel_timeline->delete_areas_and_relink(delete_areas); @@ -329,14 +350,15 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { Ghost& g = panel_timeline->ghosts[i]; // step 3 - move clips - g.clip->timeline_in = g.in; - g.clip->timeline_out = g.out; - g.clip->track = g.track; - g.clip->clip_in = g.clip_in; + Clip* c = sequence->get_clip(g.clip); + c->timeline_in = g.in; + c->timeline_out = g.out; + c->track = g.track; + c->clip_in = g.clip_in; } for (int i=0;ighosts.size();i++) { // step 4 - set clips back to deletable - panel_timeline->ghosts[i].clip->undeletable = false; + sequence->get_clip(panel_timeline->ghosts[i].clip)->undeletable = false; } } @@ -395,36 +417,37 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { // one of these days it might be nice to have multiple clips in the effects panel bool got_vclip = false; bool got_aclip = false; - Clip* vclip = NULL; - Clip* aclip = NULL; + int vclip = -1; + int aclip = -1; for (int i=0;iclip_count();i++) { Clip* clip = sequence->get_clip(i); if (clip != NULL && panel_timeline->is_clip_selected(clip)) { if (clip->track < 0) { if (got_vclip) { - vclip = NULL; + vclip = -1; } else { - vclip = clip; + vclip = i; got_vclip = true; } } else { if (got_aclip) { - aclip = NULL; + aclip = -1; } else { - aclip = clip; + aclip = i; got_aclip = true; } } } } // check if aclip is linked to vclip - QVector selected_clips; - if (vclip != NULL) selected_clips.append(vclip); - if (aclip != NULL) selected_clips.append(aclip); - if (vclip != NULL && aclip != NULL) { + QVector selected_clips; + if (vclip != -1) selected_clips.append(vclip); + if (aclip != -1) selected_clips.append(aclip); + if (vclip != -1 && aclip != -1) { bool found = false; - for (int i=0;ilinked.size();i++) { - if (vclip->linked.at(i) == aclip->id) { + Clip* vclip_ref = sequence->get_clip(vclip); + for (int i=0;ilinked.size();i++) { + if (vclip_ref->linked.at(i) == aclip) { found = true; break; } @@ -449,7 +472,7 @@ void TimelineWidget::init_ghosts() { if (panel_timeline->trim_target > -1 || panel_timeline->tool == TIMELINE_TOOL_SLIP) { // used for trim ops g.ghost_length = g.old_out - g.old_in; - g.media_length = g.clip->media->get_length_in_frames(sequence->frame_rate); + g.media_length = sequence->get_clip(g.clip)->media->get_length_in_frames(sequence->frame_rate); } } for (int i=0;iselections.size();i++) { @@ -508,6 +531,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { // validate ghosts for (int i=0;ighosts.size();i++) { Ghost& g = panel_timeline->ghosts[i]; + Clip* c = sequence->get_clip(g.clip); if (panel_timeline->trim_in) { // prevent clip length from being less than 1 frame long @@ -518,7 +542,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { validator = g.old_in + frame_diff; if (validator < 0) frame_diff -= validator; - if (!g.clip->media_stream->infinite_length) { + if (!c->media_stream->infinite_length) { // prevent clip_in from going below 0 validator = g.old_clip_in + frame_diff; if (validator < 0) frame_diff -= validator; @@ -547,7 +571,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { validator = g.ghost_length + frame_diff; if (validator < 1) frame_diff += (1 - validator); - if (!g.clip->media_stream->infinite_length) { + if (!c->media_stream->infinite_length) { // prevent clip length exceeding media length validator = g.ghost_length + frame_diff; if (validator > g.media_length) frame_diff -= validator - g.media_length; @@ -661,7 +685,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { // validate ghosts for (int i=0;ighosts.size();i++) { Ghost& g = panel_timeline->ghosts[i]; - if (!g.clip->media_stream->infinite_length) { + if (!sequence->get_clip(g.clip)->media_stream->infinite_length) { // prevent slip moving a clip below 0 clip_in validator = g.old_clip_in - frame_diff; if (validator < 0) frame_diff += validator; @@ -762,7 +786,13 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); if (c != NULL && panel_timeline->is_clip_selected(c)) { - panel_timeline->ghosts.append((Ghost){c, c->timeline_in, c->timeline_out, c->track, c->clip_in}); + Ghost g; + g.clip = i; + g.in = c->timeline_in; + g.out = c->timeline_out; + g.track = c->track; + g.clip_in = c->clip_in; + panel_timeline->ghosts.append(g); } } @@ -775,10 +805,10 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { if (cc != NULL) { // don't cache any currently selected clips - Clip* c = panel_timeline->ghosts.at(i).clip; + Clip* c = sequence->get_clip(panel_timeline->ghosts.at(i).clip); bool is_selected = false; for (int k=0;kghosts.size();k++) { - if (panel_timeline->ghosts.at(k).clip == cc) { + if (panel_timeline->ghosts.at(k).clip == j) { is_selected = true; break; } @@ -837,7 +867,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { for (int i=0;iclip_count();i++) { Clip* clip = sequence->get_clip(i); if (clip != NULL && clip->track == track) { - panel_timeline->split_clip_and_relink(clip, panel_timeline->drag_frame_start, !alt); + panel_timeline->split_clip_and_relink(i, panel_timeline->drag_frame_start, !alt); repaint = true; } }