fixed #142
This commit is contained in:
+11
-2
@@ -164,13 +164,22 @@ void load_vst_effects() {
|
||||
}
|
||||
|
||||
void init_effects() {
|
||||
dout << "Starting init effect (TODO: multithread this)";
|
||||
EffectInit* init_thread = new EffectInit();
|
||||
QObject::connect(init_thread, SIGNAL(finished()), init_thread, SLOT(deleteLater()));
|
||||
init_thread->start();
|
||||
}
|
||||
|
||||
EffectInit::EffectInit() {
|
||||
effects_loaded.lock();
|
||||
}
|
||||
|
||||
void EffectInit::run() {
|
||||
dout << "[INFO] Initializing effects...";
|
||||
load_internal_effects();
|
||||
load_shader_effects();
|
||||
load_vst_effects();
|
||||
effects_loaded.unlock();
|
||||
dout << "Completed init effect (TODO: multithread this)";
|
||||
dout << "[INFO] Finished initializing effects";
|
||||
}
|
||||
|
||||
double double_lerp(double a, double b, double t) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <QOpenGLTexture>
|
||||
#include <QJSEngine>
|
||||
#include <QMutex>
|
||||
#include <QThread>
|
||||
class QLabel;
|
||||
class QWidget;
|
||||
class CollapsibleWidget;
|
||||
@@ -262,4 +263,11 @@ private:
|
||||
int get_index_in_clip();
|
||||
};
|
||||
|
||||
class EffectInit : public QThread {
|
||||
public:
|
||||
EffectInit();
|
||||
protected:
|
||||
void run();
|
||||
};
|
||||
|
||||
#endif // EFFECT_H
|
||||
|
||||
@@ -66,11 +66,11 @@ void PreviewGenerator::parse_media() {
|
||||
&& fmt_ctx->streams[i]->codecpar->width > 0
|
||||
&& fmt_ctx->streams[i]->codecpar->height > 0) {
|
||||
|
||||
/*dout << "avg_frame_rate was:" << fmt_ctx->streams[i]->avg_frame_rate.num << "/" << fmt_ctx->streams[i]->avg_frame_rate.den;
|
||||
dout << "avg_frame_rate was:" << fmt_ctx->streams[i]->avg_frame_rate.num << "/" << fmt_ctx->streams[i]->avg_frame_rate.den;
|
||||
dout << "r_frame_rate was:" << fmt_ctx->streams[i]->r_frame_rate.num << "/" << fmt_ctx->streams[i]->r_frame_rate.den;
|
||||
dout << "codec_frame_rate was:" << fmt_ctx->streams[i]->codec->framerate.num << "/" << fmt_ctx->streams[i]->codec->framerate.den;
|
||||
dout << "nb_frames was:" << fmt_ctx->streams[i]->nb_frames;
|
||||
dout << "duration was:" << fmt_ctx->streams[i]->duration << "OR fmt_ctx's duration is:" << fmt_ctx->duration;*/
|
||||
dout << "duration was:" << fmt_ctx->streams[i]->duration << "OR fmt_ctx's duration is:" << fmt_ctx->duration;
|
||||
|
||||
if (fmt_ctx->streams[i]->avg_frame_rate.den == 0
|
||||
&& fmt_ctx->streams[i]->duration == AV_NOPTS_VALUE) { // source is LIKELY a still image
|
||||
|
||||
+4
-2
@@ -327,8 +327,10 @@ void MainWindow::editMenu_About_To_Be_Shown() {
|
||||
}
|
||||
|
||||
void MainWindow::undo() {
|
||||
undo_stack.undo();
|
||||
update_ui(true);
|
||||
if (!panel_timeline->importing) { // workaround to prevent crash (and also users should never need to do this)
|
||||
undo_stack.undo();
|
||||
update_ui(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::redo() {
|
||||
|
||||
+22
-2
@@ -245,6 +245,18 @@ void Project::get_all_media_from_table(QList<QTreeWidgetItem*> items, QList<QTre
|
||||
}
|
||||
}
|
||||
|
||||
bool delete_clips_in_clipboard_with_media(ComboAction* ca, Media* m) {
|
||||
int delete_count = 0;
|
||||
for (int i=0;i<panel_timeline->clip_clipboard.size();i++) {
|
||||
Clip* c = panel_timeline->clip_clipboard.at(i);
|
||||
if (c->media == m) {
|
||||
ca->append(new RemoveClipsFromClipboard(i-delete_count));
|
||||
delete_count++;
|
||||
}
|
||||
}
|
||||
return (delete_count > 0);
|
||||
}
|
||||
|
||||
void Project::delete_selected_media() {
|
||||
ComboAction* ca = new ComboAction();
|
||||
QList<QTreeWidgetItem*> items = ui->treeWidget->selectedItems();
|
||||
@@ -325,7 +337,11 @@ void Project::delete_selected_media() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (confirm_delete) {
|
||||
delete_clips_in_clipboard_with_media(ca, media);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,10 +654,10 @@ void Project::delete_clips_using_selected_media() {
|
||||
} else {
|
||||
ComboAction* ca = new ComboAction();
|
||||
bool deleted = false;
|
||||
QList<QTreeWidgetItem*> items = source_table->selectedItems();
|
||||
for (int i=0;i<sequence->clips.size();i++) {
|
||||
Clip* c = sequence->clips.at(i);
|
||||
if (c != NULL) {
|
||||
QList<QTreeWidgetItem*> items = source_table->selectedItems();
|
||||
for (int j=0;j<items.size();j++) {
|
||||
Media* m = get_footage_from_tree(items.at(j));
|
||||
if (c->media == m) {
|
||||
@@ -651,6 +667,10 @@ void Project::delete_clips_using_selected_media() {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int j=0;j<items.size();j++) {
|
||||
Media* m = get_footage_from_tree(items.at(j));
|
||||
if (delete_clips_in_clipboard_with_media(ca, m)) deleted = true;
|
||||
}
|
||||
if (deleted) {
|
||||
undo_stack.push(ca);
|
||||
update_ui(true);
|
||||
|
||||
+3
-1
@@ -164,6 +164,9 @@ public:
|
||||
bool creating;
|
||||
int creating_object;
|
||||
|
||||
// clipboard
|
||||
QVector<Clip*> clip_clipboard;
|
||||
|
||||
Ui::Timeline *ui;
|
||||
public slots:
|
||||
void repaint_timeline();
|
||||
@@ -203,7 +206,6 @@ private:
|
||||
void decheck_tool_buttons(QObject* sender);
|
||||
void set_tool(int tool);
|
||||
long last_frame;
|
||||
QVector<Clip*> clip_clipboard;
|
||||
int scroll;
|
||||
|
||||
int default_track_height;
|
||||
|
||||
@@ -132,6 +132,8 @@ void AudioSenderThread::run() {
|
||||
// got all the bytes, write again
|
||||
written_bytes += send_audio_to_output(0, audio_ibuffer_size);
|
||||
}
|
||||
|
||||
dout << "read to" << audio_ibuffer_read;
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
+38
-41
@@ -179,20 +179,25 @@ void cache_audio_worker(Clip* c, Clip* nest) {
|
||||
|
||||
rev_frame->nb_samples += frame->nb_samples;
|
||||
|
||||
// if (c->frame->pts == c->rev_target) {
|
||||
if ((c->frame->pts >= c->reverse_target) || (ret == AVERROR_EOF)) {
|
||||
/*dout << "time for the end of rev cache" << rev_frame->nb_samples << c->rev_target << c->frame->pts << c->frame->pkt_duration << c->frame->nb_samples;
|
||||
/*
|
||||
#ifdef AUDIOWARNINGS
|
||||
dout << "time for the end of rev cache" << rev_frame->nb_samples << c->rev_target << c->frame->pts << c->frame->pkt_duration << c->frame->nb_samples;
|
||||
dout << "diff:" << (c->frame->pkt_pts + c->frame->pkt_duration) - c->rev_target;
|
||||
int cutoff = qRound64 ((((c->frame->pkt_pts + c->frame->pkt_duration) - c->rev_target) * timebase) * c->sequence->audio_frequency);
|
||||
#endif
|
||||
int cutoff = qRound64((((c->frame->pkt_pts + c->frame->pkt_duration) - c->reverse_target) * timebase) * c->sequence->audio_frequency);
|
||||
if (cutoff > 0) {
|
||||
#ifdef AUDIOWARNINGS
|
||||
dout << "cut off" << cutoff << "samples (rate:" << c->sequence->audio_frequency << ")";
|
||||
#endif
|
||||
rev_frame->nb_samples -= cutoff;
|
||||
}*/
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef AUDIOWARNINGS
|
||||
dout << "pre cutoff deets::: rev_frame.pts:" << rev_frame->pts << "rev_frame.nb_samples" << rev_frame->nb_samples << "rev_target:" << c->reverse_target;
|
||||
#endif
|
||||
rev_frame->nb_samples = qRound64(static_cast<double>(c->reverse_target - rev_frame->pts) / c->stream->codecpar->sample_rate * c->sequence->audio_frequency);
|
||||
rev_frame->nb_samples = qRound64(static_cast<double>(c->reverse_target - rev_frame->pts) / c->stream->codecpar->sample_rate * (c->sequence->audio_frequency / c->speed));
|
||||
#ifdef AUDIOWARNINGS
|
||||
dout << "post cutoff deets::" << rev_frame->nb_samples;
|
||||
#endif
|
||||
@@ -337,6 +342,7 @@ void cache_audio_worker(Clip* c, Clip* nest) {
|
||||
#ifdef AUDIOWARNINGS
|
||||
if (c->audio_buffer_write >= buffer_timeline_out) dout << "timeline out at fsi" << c->frame_sample_index << "of frame ts" << c->frame->pts;
|
||||
#endif
|
||||
|
||||
audio_write_lock.unlock();
|
||||
|
||||
if (c->frame_sample_index == nb_bytes) {
|
||||
@@ -360,25 +366,20 @@ void cache_video_worker(Clip* c, long playhead) {
|
||||
int64_t target_pts = seconds_to_timestamp(c, playhead_to_clip_seconds(c, playhead));
|
||||
|
||||
int limit = c->max_queue_size;
|
||||
if (c->reverse) limit *= 2;
|
||||
/*if (c->reverse) {
|
||||
bool found = false;
|
||||
for (int i=0;i<c->queue.size();i++) {
|
||||
if (target_pts > c->queue.at(i)->pts && target_pts <= c->queue.at(i)->pts + c->queue.at(i)->pkt_duration) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// we need like one more frame
|
||||
limit = c->queue.size() + 1;
|
||||
}
|
||||
}*/
|
||||
if (c->ignore_reverse) {
|
||||
// waiting for one frame
|
||||
limit = c->queue.size() + 1;
|
||||
} else if (c->reverse) {
|
||||
limit *= 2;
|
||||
}
|
||||
|
||||
if (c->queue.size() < limit) {
|
||||
bool reverse = (c->reverse && !c->ignore_reverse);
|
||||
c->ignore_reverse = false;
|
||||
|
||||
int64_t eighth_second = av_q2d(av_inv_q(c->stream->time_base))*0.125;
|
||||
int64_t smallest_pts = INT64_MAX;
|
||||
if (c->reverse && c->queue.size() > 0) {
|
||||
if (reverse && c->queue.size() > 0) {
|
||||
int64_t quarter_sec = qRound64(av_q2d(av_inv_q(c->stream->time_base))) >> 2;
|
||||
for (int i=0;i<c->queue.size();i++) {
|
||||
smallest_pts = qMin(smallest_pts, c->queue.at(i)->pts);
|
||||
@@ -401,7 +402,7 @@ void cache_video_worker(Clip* c, long playhead) {
|
||||
if (read_ret >= 0) {
|
||||
bool send_it = false;
|
||||
|
||||
if (c->reverse) {
|
||||
if (reverse) {
|
||||
send_it = true;
|
||||
} else if (send_frame->pts > target_pts - eighth_second) {
|
||||
send_it = true;
|
||||
@@ -438,7 +439,7 @@ void cache_video_worker(Clip* c, long playhead) {
|
||||
av_frame_free(&frame);
|
||||
break;
|
||||
} else {
|
||||
if (c->reverse && ((smallest_pts == target_pts && frame->pts >= smallest_pts) || (smallest_pts != target_pts && frame->pts > smallest_pts))) {
|
||||
if (reverse && ((smallest_pts == target_pts && frame->pts >= smallest_pts) || (smallest_pts != target_pts && frame->pts > smallest_pts))) {
|
||||
av_frame_free(&frame);
|
||||
break;
|
||||
} else {
|
||||
@@ -446,27 +447,23 @@ void cache_video_worker(Clip* c, long playhead) {
|
||||
c->queue_lock.lock();
|
||||
c->queue.append(frame);
|
||||
|
||||
if (!c->reverse && c->queue.size() == limit) {
|
||||
// if (rendering) {
|
||||
// see if we got the frame we needed (used for speed ups primarily)
|
||||
bool found = false;
|
||||
for (int i=0;i<c->queue.size();i++) {
|
||||
// TODO/NOTE: this will not work on clips that are sped up AND reversed
|
||||
if (c->queue.at(i)->pts >= target_pts) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
c->queue_lock.unlock();
|
||||
if (!reverse && c->queue.size() == limit) {
|
||||
// see if we got the frame we needed (used for speed ups primarily)
|
||||
bool found = false;
|
||||
for (int i=0;i<c->queue.size();i++) {
|
||||
// TODO/NOTE: this will not work on clips that are sped up AND reversed
|
||||
if (c->queue.at(i)->pts >= target_pts) {
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
// remove earliest frame and loop to store another
|
||||
c->queue_remove_earliest();
|
||||
}
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
if (found) {
|
||||
c->queue_lock.unlock();
|
||||
break;
|
||||
} else {
|
||||
// remove earliest frame and loop to store another
|
||||
c->queue_remove_earliest();
|
||||
}
|
||||
}
|
||||
c->queue_lock.unlock();
|
||||
}
|
||||
|
||||
@@ -197,7 +197,8 @@ void get_clip_frame(Clip* c, long playhead) {
|
||||
#ifdef GCF_DEBUG
|
||||
dout << "GCF ==> WAIT - target pts:" << target_pts << "closest frame:" << target_frame->pts;
|
||||
#endif
|
||||
//if (c->queue.size() >= c->max_queue_size) c->queue_remove_earliest();
|
||||
if (c->queue.size() >= c->max_queue_size) c->queue_remove_earliest();
|
||||
c->ignore_reverse = true;
|
||||
target_frame = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -35,7 +35,8 @@ Clip::Clip(Sequence* s) :
|
||||
autoscale(config.autoscale_by_default),
|
||||
maintain_audio_pitch(false),
|
||||
reverse(false),
|
||||
use_existing_frame(false)
|
||||
use_existing_frame(false),
|
||||
ignore_reverse(false)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ struct Clip
|
||||
bool finished_opening;
|
||||
bool replaced;
|
||||
int skip_type;
|
||||
bool ignore_reverse;
|
||||
|
||||
// caching functions
|
||||
bool use_existing_frame;
|
||||
|
||||
@@ -1719,8 +1719,34 @@ MoveEffectCommand::MoveEffectCommand() :
|
||||
|
||||
void MoveEffectCommand::undo() {
|
||||
clip->effects.move(to, from);
|
||||
mainWindow->setWindowModified(old_project_changed);
|
||||
}
|
||||
|
||||
void MoveEffectCommand::redo() {
|
||||
clip->effects.move(from, to);
|
||||
mainWindow->setWindowModified(true);
|
||||
}
|
||||
|
||||
RemoveClipsFromClipboard::RemoveClipsFromClipboard(int index) :
|
||||
pos(index),
|
||||
old_project_changed(mainWindow->isWindowModified()),
|
||||
done(false)
|
||||
{}
|
||||
|
||||
RemoveClipsFromClipboard::~RemoveClipsFromClipboard() {
|
||||
if (done) {
|
||||
delete clip;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveClipsFromClipboard::undo() {
|
||||
panel_timeline->clip_clipboard.insert(pos, clip);
|
||||
done = false;
|
||||
}
|
||||
|
||||
void RemoveClipsFromClipboard::redo() {
|
||||
qDebug() << "removed" << pos << "from clipboard";
|
||||
clip = panel_timeline->clip_clipboard.at(pos);
|
||||
panel_timeline->clip_clipboard.removeAt(pos);
|
||||
done = true;
|
||||
}
|
||||
|
||||
@@ -557,4 +557,17 @@ private:
|
||||
bool old_project_changed;
|
||||
};
|
||||
|
||||
class RemoveClipsFromClipboard : public QUndoCommand {
|
||||
public:
|
||||
RemoveClipsFromClipboard(int index);
|
||||
~RemoveClipsFromClipboard();
|
||||
void undo();
|
||||
void redo();
|
||||
private:
|
||||
int pos;
|
||||
Clip* clip;
|
||||
bool old_project_changed;
|
||||
bool done;
|
||||
};
|
||||
|
||||
#endif // UNDO_H
|
||||
|
||||
@@ -235,7 +235,6 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
|
||||
}
|
||||
|
||||
if (config.enable_drag_files_to_timeline && event->mimeData()->hasUrls()) {
|
||||
dout << "TODO get data for:";
|
||||
QList<QUrl> urls = event->mimeData()->urls();
|
||||
if (!urls.isEmpty()) {
|
||||
QStringList file_list;
|
||||
@@ -247,6 +246,8 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
|
||||
panel_project->process_file_list(false, file_list, NULL, false);
|
||||
|
||||
for (int i=0;i<panel_project->last_imported_media.size();i++) {
|
||||
// waits for media to have a duration
|
||||
// TODO would be much nicer if this was multithreaded
|
||||
panel_project->last_imported_media.at(i)->ready_lock.lock();
|
||||
panel_project->last_imported_media.at(i)->ready_lock.unlock();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user