diff --git a/effects/effects.h b/effects/effects.h index 32891fd2a..5a887bdad 100644 --- a/effects/effects.h +++ b/effects/effects.h @@ -89,7 +89,10 @@ private: int prev_x; int prev_y; int prev_rot; + int perp_x; + int perp_y; double t; + bool inside; }; class TextEffect : public Effect { diff --git a/effects/shakeeffect.cpp b/effects/shakeeffect.cpp index 23e7224ab..f5e1b4207 100644 --- a/effects/shakeeffect.cpp +++ b/effects/shakeeffect.cpp @@ -12,7 +12,7 @@ #include "project/sequence.h" #include "panels/timeline.h" -ShakeEffect::ShakeEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SHAKE_EFFECT) { +ShakeEffect::ShakeEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SHAKE_EFFECT), inside(false) { ui_layout->addWidget(new QLabel("Intensity:"), 0, 0); intensity_val = new LabelSlider(); intensity_val->set_minimum_value(0); @@ -88,6 +88,22 @@ void ShakeEffect::process_gl(int*, int*) { prev_y = next_y; next_x = (qrand() % (int) (intensity_val->value() * 2)) - intensity_val->value(); next_y = (qrand() % (int) (intensity_val->value() * 2)) - intensity_val->value(); + + // find perpendicular slope that passes through (mid_x, mid_y) + int mid_x = (prev_x + next_x) / 2; + int mid_y = (prev_y + next_y) / 2; + int slope_num = (next_y-prev_y); + if (slope_num > 0) { + int slope_den = (next_x-prev_x); + int add = (next_x-prev_x)/4; + if (inside) add = -add; + inside = !inside; + perp_x = mid_x + add; + perp_y = (-(slope_den / slope_num)) * perp_x + mid_y; + } else { + perp_x = mid_x; + perp_y = mid_y; + } } else { prev_x = 0; prev_y = 0; @@ -106,10 +122,16 @@ void ShakeEffect::process_gl(int*, int*) { } shake_progress = 0; } - t = 1 - qPow(((double) shake_progress / (double) shake_limit)-1, 2); - offset_x = lerp(prev_x, next_x, t); - offset_y = lerp(prev_y, next_y, t); + + t = (double) shake_progress / (double) shake_limit; + + double oneminust = 1 - t; + + offset_x = (qPow(oneminust, 2)*prev_x) + (2*oneminust*t*perp_x) + (qPow(t, 2) * next_x); + offset_y = (qPow(oneminust, 2)*prev_y) + (2*oneminust*t*perp_y) + (qPow(t, 2) * next_y); + offset_rot = lerp(prev_rot, next_rot, t); + glTranslatef(offset_x, offset_y, 0); glRotatef(offset_rot, 0, 0, 1); shake_progress++; diff --git a/mainwindow.cpp b/mainwindow.cpp index d243b2a4c..c5f4d7df3 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -140,7 +140,7 @@ MainWindow::~MainWindow() { QString data_dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); if (!data_dir.isEmpty() && !autorecovery_filename.isEmpty()) { if (QFile::exists(autorecovery_filename)) { - QFile::remove(autorecovery_filename); + QFile::rename(autorecovery_filename, autorecovery_filename + "." + QDateTime::currentDateTimeUtc().toString("yyyyMMddHHmmss")); } } if (!config_dir.isEmpty()) { diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 3995832f7..d7e62a524 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -46,7 +46,11 @@ void cache_audio_worker(Clip* c, Clip* nest) { // no more audio left in frame, get a new one if (!c->reached_end) { retrieve_next_frame_raw_data(c, frame); - apply_audio_effects(c, frame, av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast(frame->format), 1)); + int byte_count = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast(frame->format), 1); + apply_audio_effects(c, frame, byte_count); + if (nest != NULL) { + apply_audio_effects(nest, frame, byte_count); + } } else { // set by retrieve_next_frame_raw_data indicating no more frames in file, // but there still may be samples in swresample diff --git a/project/clip.cpp b/project/clip.cpp index 261b4eb11..6d6721984 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -131,6 +131,12 @@ void Clip::run_video_pre_effect_stack(long playhead, int* anchor_x, int* anchor_ } } +void Clip::run_video_post_effect_stack() { + for (int j=0;jis_enabled()) effects.at(j)->post_gl(); + } +} + Clip::~Clip() { if (open) { close_clip(this); diff --git a/project/clip.h b/project/clip.h index cd8365635..9c451f9c1 100644 --- a/project/clip.h +++ b/project/clip.h @@ -43,6 +43,7 @@ struct Clip void reset(); void refresh(); void run_video_pre_effect_stack(long playhead, int *anchor_x, int *anchor_y); + void run_video_post_effect_stack(); // timeline variables Sequence* sequence; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 3f6bc438e..b69881fae 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -204,9 +204,7 @@ void ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { c->texture->release(); // perform all transform effects - for (int j=0;jeffects.size();j++) { - if (c->effects.at(j)->is_enabled()) c->effects.at(j)->post_gl(); - } + c->run_video_post_effect_stack(); } } else if (render_audio && c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && @@ -218,6 +216,7 @@ void ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { break; case MEDIA_TYPE_SEQUENCE: compose_sequence(c, render_audio); + c->run_video_post_effect_stack(); break; } }