workarea in/out added #108

This commit is contained in:
itsmattkc
2018-07-22 19:57:03 +01:00
parent 6109ed9002
commit 1fded74767
18 changed files with 335 additions and 55 deletions
+10 -1
View File
@@ -49,6 +49,9 @@ ExportDialog::ExportDialog(QWidget *parent) :
{
ui->setupUi(this);
ui->rangeCombobox->setCurrentIndex(0);
ui->rangeCombobox->setEnabled(sequence->using_workarea);
format_strings.resize(FORMAT_SIZE);
format_strings[FORMAT_3GPP] = "3GPP";
format_strings[FORMAT_AIFF] = "AIFF";
@@ -454,7 +457,6 @@ void ExportDialog::on_pushButton_clicked()
}
}
et = new ExportThread();
et->surface.create();
@@ -487,6 +489,13 @@ void ExportDialog::on_pushButton_clicked()
et->audio_bitrate = ui->audiobitrateSpinbox->value();
}
et->start_frame = 0;
et->end_frame = sequence->getEndFrame(); // entire sequence
if (ui->rangeCombobox->currentIndex() == 1) {
et->start_frame = qMax(sequence->workarea_in, et->start_frame);
et->end_frame = qMin(sequence->workarea_out, et->end_frame);
}
et->ed = this;
cancelled = false;
+27 -2
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>299</width>
<height>372</height>
<width>557</width>
<height>659</height>
</rect>
</property>
<property name="windowTitle">
@@ -28,6 +28,31 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Range:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="rangeCombobox">
<item>
<property name="text">
<string>Entire Sequence</string>
</property>
</item>
<item>
<property name="text">
<string>In to Out</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="videoGroupbox">
<property name="title">
+4 -8
View File
@@ -53,10 +53,6 @@ void ExportThread::run() {
panel_timeline->pause();
// av_log_set_level(AV_LOG_DEBUG);
// TODO make customizable
long start = 0;
long end = sequence->getEndFrame();
if (!panel_viewer->viewer_widget->context()->makeCurrent(&surface)) {
qDebug() << "[ERROR] Make current failed";
ed->export_error = "could not make OpenGL context current";
@@ -283,7 +279,7 @@ void ExportThread::run() {
qDebug() << "[ERROR] Could not write output file header." << ret;
ed->export_error = "could not write output file header (" + QString::number(ret) + ")";
} else {
panel_timeline->seek(start);
panel_timeline->seek(start_frame);
QOpenGLFramebufferObject fbo(video_width, video_height, QOpenGLFramebufferObject::CombinedDepthStencil, GL_TEXTURE_RECTANGLE);
fbo.bind();
@@ -296,10 +292,10 @@ void ExportThread::run() {
long file_audio_samples = 0;
while (panel_timeline->playhead < end && !fail) {
while (panel_timeline->playhead < end_frame && !fail) {
panel_viewer->viewer_widget->paintGL();
double timecode_secs = (double) panel_timeline->playhead / sequence->frame_rate;
double timecode_secs = (double) (panel_timeline->playhead-start_frame) / sequence->frame_rate;
if (video_enabled) {
// get image from opengl
glReadPixels(0, 0, video_width, video_height, GL_RGBA, GL_UNSIGNED_BYTE, video_frame->data[0]);
@@ -338,7 +334,7 @@ void ExportThread::run() {
file_audio_samples += swr_frame->nb_samples;
}
}
emit progress_changed(((float) panel_timeline->playhead / (float) end) * 100);
emit progress_changed(((double) (panel_timeline->playhead-start_frame) / (double) (end_frame-start_frame)) * 100);
panel_timeline->playhead++;
}
+2
View File
@@ -28,6 +28,8 @@ public:
int audio_codec;
int audio_sampling_rate;
int audio_bitrate;
long start_frame;
long end_frame;
QOffscreenSurface surface;
+38 -6
View File
@@ -357,11 +357,9 @@ void MainWindow::on_actionProject_triggered()
{
if (can_close_project()) {
panel_effect_controls->clear_effects(true);
panel_project->new_project();
undo_stack.clear();
panel_timeline->redraw_all_clips(false);
project_url.clear();
project_changed = false;
panel_project->new_project();
}
}
@@ -617,15 +615,49 @@ void MainWindow::on_actionScroll_Wheel_Zooms_triggered()
void MainWindow::on_actionLink_Unlink_triggered()
{
panel_timeline->toggle_links();
if (panel_timeline->focused()) panel_timeline->toggle_links();
}
void MainWindow::on_actionRipple_To_In_Point_triggered()
{
panel_timeline->ripple_to_in_point(true);
if (panel_timeline->focused()) panel_timeline->ripple_to_in_point(true);
}
void MainWindow::on_actionRipple_to_Out_Point_triggered()
{
panel_timeline->ripple_to_in_point(false);
if (panel_timeline->focused()) panel_timeline->ripple_to_in_point(false);
}
void MainWindow::on_actionSet_In_Point_triggered()
{
if (panel_timeline->focused()) panel_timeline->set_in_point();
}
void MainWindow::on_actionSet_Out_Point_triggered()
{
if (panel_timeline->focused()) panel_timeline->set_out_point();
}
void MainWindow::on_actionClear_In_Out_triggered()
{
if (panel_timeline->focused() && sequence->using_workarea) {
TimelineAction* ta = new TimelineAction();
ta->set_in_out(sequence, false, 0, 0);
undo_stack.push(ta);
panel_timeline->repaint_timeline();
}
}
void MainWindow::on_actionDelete_In_Out_triggered()
{
if (panel_timeline->focused()) {
panel_timeline->delete_in_out(false);
}
}
void MainWindow::on_actionRipple_Delete_In_Out_triggered()
{
if (panel_timeline->focused()) {
panel_timeline->delete_in_out(true);
}
}
+10
View File
@@ -158,6 +158,16 @@ private slots:
void on_actionRipple_to_Out_Point_triggered();
void on_actionSet_In_Point_triggered();
void on_actionSet_Out_Point_triggered();
void on_actionClear_In_Out_triggered();
void on_actionDelete_In_Out_triggered();
void on_actionRipple_Delete_In_Out_triggered();
private:
Ui::MainWindow *ui;
void setup_layout();
+40
View File
@@ -79,6 +79,12 @@
<addaction name="actionRipple_To_In_Point"/>
<addaction name="actionRipple_to_Out_Point"/>
<addaction name="actionSplit_at_Playhead"/>
<addaction name="separator"/>
<addaction name="actionSet_In_Point"/>
<addaction name="actionSet_Out_Point"/>
<addaction name="actionClear_In_Out"/>
<addaction name="actionDelete_In_Out"/>
<addaction name="actionRipple_Delete_In_Out"/>
</widget>
<widget class="QMenu" name="menuWindow">
<property name="title">
@@ -639,6 +645,40 @@
<string>W</string>
</property>
</action>
<action name="actionSet_In_Point">
<property name="text">
<string>Set In Point</string>
</property>
<property name="shortcut">
<string>I</string>
</property>
</action>
<action name="actionSet_Out_Point">
<property name="text">
<string>Set Out Point</string>
</property>
<property name="shortcut">
<string>O</string>
</property>
</action>
<action name="actionClear_In_Out">
<property name="text">
<string>Clear In/Out</string>
</property>
<property name="shortcut">
<string>G</string>
</property>
</action>
<action name="actionDelete_In_Out">
<property name="text">
<string>Delete In/Out</string>
</property>
</action>
<action name="actionRipple_Delete_In_Out">
<property name="text">
<string>Ripple Delete In/Out</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
+13 -4
View File
@@ -406,9 +406,9 @@ void Project::clear() {
void Project::new_project() {
// clear existing project
set_sequence(NULL);
clear();
project_changed = false;
set_sequence(NULL);
}
QTreeWidgetItem* Project::find_loaded_folder_by_id(int id) {
@@ -579,6 +579,11 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
s->audio_layout = attr.value().toInt();
} else if (attr.name() == "open") {
open_sequence = true;
} else if (attr.name() == "workareaIn") {
s->using_workarea = true;
s->workarea_in = attr.value().toLong();
} else if (attr.name() == "workareaOut") {
s->workarea_out = attr.value().toLong();
}
}
@@ -596,11 +601,11 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
} else if (attr.name() == "id") {
c->load_id = attr.value().toInt();
} else if (attr.name() == "clipin") {
c->clip_in = attr.value().toInt();
c->clip_in = attr.value().toLong();
} else if (attr.name() == "in") {
c->timeline_in = attr.value().toInt();
c->timeline_in = attr.value().toLong();
} else if (attr.name() == "out") {
c->timeline_out = attr.value().toInt();
c->timeline_out = attr.value().toLong();
} else if (attr.name() == "track") {
c->track = attr.value().toInt();
} else if (attr.name() == "r") {
@@ -842,6 +847,10 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int
if (s == sequence) {
stream.writeAttribute("open", "1");
}
if (s->using_workarea) {
stream.writeAttribute("workareaIn", QString::number(s->workarea_in));
stream.writeAttribute("workareaOut", QString::number(s->workarea_out));
}
for (int j=0;j<s->clip_count();j++) {
Clip* c = s->get_clip(j);
if (c != NULL) {
+1 -1
View File
@@ -15,7 +15,7 @@ class QXmlStreamWriter;
class QXmlStreamReader;
class QFile;
#define SAVE_VERSION "180719"
#define SAVE_VERSION "180722"
#define MEDIA_TYPE_FOOTAGE 0
#define MEDIA_TYPE_SEQUENCE 1
+32 -8
View File
@@ -35,7 +35,6 @@ Timeline::Timeline(QWidget *parent) :
edit_tool_selects_links(false),
edit_tool_also_seeks(false),
select_also_seeks(false),
using_workarea(false),
paste_seeks(true),
snapping(true),
last_frame(0),
@@ -206,6 +205,14 @@ int Timeline::calculate_track_height(int track, int value) {
return vector.at(index);
}
void Timeline::set_in_point() {
ui->headers->set_in_point(playhead);
}
void Timeline::set_out_point() {
ui->headers->set_out_point(playhead);
}
void Timeline::update_sequence() {
bool null_sequence = (sequence == NULL);
@@ -216,16 +223,14 @@ void Timeline::update_sequence() {
ui->pushButton_4->setEnabled(!null_sequence);
ui->pushButton_5->setEnabled(!null_sequence);
ui->headers->setEnabled(!null_sequence);
// ui->video_area->setEnabled(!null_sequence);
// ui->audio_area->setEnabled(!null_sequence);
if (null_sequence) {
setWindowTitle("Timeline: <none>");
} else {
setWindowTitle("Timeline: " + sequence->name);
reset_all_audio();
redraw_all_clips(false);
playback_updater.setInterval(qFloor(1000 / sequence->frame_rate));
reset_all_audio();
}
}
@@ -279,6 +284,27 @@ void Timeline::select_all() {
repaint_timeline();
}
void Timeline::delete_in_out(bool ripple) {
if (sequence != NULL && sequence->using_workarea) {
QVector<Selection> areas;
int video_tracks = 0, audio_tracks = 0;
sequence->get_track_limits(&video_tracks, &audio_tracks);
for (int i=video_tracks;i<=audio_tracks;i++) {
Selection s;
s.in = sequence->workarea_in;
s.out = sequence->workarea_out;
s.track = i;
areas.append(s);
}
TimelineAction* ta = new TimelineAction();
panel_timeline->delete_areas_and_relink(ta, areas);
if (ripple) ta->ripple(sequence, sequence->workarea_in, sequence->workarea_in - sequence->workarea_out);
ta->set_in_out(sequence, false, 0, 0);
undo_stack.push(ta);
redraw_all_clips(true);
}
}
void Timeline::delete_selection(bool ripple_delete) {
if (selections.size() > 0) {
panel_effect_controls->clear_effects(true);
@@ -301,7 +327,6 @@ void Timeline::delete_selection(bool ripple_delete) {
// it feels a little more intuitive with this here
ripple_point++;
QVector<int> ignore;
bool can_ripple = true;
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
@@ -329,7 +354,7 @@ void Timeline::delete_selection(bool ripple_delete) {
}
}
}
if (can_ripple) ta->ripple(sequence, ripple_point, -ripple_length, ignore);
if (can_ripple) ta->ripple(sequence, ripple_point, -ripple_length);
}
selections.clear();
@@ -743,10 +768,9 @@ void Timeline::ripple_to_in_point(bool in) {
}
// trim and move clips around the in point
QVector<int> ignore;
TimelineAction* ta = new TimelineAction();
delete_areas_and_relink(ta, areas);
ta->ripple(sequence, in_point, (in) ? (in_point - playhead) : (playhead - in_point), ignore);
ta->ripple(sequence, in_point, (in) ? (in_point - playhead) : (playhead - in_point));
undo_stack.push(ta);
redraw_all_clips(true);
+4 -5
View File
@@ -85,6 +85,9 @@ public:
bool has_clip_been_split(int c);
void toggle_links();
void ripple_to_in_point(bool in);
void set_in_point();
void set_out_point();
void delete_in_out(bool ripple);
int get_snap_range();
int getScreenPointFromFrame(long frame);
@@ -93,11 +96,7 @@ public:
bool snap_to_point(long point, long* l);
void snap_to_clip(long* l, bool playhead_inclusive);
long playhead;
bool using_workarea;
long workarea_in;
long workarea_out;
long playhead;
// playback functions
void go_to_start();
+5 -1
View File
@@ -5,7 +5,11 @@
#include <QDebug>
Sequence::Sequence() {}
Sequence::Sequence() :
using_workarea(false),
workarea_in(0),
workarea_out(0)
{}
Sequence::~Sequence() {
// dealloc all clips
+4
View File
@@ -23,6 +23,10 @@ public:
double frame_rate;
int audio_frequency;
int audio_layout;
bool using_workarea;
long workarea_in;
long workarea_out;
private:
QVector<Clip*> clips;
};
+40 -1
View File
@@ -24,7 +24,12 @@ QUndoStack undo_stack;
#define TA_ADD_CLIP_IN 7
#define TA_ADD_TRACK 8
TimelineAction::TimelineAction() : done(false), change_seq(false), ripple_enabled(false) {}
TimelineAction::TimelineAction() :
done(false),
change_seq(false),
ripple_enabled(false),
change_in_out(false)
{}
TimelineAction::~TimelineAction() {
for (int i=0;i<clips_to_add.size();i++) {
@@ -129,6 +134,25 @@ void TimelineAction::delete_media(QTreeWidgetItem* item) {
deleted_media.append(item);
}
void TimelineAction::ripple(Sequence* s, long point, long length) {
QVector<int> i;
ripple(s, point, length, i);
}
void TimelineAction::set_in_out(Sequence* s, bool enabled, long in, long out) {
change_in_out = true;
change_in_out_sequence = s;
old_in_out_enabled = s->using_workarea;
old_sequence_in = s->workarea_in;
old_sequence_out = s->workarea_out;
new_in_out_enabled = enabled;
new_sequence_in = in;
new_sequence_out = out;
}
void TimelineAction::ripple(Sequence* s, long point, long length, QVector<int>& ignore) {
ripple_enabled = true;
ripple_point = point;
@@ -220,6 +244,14 @@ void TimelineAction::undo() {
}
}
// un-change workarea
if (change_in_out) {
change_in_out_sequence->using_workarea = old_in_out_enabled;
change_in_out_sequence->workarea_in = old_sequence_in;
change_in_out_sequence->workarea_out = old_sequence_out;
}
// un-change current active sequence
if (change_seq) {
set_sequence(old_seq);
}
@@ -388,6 +420,13 @@ void TimelineAction::redo() {
}
}
// change sequence workarea
if (change_in_out) {
change_in_out_sequence->using_workarea = new_in_out_enabled;
change_in_out_sequence->workarea_in = new_sequence_in;
change_in_out_sequence->workarea_out = new_sequence_out;
}
// change current sequence
if (change_seq) {
old_seq = sequence;
+11
View File
@@ -30,7 +30,9 @@ public:
void delete_clip(Sequence* s, int clip);
void add_media(QTreeWidgetItem* item);
void delete_media(QTreeWidgetItem* item);
void ripple(Sequence* s, long point, long length);
void ripple(Sequence* s, long point, long length, QVector<int> &ignore);
void set_in_out(Sequence* s, bool enabled, long in, long out);
void undo();
void redo();
private:
@@ -73,6 +75,15 @@ private:
QVector<int> rippled_clips;
QVector<int> ripple_ignores;
bool change_in_out;
Sequence* change_in_out_sequence;
bool old_in_out_enabled;
bool new_in_out_enabled;
long old_sequence_in;
long new_sequence_in;
long old_sequence_out;
long new_sequence_out;
void new_action(Sequence* s, int action, int clip, long old_val, long new_val);
void offset_links(QVector<Clip*>& clips, int offset);
};
+85 -17
View File
@@ -3,42 +3,110 @@
#include "panels/panels.h"
#include "panels/timeline.h"
#include "project/sequence.h"
#include "project/undo.h"
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>
#define CLICK_RANGE 5
#define PLAYHEAD_SIZE 6
TimelineHeader::TimelineHeader(QWidget *parent) : QWidget(parent)
{
dragging = false;
TimelineHeader::TimelineHeader(QWidget *parent) : QWidget(parent), dragging(false), resizing_workarea(false) {
setCursor(Qt::ArrowCursor);
setMouseTracking(true);
}
void set_playhead(QMouseEvent* event) {
long frame = panel_timeline->getFrameFromScreenPoint(event->pos().x());
void set_playhead(int mouse_x) {
long frame = panel_timeline->getFrameFromScreenPoint(mouse_x);
panel_timeline->snap_to_clip(&frame, false);
panel_timeline->seek(frame);
panel_timeline->repaint_timeline();
}
void TimelineHeader::mousePressEvent(QMouseEvent* event) {
/*if (panel_timeline->using_workarea) {
event->pos().x()
if (panel_timeline->workarea_in)
} else {
void TimelineHeader::set_in_point(long new_in) {
long new_out = sequence->workarea_out;
if (new_out == new_in) {
new_in--;
} else if (new_out < new_in) {
new_out = sequence->getEndFrame();
}
}*/
set_playhead(event);
TimelineAction* ta = new TimelineAction();
ta->set_in_out(sequence, true, new_in, new_out);
undo_stack.push(ta);
update();
}
void TimelineHeader::set_out_point(long new_out) {
long new_in = sequence->workarea_in;
if (new_out == new_in) {
new_out++;
} else if (new_in > new_out) {
new_in = 0;
}
TimelineAction* ta = new TimelineAction();
ta->set_in_out(sequence, true, new_in, new_out);
undo_stack.push(ta);
update();
}
void TimelineHeader::mousePressEvent(QMouseEvent* event) {
if (resizing_workarea) {
sequence_end = sequence->getEndFrame();
} else {
set_playhead(event->pos().x());
}
dragging = true;
}
void TimelineHeader::mouseMoveEvent(QMouseEvent* event) {
if (dragging) set_playhead(event);
if (dragging) {
if (resizing_workarea) {
long frame = panel_timeline->getFrameFromScreenPoint(event->pos().x());
panel_timeline->snap_to_clip(&frame, true);
if (resizing_workarea_in) {
temp_workarea_in = qMax(qMin(temp_workarea_out-1, frame), 0L);
} else {
temp_workarea_out = qMin(qMax(temp_workarea_in+1, frame), sequence_end);
}
panel_timeline->repaint_timeline();
} else {
set_playhead(event->pos().x());
}
} else {
resizing_workarea = false;
unsetCursor();
if (sequence->using_workarea) {
long min_frame = panel_timeline->getFrameFromScreenPoint(event->pos().x() - CLICK_RANGE) - 1;
long max_frame = panel_timeline->getFrameFromScreenPoint(event->pos().x() + CLICK_RANGE) + 1;
if (sequence->workarea_in > min_frame && sequence->workarea_in < max_frame) {
resizing_workarea = true;
resizing_workarea_in = true;
} else if (sequence->workarea_out > min_frame && sequence->workarea_out < max_frame) {
resizing_workarea = true;
resizing_workarea_in = false;
}
if (resizing_workarea) {
temp_workarea_in = sequence->workarea_in;
temp_workarea_out = sequence->workarea_out;
setCursor(Qt::SizeHorCursor);
}
}
}
}
void TimelineHeader::mouseReleaseEvent(QMouseEvent *) {
void TimelineHeader::mouseReleaseEvent(QMouseEvent*) {
if (resizing_workarea) {
TimelineAction* ta = new TimelineAction();
ta->set_in_out(sequence, true, temp_workarea_in, temp_workarea_out);
undo_stack.push(ta);
}
resizing_workarea = false;
dragging = false;
panel_timeline->snapped = false;
panel_timeline->repaint_timeline();
@@ -60,9 +128,9 @@ void TimelineHeader::paintEvent(QPaintEvent*) {
// draw in/out selection
int in_x;
if (panel_timeline->using_workarea) {
in_x = panel_timeline->getScreenPointFromFrame(panel_timeline->workarea_in);
int out_x = panel_timeline->getScreenPointFromFrame(panel_timeline->workarea_out);
if (sequence->using_workarea) {
in_x = panel_timeline->getScreenPointFromFrame(resizing_workarea ? temp_workarea_in : sequence->workarea_in);
int out_x = panel_timeline->getScreenPointFromFrame(resizing_workarea ? temp_workarea_out :sequence->workarea_out);
p.fillRect(QRect(in_x, 0, out_x-in_x, height()), QColor(0, 192, 255, 128));
p.setPen(Qt::white);
p.drawLine(in_x, 0, in_x, height());
+8
View File
@@ -8,6 +8,8 @@ class TimelineHeader : public QWidget
Q_OBJECT
public:
explicit TimelineHeader(QWidget *parent = 0);
void set_in_point(long p);
void set_out_point(long p);
protected:
void paintEvent(QPaintEvent*);
@@ -18,6 +20,12 @@ protected:
private:
bool dragging;
bool resizing_workarea;
bool resizing_workarea_in;
long temp_workarea_in;
long temp_workarea_out;
long sequence_end;
signals:
public slots:
+1 -1
View File
@@ -755,7 +755,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
}
}
}
panel_timeline->snapped = (temp_frame_diff == frame_diff);
if (temp_frame_diff != frame_diff) panel_timeline->snapped = false;
// apply changes to ghosts
for (int i=0;i<panel_timeline->ghosts.size();i++) {