First commit of brand new rewrite

This commit is contained in:
itsmattkc
2018-05-30 03:24:12 +10:00
commit 244c092591
86 changed files with 8016 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutDialog)
{
ui->setupUi(this);
}
AboutDialog::~AboutDialog()
{
delete ui;
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef ABOUTDIALOG_H
#define ABOUTDIALOG_H
#include <QDialog>
namespace Ui {
class AboutDialog;
}
class AboutDialog : public QDialog
{
Q_OBJECT
public:
explicit AboutDialog(QWidget *parent = 0);
~AboutDialog();
private:
Ui::AboutDialog *ui;
};
#endif // ABOUTDIALOG_H
+77
View File
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutDialog</class>
<widget class="QDialog" name="AboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>180</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Olive is a professional video editor.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AboutDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+437
View File
@@ -0,0 +1,437 @@
#include "exportdialog.h"
#include "ui_exportdialog.h"
#include <QOpenGLWidget>
#include <QFileDialog>
#include <QThread>
#include <QDebug>
#include "panels/panels.h"
#include "panels/viewer.h"
#include "panels/timeline.h"
#include "ui/viewerwidget.h"
#include "project/sequence.h"
#include "io/exportthread.h"
extern "C" {
#include <libavformat/avformat.h>
}
enum ExportFormats {
FORMAT_3GPP,
FORMAT_AIFF,
FORMAT_APNG,
FORMAT_AVI,
FORMAT_DNXHD,
FORMAT_AC3,
FORMAT_FLV,
FORMAT_GIF,
FORMAT_IMG,
FORMAT_MP2,
FORMAT_MP3,
FORMAT_MPEG1,
FORMAT_MPEG2,
FORMAT_MPEG4,
FORMAT_MPEGTS,
FORMAT_MKV,
FORMAT_OGG,
FORMAT_MOV,
FORMAT_WAV,
FORMAT_WEBM,
FORMAT_WMV,
FORMAT_SIZE
};
ExportDialog::ExportDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ExportDialog)
{
ui->setupUi(this);
format_strings.resize(FORMAT_SIZE);
format_strings[FORMAT_3GPP] = "3GPP";
format_strings[FORMAT_AIFF] = "AIFF";
format_strings[FORMAT_APNG] = "Animated PNG";
format_strings[FORMAT_AVI] = "AVI";
format_strings[FORMAT_DNXHD] = "DNxHD";
format_strings[FORMAT_AC3] = "Dolby Digital (AC3)";
format_strings[FORMAT_FLV] = "FLV";
format_strings[FORMAT_GIF] = "GIF";
format_strings[FORMAT_IMG] = "Image Sequence";
format_strings[FORMAT_MP2] = "MP2 Audio";
format_strings[FORMAT_MP3] = "MP3 Audio";
format_strings[FORMAT_MPEG1] = "MPEG-1 Video";
format_strings[FORMAT_MPEG2] = "MPEG-2 Video";
format_strings[FORMAT_MPEG4] = "MPEG-4 Video";
format_strings[FORMAT_MPEGTS] = "MPEG-TS";
format_strings[FORMAT_MKV] = "Matroska MKV";
format_strings[FORMAT_OGG] = "Ogg";
format_strings[FORMAT_MOV] = "QuickTime MOV";
format_strings[FORMAT_WAV] = "WAVE Audio";
format_strings[FORMAT_WEBM] = "WebM";
format_strings[FORMAT_WMV] = "Windows Media";
for (int i=0;i<FORMAT_SIZE;i++) {
ui->formatCombobox->addItem(format_strings[i]);
}
ui->formatCombobox->setCurrentIndex(FORMAT_MPEG4);
}
ExportDialog::~ExportDialog()
{
delete ui;
}
void ExportDialog::on_formatCombobox_currentIndexChanged(int index)
{
format_vcodecs.clear();
format_acodecs.clear();
ui->vcodecCombobox->clear();
ui->acodecCombobox->clear();
int default_vcodec = 0;
int default_acodec = 0;
switch (index) {
case FORMAT_3GPP:
format_vcodecs.append(AV_CODEC_ID_MPEG4);
format_vcodecs.append(AV_CODEC_ID_H264);
format_acodecs.append(AV_CODEC_ID_AAC);
default_vcodec = 1;
break;
case FORMAT_AIFF:
format_acodecs.append(AV_CODEC_ID_PCM_S16LE);
break;
case FORMAT_APNG:
format_vcodecs.append(AV_CODEC_ID_APNG);
break;
case FORMAT_AVI:
format_vcodecs.append(AV_CODEC_ID_H264);
format_vcodecs.append(AV_CODEC_ID_MPEG4);
format_vcodecs.append(AV_CODEC_ID_MJPEG);
format_vcodecs.append(AV_CODEC_ID_MSVIDEO1);
format_vcodecs.append(AV_CODEC_ID_RAWVIDEO);
format_vcodecs.append(AV_CODEC_ID_HUFFYUV);
format_vcodecs.append(AV_CODEC_ID_DVVIDEO);
format_acodecs.append(AV_CODEC_ID_AAC);
format_acodecs.append(AV_CODEC_ID_AC3);
format_acodecs.append(AV_CODEC_ID_FLAC);
format_acodecs.append(AV_CODEC_ID_MP2);
format_acodecs.append(AV_CODEC_ID_MP3);
format_acodecs.append(AV_CODEC_ID_PCM_S16LE);
default_vcodec = 3;
default_acodec = 5;
break;
case FORMAT_DNXHD:
format_vcodecs.append(AV_CODEC_ID_DNXHD);
format_acodecs.append(AV_CODEC_ID_PCM_S16LE);
break;
case FORMAT_AC3:
format_acodecs.append(AV_CODEC_ID_AC3);
format_acodecs.append(AV_CODEC_ID_EAC3);
break;
case FORMAT_FLV:
format_vcodecs.append(AV_CODEC_ID_FLV1);
format_acodecs.append(AV_CODEC_ID_MP3);
break;
case FORMAT_GIF:
format_vcodecs.append(AV_CODEC_ID_GIF);
break;
case FORMAT_IMG:
format_vcodecs.append(AV_CODEC_ID_BMP);
format_vcodecs.append(AV_CODEC_ID_MJPEG);
format_vcodecs.append(AV_CODEC_ID_JPEG2000);
format_vcodecs.append(AV_CODEC_ID_PSD);
format_vcodecs.append(AV_CODEC_ID_PNG);
format_vcodecs.append(AV_CODEC_ID_TIFF);
default_vcodec = 4;
break;
case FORMAT_MP2:
format_acodecs.append(AV_CODEC_ID_MP2);
break;
case FORMAT_MP3:
format_acodecs.append(AV_CODEC_ID_MP3);
break;
case FORMAT_MPEG1:
format_vcodecs.append(AV_CODEC_ID_MPEG1VIDEO);
format_acodecs.append(AV_CODEC_ID_AC3);
format_acodecs.append(AV_CODEC_ID_MP2);
format_acodecs.append(AV_CODEC_ID_MP3);
format_acodecs.append(AV_CODEC_ID_PCM_S16LE);
default_acodec = 1;
break;
case FORMAT_MPEG2:
format_vcodecs.append(AV_CODEC_ID_MPEG2VIDEO);
format_acodecs.append(AV_CODEC_ID_AC3);
format_acodecs.append(AV_CODEC_ID_MP2);
format_acodecs.append(AV_CODEC_ID_MP3);
format_acodecs.append(AV_CODEC_ID_PCM_S16LE);
default_acodec = 1;
break;
case FORMAT_MPEG4:
format_vcodecs.append(AV_CODEC_ID_MPEG4);
format_vcodecs.append(AV_CODEC_ID_H264);
format_acodecs.append(AV_CODEC_ID_AAC);
format_acodecs.append(AV_CODEC_ID_AC3);
format_acodecs.append(AV_CODEC_ID_MP2);
format_acodecs.append(AV_CODEC_ID_MP3);
default_vcodec = 1;
break;
case FORMAT_MPEGTS:
format_vcodecs.append(AV_CODEC_ID_MPEG2VIDEO);
format_acodecs.append(AV_CODEC_ID_AAC);
format_acodecs.append(AV_CODEC_ID_AC3);
format_acodecs.append(AV_CODEC_ID_MP2);
format_acodecs.append(AV_CODEC_ID_MP3);
default_acodec = 2;
break;
case FORMAT_MKV:
format_vcodecs.append(AV_CODEC_ID_MPEG4);
format_vcodecs.append(AV_CODEC_ID_H264);
format_acodecs.append(AV_CODEC_ID_AAC);
format_acodecs.append(AV_CODEC_ID_AC3);
format_acodecs.append(AV_CODEC_ID_EAC3);
format_acodecs.append(AV_CODEC_ID_FLAC);
format_acodecs.append(AV_CODEC_ID_MP2);
format_acodecs.append(AV_CODEC_ID_MP3);
format_acodecs.append(AV_CODEC_ID_OPUS);
format_acodecs.append(AV_CODEC_ID_PCM_S16LE);
format_acodecs.append(AV_CODEC_ID_VORBIS);
format_acodecs.append(AV_CODEC_ID_WAVPACK);
format_acodecs.append(AV_CODEC_ID_WMAV1);
format_acodecs.append(AV_CODEC_ID_WMAV2);
default_vcodec = 1;
break;
case FORMAT_OGG:
format_vcodecs.append(AV_CODEC_ID_THEORA);
format_acodecs.append(AV_CODEC_ID_OPUS);
format_acodecs.append(AV_CODEC_ID_VORBIS);
default_acodec = AV_CODEC_ID_VORBIS;
break;
case FORMAT_MOV:
format_vcodecs.append(AV_CODEC_ID_QTRLE);
format_vcodecs.append(AV_CODEC_ID_MPEG4);
format_vcodecs.append(AV_CODEC_ID_H264);
format_vcodecs.append(AV_CODEC_ID_MJPEG);
format_vcodecs.append(AV_CODEC_ID_PRORES);
format_acodecs.append(AV_CODEC_ID_AAC);
format_acodecs.append(AV_CODEC_ID_AC3);
format_acodecs.append(AV_CODEC_ID_MP2);
format_acodecs.append(AV_CODEC_ID_MP3);
format_acodecs.append(AV_CODEC_ID_PCM_S16LE);
default_vcodec = 2;
break;
case FORMAT_WAV:
format_acodecs.append(AV_CODEC_ID_PCM_S16LE);
break;
case FORMAT_WEBM:
format_vcodecs.append(AV_CODEC_ID_VP8);
format_vcodecs.append(AV_CODEC_ID_VP9);
format_acodecs.append(AV_CODEC_ID_OPUS);
format_acodecs.append(AV_CODEC_ID_VORBIS);
default_vcodec = 1;
break;
case FORMAT_WMV:
format_vcodecs.append(AV_CODEC_ID_WMV1);
format_vcodecs.append(AV_CODEC_ID_WMV2);
format_acodecs.append(AV_CODEC_ID_WMAV1);
format_acodecs.append(AV_CODEC_ID_WMAV2);
default_vcodec = 1;
default_acodec = 1;
break;
default:
qDebug() << "[ERROR] Invalid format selection - this is a bug, please inform the developers";
}
AVCodec* codec_info;
for (int i=0;i<format_vcodecs.size();i++) {
codec_info = avcodec_find_encoder((enum AVCodecID) format_vcodecs.at(i));
if (codec_info == NULL) {
ui->vcodecCombobox->addItem("NULL");
} else {
ui->vcodecCombobox->addItem(codec_info->long_name);
}
}
for (int i=0;i<format_acodecs.size();i++) {
codec_info = avcodec_find_encoder((enum AVCodecID) format_acodecs.at(i));
if (codec_info == NULL) {
ui->acodecCombobox->addItem("NULL");
} else {
ui->acodecCombobox->addItem(codec_info->long_name);
}
}
ui->vcodecCombobox->setCurrentIndex(default_vcodec);
ui->acodecCombobox->setCurrentIndex(default_acodec);
bool video_enabled = format_vcodecs.size() != 0;
bool audio_enabled = format_acodecs.size() != 0;
ui->videoGroupbox->setChecked(video_enabled);
ui->audioGroupbox->setChecked(audio_enabled);
ui->videoGroupbox->setEnabled(video_enabled);
ui->audioGroupbox->setEnabled(audio_enabled);
}
void ExportDialog::on_pushButton_2_clicked()
{
close();
}
void ExportDialog::on_pushButton_clicked()
{
QString ext;
switch (ui->formatCombobox->currentIndex()) {
case FORMAT_3GPP:
ext = "3gp";
break;
case FORMAT_AIFF:
ext = "aiff";
break;
case FORMAT_APNG:
ext = "apng";
break;
case FORMAT_AVI:
ext = "avi";
break;
case FORMAT_DNXHD:
ext = "mxf";
break;
case FORMAT_AC3:
ext = "ac3";
break;
case FORMAT_FLV:
ext = "flv";
break;
case FORMAT_GIF:
ext = "gif";
break;
case FORMAT_IMG:
// ext_name = "";
// ext = "";
// ext is determined from codec, but we prevent the switch from going to 'default' here
qDebug() << "[INFO] Image export not implemented yet";
return;
break;
case FORMAT_MP3:
ext = "mp3";
break;
case FORMAT_MPEG1:
if (ui->videoGroupbox->isChecked() && !ui->audioGroupbox->isChecked()) {
ext = "m1v";
} else if (!ui->videoGroupbox->isChecked() && ui->audioGroupbox->isChecked()) {
ext = "m1a";
} else {
ext = "mpg";
}
break;
case FORMAT_MPEG2:
if (ui->videoGroupbox->isChecked() && !ui->audioGroupbox->isChecked()) {
ext = "m2v";
} else if (!ui->videoGroupbox->isChecked() && ui->audioGroupbox->isChecked()) {
ext = "m2a";
} else {
ext = "mpg";
}
break;
case FORMAT_MPEG4:
if (ui->videoGroupbox->isChecked() && !ui->audioGroupbox->isChecked()) {
ext = "m4v";
} else if (!ui->videoGroupbox->isChecked() && ui->audioGroupbox->isChecked()) {
ext = "m4a";
} else {
ext = "mp4";
}
break;
case FORMAT_MPEGTS:
ext = "ts";
break;
case FORMAT_MKV:
if (!ui->videoGroupbox->isChecked()) {
ext = "mka";
} else {
ext = "mkv";
}
break;
case FORMAT_OGG:
ext = "ogg";
break;
case FORMAT_MOV:
ext = "mov";
break;
case FORMAT_WEBM:
ext = "webm";
break;
case FORMAT_WMV:
if (ui->videoGroupbox->isChecked()) {
ext = "wmv";
} else {
ext = "wma";
}
break;
default:
qDebug() << "[ERROR] Invalid format - this is a bug, please inform the developers";
return;
}
QString filename = QFileDialog::getSaveFileName(this, "Export Media", "", format_strings[ui->formatCombobox->currentIndex()] + " (*." + ext + ")");
if (!filename.isEmpty()) {
ExportThread* et = new ExportThread();
et->surface.create();
connect(et, SIGNAL(finished()), et, SLOT(deleteLater()));
connect(et, SIGNAL(progress_changed(int)), this, SLOT(update_progress_bar(int)));
panel_viewer->viewer_widget->context()->doneCurrent();
panel_viewer->viewer_widget->context()->moveToThread(et);
et->filename = filename;
et->video_enabled = ui->videoGroupbox->isChecked();
et->video_codec = format_vcodecs.at(ui->vcodecCombobox->currentIndex());
et->video_width = ui->widthSpinbox->value();
et->video_height = ui->heightSpinbox->value();
et->video_frame_rate = ui->framerateSpinbox->value();
et->video_bitrate = ui->videobitrateSpinbox->value();
et->audio_enabled = ui->audioGroupbox->isChecked();
et->audio_codec = format_acodecs.at(ui->acodecCombobox->currentIndex());
et->audio_sampling_rate = 48000;
et->audio_bitrate = ui->audiobitrateSpinbox->value();
et->start();
}
}
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);
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef EXPORTDIALOG_H
#define EXPORTDIALOG_H
#include <QDialog>
namespace Ui {
class ExportDialog;
}
struct Sequence;
class ExportDialog : public QDialog
{
Q_OBJECT
public:
explicit ExportDialog(QWidget *parent = 0);
~ExportDialog();
void set_defaults(Sequence* s);
private slots:
void on_formatCombobox_currentIndexChanged(int index);
void on_pushButton_2_clicked();
void on_pushButton_clicked();
void update_progress_bar(int value);
private:
Ui::ExportDialog *ui;
QVector<QString> format_strings;
QVector<int> format_vcodecs;
QVector<int> format_acodecs;
};
#endif // EXPORTDIALOG_H
+232
View File
@@ -0,0 +1,232 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExportDialog</class>
<widget class="QDialog" name="ExportDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>299</width>
<height>372</height>
</rect>
</property>
<property name="windowTitle">
<string>Export</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Format: </string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="formatCombobox"/>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="videoGroupbox">
<property name="title">
<string>Video</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Codec:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="vcodecCombobox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Width:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="widthSpinbox">
<property name="maximum">
<number>16777216</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Height:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="heightSpinbox">
<property name="maximum">
<number>16777216</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Frame Rate:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="framerateSpinbox">
<property name="maximum">
<double>60.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Bitrate (Mbps/CBR):</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="videobitrateSpinbox">
<property name="maximum">
<double>100.000000000000000</double>
</property>
<property name="value">
<double>2.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="audioGroupbox">
<property name="title">
<string>Audio</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Codec:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="acodecCombobox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Sampling Rate:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="samplingRateSpinbox">
<property name="maximum">
<number>96000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Bitrate (Kbps/CBR):</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="audiobitrateSpinbox">
<property name="maximum">
<number>320</number>
</property>
<property name="value">
<number>256</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="enabled">
<bool>false</bool>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Export</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+110
View File
@@ -0,0 +1,110 @@
#include "newsequencedialog.h"
#include "ui_newsequencedialog.h"
#include "panels/panels.h"
#include "panels/project.h"
#include "project/sequence.h"
#include <QVariant>
#include <QDebug>
extern "C" {
#include <libavcodec/avcodec.h>
}
NewSequenceDialog::NewSequenceDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::NewSequenceDialog)
{
ui->setupUi(this);
ui->frame_rate_combobox->addItem("10 FPS", 10.0f);
ui->frame_rate_combobox->addItem("12.5 FPS", 12.5f);
ui->frame_rate_combobox->addItem("15 FPS", 15.0f);
ui->frame_rate_combobox->addItem("25 FPS", 25.0f);
ui->frame_rate_combobox->addItem("29.97 FPS", 29.97f);
ui->frame_rate_combobox->addItem("30 FPS", (float) 30.0f);
ui->frame_rate_combobox->addItem("50 FPS", (float) 50.0f);
ui->frame_rate_combobox->addItem("59.94 FPS", (float) 59.94f);
ui->frame_rate_combobox->addItem("60 FPS", (float) 60.0f);
ui->frame_rate_combobox->setCurrentIndex(4);
ui->audio_frequency_combobox->addItem("22050 Hz", 22050);
ui->audio_frequency_combobox->addItem("24000 Hz", 24000);
ui->audio_frequency_combobox->addItem("32000 Hz", 32000);
ui->audio_frequency_combobox->addItem("44100 Hz", 44100);
ui->audio_frequency_combobox->addItem("48000 Hz", 48000);
ui->audio_frequency_combobox->addItem("88200 Hz", 88200);
ui->audio_frequency_combobox->addItem("96000 Hz", 96000);
ui->audio_frequency_combobox->setCurrentIndex(4);
}
NewSequenceDialog::~NewSequenceDialog()
{
delete ui;
}
void NewSequenceDialog::set_sequence_name(const QString& s) {
ui->lineEdit->setText(s);
}
void NewSequenceDialog::on_buttonBox_accepted()
{
Sequence* s = new Sequence();
s->name = ui->lineEdit->text();
s->width = ui->width_numeric->value();
s->height = ui->height_numeric->value();
s->frame_rate = ui->frame_rate_combobox->currentData().toFloat();
s->audio_frequency = ui->audio_frequency_combobox->currentData().toInt();
s->audio_layout = AV_CH_LAYOUT_STEREO;
panel_project->new_sequence(s);
}
void NewSequenceDialog::on_comboBox_currentIndexChanged(int index)
{
switch (index) {
case 0: // FILM 4K
ui->width_numeric->setValue(4096);
ui->height_numeric->setValue(2160);
break;
case 1: // TV 4K
ui->width_numeric->setValue(3840);
ui->height_numeric->setValue(2160);
break;
case 2: // 1080p
ui->width_numeric->setValue(1920);
ui->height_numeric->setValue(1080);
break;
case 3: // 720p
ui->width_numeric->setValue(1280);
ui->height_numeric->setValue(720);
break;
case 4: // 480p
ui->width_numeric->setValue(640);
ui->height_numeric->setValue(480);
break;
case 5: // 360p
ui->width_numeric->setValue(640);
ui->height_numeric->setValue(360);
break;
case 6: // 240p
ui->width_numeric->setValue(320);
ui->height_numeric->setValue(240);
break;
case 7: // 144p
ui->width_numeric->setValue(192);
ui->height_numeric->setValue(144);
break;
case 8: // NTSC (480i)
ui->width_numeric->setValue(720);
ui->height_numeric->setValue(480);
break;
case 9: // PAL (576i)
ui->width_numeric->setValue(720);
ui->height_numeric->setValue(576);
break;
}
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef NEWSEQUENCEDIALOG_H
#define NEWSEQUENCEDIALOG_H
#include <QDialog>
class Project;
namespace Ui {
class NewSequenceDialog;
}
class NewSequenceDialog : public QDialog
{
Q_OBJECT
public:
explicit NewSequenceDialog(QWidget *parent = 0);
~NewSequenceDialog();
void set_sequence_name(const QString& s);
private slots:
void on_buttonBox_accepted();
void on_comboBox_currentIndexChanged(int index);
private:
Ui::NewSequenceDialog *ui;
};
#endif // NEWSEQUENCEDIALOG_H
+360
View File
@@ -0,0 +1,360 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewSequenceDialog</class>
<widget class="QDialog" name="NewSequenceDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>298</width>
<height>341</height>
</rect>
</property>
<property name="windowTitle">
<string>New Sequence</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Preset: </string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox">
<property name="currentIndex">
<number>2</number>
</property>
<item>
<property name="text">
<string>Film 4K</string>
</property>
</item>
<item>
<property name="text">
<string>TV 4K (Ultra HD/2160p)</string>
</property>
</item>
<item>
<property name="text">
<string>1080p</string>
</property>
</item>
<item>
<property name="text">
<string>720p</string>
</property>
</item>
<item>
<property name="text">
<string>480p</string>
</property>
</item>
<item>
<property name="text">
<string>360p</string>
</property>
</item>
<item>
<property name="text">
<string>240p</string>
</property>
</item>
<item>
<property name="text">
<string>144p</string>
</property>
</item>
<item>
<property name="text">
<string>NTSC (480i)</string>
</property>
</item>
<item>
<property name="text">
<string>PAL (576i)</string>
</property>
</item>
<item>
<property name="text">
<string>Custom</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Video</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2" colspan="2">
<widget class="QSpinBox" name="height_numeric">
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>1080</number>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QSpinBox" name="width_numeric">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>1920</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Width: </string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Pixel Aspect Ratio: </string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interlacing:</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Height: </string>
</property>
</widget>
</item>
<item row="4" column="2" colspan="2">
<widget class="QComboBox" name="par_combobox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Square Pixels (1.0)</string>
</property>
</item>
</widget>
</item>
<item row="6" column="2" colspan="2">
<widget class="QComboBox" name="interlacing_combobox">
<item>
<property name="text">
<string>None (Progressive)</string>
</property>
</item>
<item>
<property name="text">
<string>Upper Field First</string>
</property>
</item>
<item>
<property name="text">
<string>Lower Field First</string>
</property>
</item>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QComboBox" name="frame_rate_combobox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Frame Rate:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Audio</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Sample Rate: </string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="audio_frequency_combobox"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_2" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Name: </string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="text">
<string>Sequence 01</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>NewSequenceDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>NewSequenceDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+16
View File
@@ -0,0 +1,16 @@
#include "effects/effects.h"
#include <QVector>
QVector<QString> video_effect_names;
QVector<QString> audio_effect_names;
void init_effects() {
video_effect_names.resize(VIDEO_EFFECT_COUNT);
audio_effect_names.resize(AUDIO_EFFECT_COUNT);
video_effect_names[VIDEO_TRANSFORM_EFFECT] = "Transform";
audio_effect_names[AUDIO_VOLUME_EFFECT] = "Volume";
audio_effect_names[AUDIO_PAN_EFFECT] = "Pan";
}
+61
View File
@@ -0,0 +1,61 @@
#ifndef EFFECTS_H
#define EFFECTS_H
#include "project/effect.h"
class QSpinBox;
class QCheckBox;
enum VideoEffects {
VIDEO_TRANSFORM_EFFECT,
VIDEO_EFFECT_COUNT
};
enum AudioEffects {
AUDIO_VOLUME_EFFECT,
AUDIO_PAN_EFFECT,
AUDIO_EFFECT_COUNT
};
extern QVector<QString> video_effect_names;
extern QVector<QString> audio_effect_names;
void init_effects();
// video effects
class TransformEffect : public Effect {
Q_OBJECT
public:
TransformEffect(Clip* c);
void process_gl(int* anchor_x, int* anchor_y);
private:
QSpinBox* position_x;
QSpinBox* position_y;
QSpinBox* scale_x;
QSpinBox* scale_y;
QCheckBox* uniform_scale_box;
QSpinBox* rotation;
QSpinBox* anchor_x_box;
QSpinBox* anchor_y_box;
QSpinBox* opacity;
public slots:
void toggle_uniform_scale(bool enabled);
};
// audio effects
class VolumeEffect : public Effect {
public:
VolumeEffect(Clip* c);
void process_audio(uint8_t* samples, int nb_bytes);
private:
QSpinBox* volume_val;
};
class PanEffect : public Effect {
public:
PanEffect(Clip* c);
void process_audio(uint8_t* samples, int nb_bytes);
private:
QSpinBox* pan_val;
};
#endif // EFFECTS_H
+50
View File
@@ -0,0 +1,50 @@
#include "effects/effects.h"
#include <QGridLayout>
#include <QSpinBox>
#include <QLabel>
#include "ui/collapsiblewidget.h"
PanEffect::PanEffect(Clip* c) : Effect(c) {
container = new CollapsibleWidget();
container->setText(audio_effect_names[AUDIO_PAN_EFFECT]);
ui = new QWidget();
QGridLayout* ui_layout = new QGridLayout();
ui_layout->addWidget(new QLabel("Pan:"), 0, 0);
pan_val = new QSpinBox();
pan_val->setMinimum(-100);
pan_val->setMaximum(100);
ui_layout->addWidget(pan_val, 0, 1);
ui->setLayout(ui_layout);
container->setContents(ui);
// set defaults
pan_val->setValue(0);
}
void PanEffect::process_audio(uint8_t *samples, int nb_bytes) {
for (int i=0;i<nb_bytes;i+=4) {
int16_t left_sample = (int16_t) ((samples[i+1] << 8) | samples[i]);
int16_t right_sample = (int16_t) ((samples[i+3] << 8) | samples[i+2]);
float val = pan_val->value()*0.01;
if (val < 0) {
// affect right channel
right_sample *= (1-abs(val));
} else {
// affect left channel
left_sample *= (1-val);
}
samples[i+3] = (uint8_t) (right_sample >> 8);
samples[i+2] = (uint8_t) right_sample;
samples[i+1] = (uint8_t) (left_sample >> 8);
samples[i] = (uint8_t) left_sample;
}
}
+119
View File
@@ -0,0 +1,119 @@
#include "effects/effects.h"
#include <QDebug>
#include <QWidget>
#include <QLabel>
#include <QGridLayout>
#include <QSpinBox>
#include <QCheckBox>
#include <QOpenGLFunctions>
#include "ui/collapsiblewidget.h"
#include "project/clip.h"
#include "project/sequence.h"
#include "io/media.h"
TransformEffect::TransformEffect(Clip* c) : Effect(c) {
container = new CollapsibleWidget();
container->setText(video_effect_names[VIDEO_TRANSFORM_EFFECT]);
ui = new QWidget();
QGridLayout* ui_layout = new QGridLayout();
ui_layout->addWidget(new QLabel("Position:"), 0, 0);
position_x = new QSpinBox();
position_x->setMinimum(-QWIDGETSIZE_MAX);
position_x->setMaximum(QWIDGETSIZE_MAX);
ui_layout->addWidget(position_x, 0, 1);
position_y = new QSpinBox();
position_y->setMinimum(-QWIDGETSIZE_MAX);
position_y->setMaximum(QWIDGETSIZE_MAX);
ui_layout->addWidget(position_y, 0, 2);
ui_layout->addWidget(new QLabel("Scale:"), 1, 0);
scale_x = new QSpinBox();
scale_x->setMinimum(0);
scale_x->setMaximum(1200);
ui_layout->addWidget(scale_x, 1, 1);
scale_y = new QSpinBox();
scale_y->setMinimum(0);
scale_y->setMaximum(1200);
ui_layout->addWidget(scale_y, 1, 2);
uniform_scale_box = new QCheckBox();
uniform_scale_box->setText("Uniform Scale");
ui_layout->addWidget(uniform_scale_box, 2, 1);
ui_layout->addWidget(new QLabel("Rotation:"), 3, 0);
rotation = new QSpinBox();
rotation->setMinimum(-QWIDGETSIZE_MAX);
rotation->setMaximum(QWIDGETSIZE_MAX);
ui_layout->addWidget(rotation, 3, 1);
ui_layout->addWidget(new QLabel("Anchor Point:"), 4, 0);
anchor_x_box = new QSpinBox();
anchor_x_box->setMinimum(-QWIDGETSIZE_MAX);
anchor_x_box->setMaximum(QWIDGETSIZE_MAX);
ui_layout->addWidget(anchor_x_box, 4, 1);
anchor_y_box = new QSpinBox();
anchor_y_box->setMinimum(-QWIDGETSIZE_MAX);
anchor_y_box->setMaximum(QWIDGETSIZE_MAX);
ui_layout->addWidget(anchor_y_box, 4, 2);
ui_layout->addWidget(new QLabel("Opacity:"), 5, 0);
opacity = new QSpinBox();
opacity->setMinimum(0);
opacity->setMaximum(100);
ui_layout->addWidget(opacity, 5, 1);
ui->setLayout(ui_layout);
container->setContents(ui);
// set defaults
position_x->setValue(c->sequence->width/2);
position_y->setValue(c->sequence->height/2);
scale_x->setValue(100);
scale_y->setValue(100);
scale_y->setEnabled(false);
uniform_scale_box->setChecked(true);
anchor_x_box->setValue(c->media_stream->video_width/2);
anchor_y_box->setValue(c->media_stream->video_height/2);
opacity->setValue(100);
connect(position_x, SIGNAL(valueChanged(int)), this, SLOT(field_changed()));
connect(position_y, SIGNAL(valueChanged(int)), this, SLOT(field_changed()));
connect(rotation, SIGNAL(valueChanged(int)), this, SLOT(field_changed()));
connect(scale_x, SIGNAL(valueChanged(int)), this, SLOT(field_changed()));
connect(scale_y, SIGNAL(valueChanged(int)), this, SLOT(field_changed()));
connect(anchor_x_box, SIGNAL(valueChanged(int)), this, SLOT(field_changed()));
connect(anchor_y_box, SIGNAL(valueChanged(int)), this, SLOT(field_changed()));
connect(opacity, SIGNAL(valueChanged(int)), this, SLOT(field_changed()));
connect(uniform_scale_box, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool)));
connect(uniform_scale_box, SIGNAL(toggled(bool)), this, SLOT(field_changed()));
}
void TransformEffect::toggle_uniform_scale(bool enabled) {
scale_y->setEnabled(!enabled);
}
void TransformEffect::process_gl(int* anchor_x, int* anchor_y) {
// position
glTranslatef(position_x->value()-(parent_clip->sequence->width/2), position_y->value()-(parent_clip->sequence->height/2), 0);
// anchor point
*anchor_x += anchor_x_box->value();
*anchor_y += anchor_y_box->value();
// rotation
glRotatef(rotation->value(), 0, 0, 1);
// scale
float sx = scale_x->value()*0.01;
float sy = (uniform_scale_box->isChecked()) ? sx : scale_y->value()*0.01;
glScalef(sx, sy, 1);
// opacity
glColor4f(1.0, 1.0, 1.0, opacity->value()*0.01);
}
+38
View File
@@ -0,0 +1,38 @@
#include "effects/effects.h"
#include <QGridLayout>
#include <QSpinBox>
#include <QLabel>
#include "ui/collapsiblewidget.h"
VolumeEffect::VolumeEffect(Clip* c) : Effect(c) {
container = new CollapsibleWidget();
container->setText(audio_effect_names[AUDIO_VOLUME_EFFECT]);
ui = new QWidget();
QGridLayout* ui_layout = new QGridLayout();
ui_layout->addWidget(new QLabel("Volume:"), 0, 0);
volume_val = new QSpinBox();
volume_val->setMinimum(0);
volume_val->setMaximum(100);
ui_layout->addWidget(volume_val, 0, 1);
ui->setLayout(ui_layout);
container->setContents(ui);
// set defaults
volume_val->setValue(100);
}
void VolumeEffect::process_audio(uint8_t *samples, int nb_bytes) {
for (int i=0;i<nb_bytes;i+=2) {
int16_t full_sample = (int16_t) ((samples[i+1] << 8) | samples[i]);
full_sample *= volume_val->value()*0.01;
samples[i+1] = (uint8_t) (full_sample >> 8);
samples[i] = (uint8_t) full_sample;
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

+19
View File
@@ -0,0 +1,19 @@
<RCC>
<qresource prefix="/icons">
<file>play.png</file>
<file>ff.png</file>
<file>next.png</file>
<file>pause.png</file>
<file>prev.png</file>
<file>rew.png</file>
<file>arrow.png</file>
<file>beam.png</file>
<file>razor.png</file>
<file>full-icon.png</file>
<file>audiosource.png</file>
<file>videosource.png</file>
<file>ripple.png</file>
<file>rolling.png</file>
<file>slip.png</file>
</qresource>
</RCC>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

+1
View File
@@ -0,0 +1 @@
olicon ICON "olive.ico"
+49
View File
@@ -0,0 +1,49 @@
#include "config.h"
#ifdef _WIN32
#include <direct.h>
#include <windows.h>
#endif
const char* version = "Olive (May 2018 | Pre-Alpha)";
float scale = 1.0f;
bool vsync = true;
bool hwaccel = false;
int padding = 8;
bool custom_scale = false;
bool saved_layout = false;
bool left_mouse_dominant = true;
bool show_track_lines = false;
void load_config() {
/*if (!custom_scale) {
#ifdef _WIN32
// Get Windows UI scale - TODO may not be compatible with XP
HDC screen = GetDC(0);
int dpiX = GetDeviceCaps (screen, LOGPIXELSX);
//int dpiY = GetDeviceCaps (screen, LOGPIXELSY);
scale = (float) dpiX / 96;
ReleaseDC (0, screen);
#endif
}*/
padding *= scale;
/*DIR* dir = opendir("conf");
if (dir) {
closedir(dir);
} else if (ENOENT == errno) {
// no config directory, assume this is the first time opening Olive
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "INFO", "NOTE: This version of Olive is INCOMPLETE and very likely to crash. It comes with NO WARRANTY or guarantee of functionality.\n\nRegardless, thanks for checking out the project and I hope you enjoy using it!", NULL);
}*/
}
void save_config() {
/*#ifdef _WIN32
_mkdir("conf");
#else
mkdir("conf", 0777);
#endif*/
}
+16
View File
@@ -0,0 +1,16 @@
#ifndef CONFIG_H
#define CONFIG_H
extern const char* version;
extern float scale;
extern bool vsync;
extern bool hwaccel;
extern int padding;
extern bool custom_scale;
extern bool saved_layout;
extern bool show_track_lines;
void load_config();
void save_config();
#endif // CONFIG_H
+342
View File
@@ -0,0 +1,342 @@
#include "exportthread.h"
#include "project/sequence.h"
#include "panels/panels.h"
#include "panels/timeline.h"
#include "panels/viewer.h"
#include "ui/viewerwidget.h"
#include "playback/playback.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
}
#include <QDebug>
#include <QApplication>
#include <QOffscreenSurface>
#include <QOpenGLFramebufferObject>
#include <QOpenGlPaintDevice>
#include <QPainter>
bool encode(AVFormatContext* fmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame, AVPacket* packet, AVStream* stream) {
int ret = avcodec_send_frame(codec_ctx, frame);
if (ret < 0) {
qDebug() << "[ERROR] Failed to send frame to encoder." << ret;
return false;
} else {
while (ret >= 0) {
ret = avcodec_receive_packet(codec_ctx, packet);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
// do nothing, encoder needs more input
} else if (ret < 0) {
qDebug() << "[ERROR] Failed to receive packet from encoder." << ret;
return false;
} else {
packet->stream_index = stream->index;
av_interleaved_write_frame(fmt_ctx, packet);
}
}
}
return true;
}
void ExportThread::run() {
Sequence* sequence = panel_timeline->sequence;
// TODO make customizable
long start = 0;
long end = sequence->getEndFrame();
if (panel_viewer->viewer_widget->context()->makeCurrent(&surface)) {
qDebug() << "make current succeeded";
} else {
qDebug() << "make current failed";
}
panel_viewer->viewer_widget->multithreaded = false;
panel_viewer->viewer_widget->initializeOpenGLFunctions();
AVFormatContext* fmt_ctx = NULL;
QByteArray ba = filename.toLatin1();
char* c_filename = new char[ba.size()+1];
strcpy(c_filename, ba.data());
avformat_alloc_output_context2(&fmt_ctx, NULL, NULL, c_filename);
if (!fmt_ctx) {
qDebug() << "[ERROR] Could not create output context";
} else {
AVStream* video_stream;
AVCodec* vcodec;
AVCodecContext* vcodec_ctx;
AVFrame* video_frame;
SwsContext* sws_ctx = NULL;
// AVStream* audio_stream;
// AVCodec* acodec;
// AVFrame* audio_frame;
// AVCodecContext* acodec_ctx;
AVPacket video_pkt;
// AVPacket audio_pkt;
// SwrContext* swr_ctx = NULL;
int ret;
bool fail = false;
if (video_enabled) {
// initialize array contain opengl data
video_stream = avformat_new_stream(fmt_ctx, NULL);
if (!video_stream) {
qDebug() << "[ERROR] Could not allocate output streams";
fail = true;
} else {
vcodec = avcodec_find_encoder((enum AVCodecID) video_codec);
if (!vcodec) {
qDebug() << "[ERROR] Could not find video encoder";
fail = true;
} else {
vcodec_ctx = avcodec_alloc_context3(vcodec);
if (!vcodec_ctx) {
qDebug() << "[ERROR] Could not find allocate video encoding context";
fail = true;
} else {
vcodec_ctx->width = sequence->width;
vcodec_ctx->height = sequence->height;
vcodec_ctx->sample_aspect_ratio = av_d2q(sequence->width/sequence->height, INT_MAX);
vcodec_ctx->pix_fmt = vcodec->pix_fmts[0]; // maybe be breakable code
vcodec_ctx->framerate = av_d2q(sequence->frame_rate, INT_MAX);
vcodec_ctx->bit_rate = video_bitrate * 1000000;
vcodec_ctx->time_base = av_inv_q(vcodec_ctx->framerate);
ret = avcodec_open2(vcodec_ctx, vcodec, NULL);
if (ret < 0) {
qDebug() << "[ERROR] Could not open output video encoder." << ret;
fail = true;
} else {
ret = avcodec_parameters_from_context(video_stream->codecpar, vcodec_ctx);
if (ret < 0) {
qDebug() << "[ERROR] Could not copy video encoder parameters to output stream." << ret;
fail = true;
} else {
if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
vcodec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
video_stream->time_base = vcodec_ctx->time_base;
// initialize raw video frame
video_frame = av_frame_alloc();
av_frame_make_writable(video_frame);
video_frame->format = AV_PIX_FMT_RGBA;
video_frame->width = video_width;
video_frame->height = video_height;
av_frame_get_buffer(video_frame, 0);
av_init_packet(&video_pkt);
sws_ctx = sws_getContext(
video_width,
video_height,
AV_PIX_FMT_RGBA,
video_width,
video_height,
AV_PIX_FMT_YUV420P,
SWS_FAST_BILINEAR,
NULL,
NULL,
NULL
);
}
}
}
}
}
}
// if (audio_enabled && !fail) {
// audio_stream = avformat_new_stream(fmt_ctx, NULL);
// if (!audio_stream) {
// qDebug() << "[ERROR] Could not allocate output streams";
// fail = true;
// } else {
// acodec = avcodec_find_encoder((enum AVCodecID) audio_codec);
// if (!acodec) {
// qDebug() << "[ERROR] Could not find audio encoder";
// fail = true;
// } else {
// acodec_ctx = avcodec_alloc_context3(acodec);
// if (!acodec_ctx) {
// qDebug() << "[ERROR] Could not find allocate audio encoding context";
// fail = true;
// } else {
// acodec_ctx->sample_rate = audio_sampling_rate;
// acodec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
// acodec_ctx->channels = av_get_channel_layout_nb_channels(acodec_ctx->channel_layout);
// acodec_ctx->sample_fmt = acodec->sample_fmts[0];
// acodec_ctx->time_base = {1, audio_sampling_rate};
// acodec_ctx->bit_rate = audio_bitrate * 1000;
// ret = avcodec_open2(acodec_ctx, acodec, NULL);
// if (ret < 0) {
// qDebug() << "[ERROR] Could not open output audio encoder." << ret;
// fail = true;
// } else {
// ret = avcodec_parameters_from_context(audio_stream->codecpar, acodec_ctx);
// if (ret < 0) {
// qDebug() << "[ERROR] Could not copy audio encoder parameters to output stream." << ret;
// fail = true;
// } else {
// if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
// acodec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
// }
// audio_stream->time_base = acodec_ctx->time_base;
// // init audio resampler context
// swr_ctx = swr_alloc_set_opts(
// NULL,
// acodec_ctx->channel_layout,
// acodec_ctx->sample_fmt,
// acodec_ctx->sample_rate,
// sequence->audio_layout,
// AV_SAMPLE_FMT_S16,
// sequence->audio_frequency,
// 0,
// NULL
// );
// swr_init(swr_ctx);
// // initialize raw audio frame
// audio_frame = av_frame_alloc();
// audio_frame->nb_samples = acodec_ctx->frame_size;
// if (audio_frame->nb_samples == 0) audio_frame->nb_samples = 2048; // should probably be way smaller?
// audio_frame->format = acodec_ctx->sample_fmt;
// audio_frame->channels = acodec_ctx->channels;
// audio_frame->channel_layout = acodec_ctx->channel_layout;
// ret = av_frame_get_buffer(audio_frame, 0);
// if (ret < 0) {
// qDebug() << "[ERROR] Could not allocate audio buffer." << ret;
// }
// // av_samples_alloc(&audio_frame->data[0], NULL, av_get_channel_layout_nb_channels(audio_frame->channel_layout), audio_frame->nb_samples, acodec_ctx->sample_fmt, 0);
// av_frame_make_writable(audio_frame);
// av_init_packet(&audio_pkt);
// }
// }
// }
// }
// }
// }
if (!fail) {
av_dump_format(fmt_ctx, 0, c_filename, 1);
ret = avio_open(&fmt_ctx->pb, c_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
qDebug() << "[ERROR] Could not open output file." << ret;
} else {
ret = avformat_write_header(fmt_ctx, NULL);
if (ret < 0) {
qDebug() << "[ERROR] Could not write output file header." << ret;
} else {
panel_timeline->seek(0);
// 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);
}
}
QOpenGLFramebufferObject fbo(video_width, video_height, QOpenGLFramebufferObject::CombinedDepthStencil, GL_TEXTURE_RECTANGLE);
fbo.bind();
QOpenGLPaintDevice fbo_dev(video_width, video_height);
QPainter painter(&fbo_dev);
painter.beginNativePainting();
AVFrame* sws_frame = av_frame_alloc();
sws_frame->format = AV_PIX_FMT_YUV420P;
sws_frame->width = video_frame->width;
sws_frame->height = video_frame->height;
av_frame_get_buffer(sws_frame, 0);
uint8_t* flip_buffer = new uint8_t[video_frame->width * video_frame->height * 4];
while (panel_timeline->playhead < end && !fail) {
panel_viewer->viewer_widget->paintGL();
double timecode_secs = (double) panel_timeline->playhead / sequence->frame_rate;
if (video_enabled) {
// get image from opengl
glReadPixels(0, 0, video_width, video_height, GL_RGBA, GL_UNSIGNED_BYTE, flip_buffer);
// flip image vertically because opengl sucks ass
int linesize = video_width*4;
for (int i=video_height-1;i>=0;i--) {
int src_index = i*linesize;
int dst_index = (video_height-i)*linesize;
memcpy(video_frame->data[0]+dst_index, flip_buffer+src_index, linesize);
}
// change pixel format
sws_scale(sws_ctx, video_frame->data, video_frame->linesize, 0, video_frame->height, sws_frame->data, sws_frame->linesize);
sws_frame->pts = round(timecode_secs/av_q2d(video_stream->time_base));
// send to encoder
if (!encode(fmt_ctx, vcodec_ctx, sws_frame, &video_pkt, video_stream)) fail = true;
}
emit progress_changed(((float) panel_timeline->playhead / (float) end) * 100);
panel_timeline->playhead++;
}
delete [] flip_buffer;
painter.endNativePainting();
fbo.release();
av_frame_free(&sws_frame);
if (!fail) {
// flush remaining packets
if (video_enabled) {
if (!encode(fmt_ctx, vcodec_ctx, NULL, &video_pkt, video_stream)) fail = true;
}
// if (audio_enabled) {
// if (!encode(fmt_ctx, acodec_ctx, NULL, &audio_pkt, audio_stream)) return false;
// }
}
if (!fail) {
ret = av_write_trailer(fmt_ctx);
if (ret < 0) {
qDebug() << "[ERROR] Could not write output file trailer." << ret;
}
emit progress_changed(100);
}
}
}
av_packet_unref(&video_pkt);
av_frame_free(&video_frame);
avcodec_free_context(&vcodec_ctx);
// avcodec_free_context(&acodec_ctx);
avio_closep(&fmt_ctx->pb);
avformat_free_context(fmt_ctx);
// qDebug() << "Render took: %ih %im %is\n", render_time/3600000, render_time/60000, render_time/1000;
if (sws_ctx != NULL) sws_freeContext(sws_ctx);
// if (swr_ctx != NULL) swr_free(&swr_ctx);
}
}
delete [] c_filename;
panel_viewer->viewer_widget->context()->doneCurrent();
panel_viewer->viewer_widget->context()->moveToThread(qApp->thread());
panel_viewer->viewer_widget->multithreaded = true;
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef EXPORTTHREAD_H
#define EXPORTTHREAD_H
#include <QThread>
#include <QOffscreenSurface>
class ExportThread : public QThread {
Q_OBJECT
public:
void run() override;
// export parameters
QString filename;
bool video_enabled;
int video_codec;
int video_width;
int video_height;
double video_frame_rate;
double video_bitrate;
bool audio_enabled;
int audio_codec;
int audio_sampling_rate;
int audio_bitrate;
QOffscreenSurface surface;
signals:
void progress_changed(int value);
};
#endif // EXPORTTHREAD_H
+9
View File
@@ -0,0 +1,9 @@
#include "media.h"
extern "C" {
#include <libavformat/avformat.h>
}
long Media::get_length_in_frames(float frame_rate) {
return ceil((float) length / (float) AV_TIME_BASE * frame_rate);
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef MEDIA_H
#define MEDIA_H
#include <QString>
#include <QVector>
#include <QMetaType>
#include <QVariant>
struct Sequence;
struct MediaStream {
int file_index;
int video_width;
int video_height;
bool infinite_length;
};
struct Media
{
QString url;
QString name;
bool is_sequence;
int64_t length;
QVector<MediaStream> video_tracks;
QVector<MediaStream> audio_tracks;
Sequence* sequence;
long get_length_in_frames(float frame_rate);
};
#endif // MEDIA_H
+18
View File
@@ -0,0 +1,18 @@
#include "mainwindow.h"
#include <QApplication>
extern "C" {
#include <libavformat/avformat.h>
}
int main(int argc, char *argv[])
{
// init ffmpeg subsystem
av_register_all();
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
+165
View File
@@ -0,0 +1,165 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "io/config.h"
#include "panels/panels.h"
#include "panels/project.h"
#include "panels/effectcontrols.h"
#include "panels/viewer.h"
#include "panels/timeline.h"
#include "dialogs/aboutdialog.h"
#include "dialogs/newsequencedialog.h"
#include "dialogs/exportdialog.h"
#include <QDebug>
#include <QStyleFactory>
void MainWindow::setup_layout() {
panel_project = new Project(this);
panel_effect_controls = new EffectControls(this);
panel_viewer = new Viewer(this);
panel_timeline = new Timeline(this);
addDockWidget(Qt::TopDockWidgetArea, panel_project);
addDockWidget(Qt::TopDockWidgetArea, panel_effect_controls);
addDockWidget(Qt::TopDockWidgetArea, panel_viewer);
addDockWidget(Qt::BottomDockWidgetArea, panel_timeline);
setCentralWidget(NULL);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// set up style?
qApp->setStyle(QStyleFactory::create("Fusion"));
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, QColor(53,53,53));
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, QColor(25,25,25));
darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53));
darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, QColor(53,53,53));
darkPalette.setColor(QPalette::ButtonText, Qt::white); darkPalette.setColor(QPalette::BrightText, Qt::red);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128));
darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
darkPalette.setColor(QPalette::HighlightedText, Qt::black);
qApp->setPalette(darkPalette);
// end style
setWindowState(Qt::WindowMaximized);
ui->setupUi(this);
setWindowTitle("Olive (May 2018 | Pre-Alpha)");
statusBar()->showMessage("Welcome to Olive::Qt");
setup_layout();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_action_Import_triggered()
{
panel_project->import_dialog();
}
void MainWindow::on_actionExit_triggered()
{
QApplication::quit();
}
void MainWindow::on_actionAbout_triggered()
{
AboutDialog a(this);
a.exec();
}
void MainWindow::on_actionDelete_triggered()
{
if (panel_timeline->focused()) {
panel_timeline->delete_selection(false);
}
}
void MainWindow::on_actionSelect_All_triggered()
{
if (panel_timeline->focused()) {
panel_timeline->select_all();
}
}
void MainWindow::on_actionSequence_triggered()
{
NewSequenceDialog nsd;
nsd.set_sequence_name(panel_project->get_next_sequence_name());
nsd.exec();
}
void MainWindow::on_actionZoom_In_triggered()
{
if (panel_timeline->focused()) {
panel_timeline->zoom_in();
}
}
void MainWindow::on_actionZoom_out_triggered()
{
if (panel_timeline->focused()) {
panel_timeline->zoom_out();
}
}
void MainWindow::on_actionTimeline_Track_Lines_toggled(bool e)
{
show_track_lines = e;
panel_timeline->redraw_all_clips();
}
void MainWindow::on_actionExport_triggered()
{
ExportDialog e;
if (panel_timeline->sequence != NULL) e.set_defaults(panel_timeline->sequence);
e.exec();
}
void MainWindow::on_actionProject_2_toggled(bool arg1)
{
panel_project->setVisible(arg1);
}
void MainWindow::on_actionEffect_Controls_toggled(bool arg1)
{
panel_effect_controls->setVisible(arg1);
}
void MainWindow::on_actionViewer_toggled(bool arg1)
{
panel_viewer->setVisible(arg1);
}
void MainWindow::on_actionTimeline_toggled(bool arg1)
{
panel_timeline->setVisible(arg1);
}
void MainWindow::on_actionRipple_Delete_triggered()
{
panel_timeline->delete_selection(true);
}
+59
View File
@@ -0,0 +1,59 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class Project;
class EffectControls;
class Viewer;
class Timeline;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_action_Import_triggered();
void on_actionExit_triggered();
void on_actionAbout_triggered();
void on_actionDelete_triggered();
void on_actionSelect_All_triggered();
void on_actionSequence_triggered();
void on_actionZoom_In_triggered();
void on_actionZoom_out_triggered();
void on_actionTimeline_Track_Lines_toggled(bool arg1);
void on_actionExport_triggered();
void on_actionProject_2_toggled(bool arg1);
void on_actionEffect_Controls_toggled(bool arg1);
void on_actionViewer_toggled(bool arg1);
void on_actionTimeline_toggled(bool arg1);
void on_actionRipple_Delete_triggered();
private:
Ui::MainWindow *ui;
void setup_layout();
};
#endif // MAINWINDOW_H
+296
View File
@@ -0,0 +1,296 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>653</width>
<height>394</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="windowIcon">
<iconset resource="icons/icons.qrc">
<normaloff>:/icons/full-icon.png</normaloff>:/icons/full-icon.png</iconset>
</property>
<widget class="QWidget" name="centralWidget"/>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>653</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
<property name="title">
<string>&amp;File</string>
</property>
<widget class="QMenu" name="menu_New">
<property name="title">
<string>&amp;New</string>
</property>
<addaction name="actionProject"/>
<addaction name="separator"/>
<addaction name="actionSequence"/>
</widget>
<addaction name="menu_New"/>
<addaction name="action_Open_Project"/>
<addaction name="action_Save_Project"/>
<addaction name="actionSave_Project_As"/>
<addaction name="separator"/>
<addaction name="action_Import"/>
<addaction name="separator"/>
<addaction name="actionExport"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
<string>&amp;Edit</string>
</property>
<addaction name="action_Undo"/>
<addaction name="action_Redo"/>
<addaction name="separator"/>
<addaction name="actionCu_t"/>
<addaction name="actionCop_y"/>
<addaction name="action_Paste"/>
<addaction name="actionDelete"/>
<addaction name="actionRipple_Delete"/>
<addaction name="separator"/>
<addaction name="actionSelect_All"/>
</widget>
<widget class="QMenu" name="menuWindow">
<property name="title">
<string>&amp;Window</string>
</property>
<addaction name="actionProject_2"/>
<addaction name="actionEffect_Controls"/>
<addaction name="actionViewer"/>
<addaction name="actionTimeline"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="actionAbout"/>
</widget>
<widget class="QMenu" name="menu_View">
<property name="title">
<string>&amp;View</string>
</property>
<addaction name="actionTimeline_Track_Lines"/>
<addaction name="actionZoom_In"/>
<addaction name="actionZoom_out"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menuEdit"/>
<addaction name="menu_View"/>
<addaction name="menuWindow"/>
<addaction name="menu_Help"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="action_Open_Project">
<property name="text">
<string>&amp;Open Project</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="action_Save_Project">
<property name="text">
<string>&amp;Save Project</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="actionSave_Project_As">
<property name="text">
<string>Save Project &amp;As</string>
</property>
</action>
<action name="action_Import">
<property name="text">
<string>&amp;Import...</string>
</property>
<property name="shortcut">
<string>Ctrl+I</string>
</property>
</action>
<action name="actionExport">
<property name="text">
<string>&amp;Export...</string>
</property>
<property name="shortcut">
<string>Ctrl+M</string>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>E&amp;xit</string>
</property>
</action>
<action name="actionAbout">
<property name="text">
<string>About...</string>
</property>
</action>
<action name="action_Undo">
<property name="text">
<string>&amp;Undo</string>
</property>
<property name="shortcut">
<string>Ctrl+Z</string>
</property>
</action>
<action name="action_Redo">
<property name="text">
<string>&amp;Redo</string>
</property>
<property name="shortcut">
<string>Ctrl+Y</string>
</property>
</action>
<action name="actionCu_t">
<property name="text">
<string>Cu&amp;t</string>
</property>
<property name="shortcut">
<string>Ctrl+X</string>
</property>
</action>
<action name="actionCop_y">
<property name="text">
<string>Cop&amp;y</string>
</property>
<property name="shortcut">
<string>Ctrl+C</string>
</property>
</action>
<action name="action_Paste">
<property name="text">
<string>&amp;Paste</string>
</property>
<property name="shortcut">
<string>Ctrl+V</string>
</property>
</action>
<action name="actionDelete">
<property name="text">
<string>Delete</string>
</property>
<property name="shortcut">
<string>Del</string>
</property>
</action>
<action name="actionSelect_All">
<property name="text">
<string>Select &amp;All</string>
</property>
<property name="shortcut">
<string>Ctrl+A</string>
</property>
</action>
<action name="actionTimeline_Track_Lines">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Track Lines</string>
</property>
</action>
<action name="actionProject">
<property name="text">
<string>Project...</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
<action name="actionSequence">
<property name="text">
<string>Sequence...</string>
</property>
</action>
<action name="actionZoom_In">
<property name="text">
<string>Zoom In</string>
</property>
<property name="shortcut">
<string>=</string>
</property>
</action>
<action name="actionZoom_out">
<property name="text">
<string>Zoom Out</string>
</property>
<property name="shortcut">
<string>-</string>
</property>
</action>
<action name="actionProject_2">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Project</string>
</property>
</action>
<action name="actionEffect_Controls">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Effect Controls</string>
</property>
</action>
<action name="actionViewer">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Viewer</string>
</property>
</action>
<action name="actionTimeline">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Timeline</string>
</property>
</action>
<action name="actionRipple_Delete">
<property name="text">
<string>Ripple Delete</string>
</property>
<property name="shortcut">
<string>Shift+Del</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="icons/icons.qrc"/>
</resources>
<connections/>
</ui>
+105
View File
@@ -0,0 +1,105 @@
#-------------------------------------------------
#
# Project created by QtCreator 2018-05-11T10:31:59
#
#-------------------------------------------------
QT += core gui multimedia opengl
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = olive-qt
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp \
panels/project.cpp \
panels/effectcontrols.cpp \
panels/viewer.cpp \
panels/timeline.cpp \
ui/sourcetable.cpp \
dialogs/aboutdialog.cpp \
ui/timelinewidget.cpp \
io/media.cpp \
project/sequence.cpp \
project/clip.cpp \
playback/playback.cpp \
playback/audio.cpp \
io/config.cpp \
dialogs/newsequencedialog.cpp \
ui/viewerwidget.cpp \
ui/viewercontainer.cpp \
dialogs/exportdialog.cpp \
ui/collapsiblewidget.cpp \
effects/transformeffect.cpp \
panels/panels.cpp \
effects/volumeeffect.cpp \
effects/paneffect.cpp \
project/effect.cpp \
effects/effects.cpp \
playback/cacher.cpp \
io/exportthread.cpp
HEADERS += \
mainwindow.h \
panels/project.h \
panels/effectcontrols.h \
panels/viewer.h \
panels/timeline.h \
ui/sourcetable.h \
dialogs/aboutdialog.h \
ui/timelinewidget.h \
io/media.h \
project/sequence.h \
project/clip.h \
playback/playback.h \
playback/audio.h \
effects/effects.h \
io/config.h \
ui/timeline-tools.h \
dialogs/newsequencedialog.h \
ui/viewerwidget.h \
ui/viewercontainer.h \
dialogs/exportdialog.h \
ui/collapsiblewidget.h \
project/effect.h \
panels/panels.h \
playback/cacher.h \
io/exportthread.h
FORMS += \
mainwindow.ui \
panels/project.ui \
panels/effectcontrols.ui \
panels/viewer.ui \
panels/timeline.ui \
dialogs/aboutdialog.ui \
dialogs/newsequencedialog.ui \
dialogs/exportdialog.ui
win32 {
LIBS += -L../ffmpeg/lib -lavutil -lavformat -lavcodec -lswscale -lswresample opengl32.lib
INCLUDEPATH = ../ffmpeg/include
RC_FILE = icons/win.rc
}
linux {
LIBS += -lavutil -lavformat -lavcodec -lswscale -lswresample
}
RESOURCES += \
icons/icons.qrc \
styles/styles.qrc
+375
View File
@@ -0,0 +1,375 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.1, 2018-05-30T03:21:31. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{89fae42a-e0bc-4377-8782-ec7014933bdd}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuelist type="QVariantList" key="ClangStaticAnalyzer.SuppressedDiagnostics"/>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.10.1 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.10.1 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5101.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">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/olive/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<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">E:/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<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">E:/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy Configuration</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">E:/olive/build-olive-qt-Desktop_Qt_5_10_1_MSVC2017_64bit-Debug/debug/olive-qt.exe</value>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">E:/olive/build-olive-qt-Desktop_Qt_5_10_1_MSVC2017_64bit-Debug/debug/</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run E:\olive\build-olive-qt-Desktop_Qt_5_10_1_MSVC2017_64bit-Debug\debug\olive-qt.exe</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">VC run</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</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>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<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:E:/olive/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">E:/olive/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">2</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>
+315
View File
@@ -0,0 +1,315 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.1, 2018-05-26T16:50:57. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{3af06612-75ce-48d7-b444-7dc372f1566d}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.10.1 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.10.1 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5101.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">C:/Users/Matt/Documents/temp</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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<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">//neptune/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<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">//neptune/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy Configuration</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable"></value>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</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>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>
+375
View File
@@ -0,0 +1,375 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.1, 2018-05-26T15:37:44. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{89fae42a-e0bc-4377-8782-ec7014933bdd}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuelist type="QVariantList" key="ClangStaticAnalyzer.SuppressedDiagnostics"/>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.10.1 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.10.1 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5101.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">E:/olive/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<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">E:/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<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">E:/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<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="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy Configuration</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">E:/olive/build-olive-qt-Desktop_Qt_5_10_1_MSVC2017_64bit-Debug/debug/olive-qt.exe</value>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">E:/olive/build-olive-qt-Desktop_Qt_5_10_1_MSVC2017_64bit-Debug/debug/</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run E:\olive\build-olive-qt-Desktop_Qt_5_10_1_MSVC2017_64bit-Debug\debug\olive-qt.exe</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">VC run</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</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>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">olive-qt</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">olive-qt2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:E:/olive/olive-qt/olive-qt.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-qt.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">E:/olive/build-olive-qt-Desktop_Qt_5_10_1_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>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">2</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>
+59
View File
@@ -0,0 +1,59 @@
#include "effectcontrols.h"
#include "ui_effectcontrols.h"
#include <QMenu>
#include <QDebug>
#include <QVBoxLayout>
#include "effects/effects.h"
#include "project/clip.h"
#include "project/effect.h"
#include "ui/collapsiblewidget.h"
EffectControls::EffectControls(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::EffectControls)
{
ui->setupUi(this);
init_effects();
clip = NULL;
set_clip(NULL);
}
EffectControls::~EffectControls()
{
delete ui;
}
void EffectControls::on_pushButton_clicked()
{
QMenu effects_menu(this);
for (int i=0;i<video_effect_names.size();i++) {
effects_menu.addAction(video_effect_names.at(i));
}
effects_menu.addSeparator();
for (int i=0;i<audio_effect_names.size();i++) {
effects_menu.addAction(audio_effect_names.at(i));
}
effects_menu.exec(QCursor::pos());
}
void EffectControls::set_clip(Clip* c) {
// clear ui->scrollAreaWidgetContents
if (clip != NULL) {
for (int i=0;i<clip->effects.size();i++) {
clip->effects.at(i)->container->setParent(NULL);
}
}
ui->pushButton->setEnabled(c != NULL);
if (c != NULL) {
for (int i=0;i<c->effects.size();i++) {
static_cast<QVBoxLayout*>(ui->scrollAreaWidgetContents->layout())->insertWidget(i, c->effects.at(i)->container);
}
}
clip = c;
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef EFFECTCONTROLS_H
#define EFFECTCONTROLS_H
#include <QDockWidget>
struct Clip;
namespace Ui {
class EffectControls;
}
class EffectControls : public QDockWidget
{
Q_OBJECT
public:
explicit EffectControls(QWidget *parent = 0);
~EffectControls();
void set_clip(Clip* c);
private slots:
void on_pushButton_clicked();
private:
Ui::EffectControls *ui;
Clip* clip;
};
#endif // EFFECTCONTROLS_H
+98
View File
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EffectControls</class>
<widget class="QDockWidget" name="EffectControls">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="features">
<set>QDockWidget::AllDockWidgetFeatures</set>
</property>
<property name="windowTitle">
<string>Effect Controls</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>398</width>
<height>253</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>[+] Add Effect</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
+6
View File
@@ -0,0 +1,6 @@
#include "panels.h"
Project* panel_project;
EffectControls* panel_effect_controls;
Viewer* panel_viewer;
Timeline* panel_timeline;
+14
View File
@@ -0,0 +1,14 @@
#ifndef PANELS_H
#define PANELS_H
class Project;
class EffectControls;
class Viewer;
class Timeline;
extern Project* panel_project;
extern EffectControls* panel_effect_controls;
extern Viewer* panel_viewer;
extern Timeline* panel_timeline;
#endif // PANELS_H
+164
View File
@@ -0,0 +1,164 @@
#include "project.h"
#include "ui_project.h"
#include "io/media.h"
#include <QFileDialog>
#include <QString>
#include <QVariant>
#include <QDebug>
#include <QCharRef>
#include <QMessageBox>
#include "panels/timeline.h"
#include "project/sequence.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}
Project::Project(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::Project)
{
ui->setupUi(this);
}
Project::~Project()
{
delete ui;
}
QString Project::get_next_sequence_name() {
int n = 1;
bool found = true;
QString name;
while (found) {
found = false;
name = "Sequence ";
if (n < 10) {
name += "0";
}
name += QString::number(n);
for (int i=0;i<ui->treeWidget->topLevelItemCount();i++) {
if (QString::compare(ui->treeWidget->topLevelItem(i)->text(0), name, Qt::CaseInsensitive) == 0) {
found = true;
n++;
break;
}
}
}
return name;
}
void Project::new_sequence(Sequence *s) {
Media* m = new Media();
m->is_sequence = true;
m->sequence = s;
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, s->name);
item->setData(0, Qt::UserRole + 1, QVariant::fromValue(reinterpret_cast<quintptr>(m)));
ui->treeWidget->addTopLevelItem(item);
source_table = ui->treeWidget;
}
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;
if (file[lastcharindex].isDigit()) {
bool is_img_sequence = false;
QString sequence_test(file);
char lastchar = sequence_test.at(lastcharindex).toLatin1();
sequence_test[lastcharindex] = lastchar + 1;
if (QFileInfo::exists(sequence_test)) is_img_sequence = true;
sequence_test[lastcharindex] = lastchar - 1;
if (QFileInfo::exists(sequence_test)) is_img_sequence = true;
if (is_img_sequence &&
QMessageBox::question(this, "Image sequence detected", "The file '" + file + "' appears to be part of an image sequence. Would you like to import it as such?", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) {
// change url to an image sequence instead
int digit_count = 0;
QString ext = file.mid(lastcharindex+1);
while (file[lastcharindex].isDigit()) {
digit_count++;
lastcharindex--;
}
QString new_filename = file.left(lastcharindex+1) + "%";
if (digit_count < 10) {
new_filename += "0";
}
new_filename += QString::number(digit_count) + "d" + ext;
file = new_filename;
}
}
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));
item->setData(0, Qt::UserRole + 1, QVariant::fromValue(reinterpret_cast<quintptr>(m)));
ui->treeWidget->addTopLevelItem(item);
}
}
avformat_close_input(&pFormatCtx);
delete [] filename;
}
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef PROJECT_H
#define PROJECT_H
#include <QDockWidget>
#include <QVector>
struct Media;
struct Sequence;
class Timeline;
class Viewer;
class SourceTable;
namespace Ui {
class Project;
}
class Project : public QDockWidget
{
Q_OBJECT
public:
explicit Project(QWidget *parent = 0);
~Project();
void import_dialog();
void new_sequence(Sequence* s);
QString get_next_sequence_name();
SourceTable* source_table;
private:
Ui::Project *ui;
};
#endif // PROJECT_H
+95
View File
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Project</class>
<widget class="QDockWidget" name="Project">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>504</width>
<height>371</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Project</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="SourceTable" name="treeWidget">
<property name="editTriggers">
<set>QAbstractItemView::CurrentChanged|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
<property name="dragEnabled">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragOnly</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="headerHidden">
<bool>false</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<attribute name="headerDefaultSectionSize">
<number>200</number>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Duration</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>SourceTable</class>
<extends>QTreeWidget</extends>
<header>ui/sourcetable.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
+320
View File
@@ -0,0 +1,320 @@
#include "timeline.h"
#include "ui_timeline.h"
#include "panels/panels.h"
#include "panels/effectcontrols.h"
#include "ui/timelinewidget.h"
#include "project/sequence.h"
#include "project/clip.h"
#include "ui/viewerwidget.h"
#include "playback/audio.h"
#include "panels/viewer.h"
#include "playback/cacher.h"
#include "playback/playback.h"
#include <QTime>
Timeline::Timeline(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::Timeline)
{
selecting = moving_init = moving_proc = splitting = importing = playing = trim_in = false;
last_frame = playhead = 0;
trim_target = -1;
ui->setupUi(this);
ui->video_area->bottom_align = true;
tool_buttons.append(ui->toolArrowButton);
tool_buttons.append(ui->toolEditButton);
tool_buttons.append(ui->toolRippleButton);
tool_buttons.append(ui->toolRazorButton);
tool_buttons.append(ui->toolSlipButton);
tool_buttons.append(ui->toolRollingButton);
ui->toolArrowButton->click();
zoom = 1.0f;
sequence = NULL;
set_sequence(NULL);
connect(&playback_updater, SIGNAL(timeout()), this, SLOT(repaint_timeline()));
}
Timeline::~Timeline()
{
delete ui;
}
void Timeline::go_to_start() {
seek(0);
}
void Timeline::previous_frame() {
seek(playhead-1);
}
void Timeline::next_frame() {
seek(playhead+1);
}
void Timeline::seek(long p) {
pause();
// reset all clip audio
for (int i=0;i<sequence->clip_count();i++) {
Clip& c = sequence->get_clip(i);
c.reset_audio = true;
c.frame_sample_index = 0;
}
clear_cache(true, true);
switch_audio_cache = true;
reading_audio_cache_A = false;
playhead = p;
}
bool Timeline::toggle_play() {
if (playing) {
pause();
} else {
play();
}
return playing;
}
void Timeline::play() {
playhead_start = playhead;
playback_timer.start();
playback_updater.start();
playing = true;
if (switch_audio_cache) {
// add something to pre-cache audio
}
}
void Timeline::pause() {
playing = false;
}
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);
for (int i=0;i<tool_buttons.count();i++) {
tool_buttons[i]->setEnabled(!null_sequence);
}
ui->pushButton_4->setEnabled(!null_sequence);
ui->pushButton_5->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);
redraw_all_clips();
playback_updater.setInterval(floor(1000 / sequence->frame_rate));
}
}
bool Timeline::focused() {
return (ui->video_area->hasFocus() || ui->audio_area->hasFocus());
}
void Timeline::repaint_timeline() {
if (playing) {
playhead = playhead_start + (playback_timer.elapsed() * 0.001 * sequence->frame_rate);
}
ui->video_area->update();
ui->audio_area->update();
if (last_frame != playhead) {
panel_viewer->viewer_widget->update();
last_frame = playhead;
}
}
void Timeline::redraw_all_clips() {
ui->video_area->redraw_clips();
ui->audio_area->redraw_clips();
}
void Timeline::select_all() {
selections.clear();
for (int i=0;i<sequence->clip_count();i++) {
Clip& c = sequence->get_clip(i);
selections.append({c.timeline_in, c.timeline_out, c.track});
}
}
void Timeline::delete_selection(bool ripple_delete) {
if (selections.size() > 0) {
panel_effect_controls->set_clip(NULL);
long ripple_point = selections.at(0).in;
long ripple_length = selections.at(0).out - selections.at(0).in;
for (int i=0;i<selections.size();i++) {
const Selection& s = selections.at(i);
sequence->delete_area(s.in, s.out, s.track);
if (ripple_delete) {
if (ripple_point > s.in) ripple_point = s.in;
if (ripple_length > s.out - s.in) ripple_length = s.out - s.in;
}
}
selections.clear();
if (ripple_delete) {
long validator;
for (int i=0;i<sequence->clip_count();i++) {
// check every clip after and see if it'll collide
// NOTE, we could probably re-use the validation code for the ripple tool here for optimization (since it's technically better code I think)
Clip& c = sequence->get_clip(i);
if (c.timeline_in >= ripple_point) {
for (int j=0;j<sequence->clip_count();j++) {
Clip& cc = sequence->get_clip(j);
if (cc.timeline_in < ripple_point) {
validator = c.timeline_in - ripple_length - cc.timeline_out;
if (validator < 0) ripple_length += validator;
if (ripple_length <= 0) {
// we've seen all we need to see here (can't ripple so stop looping)
i = j = sequence->clip_count();
}
}
}
}
}
if (ripple_length > 0) ripple(ripple_point, -ripple_length);
}
redraw_all_clips();
}
}
void Timeline::zoom_in() {
zoom *= 2;
redraw_all_clips();
}
void Timeline::zoom_out() {
zoom /= 2;
redraw_all_clips();
}
void Timeline::ripple(long ripple_point, long ripple_length) {
for (int i=0;i<sequence->clip_count();i++) {
Clip& c = sequence->get_clip(i);
if (c.timeline_in >= ripple_point) {
c.timeline_in += ripple_length;
c.timeline_out += ripple_length;
}
}
for (int i=0;i<selections.size();i++) {
Selection& s = selections[i];
if (s.in >= ripple_point) {
s.in += ripple_length;
s.out += ripple_length;
}
}
}
void Timeline::decheck_tool_buttons(QObject* sender) {
for (int i=0;i<tool_buttons.count();i++) {
if (tool_buttons[i] != sender) {
tool_buttons[i]->setChecked(false);
}
}
}
void Timeline::on_toolEditButton_toggled(bool checked)
{
if (checked) {
decheck_tool_buttons(sender());
ui->timeline_area->setCursor(Qt::IBeamCursor);
tool = TIMELINE_TOOL_EDIT;
}
}
void Timeline::on_toolArrowButton_toggled(bool checked)
{
if (checked) {
decheck_tool_buttons(sender());
ui->timeline_area->setCursor(Qt::ArrowCursor);
tool = TIMELINE_TOOL_POINTER;
}
}
void Timeline::on_toolRazorButton_toggled(bool checked)
{
if (checked) {
decheck_tool_buttons(sender());
ui->timeline_area->setCursor(Qt::IBeamCursor);
tool = TIMELINE_TOOL_RAZOR;
}
}
void Timeline::on_pushButton_4_clicked()
{
zoom_in();
}
void Timeline::on_pushButton_5_clicked()
{
zoom_out();
}
bool Timeline::is_clip_selected(int clip_index) {
Clip& clip = sequence->get_clip(clip_index);
for (int i=0;i<selections.size();i++) {
const Selection& s = selections.at(i);
if (clip.track == s.track && clip.timeline_in >= s.in && clip.timeline_out <= s.out) {
return true;
}
}
return false;
}
void Timeline::on_toolRippleButton_toggled(bool checked)
{
if (checked) {
decheck_tool_buttons(sender());
ui->timeline_area->setCursor(Qt::ArrowCursor);
tool = TIMELINE_TOOL_RIPPLE;
}
}
void Timeline::on_toolRollingButton_toggled(bool checked)
{
if (checked) {
decheck_tool_buttons(sender());
ui->timeline_area->setCursor(Qt::ArrowCursor);
tool = TIMELINE_TOOL_ROLLING;
}
}
void Timeline::on_toolSlipButton_toggled(bool checked)
{
if (checked) {
decheck_tool_buttons(sender());
ui->timeline_area->setCursor(Qt::ArrowCursor);
tool = TIMELINE_TOOL_SLIP;
}
}
+143
View File
@@ -0,0 +1,143 @@
#ifndef TIMELINE_H
#define TIMELINE_H
#include "ui/timeline-tools.h"
#include <QDockWidget>
#include <QVector>
#include <QTime>
#include <QTimer>
class QPushButton;
class SourceTable;
class ViewerWidget;
struct Sequence;
struct Clip;
struct Media;
struct MediaStream;
struct Ghost {
Clip* clip;
long in;
long out;
int track;
long clip_in;
long old_in;
long old_out;
int old_track;
long old_clip_in;
// importing variables
Media* media;
MediaStream* media_stream;
// other variables
long ghost_length;
long media_length;
};
struct Selection {
long in;
long out;
int track;
long old_in;
long old_out;
int old_track;
};
namespace Ui {
class Timeline;
}
class Timeline : public QDockWidget
{
Q_OBJECT
public:
explicit Timeline(QWidget *parent = 0);
~Timeline();
bool focused();
void zoom_in();
void zoom_out();
void set_sequence(Sequence* s);
Sequence* sequence;
long playhead;
// playback functions
void go_to_start();
void previous_frame();
void next_frame();
void seek(long p);
bool toggle_play();
void play();
void pause();
void go_to_end();
bool playing;
long playhead_start;
QTime playback_timer;
QTimer playback_updater;
// shared information
int tool;
float zoom;
long drag_frame_start;
int drag_track_start;
void redraw_all_clips();
// selecting functions
bool selecting;
QVector<Selection> selections;
bool is_clip_selected(int clip_index);
void delete_selection(bool ripple);
void select_all();
// moving
bool moving_init;
bool moving_proc;
QVector<Ghost> ghosts;
// trimming
int trim_target;
bool trim_in;
// splitting
bool splitting;
// importing
bool importing;
// ripple
void ripple(long ripple_point, long ripple_length);
public slots:
void repaint_timeline();
private slots:
void on_toolEditButton_toggled(bool checked);
void on_toolArrowButton_toggled(bool checked);
void on_toolRazorButton_toggled(bool checked);
void on_pushButton_4_clicked();
void on_pushButton_5_clicked();
void on_toolRippleButton_toggled(bool checked);
void on_toolRollingButton_toggled(bool checked);
void on_toolSlipButton_toggled(bool checked);
private:
Ui::Timeline *ui;
QVector<QPushButton*> tool_buttons;
void decheck_tool_buttons(QObject* sender);
void set_tool(int tool);
long last_frame;
};
#endif // TIMELINE_H
+355
View File
@@ -0,0 +1,355 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Timeline</class>
<widget class="QDockWidget" name="Timeline">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>840</width>
<height>535</height>
</rect>
</property>
<property name="windowTitle">
<string>Timeline</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>4</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="toolArrowButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Pointer Tool (V)</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/arrow.png</normaloff>:/icons/arrow.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toolEditButton">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Edit Tool (X)</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/beam.png</normaloff>:/icons/beam.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toolRippleButton">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Ripple Tool (B)</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/ripple.png</normaloff>:/icons/ripple.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toolRollingButton">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Rolling Tool (N)</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/rolling.png</normaloff>:/icons/rolling.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toolRazorButton">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Razor Tool (C)</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/razor.png</normaloff>:/icons/razor.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="toolSlipButton">
<property name="toolTip">
<string>Slip Tool (Y)</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/slip.png</normalon>
</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Zoom In (=)</string>
</property>
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_5">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Zoom Out (-)</string>
</property>
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QScrollArea" name="timeline_area">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>789</width>
<height>494</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="TimelineWidget" name="video_area" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
</widget>
<widget class="TimelineWidget" name="audio_area" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>TimelineWidget</class>
<extends>QWidget</extends>
<header>ui/timelinewidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../icons/icons.qrc"/>
</resources>
<connections/>
</ui>
+79
View File
@@ -0,0 +1,79 @@
#include "viewer.h"
#include "ui_viewer.h"
#include "playback/audio.h"
#include "timeline.h"
#include "project/sequence.h"
#include "panels/panels.h"
extern "C" {
#include <libavcodec/avcodec.h>
}
Viewer::Viewer(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::Viewer)
{
ui->setupUi(this);
ui->glViewerPane->child = ui->openGLWidget;
viewer_widget = ui->openGLWidget;
set_sequence(NULL);
}
Viewer::~Viewer()
{
init_audio(NULL);
delete ui;
}
void Viewer::set_sequence(Sequence* s) {
bool null_sequence = (s == NULL);
sequence = s;
ui->openGLWidget->setEnabled(!null_sequence);
ui->openGLWidget->setVisible(!null_sequence);
ui->pushButton->setEnabled(!null_sequence);
ui->pushButton_2->setEnabled(!null_sequence);
ui->pushButton_3->setEnabled(!null_sequence);
ui->pushButton_4->setEnabled(!null_sequence);
ui->pushButton_5->setEnabled(!null_sequence);
if (!null_sequence) {
ui->glViewerPane->aspect_ratio = (float) sequence->width / (float) sequence->height;
ui->glViewerPane->adjust();
}
init_audio(s);
update();
}
void Viewer::on_pushButton_clicked()
{
panel_timeline->go_to_start();
}
void Viewer::on_pushButton_5_clicked()
{
panel_timeline->go_to_end();
}
void Viewer::on_pushButton_2_clicked()
{
panel_timeline->previous_frame();
}
void Viewer::on_pushButton_4_clicked()
{
panel_timeline->next_frame();
}
void Viewer::on_pushButton_3_clicked()
{
if (panel_timeline->toggle_play()) {
// playing
ui->pushButton_3->setIcon(QIcon(":/icons/pause.png"));
} else {
ui->pushButton_3->setIcon(QIcon(":/icons/play.png"));
}
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef VIEWER_H
#define VIEWER_H
#include <QDockWidget>
class Timeline;
class ViewerWidget;
struct Sequence;
namespace Ui {
class Viewer;
}
class Viewer : public QDockWidget
{
Q_OBJECT
public:
explicit Viewer(QWidget *parent = 0);
~Viewer();
void set_sequence(Sequence* s);
void compose();
Sequence* sequence;
ViewerWidget* viewer_widget;
private slots:
void on_pushButton_clicked();
void on_pushButton_5_clicked();
void on_pushButton_2_clicked();
void on_pushButton_4_clicked();
void on_pushButton_3_clicked();
private:
Ui::Viewer *ui;
};
#endif // VIEWER_H
+319
View File
@@ -0,0 +1,319 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Viewer</class>
<widget class="QDockWidget" name="Viewer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>583</width>
<height>396</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Viewer</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="ViewerContainer" name="glViewerPane" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<widget class="ViewerWidget" name="openGLWidget">
<property name="geometry">
<rect>
<x>130</x>
<y>60</y>
<width>301</width>
<height>221</height>
</rect>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
</widget>
</widget>
</item>
<item>
<widget class="QWidget" name="playbackControls" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>36</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/prev.png</normaloff>:/icons/prev.png</iconset>
</property>
<property name="iconSize">
<size>
<width>14</width>
<height>14</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>36</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/rew.png</normaloff>:/icons/rew.png</iconset>
</property>
<property name="iconSize">
<size>
<width>14</width>
<height>14</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>36</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/play.png</normalon>
</iconset>
</property>
<property name="iconSize">
<size>
<width>14</width>
<height>14</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>36</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/ff.png</normalon>
</iconset>
</property>
<property name="iconSize">
<size>
<width>14</width>
<height>14</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>36</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/next.png</normaloff>:/icons/next.png</iconset>
</property>
<property name="iconSize">
<size>
<width>14</width>
<height>14</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>ViewerWidget</class>
<extends>QOpenGLWidget</extends>
<header>ui/viewerwidget.h</header>
</customwidget>
<customwidget>
<class>ViewerContainer</class>
<extends>QWidget</extends>
<header>ui/viewercontainer.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../icons/icons.qrc"/>
</resources>
<connections/>
</ui>
+72
View File
@@ -0,0 +1,72 @@
#include "audio.h"
#include "project/sequence.h"
#include <QAudioOutput>
#include <QDebug>
extern "C" {
#include <libavcodec/avcodec.h>
}
QAudioOutput* audio_output;
QIODevice* audio_io_device;
bool audio_device_set = false;
uint8_t* audio_cache_A = NULL;
uint8_t* audio_cache_B = NULL;
int audio_cache_size = 0;
bool switch_audio_cache = true;
bool reading_audio_cache_A = false;
void init_audio(Sequence* s) {
if (audio_cache_A != NULL) {
delete [] audio_cache_A;
audio_cache_A = NULL;
}
if (audio_cache_B != NULL) {
delete [] audio_cache_B;
audio_cache_B = NULL;
}
if (audio_device_set) {
audio_output->stop();
delete audio_output;
audio_device_set = false;
}
if (s != NULL) {
QAudioFormat audio_format;
audio_format.setSampleRate(s->audio_frequency);
audio_format.setChannelCount(av_get_channel_layout_nb_channels(s->audio_layout));
audio_format.setSampleSize(16);
audio_format.setCodec("audio/pcm");
audio_format.setByteOrder(QAudioFormat::LittleEndian);
audio_format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (!info.isFormatSupported(audio_format)) {
qWarning() << "[WARNING] Couldn't initialize audio. Audio format is not supported by backend";
} else {
audio_output = new QAudioOutput(audio_format);
// connect
audio_io_device = audio_output->start();
audio_device_set = true;
audio_cache_size = av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(s->audio_layout), s->audio_frequency/8, AV_SAMPLE_FMT_S16, 1);
audio_cache_A = new uint8_t[audio_cache_size];
audio_cache_B = new uint8_t[audio_cache_size];
clear_cache(true, true);
}
}
}
void clear_cache(bool clear_A, bool clear_B) {
if (clear_A) {
memset(audio_cache_A, 0, audio_cache_size);
}
if (clear_B) {
memset(audio_cache_B, 0, audio_cache_size);
}
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef AUDIO_H
#define AUDIO_H
#include <QIODevice>
#include <QMutex>
struct Sequence;
extern QIODevice* audio_io_device;
extern uint8_t* audio_cache_A;
extern uint8_t* audio_cache_B;
extern int audio_cache_size;
extern bool switch_audio_cache;
extern bool reading_audio_cache_A;
void init_audio(Sequence* s);
void clear_cache(bool clear_A, bool clear_B);
#endif // AUDIO_H
+339
View File
@@ -0,0 +1,339 @@
#include "cacher.h"
#include "project/clip.h"
#include "project/sequence.h"
#include "io/media.h"
#include "playback/audio.h"
#include "playback/playback.h"
#include "effects/effects.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
#include <QDebug>
void cache_audio_worker(Clip* c, bool write_A) {
// gets one frame worth of audio and sends it to the audio buffer
AVFrame* frame = c->cache_A.frames[0];
uint8_t* cache = (write_A) ? audio_cache_A : audio_cache_B;
int bytes_written = 0;
int j = 0;
while (bytes_written < audio_cache_size && !c->reached_end) {
// is there audio left in the frame
if (c->frame_sample_index == 0) {
// no more audio left in frame, get a new one
retrieve_next_frame_raw_data(c, frame);
}
if (!c->reached_end) {
int nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast<AVSampleFormat>(frame->format), 1);
int limit = std::min(c->frame_sample_index + audio_cache_size - bytes_written, nb_bytes);
// perform all audio effects
for (unsigned int j=0;j<c->effects.size();j++) {
c->effects[j]->process_audio(frame->data[0], limit);
}
// mix audio into cache
for (int i=c->frame_sample_index;i<limit;i++) {
cache[j] += frame->data[0][i];
j++;
}
bytes_written += limit - c->frame_sample_index;
c->frame_sample_index = (limit == nb_bytes) ? 0 : limit;
}
}
}
void cache_video_worker(Clip* c, long playhead, ClipCache* cache) {
cache->mutex.lock();
cache->offset = playhead;
for (size_t i=0;i<c->cache_size;i++) {
retrieve_next_frame_raw_data(c, cache->frames[i]);
}
cache->written = true;
cache->unread = true;
cache->mutex.unlock();
}
void reset_cache(Clip* c, long target_frame) {
// if we seek to a whole other place in the timeline, we'll need to reset the cache with new values
if (c->media_stream->infinite_length) {
// if this clip is a still image, we only need one frame
if (!c->cache_A.written) {
retrieve_next_frame_raw_data(c, c->cache_A.frames[0]);
c->cache_A.written = true;
}
} else {
// flush ffmpeg codecs
avcodec_flush_buffers(c->codecCtx);
double timebase = av_q2d(c->stream->time_base);
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// seeks to nearest keyframe (target_frame represents internal clip frame)
av_seek_frame(c->formatCtx, c->media_stream->file_index, clip_frame_to_seconds(c, target_frame) / timebase, AVSEEK_FLAG_BACKWARD);
// play up to the frame we actually want
long retrieved_frame = 0;
AVFrame* temp = av_frame_alloc();
do {
retrieve_next_frame(c, temp);
if (retrieved_frame == 0) {
if (target_frame != 0) {
// retrieved_frame = floor(av_frame_get_best_effort_timestamp(temp) * timebase * av_q2d(c->stream->avg_frame_rate));
retrieved_frame = floor(temp->pts * timebase * av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, temp)));
}
} else {
retrieved_frame++;
}
} while (retrieved_frame < target_frame);
av_frame_free(&temp);
} else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
// seek (target_frame represents timeline timecode in frames, not clip timecode)
swr_drop_output(c->swr_ctx, swr_get_out_samples(c->swr_ctx, 0));
av_seek_frame(c->formatCtx, c->media_stream->file_index, playhead_to_seconds(c, target_frame) / timebase, AVSEEK_FLAG_ANY);
}
}
}
Cacher::Cacher(Clip* c) : clip(c) {}
void open_clip_worker(Clip* clip) {
// opens file resource for FFmpeg and prepares Clip struct for playback
QByteArray ba = clip->media->url.toUtf8();
const char* filename = ba.constData();
int errCode = avformat_open_input(
&clip->formatCtx,
filename,
NULL,
NULL
);
if (errCode != 0) {
char err[1024];
av_strerror(errCode, err, 1024);
qDebug() << "[ERROR] Could not open" << filename << "-" << err;
}
errCode = avformat_find_stream_info(clip->formatCtx, NULL);
if (errCode < 0) {
char err[1024];
av_strerror(errCode, err, 1024);
qDebug() << "[ERROR] Could not open" << filename << "-" << err;
}
av_dump_format(clip->formatCtx, 0, filename, 0);
clip->stream = clip->formatCtx->streams[clip->media_stream->file_index];
clip->codec = avcodec_find_decoder(clip->stream->codecpar->codec_id);
clip->codecCtx = avcodec_alloc_context3(clip->codec);
avcodec_parameters_to_context(clip->codecCtx, clip->stream->codecpar);
AVDictionary* opts = NULL;
// decoding optimization configuration
if (clip->stream->codecpar->codec_id != AV_CODEC_ID_PNG &&
clip->stream->codecpar->codec_id != AV_CODEC_ID_APNG &&
clip->stream->codecpar->codec_id != AV_CODEC_ID_TIFF &&
clip->stream->codecpar->codec_id != AV_CODEC_ID_PSD) {
av_dict_set(&opts, "threads", "auto", 0);
}
if (clip->stream->codecpar->codec_id == AV_CODEC_ID_H264) {
av_dict_set(&opts, "tune", "fastdecode", 0);
av_dict_set(&opts, "tune", "zerolatency", 0);
}
// Open codec
if (avcodec_open2(clip->codecCtx, clip->codec, &opts) < 0) {
qDebug() << "[ERROR] Could not open codec";
}
if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// set up swscale context - primarily used for colorspace conversion
// as "scaling" is actually done by OpenGL
int dest_format = AV_PIX_FMT_RGBA;
clip->sws_ctx = sws_getContext(
clip->stream->codecpar->width,
clip->stream->codecpar->height,
static_cast<AVPixelFormat>(clip->stream->codecpar->format),
ceil(clip->stream->codecpar->width/2)*2,
ceil(clip->stream->codecpar->height/2)*2,
static_cast<AVPixelFormat>(dest_format),
SWS_FAST_BILINEAR,
NULL,
NULL,
NULL
);
// create memory cache for video
if (clip->media_stream->infinite_length) {
clip->cache_size = 1;
} else {
clip->cache_size = ceil(av_q2d(av_guess_frame_rate(clip->formatCtx, clip->stream, NULL))/4); // cache is half a second in total
// infinite length doesn't need cache B
clip->cache_B.frames = new AVFrame* [clip->cache_size];
}
clip->cache_A.frames = new AVFrame* [clip->cache_size];
for (size_t i=0;i<clip->cache_size;i++) {
clip->cache_A.frames[i] = av_frame_alloc();
av_frame_make_writable(clip->cache_A.frames[i]);
clip->cache_A.frames[i]->width = clip->stream->codecpar->width;
clip->cache_A.frames[i]->height = clip->stream->codecpar->height;
clip->cache_A.frames[i]->format = dest_format;
av_frame_get_buffer(clip->cache_A.frames[i], 0);
clip->cache_A.frames[i]->linesize[0] = clip->stream->codecpar->width*4;
if (!clip->media_stream->infinite_length) {
clip->cache_B.frames[i] = av_frame_alloc();
av_frame_make_writable(clip->cache_B.frames[i]);
clip->cache_B.frames[i]->width = clip->stream->codecpar->width;
clip->cache_B.frames[i]->height = clip->stream->codecpar->height;
clip->cache_B.frames[i]->format = dest_format;
av_frame_get_buffer(clip->cache_B.frames[i], 0);
clip->cache_B.frames[i]->linesize[0] = clip->stream->codecpar->width*4;
}
}
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
// if FFmpeg can't pick up the channel layout (usually WAV), assume
// based on channel count (doesn't support surround sound sources yet)
if (clip->codecCtx->channel_layout == 0) {
switch (clip->stream->codecpar->channels) {
case 1: clip->codecCtx->channel_layout = AV_CH_LAYOUT_MONO;
default:
clip->codecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
qDebug() << "[WARNING] Could not detect audio channel layout - assuming stereo";
break;
}
}
int sample_format = AV_SAMPLE_FMT_S16;
// init resampling context
clip->swr_ctx = swr_alloc_set_opts(
NULL,
clip->sequence->audio_layout,
static_cast<AVSampleFormat>(sample_format),
clip->sequence->audio_frequency,
clip->stream->codecpar->channel_layout,
static_cast<AVSampleFormat>(clip->stream->codecpar->format),
clip->stream->codecpar->sample_rate,
0,
NULL
);
swr_init(clip->swr_ctx);
// set up cache
clip->cache_A.frames = new AVFrame* [1];
clip->cache_A.frames[0] = av_frame_alloc();
clip->cache_A.frames[0]->format = sample_format;
clip->cache_A.frames[0]->channel_layout = clip->sequence->audio_layout;
clip->cache_A.frames[0]->channels = av_get_channel_layout_nb_channels(clip->cache_A.frames[0]->channel_layout);
clip->cache_A.frames[0]->sample_rate = clip->sequence->audio_frequency;
av_frame_make_writable(clip->cache_A.frames[0]);
clip->reset_audio = true;
}
clip->frame = av_frame_alloc();
qDebug() << "[INFO] Clip opened on track" << clip->track;
clip->open = true;
}
void cache_clip_worker(Clip* clip, long playhead, bool write_A, bool write_B, bool reset) {
if (reset) {
// note: for video, playhead is in "internal clip" frames - for audio, it's the timeline playhead
reset_cache(clip, playhead);
clip->reset_audio = false;
}
if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
if (write_A) {
cache_video_worker(clip, playhead, &clip->cache_A);
playhead += clip->cache_size;
}
if (write_B) {
cache_video_worker(clip, playhead, &clip->cache_B);
}
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
if (write_A) {
cache_audio_worker(clip, true);
}
if (write_B) {
cache_audio_worker(clip, false);
}
}
}
void close_clip_worker(Clip* clip) {
// closes ffmpeg file handle and frees any memory used for caching
if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
sws_freeContext(clip->sws_ctx);
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
swr_free(&clip->swr_ctx);
}
avcodec_close(clip->codecCtx);
avcodec_free_context(&clip->codecCtx);
avformat_close_input(&clip->formatCtx);
for (size_t i=0;i<clip->cache_size;i++) {
av_frame_free(&clip->cache_A.frames[i]);
if (!clip->media_stream->infinite_length) av_frame_free(&clip->cache_B.frames[i]);
}
delete [] clip->cache_A.frames;
if (!clip->media_stream->infinite_length) delete [] clip->cache_B.frames;
av_frame_free(&clip->frame);
clip->reset();
// remove clip from current_clips
cc_lock.lock();
bool found = false;
for (int i=0;i<current_clips.count();i++) {
if (current_clips[i] == clip) {
current_clips.erase(current_clips.begin()+i);
found = true;
i = current_clips.count();
}
}
cc_lock.unlock();
if (!found) qDebug() << "[WARNING] Could not remove clip from current clips";
qDebug() << "[INFO] Clip closed on track" << clip->track;
}
void Cacher::run() {
// open_lock is used to prevent the clip from being destroyed before the cacher has closed it properly
clip->open_lock.lock();
open_clip_worker(clip);
caching = true;
while (true) {
clip->can_cache.wait(&clip->lock);
if (!caching) {
break;
} else {
cache_clip_worker(clip, playhead, write_A, write_B, reset);
}
}
close_clip_worker(clip);
clip->lock.unlock();
clip->open_lock.unlock();
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef CACHER_H
#define CACHER_H
#include <QThread>
struct Clip;
class Cacher : public QThread
{
// Q_OBJECT
public:
Cacher(Clip* c);
void run() override;
bool caching;
// must be set before caching
long playhead;
bool write_A;
bool write_B;
bool reset;
private:
Clip* clip;
};
void open_clip_worker(Clip* clip);
void cache_clip_worker(Clip* clip, long playhead, bool write_A, bool write_B, bool reset);
void close_clip_worker(Clip* clip);
#endif // CACHER_H
+288
View File
@@ -0,0 +1,288 @@
#include "playback.h"
#include "project/clip.h"
#include "project/sequence.h"
#include "io/media.h"
#include "playback/audio.h"
#include "playback/cacher.h"
#include "panels/timeline.h"
#include <algorithm>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
#include <QObject>
#include <QOpenGLTexture>
#include <QDebug>
#include <QOpenGLPixelTransferOptions>
QList<Clip*> current_clips;
bool texture_failed = false;
QMutex cc_lock;
void handle_media(Sequence* sequence, long playhead, bool multithreaded) {
for (int i=0;i<sequence->clip_count();i++) {
Clip& c = sequence->get_clip(i);
// if clip starts within one second and/or hasn't finished yet
if (is_clip_active(&c, playhead)) {
// if thread is already working, we don't want to touch this,
// but we also don't want to hang the UI thread
if (!c.open) {
if (c.lock.tryLock()) {
open_clip(&c, multithreaded);
// add to current_clips, (insertion) sorted by track so composite them in order
cc_lock.lock();
bool found = false;
for (int j=0;j<current_clips.size();j++) {
if (current_clips[j]->track < c.track) {
current_clips.insert(current_clips.begin()+j, &c);
found = true;
break;
}
}
if (!found) {
current_clips.push_back(&c);
}
cc_lock.unlock();
}
}
} else if (c.open) {
close_clip(&c);
}
}
}
void open_clip(Clip* clip, bool multithreaded) {
clip->multithreaded = multithreaded;
if (multithreaded) {
// maybe keep cacher instance in memory while clip exists for performance?
clip->cacher = new Cacher(clip);
QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater()));
clip->cacher->start(QThread::LowPriority);
} else {
open_clip_worker(clip);
clip->lock.unlock();
}
}
void close_clip(Clip* clip) {
// destroy opengl texture in main thread
if (clip->texture != NULL) {
clip->texture->destroy();
clip->texture = NULL;
}
if (clip->multithreaded) {
clip->cacher->caching = false;
clip->can_cache.wakeAll();
} else {
close_clip_worker(clip);
}
}
void cache_clip(Clip* clip, long playhead, bool write_A, bool write_B, bool reset) {
if (clip->multithreaded) {
clip->cacher->playhead = playhead;
clip->cacher->write_A = write_A;
clip->cacher->write_B = write_B;
clip->cacher->reset = reset;
clip->can_cache.wakeAll();
} else {
cache_clip_worker(clip, playhead, write_A, write_B, reset);
}
}
void get_clip_frame(Clip* c, long playhead) {
if (c->open) {
long clip_time = seconds_to_clip_frame(c, playhead_to_seconds(c, playhead));
// do we need to update the texture?
if ((!c->media_stream->infinite_length && c->texture_frame != clip_time) ||
(c->media_stream->infinite_length && c->texture_frame == -1)) {
AVFrame* current_frame = NULL;
// get frame data
if (c->media_stream->infinite_length) { // if clip is a still frame, we only need one
if (c->cache_A.written) {
// retrieve cached frame
current_frame = c->cache_A.frames[0];
} else if (c->multithreaded) {
if (c->lock.tryLock()) {
// grab image (multi-threaded)
cache_clip(c, 0, false, false, true);
c->lock.unlock();
}
} else {
// grab image (single-threaded)
reset_cache(c, playhead);
}
} else {
// keeping a RAM cache improves performance, however it's detrimental when rendering
// determine which cache contains the requested frame
bool using_cache_A = false;
bool using_cache_B = false;
AVFrame** cache = NULL;
long cache_offset = 0;
bool cache_needs_reset = false;
if (c->cache_A.written && clip_time >= c->cache_A.offset && clip_time < c->cache_A.offset + c->cache_size) {
if (c->cache_A.mutex.tryLock()) { // lock in case cacher is still writing to it
using_cache_A = true;
c->cache_A.unread = false;
cache = c->cache_A.frames;
cache_offset = c->cache_A.offset;
c->cache_A.mutex.unlock();
}
} else if (c->cache_B.written && clip_time >= c->cache_B.offset && clip_time < c->cache_B.offset + c->cache_size) {
if (c->cache_B.mutex.tryLock()) { // lock in case cacher is still writing to it
using_cache_B = true;
c->cache_B.unread = false;
cache = c->cache_B.frames;
cache_offset = c->cache_B.offset;
c->cache_B.mutex.unlock();
}
} else {
// this is technically bad, unless we just seeked
c->cache_A.unread = c->cache_B.unread = false;
cache_needs_reset = true;
}
if (cache != NULL) {
current_frame = cache[clip_time - cache_offset];
}
// determine whether we should start filling the other cache
if (!using_cache_A || !using_cache_B) {
if (c->lock.tryLock()) {
bool write_A = (!using_cache_A && !c->cache_A.unread);
bool write_B = (!using_cache_B && !c->cache_B.unread);
if (write_A || write_B) {
long playhead;
if (cache_needs_reset) {
// if we have no cache and need to seek, start us at the current playhead...
playhead = clip_time;
} else {
// ...otherwise start at the end of the current cache
playhead = cache_offset + c->cache_size;
}
cache_clip(c, playhead, write_A, write_B, cache_needs_reset);
}
c->lock.unlock();
}
}
}
if (current_frame != NULL) {
// set up opengl texture
if (c->texture == NULL) {
c->texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
c->texture->setSize(c->media_stream->video_width, c->media_stream->video_height);
c->texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
c->texture->setMipLevels(c->texture->maximumMipLevels());
c->texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
c->texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
}
c->texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, current_frame->data[0]);
c->texture_frame = clip_time;
} else {
texture_failed = true;
qDebug() << "[ERROR] Failed to retrieve frame from cache (R:" << clip_time << "| A:" << c->cache_A.offset << "-" << c->cache_A.offset+c->cache_size-1 << "| B:" << c->cache_B.offset << "-" << c->cache_B.offset+c->cache_size-1 << "| WA:" << c->cache_A.written << "| WB:" << c->cache_B.written << ")";
}
}
}
}
float playhead_to_seconds(Clip* c, long playhead) {
// returns time in seconds
return (std::max((long) 0, playhead - c->timeline_in) + c->clip_in)/c->sequence->frame_rate;
}
long seconds_to_clip_frame(Clip* c, float seconds) {
// returns time as frame number (according to clip's frame rate)
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
return floor(seconds*av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, c->frame)));
} else {
qDebug() << "[ERROR] seconds_to_clip_frame only works on video streams";
return 0;
}
}
float clip_frame_to_seconds(Clip* c, long clip_frame) {
// returns frame number as seconds (decimal)
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;
}
}
int retrieve_next_frame(Clip* c, AVFrame* f) {
int result = 0;
int receive_ret;
// could be optimized if "linked stream" shares timeline_in and clip_in, only use one read_frame?
// depends how much time av_read_frame needs, the decoding is probably far more consuming anyway
// do we need to retrieve a new packet for a new frame?
while ((receive_ret = avcodec_receive_frame(c->codecCtx, f)) == AVERROR(EAGAIN)) {
int read_ret = 0;
do {
if (c->pkt_written) {
av_packet_unref(c->pkt);
}
read_ret = av_read_frame(c->formatCtx, c->pkt);
c->pkt_written = true;
} while (read_ret >= 0 && c->pkt->stream_index != c->media_stream->file_index);
if (read_ret >= 0) {
int send_ret = avcodec_send_packet(c->codecCtx, c->pkt);
if (send_ret < 0) {
qDebug() << "[ERROR] Failed to send packet to decoder." << send_ret;
result = send_ret;
break;
}
} else {
if (read_ret != AVERROR_EOF) qDebug() << "[ERROR] Could not read frame." << read_ret;
return read_ret; // skips trying to find a frame at all
}
}
if (receive_ret < 0) {
qDebug() << "[ERROR] Failed to receive packet from decoder." << receive_ret;
result = receive_ret;
}
return result;
}
void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) {
int ret = retrieve_next_frame(c, c->frame);
if (ret >= 0) {
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize);
} else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
ret = swr_convert_frame(c->swr_ctx, output, c->frame);
if (ret < 0) {
qDebug() << "[ERROR] Failed to resample audio." << ret;
}
}
} else if (ret == AVERROR_EOF) {
c->reached_end = true;
} else {
qDebug() << "[WARNING] Raw frame data could not be retrieved." << ret;
}
}
bool is_clip_active(Clip* c, long playhead) {
return c->timeline_in < playhead + ceil(c->sequence->frame_rate) && c->timeline_out > playhead;
}
+41
View File
@@ -0,0 +1,41 @@
#ifndef PLAYBACK_H
#define PLAYBACK_H
#include <QVector>
#include <QMutex>
struct Clip;
struct ClipCache;
struct Sequence;
struct AVFrame;
extern QList<Clip*> current_clips;
extern QMutex cc_lock;
extern bool texture_failed;
void open_clip(Clip* clip, bool multithreaded);
void cache_clip(Clip* clip, long playhead, bool write_A, bool write_B, bool reset);
void close_clip(Clip* clip);
void cache_audio_worker(Clip* c, bool write_A);
void cache_video_worker(Clip* c, long playhead, ClipCache* cache);
void handle_media(Sequence* sequence, long playhead, bool multithreaded);
void reset_cache(Clip* c, long target_frame);
void get_clip_frame(Clip* c, long playhead);
float playhead_to_seconds(Clip* c, long playhead);
long seconds_to_clip_frame(Clip* c, float seconds);
float clip_frame_to_seconds(Clip* c, long clip_frame);
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);
struct ClipCacheData {
Clip& clip;
long playhead;
bool write_A;
bool write_B;
bool reset;
};
#endif // PLAYBACK_H
+81
View File
@@ -0,0 +1,81 @@
#include "clip.h"
#include "project/effect.h"
#include "io/media.h"
#include "playback/playback.h"
#include "playback/cacher.h"
#include <QDebug>
extern "C" {
#include <libavformat/avformat.h>
}
Clip::Clip() {
init();
}
Clip::Clip(const Clip &c) {
init();
copy(c);
}
Clip& Clip::operator= (const Clip& c) {
init();
copy(c);
return *this;
}
void Clip::copy(const Clip& c) {
name = c.name;
clip_in = c.clip_in;
timeline_in = c.timeline_in;
timeline_out = c.timeline_out;
track = c.track;
color_r = c.color_r;
color_g = c.color_g;
color_b = c.color_b;
sequence = c.sequence;
media = c.media;
media_stream = c.media_stream;
}
void Clip::init() {
reset();
clip_in = timeline_in = timeline_out = track = undeletable = 0;
texture = NULL;
pkt = new AVPacket();
}
void Clip::reset() {
cache_size = cache_A.offset = cache_B.offset = open = pkt_written = cache_A.written = cache_B.written = cache_A.unread = cache_B.unread = reached_end = reset_audio = frame_sample_index = 0;
texture_frame = -1;
formatCtx = NULL;
stream = NULL;
codec = NULL;
codecCtx = NULL;
texture = NULL;
cache_A.frames = NULL;
cache_B.frames = NULL;
}
Clip::~Clip() {
if (open) {
close_clip(this);
}
// make sure clip has closed before clip is destroyed
open_lock.lock();
open_lock.unlock();
for (int i=0;i<effects.size();i++) {
delete effects.at(i);
}
av_packet_unref(pkt);
delete pkt;
}
// timeline functions
long Clip::getLength() {
return timeline_out - timeline_in;
}
+95
View File
@@ -0,0 +1,95 @@
#ifndef CLIP_H
#define CLIP_H
#include <QWaitCondition>
#include <QMutex>
#include <QVector>
class Cacher;
class Effect;
struct Sequence;
struct Media;
struct MediaStream;
struct AVFormatContext;
struct AVStream;
struct AVCodec;
struct AVCodecContext;
struct AVFrame;
struct AVPacket;
struct SwsContext;
struct SwrContext;
class QOpenGLTexture;
struct ClipCache {
AVFrame** frames;
long offset;
bool written;
bool unread;
QMutex mutex;
};
struct Clip
{
Clip();
Clip(const Clip &c);
Clip& operator= (const Clip&); // explicitly defaulted copy assignment
~Clip();
void copy(const Clip& c);
void init();
void reset();
bool undeletable;
// timeline variables
QString name;
long clip_in;
long timeline_in;
long timeline_out;
int track;
uint8_t color_r;
uint8_t color_g;
uint8_t color_b;
long getLength();
// inherited information (should be copied in copy())
Media* media; // attached media
MediaStream* media_stream;
Sequence* sequence;
// other variables (should be "duplicated" in copy())
QList<Effect*> effects;
// QVector<Clip&> linkedClips;
// media handling
AVFormatContext* formatCtx;
AVStream* stream;
AVCodec* codec;
AVCodecContext* codecCtx;
AVPacket* pkt;
AVFrame* frame;
bool pkt_written;
bool reached_end;
bool open;
// caching functions
bool multithreaded;
Cacher* cacher;
QWaitCondition can_cache;
uint16_t cache_size;
ClipCache cache_A;
ClipCache cache_B;
QMutex lock;
QMutex open_lock;
// video playback variables
SwsContext* sws_ctx;
QOpenGLTexture* texture;
long texture_frame;
// audio playback variables
SwrContext* swr_ctx;
int frame_sample_index;
bool reset_audio;
};
#endif // CLIP_H
+18
View File
@@ -0,0 +1,18 @@
#include "effect.h"
#include "panels/panels.h"
#include "panels/viewer.h"
#include "ui/viewerwidget.h"
Effect::Effect(Clip* c) : parent_clip(c)
{
name = "<unnamed effect>";
type = EFFECT_TYPE_INVALID;
}
void Effect::field_changed() {
panel_viewer->viewer_widget->update();
}
void Effect::process_gl(int* anchor_x, int* anchor_y) {}
void Effect::process_audio(uint8_t* samples, int nb_bytes) {}
+31
View File
@@ -0,0 +1,31 @@
#ifndef EFFECT_H
#define EFFECT_H
#include <QObject>
#include <QString>
class QWidget;
class CollapsibleWidget;
struct Clip;
enum EffectTypes { EFFECT_TYPE_INVALID, EFFECT_TYPE_VIDEO, EFFECT_TYPE_AUDIO };
class Effect : public QObject
{
Q_OBJECT
public:
Effect(Clip* c);
int type;
QString name;
CollapsibleWidget* container;
QWidget* ui;
Clip* parent_clip;
virtual void process_gl(int* anchor_x, int* anchor_y);
virtual void process_audio(uint8_t* samples, int nb_bytes);
public slots:
void field_changed();
};
#endif // EFFECT_H
+122
View File
@@ -0,0 +1,122 @@
#include "sequence.h"
#include "project/clip.h"
#include <QDebug>
Sequence::Sequence() {
}
Sequence::~Sequence() {
}
Clip& Sequence::new_clip() {
clips.append(Clip());
return clips[clips.size() - 1];
}
Clip& Sequence::insert_clip(const Clip& c) {
clips.append(c);
return clips[clips.size() - 1];
}
int Sequence::clip_count() {
return clips.count();
}
Clip& Sequence::get_clip(int i) {
return clips[i];
}
void Sequence::delete_clip(int i) {
// remove any potential link references to clip
// for (size_t j=0;j<clip_count();j++) {
// Clip* c = getClip(j);
// for (size_t k=0;k<c->linkedClips.size();k++) {
// if (c->linkedClips[k] == clips[i]) {
// c->linkedClips.erase(c->linkedClips.begin()+k);
// }
// }
// }
// finally remove from vector
clips.removeAt(i);
}
long Sequence::getEndFrame() {
long end = 0;
for (int j=0;j<clip_count();j++) {
Clip& c = get_clip(j);
if (c.timeline_out > end) {
end = c.timeline_out;
}
}
return end;
}
void Sequence::get_track_limits(int* video_tracks, int* audio_tracks) {
int vt = 0;
int at = 0;
for (int j=0;j<clip_count();j++) {
Clip& c = get_clip(j);
if (c.track < 0 && c.track < vt) { // video clip
vt = c.track;
} else if (c.track > at) {
at = c.track;
}
}
if (video_tracks != NULL) *video_tracks = vt;
if (audio_tracks != NULL) *audio_tracks = at;
}
void Sequence::delete_area(long in, long out, int track) {
for (int i=0;i<clip_count();i++) {
Clip& c = get_clip(i);
if (c.track == track && !c.undeletable) {
if (c.timeline_in >= in && c.timeline_out <= out) {
// clips falls entirely within deletion area
delete_clip(i);
i--;
} else if (c.timeline_in < in && c.timeline_out > out) {
// middle of clip is within deletion area
clips.append(clips.at(i)); // copy clip
Clip& pre = get_clip(i);
Clip& post = get_clip(clips.size()-1);
pre.timeline_out = in;
post.timeline_in = out;
post.clip_in = pre.clip_in + pre.getLength() + (out - in);
} else if (c.timeline_in < in && c.timeline_out > in) {
// only out point is in deletion area
c.timeline_out = in;
} else if (c.timeline_in < out && c.timeline_out > out) {
// only in point is in deletion area
c.clip_in += out - c.timeline_in;
c.timeline_in = out;
}
}
}
}
void Sequence::split_clip(int i, long frame) {
Clip& pre = get_clip(i);
if (pre.timeline_in < frame && pre.timeline_out > frame) { // guard against attempts to split at in/out points
clips.append(pre); // copy clip
Clip& post = get_clip(clips.size()-1);
pre.timeline_out = frame;
post.timeline_in = frame;
post.clip_in = pre.clip_in + pre.getLength();
}
}
void Sequence::split_at_playhead(long frame) {
for (int j=0;j<clip_count();j++) {
Clip& c = get_clip(j);
if (c.timeline_in < frame && c.timeline_out > frame) {
split_clip(j, frame);
}
}
}
+32
View File
@@ -0,0 +1,32 @@
#ifndef SEQUENCE_H
#define SEQUENCE_H
#include <QVector>
#include "project/clip.h"
struct Sequence {
public:
Sequence();
~Sequence();
QString name;
Clip& new_clip();
Clip& insert_clip(const Clip& c);
int clip_count();
Clip& get_clip(int i);
void delete_clip(int i);
void delete_area(long in, long out, int track);
void split_clip(int i, long frame);
void split_at_playhead(long frame);
void get_track_limits(int* video_tracks, int* audio_tracks);
long getEndFrame();
int width;
int height;
float frame_rate;
int audio_frequency;
int audio_layout;
private:
QList<Clip> clips;
};
#endif // SEQUENCE_H
+59
View File
@@ -0,0 +1,59 @@
#include "collapsiblewidget.h"
#include <QDebug>
#include <QLabel>
#include <QCheckBox>
#include <QLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent)
{
layout = new QVBoxLayout(this);
layout->setMargin(0);
title_bar = new QHBoxLayout();
title_bar->setMargin(0);
enabled_check = new QCheckBox();
enabled_check->setChecked(true);
header = new QLabel();
collapse_button = new QPushButton("-");
collapse_button->setMaximumWidth(25);
setText("<untitled>");
title_bar->addWidget(collapse_button);
title_bar->addWidget(enabled_check);
title_bar->addWidget(header);
title_bar->addStretch();
layout->addLayout(title_bar);
line = new QFrame();
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
contents = NULL;
}
void CollapsibleWidget::setContents(QWidget* c) {
bool existing = (contents != NULL);
contents = c;
if (!existing) {
layout->addWidget(contents);
connect(enabled_check, SIGNAL(toggled(bool)), this, SLOT(on_enabled_change(bool)));
connect(collapse_button, SIGNAL(clicked()), this, SLOT(on_visible_change()));
}
}
void CollapsibleWidget::setText(const QString &s) {
header->setText(s);
}
void CollapsibleWidget::on_enabled_change(bool b) {
contents->setEnabled(b);
}
void CollapsibleWidget::on_visible_change() {
contents->setVisible(!contents->isVisible());
collapse_button->setText(contents->isVisible() ? "-" : "+");
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef COLLAPSIBLEWIDGET_H
#define COLLAPSIBLEWIDGET_H
#include <QWidget>
class QLabel;
class QCheckBox;
class QHBoxLayout;
class QVBoxLayout;
class QPushButton;
class QFrame;
class CollapsibleWidget : public QWidget
{
Q_OBJECT
public:
CollapsibleWidget(QWidget* parent = 0);
void setContents(QWidget* c);
void setText(const QString &);
private:
QLabel* header;
QCheckBox* enabled_check;
QHBoxLayout* title_bar;
QVBoxLayout* layout;
QPushButton* collapse_button;
QWidget* contents;
QFrame* line;
private slots:
void on_enabled_change(bool b);
void on_visible_change();
};
#endif // COLLAPSIBLEWIDGET_H
+9
View File
@@ -0,0 +1,9 @@
#include "playbutton.h"
PlayButton::PlayButton(QWidget* parent) : QPushButton(parent)
{
play_text = ">";
pause_text = "||";
setText(play_text);
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef PLAYBUTTON_H
#define PLAYBUTTON_H
#include <QPushButton>
class PlayButton : public QPushButton
{
public:
PlayButton(QWidget* parent = 0);
private:
QString play_text;
QString pause_text;
};
#endif // PLAYBUTTON_H
+30
View File
@@ -0,0 +1,30 @@
#include "sourcetable.h"
#include "panels/project.h"
#include "io/media.h"
#include "panels/timeline.h"
#include "panels/viewer.h"
#include "panels/panels.h"
#include <QDragEnterEvent>
SourceTable::SourceTable(QWidget* parent) : QTreeWidget(parent) {
this->sortByColumn(0, Qt::AscendingOrder);
}
void SourceTable::mouseDoubleClickEvent(QMouseEvent* )
{
if (selectedItems().count() == 0) {
panel_project->import_dialog();
} 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_timeline->set_sequence(m->sequence);
panel_viewer->set_sequence(m->sequence);
}
}
}
//void SourceTable::dragEnterEvent(QDragEnterEvent *event) {
// event->accept();
//}
+18
View File
@@ -0,0 +1,18 @@
#ifndef SOURCETABLE_H
#define SOURCETABLE_H
#include <QTreeWidget>
class Project;
class SourceTable : public QTreeWidget
{
public:
SourceTable(QWidget* parent = 0);
protected:
void mouseDoubleClickEvent(QMouseEvent *event) override;
// void dragEnterEvent(QDragEnterEvent *event) override;
private:
};
#endif // SOURCETABLE_H
+15
View File
@@ -0,0 +1,15 @@
#ifndef TIMELINETOOLS_H
#define TIMELINETOOLS_H
enum TimelineTools {
TIMELINE_TOOL_POINTER,
TIMELINE_TOOL_EDIT,
TIMELINE_TOOL_RAZOR,
TIMELINE_TOOL_RIPPLE,
TIMELINE_TOOL_ROLLING,
TIMELINE_TOOL_SLIP,
TIMELINE_TOOL_HAND,
TIMELINE_TOOL_ZOOM
};
#endif // TIMELINETOOLS_H
+799
View File
@@ -0,0 +1,799 @@
#include "timelinewidget.h"
#include "panels/panels.h"
#include "io/config.h"
#include "project/sequence.h"
#include "project/clip.h"
#include "panels/project.h"
#include "panels/timeline.h"
#include "io/media.h"
#include "ui/sourcetable.h"
#include "panels/effectcontrols.h"
#include "effects/effects.h"
#include <QPainter>
#include <QColor>
#include <QDebug>
#include <QMouseEvent>
#include <QObject>
#include <QVariant>
#include <QPointF>
TimelineWidget::TimelineWidget(QWidget *parent) : QWidget(parent)
{
bottom_align = false;
setMouseTracking(true);
track_height = 40;
clip_pixmap = NULL;
setAcceptDrops(true);
}
bool same_sign(int a, int b) {
return (a < 0) == (b < 0);
}
void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
if (static_cast<SourceTable*>(event->source()) == panel_project->source_table) {
QPoint pos = event->pos();
event->accept();
QList<QTreeWidgetItem*> items = panel_project->source_table->selectedItems();
long entry_point = getFrameFromScreenPoint(pos.x(), false);
panel_timeline->drag_frame_start = entry_point + getFrameFromScreenPoint(50, false);
panel_timeline->drag_track_start = (bottom_align) ? -1 : 0;
for (int i=0;i<items.size();i++) {
bool ignore_infinite_length = false;
Media* m = reinterpret_cast<Media*>(items.at(i)->data(0, Qt::UserRole + 1).value<quintptr>());
long duration = m->get_length_in_frames(panel_timeline->sequence->frame_rate);
Ghost g = {NULL, entry_point, entry_point + duration};
g.media = m;
g.clip_in = 0;
for (int j=0;j<m->audio_tracks.size();j++) {
g.track = j;
g.media_stream = &m->audio_tracks[j];
ignore_infinite_length = true;
panel_timeline->ghosts.append(g);
}
for (int j=0;j<m->video_tracks.size();j++) {
g.track = -1-j;
g.media_stream = &m->video_tracks[j];
if (m->video_tracks[j].infinite_length && !ignore_infinite_length) g.out = g.in + 100;
panel_timeline->ghosts.append(g);
}
entry_point += duration;
}
init_ghosts();
panel_timeline->importing = true;
}
}
void TimelineWidget::dragMoveEvent(QDragMoveEvent *event) {
if (panel_timeline->importing) {
QPoint pos = event->pos();
update_ghosts(pos);
panel_timeline->repaint_timeline();
}
}
void TimelineWidget::dragLeaveEvent(QDragLeaveEvent *event) {
if (panel_timeline->importing) {
panel_timeline->ghosts.clear();
panel_timeline->importing = false;
panel_timeline->repaint_timeline();
}
}
void TimelineWidget::dropEvent(QDropEvent* event) {
if (panel_timeline->importing) {
event->accept();
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);
Clip& c = panel_timeline->sequence->new_clip();
c.media = g.media;
c.media_stream = g.media_stream;
c.timeline_in = g.in;
c.timeline_out = g.out;
c.clip_in = g.clip_in;
c.color_r = 128;
c.color_g = 128;
c.color_b = 192;
c.sequence = panel_timeline->sequence;
c.track = g.track;
c.name = c.media->name;
if (c.track < 0) {
// add default video effects
c.effects.append(new TransformEffect(&c));
} else {
// add default audio effects
c.effects.append(new VolumeEffect(&c));
c.effects.append(new PanEffect(&c));
}
}
panel_timeline->ghosts.clear();
panel_timeline->importing = false;
panel_timeline->redraw_all_clips();
}
}
void TimelineWidget::mousePressEvent(QMouseEvent *event) {
QPoint pos = event->pos();
panel_timeline->drag_frame_start = getFrameFromScreenPoint(pos.x(), false);
panel_timeline->drag_track_start = getTrackFromScreenPoint(pos.y());
int clip_index = panel_timeline->trim_target;
if (clip_index == -1) clip_index = getClipIndexFromCoords(panel_timeline->drag_frame_start, panel_timeline->drag_track_start);
switch (panel_timeline->tool) {
case TIMELINE_TOOL_POINTER:
case TIMELINE_TOOL_RIPPLE:
{
if (clip_index >= 0) {
if (panel_timeline->is_clip_selected(clip_index)) {
// TODO if shift is down, deselect it
} else {
// if "shift" is not down
if (!(event->modifiers() & Qt::ShiftModifier)) {
panel_timeline->selections.clear();
}
Clip& clip = panel_timeline->sequence->get_clip(clip_index);
panel_timeline->selections.append({clip.timeline_in, clip.timeline_out, clip.track});
}
panel_timeline->moving_init = true;
} else {
panel_timeline->selections.clear();
}
panel_timeline->repaint_timeline();
}
break;
case TIMELINE_TOOL_EDIT:
panel_timeline->seek(panel_timeline->drag_frame_start);
panel_timeline->selecting = true;
panel_timeline->repaint_timeline();
break;
case TIMELINE_TOOL_RAZOR:
{
if (clip_index >= 0) {
panel_timeline->sequence->split_clip(clip_index, panel_timeline->drag_frame_start);
}
panel_timeline->splitting = true;
panel_timeline->redraw_all_clips();
}
break;
}
}
void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
if (panel_timeline->moving_proc) {
if (event->modifiers() & Qt::AltModifier) { // if holding alt, duplicate rather than move
// duplicate clips
for (int i=0;i<panel_timeline->ghosts.size();i++) {
Ghost& g = panel_timeline->ghosts[i];
Clip& c = panel_timeline->sequence->insert_clip(*g.clip);
c.timeline_in = g.in;
c.timeline_out = g.out;
c.track = g.track;
c.undeletable = true;
// step 2 - delete anything that exists in area that clip is moving to
panel_timeline->sequence->delete_area(g.in, g.out, g.track);
c.undeletable = false;
}
} 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;
}
for (int i=0;i<panel_timeline->ghosts.size();i++) {
Ghost& g = panel_timeline->ghosts[i];
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);
}
// 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;
}
for (int i=0;i<panel_timeline->ghosts.size();i++) {
// step 4 - set clips back to deletable
panel_timeline->ghosts[i].clip->undeletable = false;
}
}
// ripple ops
if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) {
long ripple_length, ripple_point;
if (panel_timeline->trim_in) {
ripple_length = panel_timeline->ghosts.at(0).old_in - panel_timeline->ghosts.at(0).in;
ripple_point = (ripple_length < 0) ? panel_timeline->ghosts.at(0).old_in : panel_timeline->ghosts.at(0).in;
} else {
ripple_length = panel_timeline->ghosts.at(0).old_out - panel_timeline->ghosts.at(0).out;
ripple_point = (ripple_length < 0) ? panel_timeline->ghosts.at(0).old_out : panel_timeline->ghosts.at(0).out;
}
for (int i=0;i<panel_timeline->ghosts.size();i++) {
long comp_point;
if (panel_timeline->trim_in) {
comp_point = (ripple_length < 0) ? panel_timeline->ghosts.at(i).old_in : panel_timeline->ghosts.at(i).in;
} else {
comp_point = (ripple_length < 0) ? panel_timeline->ghosts.at(i).old_out : panel_timeline->ghosts.at(i).out;
}
if (ripple_point > comp_point) ripple_point = comp_point;
}
if (panel_timeline->trim_in) {
panel_timeline->ripple(ripple_point, ripple_length);
} else {
panel_timeline->ripple(ripple_point, -ripple_length);
}
}
panel_timeline->redraw_all_clips();
}
// destroy all ghosts
panel_timeline->ghosts.clear();
panel_timeline->selecting = false;
panel_timeline->moving_proc = false;
panel_timeline->moving_init = false;
panel_timeline->splitting = false;
pre_clips.clear();
post_clips.clear();
// 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++) {
if (panel_timeline->is_clip_selected(i)) {
if (!single_select) {
// found ONE selected clip
selected_clip = i;
single_select = true;
} else {
// more than one clip is selected
single_select = false;
break;
}
}
}
if (single_select) {
panel_effect_controls->set_clip(&panel_timeline->sequence->get_clip(selected_clip));
} else {
panel_effect_controls->set_clip(NULL);
}
}
void TimelineWidget::init_ghosts() {
for (int i=0;i<panel_timeline->ghosts.size();i++) {
Ghost& g = panel_timeline->ghosts[i];
g.old_in = g.in;
g.old_out = g.out;
g.old_track = g.track;
g.old_clip_in = g.clip_in;
if (panel_timeline->trim_target > -1) {
// 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);
}
}
for (int i=0;i<panel_timeline->selections.size();i++) {
Selection& s = panel_timeline->selections[i];
s.old_in = s.in;
s.old_out = s.out;
s.old_track = s.track;
}
}
void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
int mouse_track = getTrackFromScreenPoint(mouse_pos.y());
long frame_diff = getFrameFromScreenPoint(mouse_pos.x(), false) - panel_timeline->drag_frame_start;
int track_diff = mouse_track - panel_timeline->drag_track_start;
long validator;
if (panel_timeline->trim_target > -1) {
// trim ops
// validate ghosts
for (int i=0;i<panel_timeline->ghosts.size();i++) {
Ghost& g = panel_timeline->ghosts[i];
if (panel_timeline->trim_in) {
// prevent clip length from being less than 1 frame long
validator = g.ghost_length - frame_diff;
if (validator < 1) frame_diff -= (1 - validator);
// prevent timeline in from going below 0
validator = g.old_in + frame_diff;
if (validator < 0) frame_diff -= validator;
if (!g.clip->media_stream->infinite_length) {
// prevent clip_in from going below 0
validator = g.old_clip_in + frame_diff;
if (validator < 0) frame_diff -= validator;
}
// ripple ops
if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) {
for (int j=0;j<post_clips.size();j++) {
// prevent any rippled clip from going below 0
Clip* post = post_clips.at(j);
validator = post->timeline_in - frame_diff;
if (validator < 0) frame_diff += validator;
// prevent any post-clips colliding with pre-clips
for (int k=0;k<pre_clips.size();k++) {
Clip* pre = pre_clips.at(k);
if (pre->track == post->track) {
validator = post->timeline_in - frame_diff - pre->timeline_out;
if (validator < 0) frame_diff += validator;
}
}
}
}
} else {
// prevent clip length from being less than 1 frame long
validator = g.ghost_length + frame_diff;
if (validator < 1) frame_diff += (1 - validator);
if (!g.clip->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;
}
// ripple ops
if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) {
for (int j=0;j<post_clips.size();j++) {
Clip* post = post_clips.at(j);
// prevent any post-clips colliding with pre-clips
for (int k=0;k<pre_clips.size();k++) {
Clip* pre = pre_clips.at(k);
if (pre->track == post->track) {
validator = post->timeline_in + frame_diff - pre->timeline_out;
if (validator < 0) frame_diff -= validator;
}
}
}
}
}
}
// resize ghosts
for (int i=0;i<panel_timeline->ghosts.size();i++) {
Ghost& g = panel_timeline->ghosts[i];
if (panel_timeline->trim_in) {
g.in = g.old_in + frame_diff;
g.clip_in = g.old_clip_in + frame_diff;
} else {
g.out = g.old_out + frame_diff;
}
}
// resize selections
for (int i=0;i<panel_timeline->selections.size();i++) {
Selection& s = panel_timeline->selections[i];
if (panel_timeline->trim_in) {
s.in = s.old_in + frame_diff;
} else {
s.out = s.old_out + frame_diff;
}
}
} else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->importing) { // only move clips on pointer (not ripple or rolling)
// validate ghosts
for (int i=0;i<panel_timeline->ghosts.size();i++) {
Ghost& g = panel_timeline->ghosts[i];
// prevent clips from moving below 0 on the timeline
validator = g.old_in + frame_diff;
if (validator < 0) frame_diff -= validator;
// prevent clips from crossing tracks
if (same_sign(g.old_track, panel_timeline->drag_track_start)) {
while (!same_sign(g.old_track, g.old_track + track_diff)) {
if (g.old_track < 0) {
track_diff--;
} else {
track_diff++;
}
}
}
}
// move ghosts
for (int i=0;i<panel_timeline->ghosts.size();i++) {
Ghost& g = panel_timeline->ghosts[i];
g.in = g.old_in + frame_diff;
g.out = g.old_out + frame_diff;
g.track = g.old_track;
if (panel_timeline->importing) {
int abs_track_diff = abs(track_diff);
if (g.old_track < 0) { // clip is video
g.track -= abs_track_diff;
} else { // clip is audio
g.track += abs_track_diff;
}
} else {
if (same_sign(g.old_track, panel_timeline->drag_track_start)) g.track += track_diff;
}
}
// move selections
if (!panel_timeline->importing) {
for (int i=0;i<panel_timeline->selections.size();i++) {
Selection& s = panel_timeline->selections[i];
s.in = s.old_in + frame_diff;
s.out = s.old_out + frame_diff;
s.track = s.old_track;
if (panel_timeline->importing) {
int abs_track_diff = abs(track_diff);
if (s.old_track < 0) {
s.track -= abs_track_diff;
} else {
s.track += abs_track_diff;
}
} else {
if (same_sign(s.track, panel_timeline->drag_track_start)) s.track += track_diff;
}
}
}
}
}
void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
if (panel_timeline->selecting) {
QPoint pos = event->pos();
int current_selection_track = getTrackFromScreenPoint(pos.y());
long current_selection_frame = getFrameFromScreenPoint(pos.x(), false);;
int selection_count = 1 + qMax(current_selection_track, panel_timeline->drag_track_start) - qMin(current_selection_track, panel_timeline->drag_track_start);
if (panel_timeline->selections.size() != selection_count) {
panel_timeline->selections.resize(selection_count);
}
int minimum_selection_track = qMin(current_selection_track, panel_timeline->drag_track_start);
for (int i=0;i<selection_count;i++) {
Selection* s = &panel_timeline->selections[i];
s->track = minimum_selection_track + i;
long in = panel_timeline->drag_frame_start;
long out = current_selection_frame;
s->in = qMin(in, out);
s->out = qMax(in, out);
}
panel_timeline->playhead = qMin(panel_timeline->drag_frame_start, current_selection_frame);
panel_timeline->repaint_timeline();
} else if (panel_timeline->moving_init) {
QPoint pos = event->pos();
if (panel_timeline->moving_proc) {
update_ghosts(pos);
} else {
// set up movement
// create ghosts
for (int i=0;i<panel_timeline->sequence->clip_count();i++) {
if (panel_timeline->is_clip_selected(i)) {
Clip& c = panel_timeline->sequence->get_clip(i);
panel_timeline->ghosts.append({&c, c.timeline_in, c.timeline_out, c.track, c.clip_in});
}
}
// ripple edit prep
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++) {
// don't cache any currently selected clips
Clip* c = panel_timeline->ghosts.at(i).clip;
Clip& cc = panel_timeline->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) {
is_selected = true;
break;
}
}
if (!is_selected) {
if (cc.timeline_in < c->timeline_in) {
// add clip to pre-cache UNLESS there is already a clip on that track closer to the ripple point
bool found = false;
for (int k=0;k<pre_clips.size();k++) {
Clip* ccc = pre_clips.at(k);
if (ccc->track == cc.track) {
if (ccc->timeline_in < cc.timeline_in) {
// clip is closer to ripple point than the one in cache, replace it
ccc = &cc;
}
found = true;
}
}
if (!found) {
// no clip from that track in the cache, add it
pre_clips.append(&cc);
}
} else {
// add clip to post-cache UNLESS there is already a clip on that track closer to the ripple point
bool found = false;
for (int k=0;k<post_clips.size();k++) {
Clip* ccc = post_clips.at(k);
if (ccc->track == cc.track) {
if (ccc->timeline_in > cc.timeline_in) {
// clip is closer to ripple point than the one in cache, replace it
ccc = &cc;
}
found = true;
}
}
if (!found) {
// no clip from that track in the cache, add it
post_clips.append(&cc);
}
}
}
}
}
// debug code - print the information we got
qDebug() << "found" << pre_clips.size() << "preceding clips and" << post_clips.size() << "following";
}
init_ghosts();
panel_timeline->moving_proc = true;
}
panel_timeline->repaint_timeline();
} else if (panel_timeline->splitting) {
QPoint pos = event->pos();
int track = getTrackFromScreenPoint(pos.y());
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);
repaint = true;
}
}
// redraw clips since we changed them
if (repaint) panel_timeline->redraw_all_clips();
} else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->tool == TIMELINE_TOOL_RIPPLE) {
QPoint pos = event->pos();
int lim = 5;
int mouse_track = getTrackFromScreenPoint(pos.y());
long mouse_frame_lower = getFrameFromScreenPoint(pos.x()-lim, false)-1;
long mouse_frame_upper = getFrameFromScreenPoint(pos.x()+lim, false)+1;
bool found = false;
for (int i=0;i<panel_timeline->sequence->clip_count();i++) {
Clip& c = panel_timeline->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;
panel_timeline->trim_in = true;
found = true;
break;
} else if (c.timeline_out > mouse_frame_lower && c.timeline_out < mouse_frame_upper) {
panel_timeline->trim_target = i;
panel_timeline->trim_in = false;
found = true;
break;
}
}
}
if (found) {
setCursor(Qt::SizeHorCursor);
} else {
unsetCursor();
panel_timeline->trim_target = -1;
}
} else if (panel_timeline->tool == TIMELINE_TOOL_EDIT || panel_timeline->tool == TIMELINE_TOOL_RAZOR) {
// redraw because we have a cursor
panel_timeline->repaint_timeline();
}
}
int color_brightness(int r, int g, int b) {
return (0.2126*r + 0.7152*g + 0.0722*b);
}
void TimelineWidget::redraw_clips() {
// Draw clips
if (clip_pixmap != NULL) delete clip_pixmap;
int panel_width = getScreenPointFromFrame(panel_timeline->sequence->getEndFrame()) + 100;
setMinimumWidth(panel_width);
clip_pixmap = new QPixmap(panel_width, height());
clip_pixmap->fill(Qt::transparent);
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);
if (is_track_visible(clip.track)) {
if (clip.track < 0 && clip.track < video_track_limit) { // video clip
video_track_limit = clip.track;
} else if (clip.track > audio_track_limit) {
audio_track_limit = clip.track;
}
QRect clip_rect(getScreenPointFromFrame(clip.timeline_in), getScreenPointFromTrack(clip.track), clip.getLength() * panel_timeline->zoom, track_height);
clip_painter.fillRect(clip_rect, QColor(clip.color_r, clip.color_g, clip.color_b));
clip_painter.setPen(Qt::white);
clip_painter.drawLine(clip_rect.bottomLeft(), clip_rect.topLeft());
clip_painter.drawLine(clip_rect.topLeft(), clip_rect.topRight());
clip_painter.setPen(QColor(0, 0, 0, 128));
clip_painter.drawLine(clip_rect.bottomLeft(), clip_rect.bottomRight());
clip_painter.drawLine(clip_rect.bottomRight(), clip_rect.topRight());
if (color_brightness(clip.color_r, clip.color_g, clip.color_b) > 160) {
clip_painter.setPen(Qt::black);
} else {
clip_painter.setPen(Qt::white);
}
QRect text_rect(clip_rect.left() + CLIP_TEXT_PADDING, clip_rect.top() + CLIP_TEXT_PADDING, clip_rect.width() - CLIP_TEXT_PADDING - CLIP_TEXT_PADDING, clip_rect.height() - CLIP_TEXT_PADDING - CLIP_TEXT_PADDING);
clip_painter.drawText(text_rect, 0, clip.name, &text_rect);
}
}
// Draw track lines
if (show_track_lines) {
clip_painter.setPen(QColor(0, 0, 0, 96));
audio_track_limit++;
if (video_track_limit == 0) video_track_limit--;
if (bottom_align) {
// only draw lines for video tracks
for (int i=video_track_limit;i<0;i++) {
int line_y = getScreenPointFromTrack(i) - 1;
clip_painter.drawLine(0, line_y, rect().width(), line_y);
}
} else {
// only draw lines for audio tracks
for (int i=0;i<audio_track_limit;i++) {
int line_y = getScreenPointFromTrack(i) + track_height;
clip_painter.drawLine(0, line_y, rect().width(), line_y);
}
}
}
update();
}
void TimelineWidget::paintEvent(QPaintEvent*) {
if (panel_timeline->sequence != NULL) {
QPainter p(this);
if (clip_pixmap != NULL) p.drawPixmap(0, 0, minimumWidth(), height(), *clip_pixmap);
// Draw selections
for (int i=0;i<panel_timeline->selections.size();i++) {
const Selection& s = panel_timeline->selections.at(i);
if (is_track_visible(s.track)) {
int selection_y = getScreenPointFromTrack(s.track);
int selection_x = getScreenPointFromFrame(s.in);
p.fillRect(selection_x, selection_y, getScreenPointFromFrame(s.out) - selection_x, track_height, QColor(0, 0, 0, 64));
}
}
// Draw ghosts
for (int i=0;i<panel_timeline->ghosts.size();i++) {
const Ghost& g = panel_timeline->ghosts.at(i);
if (is_track_visible(g.track)) {
int ghost_x = getScreenPointFromFrame(g.in);
int ghost_y = getScreenPointFromTrack(g.track);
int ghost_width = getScreenPointFromFrame(g.out - g.in) - 1;
int ghost_height = track_height - 1;
p.setPen(QColor(255, 255, 0));
for (int j=0;j<GHOST_THICKNESS;j++) {
p.drawRect(ghost_x+j, ghost_y+j, ghost_width-j-j, ghost_height-j-j);
}
}
}
// Draw edit cursor
if (panel_timeline->tool == TIMELINE_TOOL_EDIT || panel_timeline->tool == TIMELINE_TOOL_RAZOR) {
QPoint mouse_pos = mapFromGlobal(QCursor::pos());
int track = getTrackFromScreenPoint(mouse_pos.y());
if (is_track_visible(track)) {
int cursor_x = getScreenPointFromFrame(getFrameFromScreenPoint(mouse_pos.x(), false));
int cursor_y = getScreenPointFromTrack(track);
p.setPen(Qt::gray);
p.drawLine(cursor_x, cursor_y, cursor_x, cursor_y + track_height);
}
}
// Draw playhead
p.setPen(Qt::red);
int playhead_x = getScreenPointFromFrame(panel_timeline->playhead);
p.drawLine(playhead_x, rect().top(), playhead_x, rect().bottom());
p.setPen(QColor(0, 0, 0, 64));
int edge_y = (bottom_align) ? rect().height()-1 : 0;
p.drawLine(0, edge_y, rect().width(), edge_y);
}
}
bool TimelineWidget::is_track_visible(int track) {
return ((bottom_align && track < 0) || (!bottom_align && track >= 0));
}
// **************************************
// screen point <-> frame/track functions
// **************************************
long TimelineWidget::getFrameFromScreenPoint(int x, bool f) {
float div = (float) x / panel_timeline->zoom;
if (div < 0) {
return 0;
}
if (f) {
return floor(div);
} else {
return round(div);
}
}
int TimelineWidget::getTrackFromScreenPoint(int y) {
if (bottom_align) {
y -= rect().bottom();
if (show_track_lines) y -= 1;
} else {
y -= 1;
}
int temp_track_height = track_height;
if (show_track_lines) temp_track_height--;
return (int)floor((float) (y)/ (float) temp_track_height);
}
int TimelineWidget::getScreenPointFromFrame(long frame) {
return (int) round(frame*panel_timeline->zoom);
}
int TimelineWidget::getScreenPointFromTrack(int track) {
int temp_track_height = track_height;
if (show_track_lines) temp_track_height++;
int y = track * temp_track_height;
if (bottom_align) { // video track
y += rect().bottom();
if (show_track_lines) y += 1;
} else { // audio track
y += 1;
}
return y;
}
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);
if (c.track == track) {
if (frame >= c.timeline_in && frame < c.timeline_out) {
return i;
}
}
}
return -1;
}
+56
View File
@@ -0,0 +1,56 @@
#ifndef TIMELINEWIDGET_H
#define TIMELINEWIDGET_H
#include <QWidget>
#include "timeline-tools.h"
#define GHOST_THICKNESS 2 // thiccccc
#define CLIP_TEXT_PADDING 3
struct Sequence;
struct Clip;
class Timeline;
class TimelineWidget : public QWidget
{
Q_OBJECT
public:
explicit TimelineWidget(QWidget *parent = nullptr);
bool bottom_align;
void redraw_clips();
protected:
void paintEvent(QPaintEvent*) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dropEvent(QDropEvent* event);
void dragMoveEvent(QDragMoveEvent *event);
private:
void init_ghosts();
void update_ghosts(QPoint& mouse_pos);
bool is_track_visible(int track);
long getFrameFromScreenPoint(int x, bool floor);
int getTrackFromScreenPoint(int y);
int getScreenPointFromFrame(long frame);
int getScreenPointFromTrack(int track);
int getClipIndexFromCoords(long frame, int track);
int track_height;
QList<Clip*> pre_clips;
QList<Clip*> post_clips;
QPixmap* clip_pixmap;
// QPixmap selection_pixmap;
signals:
public slots:
};
#endif // TIMELINEWIDGET_H
+40
View File
@@ -0,0 +1,40 @@
#include "viewercontainer.h"
#include <QWidget>
#include <QResizeEvent>
// enforces aspect ratio
ViewerContainer::ViewerContainer(QWidget *parent) : QWidget(parent)
{
child = NULL;
aspect_ratio = 1;
}
void ViewerContainer::adjust() {
if (child != NULL) {
QSize widget_size = size();
int widget_x = 0;
int widget_y = 0;
int widget_width = widget_size.width();
int widget_height = widget_size.height();
float widget_ar = (float) widget_width /(float) widget_height;
bool widget_is_larger_than_sequence = widget_ar > aspect_ratio;
if (widget_is_larger_than_sequence) {
widget_width = widget_height * aspect_ratio;
widget_x = (widget_size.width() / 2) - (widget_width / 2);
} else {
widget_height = widget_width / aspect_ratio;
widget_y = (widget_size.height() / 2) - (widget_height / 2);
}
child->move(widget_x, widget_y);
child->resize(widget_width, widget_height);
}
}
void ViewerContainer::resizeEvent(QResizeEvent *event) {
event->accept();
adjust();
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef VIEWERCONTAINER_H
#define VIEWERCONTAINER_H
#include <QWidget>
class ViewerContainer : public QWidget
{
Q_OBJECT
public:
explicit ViewerContainer(QWidget *parent = nullptr);
float aspect_ratio;
QWidget* child;
void adjust();
protected:
void resizeEvent(QResizeEvent *event) override;
signals:
public slots:
};
#endif // VIEWERCONTAINER_H
+157
View File
@@ -0,0 +1,157 @@
#include "viewerwidget.h"
#include "panels/panels.h"
#include "panels/viewer.h"
#include "panels/timeline.h"
#include "project/sequence.h"
#include "project/effect.h"
#include "playback/playback.h"
#include "playback/audio.h"
#include "io/media.h"
#include <QDebug>
extern "C" {
#include <libavformat/avformat.h>
}
ViewerWidget::ViewerWidget(QWidget *parent) : QOpenGLWidget(parent)
{
multithreaded = true;
QSurfaceFormat format;
format.setDepthBufferSize(24);
setFormat(format);
// error handler - retries after 200ms if we couldn't get the entire image
retry_timer.setInterval(200);
connect(&retry_timer, SIGNAL(timeout()), this, SLOT(retry()));
}
void ViewerWidget::retry() {
update();
}
void ViewerWidget::initializeGL() {
initializeOpenGLFunctions();
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
//void ViewerWidget::resizeGL(int w, int h)
//{
//}
int audio_bytes_written = 0;
void ViewerWidget::paintGL()
{
if (multithreaded) retry_timer.stop();
glClear(GL_COLOR_BUFFER_BIT);
long playhead = panel_timeline->playhead;
handle_media(panel_viewer->sequence, playhead, multithreaded);
texture_failed = false;
bool render_audio = (panel_timeline->playing);
if (render_audio && switch_audio_cache) {
reading_audio_cache_A = !reading_audio_cache_A;
audio_bytes_written = 0;
clear_cache(!reading_audio_cache_A, reading_audio_cache_A);
}
cc_lock.lock();
for (int i=0;i<current_clips.size();i++) {
Clip* c = current_clips.at(i);
if (!c->open) {
qDebug() << "[WARNING] Tried to display clip" << i << "but it's closed";
texture_failed = true;
} else if (is_clip_active(c, playhead)) {
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// start preparing cache
get_clip_frame(c, playhead);
if (c->texture == NULL) {
qDebug() << "[WARNING] Texture hasn't been created yet";
texture_failed = true;
} else if (playhead >= c->timeline_in) {
glLoadIdentity();
int half_width = c->sequence->width/2;
int half_height = c->sequence->height/2;
glOrtho(-half_width, half_width, half_height,- half_height, -1, 1);
int anchor_x = 0;
int anchor_y = 0;
// perform all transform effects
for (unsigned int j=0;j<c->effects.size();j++) {
c->effects.at(j)->process_gl(&anchor_x, &anchor_y);
}
int anchor_right = c->media_stream->video_width - anchor_x;
int anchor_bottom = c->media_stream->video_height - anchor_y;
c->texture->bind();
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex2f(-anchor_x, -anchor_y);
glTexCoord2f(1.0, 0.0);
glVertex2f(anchor_right, -anchor_y);
glTexCoord2f(1.0, 1.0);
glVertex2f(anchor_right, anchor_bottom);
glTexCoord2f(0.0, 1.0);
glVertex2f(-anchor_x, anchor_bottom);
glEnd();
c->texture->release();
}
} else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
playhead >= c->timeline_in &&
render_audio &&
!c->reached_end &&
(switch_audio_cache || c->reset_audio)) {
// TODO doesn't new clips appearing in the timeline (they'll ALWAYS end up in the other cache with a 1/8 sec delay)
// cache audio
if (c->lock.tryLock()) {
// clip is not caching, start cache
c->lock.unlock();
cache_clip(c, playhead, !reading_audio_cache_A, reading_audio_cache_A, c->reset_audio);
}
}
}
}
if (render_audio) {
switch_audio_cache = false;
if (audio_cache_A != NULL && audio_bytes_written < audio_cache_size) {
// send cached/buffered audio to QIODevice/QAudioOutput
uint8_t* cache = reading_audio_cache_A ? audio_cache_A : audio_cache_B;
audio_bytes_written += audio_io_device->write((const char*) cache+audio_bytes_written, audio_cache_size-audio_bytes_written);
}
if (audio_bytes_written == audio_cache_size) {
// switch_cache
switch_audio_cache = true;
}
}
cc_lock.unlock();
if (texture_failed) {
if (multithreaded) {
retry_timer.start();
} else {
paintGL();
}
}
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef VIEWERWIDGET_H
#define VIEWERWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QMatrix4x4>
#include <QOpenGLTexture>
#include <QTimer>
class Viewer;
class ViewerWidget : public QOpenGLWidget, public QOpenGLFunctions
{
Q_OBJECT
public:
ViewerWidget(QWidget *parent = 0);
void initializeGL();
// void resizeGL(int w, int h);
void paintGL();
bool multithreaded;
private:
QTimer retry_timer;
private slots:
void retry();
};
#endif // VIEWERWIDGET_H