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;
}
}