refactored clip references and improved audio hotfix

This commit is contained in:
itsmattkc
2018-07-06 23:58:21 +01:00
parent 2056b1a2cd
commit 083f7daf18
17 changed files with 531 additions and 481 deletions
+1
View File
@@ -0,0 +1 @@
olive.pro.*
+2 -1
View File
@@ -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;
+16 -34
View File
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.2, 2018-07-06T11:56:30. -->
<!-- Written by QtCreator 4.6.1, 2018-07-06T23:45:10. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{0973e18b-ea93-4e4c-8225-598cb1e91b00}</value>
<value type="QByteArray">{3af06612-75ce-48d7-b444-7dc372f1566d}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
@@ -59,14 +59,14 @@
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.5.1 clang 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.5.1 clang 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.55.clang_64_kit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.11.0 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.11.0 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5110.win64_msvc2017_64_kit</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/matt/build-olive-Desktop_Qt_5_5_1_clang_64bit-Debug</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/Matt/Desktop/build-olive-Desktop_Qt_5_11_0_MSVC2017_64bit-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -84,10 +84,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
@@ -103,10 +100,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
@@ -126,7 +120,7 @@
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/matt/build-olive-Desktop_Qt_5_5_1_clang_64bit-Release</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/Matt/Desktop/build-olive-Desktop_Qt_5_11_0_MSVC2017_64bit-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -144,10 +138,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
@@ -163,10 +154,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
@@ -186,7 +174,7 @@
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/matt/build-olive-Desktop_Qt_5_5_1_clang_64bit-Profile</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/Matt/Desktop/build-olive-Desktop_Qt_5_11_0_MSVC2017_64bit-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -204,10 +192,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
@@ -223,10 +208,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
@@ -304,13 +286,13 @@
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">olive</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/Users/matt/olive/olive.pro</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:C:/Users/Matt/Desktop/olive/olive.pro</value>
<value type="bool" key="QmakeProjectManager.QmakeRunConfiguration.UseLibrarySearchPath">true</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">olive.pro</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default">/Users/matt/build-olive-Desktop_Qt_5_5_1_clang_64bit-Debug/olive.app/Contents/MacOS</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default">C:/Users/Matt/Desktop/build-olive-Desktop_Qt_5_11_0_MSVC2017_64bit-Debug</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
+7 -7
View File
@@ -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;i<selected_clips.size();i++) {
Clip* clip = selected_clips.at(i);
Clip* clip = sequence->get_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<Effect*> delete_effects;
for (int i=0;i<selected_clips.size();i++) {
Clip* c = selected_clips.at(i);
Clip* c = sequence->get_clip(selected_clips.at(i));
for (int j=0;j<c->effects.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;i<selected_clips.size();i++) {
Clip* c = selected_clips.at(i);
Clip* c = sequence->get_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<Effect*> delete_effects;
for (int i=0;i<selected_clips.size();i++) {
Clip* c = selected_clips.at(i);
Clip* c = sequence->get_clip(selected_clips.at(i));
for (int j=0;j<c->effects.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<Clip*>& clips) {
void EffectControls::set_clips(QVector<int>& 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;i<selected_clips.size();i++) {
Clip* c = selected_clips.at(i);
Clip* c = sequence->get_clip(selected_clips.at(i));
if (c != NULL) {
for (int j=0;j<c->effects.size();j++) {
if (c->effects.at(j)->container->is_focused()) {
+2 -2
View File
@@ -18,7 +18,7 @@ public:
explicit EffectControls(QWidget *parent = 0);
~EffectControls();
// void set_clip(Clip* c);
void set_clips(QVector<Clip*>& clips);
void set_clips(QVector<int>& clips);
void clear_effects(bool clear_cache);
void delete_clips();
bool is_focused();
@@ -34,7 +34,7 @@ private slots:
private:
Ui::EffectControls *ui;
QVector<Clip*> selected_clips;
QVector<int> selected_clips;
void show_menu(bool video);
void load_effects();
void reload_clips();
+11 -10
View File
@@ -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,17 +401,19 @@ void Project::load_project() {
// correct IDs in linked clips
for (int j=0;j<clip->linked.size();j++) {
bool found = false;
for (int k=0;k<temp_seq->clip_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;i<temp_seq->clip_count();i++) {
// correct actual IDs
temp_seq->get_clip(i)->id = i;
}
new_sequence(temp_seq);
@@ -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));
+78 -47
View File
@@ -268,7 +268,11 @@ void Timeline::select_all() {
selections.clear();
for (int i=0;i<sequence->clip_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,26 +446,29 @@ void Timeline::on_snappingButton_toggled(bool checked)
snapping = checked;
}
void Timeline::split_clip_and_relink(Clip* clip, long frame, bool relink) {
QVector<Clip*> pre_clips;
QVector<Clip*> post_clips;
void Timeline::split_clip_and_relink(int clip, long frame, bool relink) {
Clip* c = sequence->get_clip(clip);
if (c != NULL) {
QVector<int> pre_clips;
QVector<int> 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) {
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;i<clip->linked.size();i++) {
Clip* link = sequence->get_clip(clip->linked.at(i));
for (int i=0;i<c->linked.size();i++) {
int l = c->linked.at(i);
Clip* link = sequence->get_clip(l);
if (original_clip_is_selected != !is_clip_selected(link)) {
Clip* s = sequence->split_clip(link, frame);
if (s != NULL) {
pre_clips.append(link);
int s = sequence->split_clip(l, frame);
if (s > -1) {
pre_clips.append(l);
post_clips.append(s);
}
}
@@ -470,6 +477,7 @@ void Timeline::split_clip_and_relink(Clip* clip, long frame, bool relink) {
relink_clips_using_ids(pre_clips, post_clips);
}
}
}
void Timeline::clean_up_selections(QVector<Selection>& areas) {
for (int i=0;i<areas.size();i++) {
@@ -504,8 +512,8 @@ void Timeline::clean_up_selections(QVector<Selection>& areas) {
void Timeline::delete_areas_and_relink(QVector<Selection>& areas) {
clean_up_selections(areas);
QVector<Clip*> pre_clips;
QVector<Clip*> post_clips;
QVector<int> pre_clips;
QVector<int> post_clips;
for (int i=0;i<areas.size();i++) {
const Selection& s = areas.at(i);
@@ -526,10 +534,8 @@ void Timeline::delete_areas_and_relink(QVector<Selection>& 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<Clip*>& old_clips, QVector<Clip*>& new_clips) {
void Timeline::relink_clips_using_ids(QVector<int>& old_clips, QVector<int>& new_clips) {
// relink pasted clips
for (int i=0;i<old_clips.size();i++) {
// these indices should correspond
Clip* oc = old_clips.at(i);
Clip* nc = new_clips.at(i);
Clip* oc = sequence->get_clip(old_clips.at(i));
Clip* nc = sequence->get_clip(new_clips.at(i));
for (int j=0;j<oc->linked.size();j++) {
for (int k=0;k<old_clips.size();k++) { // find clip with that ID
if (old_clips.at(k)->id == 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<Clip*>& old_clips, QVector<Clip*>&
void Timeline::paste() {
if (clip_clipboard.size() > 0) {
// create copies and delete areas that we'll be pasting to
QVector<Selection> delete_areas;
for (int i=0;i<clip_clipboard.size();i++) {
Clip* c = clip_clipboard.at(i);
delete_areas.append((Selection){c->timeline_in + playhead, c->timeline_out + playhead, c->track});
}
delete_areas_and_relink(delete_areas);
QVector<Clip*> pasted_clips;
QVector<int> pasted_clip_ids;
long paste_end = 0;
QVector<Clip*> added_clips;
for (int i=0;i<clip_clipboard.size();i++) {
Clip* c = clip_clipboard.at(i);
// create copy of clip and offset by playhead
Clip* cc = c->copy();
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;i<pasted_clips.size();i++) {
pasted_clip_ids.append(sequence->add_clip(pasted_clips.at(i)));
}
relink_clips_using_ids(clip_clipboard, added_clips);
// ADAPT
for (int i=0;i<clip_clipboard.size();i++) {
// these indices should correspond
Clip* oc = clip_clipboard.at(i);
for (int j=0;j<oc->linked.size();j++) {
for (int k=0;k<clip_clipboard.size();k++) { // find clip with that ID
if (clip_clipboard.at(k)->load_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<Clip*> pre_splits;
QVector<Clip*> post_splits;
QVector<int> pre_splits;
QVector<int> post_splits;
// find clips within selection and split
for (int j=0;j<sequence->clip_count();j++) {
@@ -662,15 +693,15 @@ bool Timeline::split_selection() {
for (int i=0;i<selections.size();i++) {
const Selection& s = selections.at(i);
if (s.track == clip->track) {
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<Clip*> pre_clips;
QVector<Clip*> post_clips;
QVector<int> pre_clips;
QVector<int> post_clips;
for (int j=0;j<sequence->clip_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;
}
}
+3 -3
View File
@@ -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<Selection>& areas);
void delete_areas_and_relink(QVector<Selection>& areas);
void relink_clips_using_ids(QVector<Clip*>& old_clips, QVector<Clip*>& new_clips);
void relink_clips_using_ids(QVector<int>& old_clips, QVector<int>& new_clips);
void update_sequence();
void increase_track_height();
void decrease_track_height();
+2 -1
View File
@@ -3,6 +3,7 @@
#include "project/sequence.h"
#include <QAudioOutput>
#include <QtMath>
#include <QDebug>
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;
+1 -2
View File
@@ -193,8 +193,7 @@ float clip_frame_to_seconds(Clip* c, long clip_frame) {
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
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;
}
}
-1
View File
@@ -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;
+1 -1
View File
@@ -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();
+8 -3
View File
@@ -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) {}
+1
View File
@@ -27,6 +27,7 @@ public:
bool is_enabled();
virtual Effect* copy(Clip* c);
virtual void load(QXmlStreamReader* stream);
virtual void save(QXmlStreamWriter* stream);
+8 -9
View File
@@ -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;k<c->linked.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() {
+2 -2
View File
@@ -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;
+76 -46
View File
@@ -104,13 +104,17 @@ void TimelineWidget::dropEvent(QDropEvent* event) {
if (panel_timeline->importing) {
event->accept();
QVector<Clip*> added_clips;
QVector<int> added_clips;
// delete areas before adding
QVector<Selection> delete_areas;
for (int i=0;i<panel_timeline->ghosts.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;i<added_clips.size();i++) {
Clip* c = added_clips.at(i);
Clip* c = sequence->get_clip(added_clips.at(i));
for (int j=0;j<added_clips.size();j++) {
Clip* cc = added_clips.at(j);
Clip* cc = sequence->get_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;i<clip->linked.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<Clip*> old_clips;
QVector<Clip*> copy_clips;
QVector<int> old_clips;
QVector<int> new_clips;
QVector<Selection> delete_areas;
for (int i=0;i<panel_timeline->ghosts.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;i<copy_clips.size();i++) {
// step 2 - delete anything that exists in area that clip is moving to
sequence->add_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;i<panel_timeline->ghosts.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<Selection> 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;i<panel_timeline->ghosts.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;i<sequence->clip_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<Clip*> selected_clips;
if (vclip != NULL) selected_clips.append(vclip);
if (aclip != NULL) selected_clips.append(aclip);
if (vclip != NULL && aclip != NULL) {
QVector<int> 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;i<vclip->linked.size();i++) {
if (vclip->linked.at(i) == aclip->id) {
Clip* vclip_ref = sequence->get_clip(vclip);
for (int i=0;i<vclip_ref->linked.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;i<panel_timeline->selections.size();i++) {
@@ -508,6 +531,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
// validate ghosts
for (int i=0;i<panel_timeline->ghosts.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;i<panel_timeline->ghosts.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;i<sequence->clip_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;k<panel_timeline->ghosts.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;i<sequence->clip_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;
}
}