finished new/load/save

This commit is contained in:
itsmattkc
2018-06-10 23:39:28 -07:00
parent 94fae972cf
commit 093b68cb67
28 changed files with 441 additions and 154 deletions
+5 -7
View File
@@ -75,6 +75,11 @@ ExportDialog::ExportDialog(QWidget *parent) :
ui->formatCombobox->addItem(format_strings[i]);
}
ui->formatCombobox->setCurrentIndex(FORMAT_MPEG4);
ui->widthSpinbox->setValue(sequence->width);
ui->heightSpinbox->setValue(sequence->height);
ui->samplingRateSpinbox->setValue(sequence->audio_frequency);
ui->framerateSpinbox->setValue(sequence->frame_rate);
}
ExportDialog::~ExportDialog()
@@ -442,13 +447,6 @@ void ExportDialog::on_pushButton_clicked()
}
}
void ExportDialog::set_defaults(Sequence* s) {
ui->widthSpinbox->setValue(s->width);
ui->heightSpinbox->setValue(s->height);
ui->samplingRateSpinbox->setValue(s->audio_frequency);
ui->framerateSpinbox->setValue(s->frame_rate);
}
void ExportDialog::update_progress_bar(int value) {
ui->progressBar->setValue(value);
}
+1 -3
View File
@@ -15,9 +15,7 @@ class ExportDialog : public QDialog
Q_OBJECT
public:
explicit ExportDialog(QWidget *parent = 0);
~ExportDialog();
void set_defaults(Sequence* s);
~ExportDialog();
private slots:
void on_formatCombobox_currentIndexChanged(int index);
+2
View File
@@ -53,6 +53,7 @@ public:
VolumeEffect(Clip* c);
void process_audio(uint8_t* samples, int nb_bytes);
Effect* copy();
void load(QXmlStreamReader* stream);
void save(QXmlStreamWriter* stream);
QSpinBox* volume_val;
@@ -63,6 +64,7 @@ public:
PanEffect(Clip* c);
void process_audio(uint8_t* samples, int nb_bytes);
Effect* copy();
void load(QXmlStreamReader* stream);
void save(QXmlStreamWriter* stream);
QSpinBox* pan_val;
+10
View File
@@ -31,6 +31,16 @@ Effect* PanEffect::copy() {
return p;
}
void PanEffect::load(QXmlStreamReader *stream) {
while (!(stream->isEndElement() && stream->name() == "effect") && !stream->atEnd()) {
stream->readNext();
if (stream->isStartElement() && stream->name() == "pan") {
stream->readNext();
pan_val->setValue(stream->text().toInt());
}
}
}
void PanEffect::save(QXmlStreamWriter *stream) {
stream->writeTextElement("pan", QString::number(pan_val->value()));
}
+10
View File
@@ -31,6 +31,16 @@ Effect* VolumeEffect::copy() {
return v;
}
void VolumeEffect::load(QXmlStreamReader *stream) {
while (!(stream->isEndElement() && stream->name() == "effect") && !stream->atEnd()) {
stream->readNext();
if (stream->isStartElement() && stream->name() == "volume") {
stream->readNext();
volume_val->setValue(stream->text().toInt());
}
}
}
void VolumeEffect::save(QXmlStreamWriter *stream) {
stream->writeTextElement("volume", QString::number(volume_val->value()));
}
-2
View File
@@ -49,8 +49,6 @@ bool encode(AVFormatContext* fmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame,
void ExportThread::run() {
av_log_set_level(AV_LOG_DEBUG);
Sequence* sequence = panel_timeline->sequence;
// TODO make customizable
long start = 0;
long end = sequence->getEndFrame();
+59 -2
View File
@@ -15,6 +15,10 @@
#include <QDebug>
#include <QStyleFactory>
#include <QMessageBox>
#include <QFileDialog>
#define OLIVE_FILE_FILTER "Olive Project (*.ove)"
void MainWindow::setup_layout() {
panel_project = new Project(this);
@@ -133,7 +137,6 @@ void MainWindow::on_actionTimeline_Track_Lines_toggled(bool e)
void MainWindow::on_actionExport_triggered()
{
ExportDialog e(this);
if (panel_timeline->sequence != NULL) e.set_defaults(panel_timeline->sequence);
e.exec();
}
@@ -204,7 +207,61 @@ void MainWindow::on_action_Paste_triggered()
}
}
bool MainWindow::save_project_as() {
QString fn = QFileDialog::getSaveFileName(this, "Save Project As...", "", OLIVE_FILE_FILTER);
if (!fn.isEmpty()) {
project_url = fn;
panel_project->save_project();
return true;
}
return false;
}
bool MainWindow::save_project() {
if (project_url.isEmpty()) {
return save_project_as();
} else {
panel_project->save_project();
return true;
}
}
bool MainWindow::can_close_project() {
if (project_changed) {
int r = QMessageBox::question(this, "Unsaved Project", "This project has changed since it was last saved. Would you like to save it before closing?", QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes);
if (r == QMessageBox::Yes) {
return save_project();
} else if (r == QMessageBox::Cancel) {
return false;
}
}
return true;
}
void MainWindow::on_action_Save_Project_triggered()
{
panel_project->save_project();
save_project();
}
void MainWindow::on_action_Open_Project_triggered()
{
if (can_close_project()) {
QString fn = QFileDialog::getOpenFileName(this, "Open Project...", "", OLIVE_FILE_FILTER);
if (!fn.isEmpty()) {
project_url = fn;
panel_project->load_project();
}
}
}
void MainWindow::on_actionProject_triggered()
{
if (can_close_project()) {
panel_project->new_project();
}
}
void MainWindow::on_actionSave_Project_As_triggered()
{
save_project_as();
}
+9
View File
@@ -65,9 +65,18 @@ private slots:
void on_action_Save_Project_triggered();
void on_action_Open_Project_triggered();
void on_actionProject_triggered();
void on_actionSave_Project_As_triggered();
private:
Ui::MainWindow *ui;
void setup_layout();
bool save_project_as();
bool save_project();
bool can_close_project();
};
#endif // MAINWINDOW_H
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.1, 2018-06-10T00:00:44. -->
<!-- Written by QtCreator 4.6.1, 2018-06-10T11:24:49. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
+259 -71
View File
@@ -5,6 +5,8 @@
#include "panels/panels.h"
#include "panels/timeline.h"
#include "panels/viewer.h"
#include "playback/playback.h"
#include "effects/effects.h"
#include <QFileDialog>
#include <QString>
@@ -24,6 +26,9 @@ extern "C" {
#include <libavcodec/avcodec.h>
}
bool project_changed = false;
QString project_url = "";
Project::Project(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::Project)
@@ -69,13 +74,80 @@ void Project::new_sequence(Sequence *s) {
ui->treeWidget->addTopLevelItem(item);
source_table = ui->treeWidget;
project_changed = true;
}
Media* Project::import_file(QString file) {
QByteArray ba = file.toLatin1();
char* filename = new char[ba.size()+1];
strcpy(filename, ba.data());
Media* m = NULL;
AVFormatContext* pFormatCtx = NULL;
int errCode = avformat_open_input(&pFormatCtx, filename, NULL, NULL);
if(errCode != 0) {
char err[1024];
av_strerror(errCode, err, 1024);
qDebug() << "[ERROR] Could not open" << filename << "-" << err;
} else {
errCode = avformat_find_stream_info(pFormatCtx, NULL);
if (errCode < 0) {
char err[1024];
av_strerror(errCode, err, 1024);
fprintf(stderr, "[ERROR] Could not find stream information. %s\n", err);
} else {
av_dump_format(pFormatCtx, 0, filename, 0);
m = new Media();
m->is_sequence = false;
m->url = file;
// detect video/audio streams in file
for (int i=0;i<(int)pFormatCtx->nb_streams;i++) {
// Find the decoder for the video stream
if (avcodec_find_decoder(pFormatCtx->streams[i]->codecpar->codec_id) == NULL) {
qDebug() << "[ERROR] Unsupported codec in stream %d.\n";
} else {
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
qDebug() << "[WARNING] INFINITE_LENGTH calculation is inaccurate in this build\n";
// TODO BETTER infinite length calculator
bool infinite_length = (pFormatCtx->streams[i]->nb_frames == 0);
// bool infinite_length = false;
m->video_tracks.append({i, pFormatCtx->streams[i]->codecpar->width, pFormatCtx->streams[i]->codecpar->height, infinite_length});
} else if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
m->audio_tracks.append({i, 0, 0, false});
}
}
}
m->name = file.mid(file.lastIndexOf('/')+1);
m->length = pFormatCtx->duration;
QTreeWidgetItem* item = new QTreeWidgetItem();
if (m->video_tracks.size() == 0) {
item->setIcon(0, QIcon(":/icons/audiosource.png"));
} else {
item->setIcon(0, QIcon(":/icons/videosource.png"));
}
item->setText(0, m->name);
item->setText(1, QString::number(m->length));
set_media_of_tree(item, m);
ui->treeWidget->addTopLevelItem(item);
project_changed = true;
}
}
avformat_close_input(&pFormatCtx);
delete [] filename;
return m;
}
void Project::import_dialog() {
QStringList files = QFileDialog::getOpenFileNames(this, "Import media...", "", "All Files (*.*)");
for (int i=0;i<files.count();i++) {
QString file(files.at(i));
char* filename = NULL;
// heuristic to determine whether file is part of an image sequence
int lastcharindex = file.lastIndexOf(".")-1;
@@ -108,65 +180,7 @@ void Project::import_dialog() {
}
}
QByteArray ba = file.toLatin1();
filename = new char[ba.size()+1];
strcpy(filename, ba.data());
AVFormatContext* pFormatCtx = NULL;
int errCode = avformat_open_input(&pFormatCtx, filename, NULL, NULL);
if(errCode != 0) {
char err[1024];
av_strerror(errCode, err, 1024);
qDebug() << "[ERROR] Could not open" << filename << "-" << err;
} else {
errCode = avformat_find_stream_info(pFormatCtx, NULL);
if (errCode < 0) {
char err[1024];
av_strerror(errCode, err, 1024);
fprintf(stderr, "[ERROR] Could not find stream information. %s\n", err);
} else {
av_dump_format(pFormatCtx, 0, filename, 0);
Media* m = new Media();
m->is_sequence = false;
m->url = file;
// detect video/audio streams in file
for (int i=0;i<(int)pFormatCtx->nb_streams;i++) {
// Find the decoder for the video stream
if (avcodec_find_decoder(pFormatCtx->streams[i]->codecpar->codec_id) == NULL) {
qDebug() << "[ERROR] Unsupported codec in stream %d.\n";
} else {
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
qDebug() << "[WARNING] INFINITE_LENGTH calculation is inaccurate in this build\n";
// TODO BETTER infinite length calculator
bool infinite_length = (pFormatCtx->streams[i]->nb_frames == 0);
// bool infinite_length = false;
m->video_tracks.append({i, pFormatCtx->streams[i]->codecpar->width, pFormatCtx->streams[i]->codecpar->height, infinite_length});
} else if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
m->audio_tracks.append({i, 0, 0, false});
}
}
}
m->name = files.at(i).mid(files.at(i).lastIndexOf('/')+1);
m->length = pFormatCtx->duration;
QTreeWidgetItem* item = new QTreeWidgetItem();
if (m->video_tracks.size() == 0) {
item->setIcon(0, QIcon(":/icons/audiosource.png"));
} else {
item->setIcon(0, QIcon(":/icons/videosource.png"));
}
item->setText(0, m->name);
item->setText(1, QString::number(m->length));
set_media_of_tree(item, m);
ui->treeWidget->addTopLevelItem(item);
}
}
avformat_close_input(&pFormatCtx);
delete [] filename;
import_file(file);
}
}
@@ -185,26 +199,35 @@ void Project::remove_item(int i) {
}
delete m;
ui->treeWidget->takeTopLevelItem(i);
project_changed = true;
}
void Project::clear() {
int len = ui->treeWidget->topLevelItemCount();
for (int i=0;i<len;i++) {
remove_item(i);
while (ui->treeWidget->topLevelItemCount() > 0) {
remove_item(0);
}
}
void Project::set_sequence(Sequence* s) {
panel_timeline->set_sequence(s);
panel_viewer->set_sequence(s);
}
void Project::load_project() {
void Project::new_project() {
// clear existing project
set_sequence(NULL);
clear();
project_changed = false;
}
QFile file("C:/Users/Matt/Desktop/test.xml");
#define LOAD_STATE_IDLE 0
#define LOAD_STATE_MEDIA 1
#define LOAD_STATE_FOOTAGE 2
#define LOAD_STATE_TIMELINE 3
#define LOAD_STATE_SEQUENCE 4
#define LOAD_STATE_CLIP 5
#define LOAD_STATE_CLIP_EFFECTS 6
#define LOAD_STATE_EFFECT 7
void Project::load_project() {
new_project();
QFile file(project_url);
if (!file.open(QIODevice::ReadOnly/* | QIODevice::Text*/)) {
qDebug() << "[ERROR] Could not open file";
return;
@@ -212,17 +235,174 @@ void Project::load_project() {
QXmlStreamReader stream(&file);
// temp variables for loading
QVector<Media*> temp_media_list;
QString temp_name;
QString temp_url;
int temp_media_id;
Sequence* temp_seq;
Clip* temp_clip;
int state = LOAD_STATE_IDLE;
while (!stream.atEnd()) {
stream.readNext();
switch (state) {
case LOAD_STATE_IDLE:
if (stream.isStartElement()) {
if (stream.name() == "footage") {
for (int j=0;j<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name() == "id") {
temp_media_id = attr.value().toInt();
}
}
state = LOAD_STATE_FOOTAGE;
} else if (stream.name() == "sequence") {
temp_seq = new Sequence();
state = LOAD_STATE_SEQUENCE;
}
}
break;
case LOAD_STATE_FOOTAGE:
if (stream.isEndElement() && stream.name() == "footage") {
Media* m = import_file(temp_url);
m->save_id = temp_media_id;
m->name = temp_name;
temp_media_list.append(m);
state = LOAD_STATE_IDLE;
} else if (stream.isStartElement()) {
if (stream.name() == "name") {
stream.readNext();
temp_name = stream.text().toString();
} else if (stream.name() == "url") {
stream.readNext();
temp_url = stream.text().toString();
}
}
break;
case LOAD_STATE_SEQUENCE:
if (stream.isEndElement() && stream.name() == "sequence") {
new_sequence(temp_seq);
state = LOAD_STATE_IDLE;
} else if (stream.isStartElement()) {
if (stream.name() == "name") {
stream.readNext();
temp_seq->name = stream.text().toString();
} else if (stream.name() == "width") {
stream.readNext();
temp_seq->width = stream.text().toInt();
} else if (stream.name() == "height") {
stream.readNext();
temp_seq->height = stream.text().toInt();
} else if (stream.name() == "framerate") {
stream.readNext();
temp_seq->frame_rate = stream.text().toFloat();
} else if (stream.name() == "afreq") {
stream.readNext();
temp_seq->audio_frequency = stream.text().toInt();
} else if (stream.name() == "alayout") {
stream.readNext();
temp_seq->audio_layout = stream.text().toInt();
} else if (stream.name() == "clip") {
temp_clip = new Clip();
temp_clip->sequence = temp_seq;
state = LOAD_STATE_CLIP;
}
}
break;
case LOAD_STATE_CLIP:
if (stream.isEndElement() && stream.name() == "clip") {
temp_seq->add_clip(temp_clip);
state = LOAD_STATE_SEQUENCE;
} else if (stream.isStartElement()) {
if (stream.name() == "name") {
stream.readNext();
temp_clip->name = stream.text().toString();
} else if (stream.name() == "clipin") {
stream.readNext();
temp_clip->clip_in = stream.text().toInt();
} else if (stream.name() == "in") {
stream.readNext();
temp_clip->timeline_in = stream.text().toInt();
} else if (stream.name() == "out") {
stream.readNext();
temp_clip->timeline_out = stream.text().toInt();
} else if (stream.name() == "track") {
stream.readNext();
temp_clip->track = stream.text().toInt();
} else if (stream.name() == "color") {
for (int j=0;j<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name().toString() == QLatin1String("r")) {
temp_clip->color_r = attr.value().toInt();
} else if (attr.name().toString() == QLatin1String("g")) {
temp_clip->color_g = attr.value().toInt();
} else if (attr.name().toString() == QLatin1String("b")) {
temp_clip->color_b = attr.value().toInt();
}
}
} else if (stream.name() == "media") {
stream.readNext();
for (int i=0;i<temp_media_list.size();i++) {
Media* m = temp_media_list.at(i);
if (m->save_id == stream.text().toInt()) {
temp_clip->media = m;
break;
}
}
} else if (stream.name() == "stream") {
// TODO very unintelligent code - i hate this
int stream_index = stream.text().toInt();
bool found = false;
for (int i=0;i<temp_clip->media->video_tracks.size();i++) {
if (temp_clip->media->video_tracks.at(i).file_index == stream_index) {
temp_clip->media_stream = &temp_clip->media->video_tracks[i];
found = true;
break;
}
}
if (!found) {
for (int i=0;i<temp_clip->media->audio_tracks.size();i++) {
if (temp_clip->media->audio_tracks.at(i).file_index == stream_index) {
temp_clip->media_stream = &temp_clip->media->audio_tracks[i];
found = true;
break;
}
}
}
if (!found) {
qDebug() << "[WARNING] Could not load media stream - project file seems corrupt";
}
} else if (stream.name() == "effect") {
int effect_id = -1;
for (int j=0;j<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name().toString() == QLatin1String("id")) {
effect_id = attr.value().toInt();
}
}
if (effect_id != -1) {
Effect* e = create_effect(effect_id, temp_clip);
e->load(&stream);
temp_clip->effects.append(e);
state = LOAD_STATE_CLIP;
}
}
}
break;
}
qDebug() << "read element:" << stream.name() << "- text:" << stream.text() << "- start:" << stream.isStartElement() << "- end:" << stream.isEndElement();
}
if (stream.hasError()) {
qDebug() << "[ERROR] Error parsing XML." << stream.error();
}
project_changed = false;
}
void Project::save_project() {
QFile file("C:/Users/Matt/Desktop/test.xml");
QFile file(project_url);
if (!file.open(QIODevice::WriteOnly/* | QIODevice::Text*/)) {
qDebug() << "[ERROR] Could not open file";
return;
@@ -232,6 +412,10 @@ void Project::save_project() {
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("project");
stream.writeTextElement("version", "180601");
int len = ui->treeWidget->topLevelItemCount();
stream.writeStartElement("media");
for (int i=0;i<len;i++) {
@@ -292,7 +476,11 @@ void Project::save_project() {
}
stream.writeEndElement();
stream.writeEndElement();
stream.writeEndDocument();
file.close();
project_changed = false;
}
+6 -2
View File
@@ -15,6 +15,9 @@ namespace Ui {
class Project;
}
extern bool project_changed;
extern QString project_url;
class Project : public QDockWidget
{
Q_OBJECT
@@ -23,12 +26,13 @@ public:
explicit Project(QWidget *parent = 0);
~Project();
void clear();
void import_dialog();
void set_sequence(Sequence* s);
Media* import_file(QString url);
void import_dialog();
void new_sequence(Sequence* s);
QString get_next_sequence_name();
void remove_item(int i);
void new_project();
void load_project();
void save_project();
+5 -15
View File
@@ -2,6 +2,7 @@
#include "ui_timeline.h"
#include "panels/panels.h"
#include "panels/project.h"
#include "panels/effectcontrols.h"
#include "ui/timelinewidget.h"
#include "project/sequence.h"
@@ -38,8 +39,7 @@ Timeline::Timeline(QWidget *parent) :
zoom = 1.0f;
sequence = NULL;
set_sequence(NULL);
update_sequence();
connect(&playback_updater, SIGNAL(timeout()), this, SLOT(repaint_timeline()));
}
@@ -103,19 +103,8 @@ void Timeline::go_to_end() {
seek(sequence->getEndFrame());
}
void Timeline::set_sequence(Sequence *s) {
if (sequence != NULL) {
// clean up - close all open clips
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
if (c->open) {
close_clip(c);
}
}
}
sequence = s;
bool null_sequence = (s == NULL);
void Timeline::update_sequence() {
bool null_sequence = (sequence == NULL);
for (int i=0;i<tool_buttons.count();i++) {
tool_buttons[i]->setEnabled(!null_sequence);
@@ -173,6 +162,7 @@ void Timeline::repaint_timeline() {
void Timeline::redraw_all_clips() {
// add current sequence to the undo stack
sequence->undo_add_current();
project_changed = true;
ui->video_area->redraw_clips();
ui->audio_area->redraw_clips();
+1 -2
View File
@@ -67,14 +67,13 @@ public:
void paste();
bool split_selection();
void split_at_playhead();
void set_sequence(Sequence* s);
void update_sequence();
int getScreenPointFromFrame(long frame);
long getFrameFromScreenPoint(int x);
void snap_to_clip(long* l);
Sequence* sequence;
long playhead;
// playback functions
+5 -7
View File
@@ -19,19 +19,17 @@ Viewer::Viewer(QWidget *parent) :
ui->setupUi(this);
ui->glViewerPane->child = ui->openGLWidget;
viewer_widget = ui->openGLWidget;
set_sequence(NULL);
update_sequence();
}
Viewer::~Viewer()
{
init_audio(NULL);
init_audio();
delete ui;
}
void Viewer::set_sequence(Sequence* s) {
bool null_sequence = (s == NULL);
sequence = s;
void Viewer::update_sequence() {
bool null_sequence = (sequence == NULL);
ui->openGLWidget->setEnabled(!null_sequence);
ui->openGLWidget->setVisible(!null_sequence);
@@ -41,7 +39,7 @@ void Viewer::set_sequence(Sequence* s) {
ui->pushButton_4->setEnabled(!null_sequence);
ui->pushButton_5->setEnabled(!null_sequence);
init_audio(s);
init_audio();
if (!null_sequence) {
ui->glViewerPane->aspect_ratio = (float) sequence->width / (float) sequence->height;
+1 -2
View File
@@ -18,10 +18,9 @@ class Viewer : public QDockWidget
public:
explicit Viewer(QWidget *parent = 0);
~Viewer();
void set_sequence(Sequence* s);
void update_sequence();
void compose();
Sequence* sequence;
ViewerWidget* viewer_widget;
private slots:
+4 -4
View File
@@ -17,17 +17,17 @@ qint8 audio_ibuffer[audio_ibuffer_size];
int audio_ibuffer_read = 0;
QVector<int> audio_ibuffer_write;
void init_audio(Sequence* s) {
void init_audio() {
if (audio_device_set) {
audio_output->stop();
delete audio_output;
audio_device_set = false;
}
if (s != NULL) {
if (sequence != NULL) {
QAudioFormat audio_format;
audio_format.setSampleRate(s->audio_frequency);
audio_format.setChannelCount(av_get_channel_layout_nb_channels(s->audio_layout));
audio_format.setSampleRate(sequence->audio_frequency);
audio_format.setChannelCount(av_get_channel_layout_nb_channels(sequence->audio_layout));
audio_format.setSampleSize(16);
audio_format.setCodec("audio/pcm");
audio_format.setByteOrder(QAudioFormat::LittleEndian);
+1 -1
View File
@@ -17,6 +17,6 @@ extern int audio_ibuffer_read;
//extern QVector<int> audio_ibuffer_write;
void clear_audio_ibuffer();
void init_audio(Sequence* s);
void init_audio();
#endif // AUDIO_H
+17
View File
@@ -5,7 +5,9 @@
#include "io/media.h"
#include "playback/audio.h"
#include "playback/cacher.h"
#include "panels/panels.h"
#include "panels/timeline.h"
#include "panels/viewer.h"
#include <algorithm>
extern "C" {
@@ -287,3 +289,18 @@ void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) {
bool is_clip_active(Clip* c, long playhead) {
return c->timeline_in < playhead + ceil(c->sequence->frame_rate) && c->timeline_out > playhead;
}
void set_sequence(Sequence* s) {
if (sequence != NULL) {
// clean up - close all open clips
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
if (c->open) {
close_clip(c);
}
}
}
sequence = s;
panel_timeline->update_sequence();
panel_viewer->update_sequence();
}
+1
View File
@@ -29,6 +29,7 @@ int retrieve_next_frame(Clip* c, AVFrame* f);
void retrieve_next_frame_raw_data(Clip* c, AVFrame* output);
bool is_clip_active(Clip* c, long playhead);
void get_next_audio(Clip* c, bool mix);
void set_sequence(Sequence* s);
struct ClipCacheData {
Clip& clip;
-1
View File
@@ -38,7 +38,6 @@ Clip* Clip::copy() {
}
void Clip::init() {
qDebug() << "init was called";
reset();
clip_in = timeline_in = timeline_out = track = undeletable = 0;
texture = NULL;
+1
View File
@@ -29,6 +29,7 @@ void Effect::field_changed() {
}
Effect* Effect::copy() {return NULL;}
void Effect::load(QXmlStreamReader* stream) {}
void Effect::save(QXmlStreamWriter *stream) {}
void Effect::process_gl(int*, int*) {}
+2
View File
@@ -7,6 +7,7 @@ class QWidget;
class CollapsibleWidget;
struct Clip;
class QXmlStreamReader;
class QXmlStreamWriter;
enum EffectTypes { EFFECT_TYPE_INVALID, EFFECT_TYPE_VIDEO, EFFECT_TYPE_AUDIO };
@@ -24,6 +25,7 @@ public:
Clip* parent_clip;
virtual Effect* copy();
virtual void load(QXmlStreamReader* stream);
virtual void save(QXmlStreamWriter* stream);
virtual void process_gl(int* anchor_x, int* anchor_y);
+3
View File
@@ -162,3 +162,6 @@ void Sequence::redo() {
set_undo(undo_pointer);
}
}
// static variable for the currently active sequence
Sequence* sequence = NULL;
+3
View File
@@ -38,4 +38,7 @@ private:
int undo_stack_start;
};
// static variable for the currently active sequence
extern Sequence* sequence;
#endif // SEQUENCE_H
+2 -1
View File
@@ -5,6 +5,7 @@
#include "panels/timeline.h"
#include "panels/viewer.h"
#include "panels/panels.h"
#include "playback/playback.h"
#include <QDragEnterEvent>
@@ -19,7 +20,7 @@ void SourceTable::mouseDoubleClickEvent(QMouseEvent* )
} else if (selectedItems().count() == 1) {
Media* m = reinterpret_cast<Media*>(selectedItems().at(0)->data(0, Qt::UserRole + 1).value<quintptr>());
if (m->is_sequence) {
panel_project->set_sequence(m->sequence);
set_sequence(m->sequence);
}
}
}
+2 -2
View File
@@ -37,10 +37,10 @@ void TimelineHeader::mouseReleaseEvent(QMouseEvent *) {
}
void TimelineHeader::paintEvent(QPaintEvent*) {
if (panel_timeline->sequence != NULL) {
if (sequence != NULL) {
QPainter p(this);
p.setPen(Qt::gray);
int interval = panel_timeline->getScreenPointFromFrame(panel_timeline->sequence->frame_rate);
int interval = panel_timeline->getScreenPointFromFrame(sequence->frame_rate);
for (int i=0;i<width();i+=interval) {
p.drawLine(i, 0, i, height());
}
+30 -30
View File
@@ -34,7 +34,7 @@ bool same_sign(int a, int b) {
}
void TimelineWidget::resizeEvent(QResizeEvent*) {
if (panel_timeline->sequence != NULL) redraw_clips();
if (sequence != NULL) redraw_clips();
}
void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
@@ -48,7 +48,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
for (int i=0;i<items.size();i++) {
bool ignore_infinite_length = false;
Media* m = panel_project->get_media_from_tree(items.at(i));
long duration = m->get_length_in_frames(panel_timeline->sequence->frame_rate);
long duration = m->get_length_in_frames(sequence->frame_rate);
Ghost g = {NULL, entry_point, entry_point + duration};
g.media = m;
g.clip_in = 0;
@@ -94,7 +94,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) {
for (int i=0;i<panel_timeline->ghosts.size();i++) {
const Ghost& g = panel_timeline->ghosts.at(i);
panel_timeline->sequence->delete_area(g.in, g.out, g.track);
sequence->delete_area(g.in, g.out, g.track);
Clip* c = new Clip();
c->media = g.media;
@@ -105,7 +105,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) {
c->color_r = 128;
c->color_g = 128;
c->color_b = 192;
c->sequence = panel_timeline->sequence;
c->sequence = sequence;
c->track = g.track;
c->name = c->media->name;
@@ -118,7 +118,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) {
c->effects.append(create_effect(AUDIO_PAN_EFFECT, c));
}
panel_timeline->sequence->add_clip(c);
sequence->add_clip(c);
}
panel_timeline->ghosts.clear();
@@ -156,7 +156,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
panel_timeline->selections.clear();
}
Clip* clip = panel_timeline->sequence->get_clip(clip_index);
Clip* clip = sequence->get_clip(clip_index);
panel_timeline->selections.append({clip->timeline_in, clip->timeline_out, clip->track});
}
panel_timeline->moving_init = true;
@@ -173,7 +173,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
case TIMELINE_TOOL_RAZOR:
{
if (clip_index >= 0) {
panel_timeline->sequence->split_clip(clip_index, panel_timeline->drag_frame_start);
sequence->split_clip(clip_index, panel_timeline->drag_frame_start);
}
panel_timeline->splitting = true;
panel_timeline->redraw_all_clips();
@@ -195,9 +195,9 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
c->track = g.track;
// step 2 - delete anything that exists in area that clip is moving to
panel_timeline->sequence->delete_area(g.in, g.out, g.track);
sequence->delete_area(g.in, g.out, g.track);
panel_timeline->sequence->add_clip(c);
sequence->add_clip(c);
}
} else {
// move clips
@@ -212,7 +212,7 @@ 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
panel_timeline->sequence->delete_area(g.in, g.out, g.track);
sequence->delete_area(g.in, g.out, g.track);
}
// step 3 - move clips
@@ -270,7 +270,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
// find out how many clips are selected
bool single_select = false;
int selected_clip = 0;
for (int i=0;i<panel_timeline->sequence->clip_count();i++) {
for (int i=0;i<sequence->clip_count();i++) {
if (panel_timeline->is_clip_selected(i)) {
if (!single_select) {
// found ONE selected clip
@@ -284,7 +284,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
}
}
if (single_select) {
panel_effect_controls->set_clip(panel_timeline->sequence->get_clip(selected_clip));
panel_effect_controls->set_clip(sequence->get_clip(selected_clip));
} else {
panel_effect_controls->set_clip(NULL);
}
@@ -301,7 +301,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(panel_timeline->sequence->frame_rate);
g.media_length = g.clip->media->get_length_in_frames(sequence->frame_rate);
}
}
for (int i=0;i<panel_timeline->selections.size();i++) {
@@ -335,8 +335,8 @@ void validate_snapping(Ghost& g, long* frame_diff) {
panel_timeline->snapped = false;
if (panel_timeline->snapping) {
if (!subvalidate_snapping(g, frame_diff, panel_timeline->playhead)) {
for (int j=0;j<panel_timeline->sequence->clip_count();j++) {
Clip* c = panel_timeline->sequence->get_clip(j);
for (int j=0;j<sequence->clip_count();j++) {
Clip* c = sequence->get_clip(j);
if (!subvalidate_snapping(g, frame_diff, c->timeline_in)) {
subvalidate_snapping(g, frame_diff, c->timeline_out);
}
@@ -572,9 +572,9 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
} else {
// set up movement
// create ghosts
for (int i=0;i<panel_timeline->sequence->clip_count();i++) {
for (int i=0;i<sequence->clip_count();i++) {
if (panel_timeline->is_clip_selected(i)) {
Clip* c = panel_timeline->sequence->get_clip(i);
Clip* c = sequence->get_clip(i);
panel_timeline->ghosts.append({c, c->timeline_in, c->timeline_out, c->track, c->clip_in});
}
}
@@ -583,10 +583,10 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) {
for (int i=0;i<panel_timeline->ghosts.size();i++) {
// get clips before and after ripple point
for (int j=0;j<panel_timeline->sequence->clip_count();j++) {
for (int j=0;j<sequence->clip_count();j++) {
// don't cache any currently selected clips
Clip* c = panel_timeline->ghosts.at(i).clip;
Clip* cc = panel_timeline->sequence->get_clip(j);
Clip* cc = sequence->get_clip(j);
bool is_selected = false;
for (int k=0;k<panel_timeline->ghosts.size();k++) {
if (panel_timeline->ghosts.at(k).clip == cc) {
@@ -647,9 +647,9 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
} else if (panel_timeline->splitting) {
int track = panel_timeline->cursor_track;
bool repaint = false;
for (int i=0;i<panel_timeline->sequence->clip_count();i++) {
if (panel_timeline->sequence->get_clip(i)->track == track) {
panel_timeline->sequence->split_clip(i, panel_timeline->drag_frame_start);
for (int i=0;i<sequence->clip_count();i++) {
if (sequence->get_clip(i)->track == track) {
sequence->split_clip(i, panel_timeline->drag_frame_start);
repaint = true;
}
}
@@ -664,8 +664,8 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
long mouse_frame_lower = panel_timeline->getFrameFromScreenPoint(pos.x()-lim)-1;
long mouse_frame_upper = panel_timeline->getFrameFromScreenPoint(pos.x()+lim)+1;
bool found = false;
for (int i=0;i<panel_timeline->sequence->clip_count();i++) {
Clip* c = panel_timeline->sequence->get_clip(i);
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
if (c->track == mouse_track) {
if (c->timeline_in > mouse_frame_lower && c->timeline_in < mouse_frame_upper) {
panel_timeline->trim_target = i;
@@ -704,7 +704,7 @@ int color_brightness(int r, int g, int b) {
void TimelineWidget::redraw_clips() {
// Draw clips
int panel_width = panel_timeline->getScreenPointFromFrame(panel_timeline->sequence->getEndFrame()) + 100;
int panel_width = panel_timeline->getScreenPointFromFrame(sequence->getEndFrame()) + 100;
setMinimumWidth(panel_width);
clip_pixmap = QPixmap(panel_width, height());
@@ -712,8 +712,8 @@ void TimelineWidget::redraw_clips() {
QPainter clip_painter(&clip_pixmap);
int video_track_limit = 0;
int audio_track_limit = 0;
for (int i=0;i<panel_timeline->sequence->clip_count();i++) {
Clip* clip = panel_timeline->sequence->get_clip(i);
for (int i=0;i<sequence->clip_count();i++) {
Clip* clip = sequence->get_clip(i);
if (is_track_visible(clip->track)) {
if (clip->track < 0 && clip->track < video_track_limit) { // video clip
video_track_limit = clip->track;
@@ -765,7 +765,7 @@ void TimelineWidget::redraw_clips() {
}
void TimelineWidget::paintEvent(QPaintEvent*) {
if (panel_timeline->sequence != NULL) {
if (sequence != NULL) {
QPainter p(this);
p.drawPixmap(0, 0, minimumWidth(), height(), clip_pixmap);
@@ -859,8 +859,8 @@ int TimelineWidget::getScreenPointFromTrack(int track) {
}
int TimelineWidget::getClipIndexFromCoords(long frame, int track) {
for (int i=0;i<panel_timeline->sequence->clip_count();i++) {
Clip* c = panel_timeline->sequence->get_clip(i);
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
if (c->track == track) {
if (frame >= c->timeline_in && frame < c->timeline_out) {
return i;
+1 -1
View File
@@ -60,7 +60,7 @@ void ViewerWidget::paintGL()
long playhead = panel_timeline->playhead;
handle_media(panel_viewer->sequence, playhead, multithreaded);
handle_media(sequence, playhead, multithreaded);
texture_failed = false;
bool render_audio = (panel_timeline->playing || force_audio);