improved file saving/loading
This commit is contained in:
@@ -30,7 +30,7 @@ void PanEffect::load(QXmlStreamReader *stream) {
|
||||
stream->readNext();
|
||||
if (stream->isStartElement() && stream->name() == "pan") {
|
||||
stream->readNext();
|
||||
pan_val->set_value(stream->text().toFloat());
|
||||
pan_val->set_value(stream->text().toDouble());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ void PanEffect::process_audio(quint8 *samples, int nb_bytes) {
|
||||
qint16 left_sample = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
|
||||
qint16 right_sample = (qint16) (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF));
|
||||
|
||||
float val = qPow(pan_val->value()*0.01f, 3);
|
||||
double val = qPow(pan_val->value()*0.01, 3);
|
||||
if (val < 0) {
|
||||
// affect right channel
|
||||
right_sample *= (1-std::abs(val));
|
||||
|
||||
@@ -38,9 +38,9 @@ ShakeEffect::ShakeEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SHAKE_EFF
|
||||
connect(intensity_val, SIGNAL(valueChanged()), this, SLOT(field_changed()));
|
||||
connect(rotation_val, SIGNAL(valueChanged()), this, SLOT(field_changed()));
|
||||
connect(frequency_val, SIGNAL(valueChanged()), this, SLOT(field_changed()));
|
||||
connect(intensity_val, SIGNAL(valueChanged()), this, SLOT(set_values()));
|
||||
connect(rotation_val, SIGNAL(valueChanged()), this, SLOT(set_values()));
|
||||
connect(frequency_val, SIGNAL(valueChanged()), this, SLOT(set_values()));
|
||||
connect(intensity_val, SIGNAL(valueChanged()), this, SLOT(init()));
|
||||
connect(rotation_val, SIGNAL(valueChanged()), this, SLOT(init()));
|
||||
connect(frequency_val, SIGNAL(valueChanged()), this, SLOT(init()));
|
||||
}
|
||||
|
||||
void ShakeEffect::init() {
|
||||
@@ -66,11 +66,11 @@ void ShakeEffect::load(QXmlStreamReader* reader) {
|
||||
for (int i=0;i<attr.size();i++) {
|
||||
const QXmlStreamAttribute& a = attr.at(i);
|
||||
if (a.name() == "intensity") {
|
||||
intensity_val->set_value(a.value().toFloat());
|
||||
intensity_val->set_value(a.value().toDouble());
|
||||
} else if (a.name() == "rotation") {
|
||||
rotation_val->set_value(a.value().toFloat());
|
||||
rotation_val->set_value(a.value().toDouble());
|
||||
} else if (a.name() == "frequency") {
|
||||
frequency_val->set_value(a.value().toFloat());
|
||||
frequency_val->set_value(a.value().toDouble());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ void ShakeEffect::save(QXmlStreamWriter* stream) {
|
||||
|
||||
void ShakeEffect::process_gl(int*, int*) {
|
||||
if (shake_progress > shake_limit) {
|
||||
if (intensity_val->value() > 0) {
|
||||
if ((int)intensity_val->value() > 0) {
|
||||
prev_x = next_x;
|
||||
prev_y = next_y;
|
||||
next_x = (qrand() % (int) (intensity_val->value() * 2)) - intensity_val->value();
|
||||
@@ -96,7 +96,7 @@ void ShakeEffect::process_gl(int*, int*) {
|
||||
offset_x = 0;
|
||||
offset_y = 0;
|
||||
}
|
||||
if (rotation_val->value() > 0) {
|
||||
if ((int)rotation_val->value() > 0) {
|
||||
prev_rot = next_rot;
|
||||
next_rot = (qrand() % (int) (rotation_val->value() * 2)) - rotation_val->value();
|
||||
} else {
|
||||
|
||||
+45
-20
@@ -15,6 +15,7 @@
|
||||
#include "io/media.h"
|
||||
#include "ui/labelslider.h"
|
||||
#include "ui/comboboxex.h"
|
||||
#include "panels/project.h"
|
||||
|
||||
#define BLEND_MODE_NORMAL 0
|
||||
#define BLEND_MODE_SCREEN 1
|
||||
@@ -68,6 +69,9 @@ TransformEffect::TransformEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_T
|
||||
ui_layout->addWidget(blend_mode_box, 6, 1);
|
||||
|
||||
// set defaults
|
||||
scale_y->setEnabled(false);
|
||||
uniform_scale_box->setChecked(true);
|
||||
blend_mode_box->setCurrentIndex(0);
|
||||
init();
|
||||
|
||||
connect(position_x, SIGNAL(valueChanged()), this, SLOT(field_changed()));
|
||||
@@ -85,20 +89,41 @@ TransformEffect::TransformEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_T
|
||||
}
|
||||
|
||||
void TransformEffect::init() {
|
||||
MediaStream* ms = parent_clip->media->get_stream_from_file_index(parent_clip->media_stream);
|
||||
if (ms != NULL && parent_clip->sequence != NULL) {
|
||||
position_x->set_default_value(parent_clip->sequence->width/2);
|
||||
position_y->set_default_value(parent_clip->sequence->height/2);
|
||||
if (parent_clip->sequence != NULL) {
|
||||
double default_pos_x = parent_clip->sequence->width/2;
|
||||
double default_pos_y = parent_clip->sequence->height/2;
|
||||
|
||||
position_x->set_default_value(default_pos_x);
|
||||
position_y->set_default_value(default_pos_y);
|
||||
scale_x->set_default_value(100);
|
||||
scale_y->set_default_value(100);
|
||||
scale_y->setEnabled(false);
|
||||
uniform_scale_box->setChecked(true);
|
||||
default_anchor_x = ms->video_width/2;
|
||||
default_anchor_y = ms->video_height/2;
|
||||
|
||||
default_anchor_x = default_pos_x;
|
||||
default_anchor_y = default_pos_y;
|
||||
if (parent_clip->media != NULL) {
|
||||
switch (parent_clip->media_type) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
MediaStream* ms = static_cast<Media*>(parent_clip->media)->get_stream_from_file_index(parent_clip->media_stream);
|
||||
if (ms != NULL) {
|
||||
default_anchor_x = ms->video_width/2;
|
||||
default_anchor_y = ms->video_height/2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
{
|
||||
Sequence* s = static_cast<Sequence*>(parent_clip->media);
|
||||
default_anchor_x = s->width/2;
|
||||
default_anchor_y = s->height/2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anchor_x_box->set_default_value(default_anchor_x);
|
||||
anchor_y_box->set_default_value(default_anchor_y);
|
||||
opacity->set_default_value(100);
|
||||
blend_mode_box->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,31 +147,31 @@ void TransformEffect::load(QXmlStreamReader *stream) {
|
||||
stream->readNext();
|
||||
if (stream->isStartElement() && stream->name() == "posx") {
|
||||
stream->readNext();
|
||||
position_x->set_value(stream->text().toFloat());
|
||||
position_x->set_value(stream->text().toDouble());
|
||||
} else if (stream->isStartElement() && stream->name() == "posy") {
|
||||
stream->readNext();
|
||||
position_y->set_value(stream->text().toFloat());
|
||||
position_y->set_value(stream->text().toDouble());
|
||||
} else if (stream->isStartElement() && stream->name() == "scalex") {
|
||||
stream->readNext();
|
||||
scale_x->set_value(stream->text().toFloat());
|
||||
scale_x->set_value(stream->text().toDouble());
|
||||
} else if (stream->isStartElement() && stream->name() == "scaley") {
|
||||
stream->readNext();
|
||||
scale_y->set_value(stream->text().toFloat());
|
||||
scale_y->set_value(stream->text().toDouble());
|
||||
} else if (stream->isStartElement() && stream->name() == "uniformscale") {
|
||||
stream->readNext();
|
||||
uniform_scale_box->setChecked(stream->text() == "1");
|
||||
} else if (stream->isStartElement() && stream->name() == "rotation") {
|
||||
stream->readNext();
|
||||
rotation->set_value(stream->text().toFloat());
|
||||
rotation->set_value(stream->text().toDouble());
|
||||
} else if (stream->isStartElement() && stream->name() == "anchorx") {
|
||||
stream->readNext();
|
||||
anchor_x_box->set_value(stream->text().toFloat());
|
||||
anchor_x_box->set_value(stream->text().toDouble());
|
||||
} else if (stream->isStartElement() && stream->name() == "anchory") {
|
||||
stream->readNext();
|
||||
anchor_y_box->set_value(stream->text().toFloat());
|
||||
anchor_y_box->set_value(stream->text().toDouble());
|
||||
} else if (stream->isStartElement() && stream->name() == "opacity") {
|
||||
stream->readNext();
|
||||
opacity->set_value(stream->text().toFloat());
|
||||
opacity->set_value(stream->text().toDouble());
|
||||
} else if (stream->isStartElement() && stream->name() == "blendmode") {
|
||||
stream->readNext();
|
||||
blend_mode_box->setCurrentIndex(stream->text().toInt());
|
||||
@@ -183,9 +208,9 @@ void TransformEffect::process_gl(int* anchor_x, int* anchor_y) {
|
||||
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);
|
||||
float sx = scale_x->value()*0.01;
|
||||
float sy = (uniform_scale_box->isChecked()) ? sx : scale_y->value()*0.01;
|
||||
glScalef(sx, sy, 1);
|
||||
|
||||
// blend mode
|
||||
switch (blend_mode_box->currentData().toInt()) {
|
||||
|
||||
@@ -31,7 +31,7 @@ void VolumeEffect::load(QXmlStreamReader* stream) {
|
||||
stream->readNext();
|
||||
if (stream->isStartElement() && stream->name() == "volume") {
|
||||
stream->readNext();
|
||||
volume_val->set_value(stream->text().toFloat());
|
||||
volume_val->set_value(stream->text().toDouble());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#define SAVE_VERSION "180722"
|
||||
#define SAVE_VERSION "180727"
|
||||
|
||||
struct Config {
|
||||
Config();
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ void MainWindow::on_action_Import_triggered()
|
||||
|
||||
void MainWindow::on_actionExit_triggered()
|
||||
{
|
||||
QApplication::quit();
|
||||
close();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAbout_triggered()
|
||||
|
||||
@@ -29,15 +29,14 @@ EffectControls::~EffectControls()
|
||||
}
|
||||
|
||||
void EffectControls::menu_select(QAction* q) {
|
||||
EffectAddCommand* command = new EffectAddCommand();
|
||||
TimelineAction* ta = new TimelineAction();
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
Clip* clip = sequence->get_clip(selected_clips.at(i));
|
||||
if ((clip->track < 0 && video_menu) || (clip->track >= 0 && !video_menu)) {
|
||||
command->clips.append(clip);
|
||||
command->effects.append(create_effect(q->data().toInt(), clip));
|
||||
if ((sequence->get_clip(selected_clips.at(i))->track < 0) == video_menu) {
|
||||
ta->add_effect(sequence, selected_clips.at(i), q->data().toInt());
|
||||
}
|
||||
}
|
||||
undo_stack.push(command);
|
||||
undo_stack.push(ta);
|
||||
reload_clips();
|
||||
project_changed = true;
|
||||
}
|
||||
|
||||
@@ -194,38 +193,6 @@ bool EffectControls::is_focused() {
|
||||
return false;
|
||||
}
|
||||
|
||||
EffectAddCommand::EffectAddCommand() : done(false) {}
|
||||
|
||||
EffectAddCommand::~EffectAddCommand() {
|
||||
if (!done) {
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
delete effects.at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EffectAddCommand::undo() {
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
Clip* c = clips.at(i);
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
if (c->effects.at(j) == effects.at(i)) {
|
||||
c->effects.removeAt(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
panel_effect_controls->reload_clips();
|
||||
done = false;
|
||||
}
|
||||
|
||||
void EffectAddCommand::redo() {
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
clips.at(i)->effects.append(effects.at(i));
|
||||
}
|
||||
panel_effect_controls->reload_clips();
|
||||
done = true;
|
||||
}
|
||||
|
||||
EffectDeleteCommand::EffectDeleteCommand() : done(false) {}
|
||||
|
||||
EffectDeleteCommand::~EffectDeleteCommand() {
|
||||
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
bool video_menu;
|
||||
};
|
||||
|
||||
class EffectAddCommand : public QUndoCommand {
|
||||
/*class EffectAddCommand : public QUndoCommand {
|
||||
public:
|
||||
EffectAddCommand();
|
||||
~EffectAddCommand();
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
QVector<Effect*> effects;
|
||||
private:
|
||||
bool done;
|
||||
};
|
||||
};*/
|
||||
|
||||
class EffectDeleteCommand : public QUndoCommand {
|
||||
public:
|
||||
|
||||
+242
-150
@@ -523,29 +523,27 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
|
||||
break;
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
QString name;
|
||||
QString url;
|
||||
int id;
|
||||
int folder;
|
||||
int folder = 0;
|
||||
|
||||
QTreeWidgetItem* item = new_item();//import_file(url);
|
||||
Media* m = new Media();
|
||||
|
||||
for (int j=0;j<stream.attributes().size();j++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(j);
|
||||
if (attr.name() == "id") {
|
||||
id = attr.value().toInt();
|
||||
m->save_id = attr.value().toInt();
|
||||
} else if (attr.name() == "folder") {
|
||||
folder = attr.value().toInt();
|
||||
} else if (attr.name() == "name") {
|
||||
name = attr.value().toString();
|
||||
m->name = attr.value().toString();
|
||||
} else if (attr.name() == "url") {
|
||||
url = attr.value().toString();
|
||||
m->url = attr.value().toString();
|
||||
} else if (attr.name() == "duration") {
|
||||
m->length = attr.value().toLongLong();
|
||||
}
|
||||
}
|
||||
QTreeWidgetItem* item = new_item();//import_file(url);
|
||||
Media* m = new Media();
|
||||
m->url = url;
|
||||
m->name = name;
|
||||
m->save_id = id;
|
||||
|
||||
while (!(stream.name() == child_search && stream.isEndElement())) {
|
||||
/*while (!(stream.name() == child_search && stream.isEndElement())) {
|
||||
stream.readNext();
|
||||
if (stream.isStartElement()) {
|
||||
if (stream.name() == "video") {
|
||||
@@ -582,9 +580,10 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
|
||||
m->audio_tracks.append(ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
set_media_of_tree(item, m);
|
||||
|
||||
if (folder == 0) {
|
||||
ui->treeWidget->addTopLevelItem(item);
|
||||
} else {
|
||||
@@ -659,55 +658,76 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
|
||||
} else if (attr.name() == "b") {
|
||||
c->color_b = attr.value().toInt();
|
||||
} else if (attr.name() == "media") {
|
||||
c->media_type = MEDIA_TYPE_FOOTAGE;
|
||||
media_id = attr.value().toInt();
|
||||
} else if (attr.name() == "stream") {
|
||||
stream_id = attr.value().toInt();
|
||||
} else if (attr.name() == "sequence") {
|
||||
c->media_type = MEDIA_TYPE_SEQUENCE;
|
||||
|
||||
// since we haven't finished loading sequences, we defer linking this until later
|
||||
c->media = NULL;
|
||||
c->media_stream = attr.value().toInt();
|
||||
loaded_clips.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
// set media and media stream
|
||||
for (int j=0;j<loaded_media.size();j++) {
|
||||
Media* m = loaded_media.at(j);
|
||||
if (m->save_id == media_id) {
|
||||
c->media = m;
|
||||
c->media_stream = stream_id;
|
||||
break;
|
||||
/*switch (c->media_type) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
|
||||
|
||||
break;
|
||||
}*/
|
||||
if (c->media_type == MEDIA_TYPE_FOOTAGE) {
|
||||
if (media_id == 0) {
|
||||
c->media = NULL;
|
||||
} else {
|
||||
for (int j=0;j<loaded_media.size();j++) {
|
||||
Media* m = loaded_media.at(j);
|
||||
if (m->save_id == media_id) {
|
||||
c->media = m;
|
||||
c->media_stream = stream_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load links and effects
|
||||
while (!(stream.name() == "clip" && stream.isEndElement()) && !stream.atEnd()) {
|
||||
stream.readNext();
|
||||
if (stream.name() == "linked" && stream.isStartElement()) {
|
||||
while (!(stream.name() == "linked" && stream.isEndElement()) && !stream.atEnd()) {
|
||||
stream.readNext();
|
||||
if (stream.name() == "link" && stream.isStartElement()) {
|
||||
for (int k=0;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& link_attr = stream.attributes().at(k);
|
||||
if (link_attr.name() == "id") {
|
||||
c->linked.append(link_attr.value().toInt());
|
||||
break;
|
||||
if (stream.isStartElement()) {
|
||||
if (stream.name() == "linked") {
|
||||
while (!(stream.name() == "linked" && stream.isEndElement()) && !stream.atEnd()) {
|
||||
stream.readNext();
|
||||
if (stream.name() == "link" && stream.isStartElement()) {
|
||||
for (int k=0;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& link_attr = stream.attributes().at(k);
|
||||
if (link_attr.name() == "id") {
|
||||
c->linked.append(link_attr.value().toInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stream.name() == "effects" && stream.isStartElement()) {
|
||||
while (!(stream.name() == "effects" && stream.isEndElement()) && !stream.atEnd()) {
|
||||
stream.readNext();
|
||||
if (stream.name() == "effect" && stream.isStartElement()) {
|
||||
int effect_id = -1;
|
||||
for (int j=0;j<stream.attributes().size();j++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(j);
|
||||
if (attr.name().toString() == QLatin1String("id")) {
|
||||
effect_id = attr.value().toInt();
|
||||
break;
|
||||
} else if (stream.name() == "effects") {
|
||||
while (!(stream.name() == "effects" && stream.isEndElement()) && !stream.atEnd()) {
|
||||
stream.readNext();
|
||||
if (stream.name() == "effect" && stream.isStartElement()) {
|
||||
int effect_id = -1;
|
||||
for (int j=0;j<stream.attributes().size();j++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(j);
|
||||
if (attr.name().toString() == QLatin1String("id")) {
|
||||
effect_id = attr.value().toInt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (effect_id != -1) {
|
||||
Effect* e = create_effect(effect_id, c);
|
||||
e->load(&stream);
|
||||
c->effects.append(e);
|
||||
}
|
||||
}
|
||||
if (effect_id != -1) {
|
||||
Effect* e = create_effect(effect_id, c);
|
||||
e->load(&stream);
|
||||
c->effects.append(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -745,6 +765,8 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
|
||||
new_sequence(NULL, s, false, parent);
|
||||
|
||||
if (open_sequence) set_sequence(s);
|
||||
|
||||
loaded_sequences.append(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -774,6 +796,8 @@ void Project::load_project() {
|
||||
// temp variables for loading
|
||||
loaded_folders.clear();
|
||||
loaded_media.clear();
|
||||
loaded_clips.clear();
|
||||
loaded_sequences.clear();
|
||||
|
||||
// find project file version
|
||||
cont = load_worker(file, stream, LOAD_TYPE_VERSION);
|
||||
@@ -803,6 +827,17 @@ void Project::load_project() {
|
||||
cont = load_worker(file, stream, MEDIA_TYPE_SEQUENCE);
|
||||
}
|
||||
|
||||
// attach nested sequence clips to their sequences
|
||||
for (int i=0;i<loaded_clips.size();i++) {
|
||||
for (int j=0;j<loaded_sequences.size();j++) {
|
||||
if (loaded_clips.at(i)->media_stream == loaded_sequences.at(j)->save_id) {
|
||||
loaded_clips.at(i)->media = loaded_sequences.at(j);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cont) {
|
||||
QMessageBox::critical(this, "Project Load Error", "Error loading project: " + error_str, QMessageBox::Ok);
|
||||
} else if (stream.hasError()) {
|
||||
@@ -823,121 +858,138 @@ void Project::load_project() {
|
||||
file.close();
|
||||
}
|
||||
|
||||
void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int type) {
|
||||
void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int type, bool set_ids_only) {
|
||||
bool root = (parent == NULL);
|
||||
int len = root ? ui->treeWidget->topLevelItemCount() : parent->childCount();
|
||||
for (int i=0;i<len;i++) {
|
||||
QTreeWidgetItem* item = root ? ui->treeWidget->topLevelItem(i) : parent->child(i);
|
||||
int item_type = get_type_from_tree(item);
|
||||
if (item_type == MEDIA_TYPE_FOLDER) {
|
||||
if (type == SAVE_SET_FOLDER_IDS) {
|
||||
item->setData(0, Qt::UserRole + 3, folder_id); // saves a temporary ID for matching in the project file
|
||||
folder_id++;
|
||||
} else if (type == MEDIA_TYPE_FOLDER) {
|
||||
// if we're saving folders, save the folder
|
||||
stream.writeStartElement("folder");
|
||||
stream.writeAttribute("name", item->text(0));
|
||||
stream.writeAttribute("id", QString::number(item->data(0, Qt::UserRole + 3).toInt()));
|
||||
if (item->parent() == NULL) {
|
||||
stream.writeAttribute("parent", "0");
|
||||
if (type == item_type) {
|
||||
if (item_type == MEDIA_TYPE_FOLDER) {
|
||||
if (set_ids_only) {
|
||||
item->setData(0, Qt::UserRole + 3, folder_id); // saves a temporary ID for matching in the project file
|
||||
folder_id++;
|
||||
} else {
|
||||
stream.writeAttribute("parent", QString::number(item->parent()->data(0, Qt::UserRole + 3).toInt()));
|
||||
}
|
||||
stream.writeEndElement();
|
||||
}
|
||||
save_folder(stream, item, type);
|
||||
} else if (type == item_type) {
|
||||
int folder = root ? 0 : parent->data(0, Qt::UserRole + 3).toInt();
|
||||
if (type == MEDIA_TYPE_FOOTAGE) {
|
||||
Media* m = get_media_from_tree(item);
|
||||
m->save_id = media_id;
|
||||
stream.writeStartElement("footage");
|
||||
stream.writeAttribute("id", QString::number(media_id));
|
||||
stream.writeAttribute("folder", QString::number(folder));
|
||||
stream.writeAttribute("name", m->name);
|
||||
stream.writeAttribute("url", m->url);
|
||||
stream.writeAttribute("duration", QString::number(m->length));
|
||||
for (int j=0;j<m->video_tracks.size();j++) {
|
||||
MediaStream* ms = m->video_tracks.at(j);
|
||||
stream.writeStartElement("video");
|
||||
stream.writeAttribute("id", QString::number(ms->file_index));
|
||||
stream.writeAttribute("width", QString::number(ms->video_width));
|
||||
stream.writeAttribute("height", QString::number(ms->video_height));
|
||||
stream.writeAttribute("framerate", QString::number(ms->video_frame_rate));
|
||||
stream.writeAttribute("infinite", QString::number(ms->infinite_length));
|
||||
// if we're saving folders, save the folder
|
||||
stream.writeStartElement("folder");
|
||||
stream.writeAttribute("name", item->text(0));
|
||||
stream.writeAttribute("id", QString::number(item->data(0, Qt::UserRole + 3).toInt()));
|
||||
if (item->parent() == NULL) {
|
||||
stream.writeAttribute("parent", "0");
|
||||
} else {
|
||||
stream.writeAttribute("parent", QString::number(item->parent()->data(0, Qt::UserRole + 3).toInt()));
|
||||
}
|
||||
stream.writeEndElement();
|
||||
}
|
||||
for (int j=0;j<m->audio_tracks.size();j++) {
|
||||
MediaStream* ms = m->audio_tracks.at(j);
|
||||
stream.writeStartElement("audio");
|
||||
stream.writeAttribute("id", QString::number(ms->file_index));
|
||||
stream.writeAttribute("channels", QString::number(ms->audio_channels));
|
||||
stream.writeAttribute("layout", QString::number(ms->audio_layout));
|
||||
stream.writeAttribute("frequency", QString::number(ms->audio_frequency));
|
||||
save_folder(stream, item, type, set_ids_only);
|
||||
} else {
|
||||
int folder = root ? 0 : parent->data(0, Qt::UserRole + 3).toInt();
|
||||
if (type == MEDIA_TYPE_FOOTAGE) {
|
||||
Media* m = get_media_from_tree(item);
|
||||
m->save_id = media_id;
|
||||
stream.writeStartElement("footage");
|
||||
stream.writeAttribute("id", QString::number(media_id));
|
||||
stream.writeAttribute("folder", QString::number(folder));
|
||||
stream.writeAttribute("name", m->name);
|
||||
stream.writeAttribute("url", m->url);
|
||||
stream.writeAttribute("duration", QString::number(m->length));
|
||||
for (int j=0;j<m->video_tracks.size();j++) {
|
||||
MediaStream* ms = m->video_tracks.at(j);
|
||||
stream.writeStartElement("video");
|
||||
stream.writeAttribute("id", QString::number(ms->file_index));
|
||||
stream.writeAttribute("width", QString::number(ms->video_width));
|
||||
stream.writeAttribute("height", QString::number(ms->video_height));
|
||||
stream.writeAttribute("framerate", QString::number(ms->video_frame_rate));
|
||||
stream.writeAttribute("infinite", QString::number(ms->infinite_length));
|
||||
stream.writeEndElement();
|
||||
}
|
||||
for (int j=0;j<m->audio_tracks.size();j++) {
|
||||
MediaStream* ms = m->audio_tracks.at(j);
|
||||
stream.writeStartElement("audio");
|
||||
stream.writeAttribute("id", QString::number(ms->file_index));
|
||||
stream.writeAttribute("channels", QString::number(ms->audio_channels));
|
||||
stream.writeAttribute("layout", QString::number(ms->audio_layout));
|
||||
stream.writeAttribute("frequency", QString::number(ms->audio_frequency));
|
||||
stream.writeEndElement();
|
||||
}
|
||||
stream.writeEndElement();
|
||||
}
|
||||
stream.writeEndElement();
|
||||
media_id++;
|
||||
} else if (type == MEDIA_TYPE_SEQUENCE) {
|
||||
Sequence* s = get_sequence_from_tree(item);
|
||||
stream.writeStartElement("sequence");
|
||||
stream.writeAttribute("folder", QString::number(folder));
|
||||
stream.writeAttribute("name", s->name);
|
||||
stream.writeAttribute("width", QString::number(s->width));
|
||||
stream.writeAttribute("height", QString::number(s->height));
|
||||
stream.writeAttribute("framerate", QString::number(s->frame_rate));
|
||||
stream.writeAttribute("afreq", QString::number(s->audio_frequency));
|
||||
stream.writeAttribute("alayout", QString::number(s->audio_layout));
|
||||
if (s == sequence) {
|
||||
stream.writeAttribute("open", "1");
|
||||
}
|
||||
if (s->using_workarea) {
|
||||
stream.writeAttribute("workareaIn", QString::number(s->workarea_in));
|
||||
stream.writeAttribute("workareaOut", QString::number(s->workarea_out));
|
||||
}
|
||||
for (int j=0;j<s->clip_count();j++) {
|
||||
Clip* c = s->get_clip(j);
|
||||
if (c != NULL) {
|
||||
stream.writeStartElement("clip"); // clip
|
||||
stream.writeAttribute("id", QString::number(j));
|
||||
stream.writeAttribute("name", c->name);
|
||||
stream.writeAttribute("clipin", QString::number(c->clip_in));
|
||||
stream.writeAttribute("in", QString::number(c->timeline_in));
|
||||
stream.writeAttribute("out", QString::number(c->timeline_out));
|
||||
stream.writeAttribute("track", QString::number(c->track));
|
||||
if (c->opening_transition != NULL) {
|
||||
stream.writeAttribute("opening", QString::number(c->opening_transition->id));
|
||||
media_id++;
|
||||
} else if (type == MEDIA_TYPE_SEQUENCE) {
|
||||
Sequence* s = get_sequence_from_tree(item);
|
||||
if (set_ids_only) {
|
||||
s->save_id = sequence_id;
|
||||
sequence_id++;
|
||||
} else {
|
||||
stream.writeStartElement("sequence");
|
||||
stream.writeAttribute("id", QString::number(s->save_id));
|
||||
stream.writeAttribute("folder", QString::number(folder));
|
||||
stream.writeAttribute("name", s->name);
|
||||
stream.writeAttribute("width", QString::number(s->width));
|
||||
stream.writeAttribute("height", QString::number(s->height));
|
||||
stream.writeAttribute("framerate", QString::number(s->frame_rate));
|
||||
stream.writeAttribute("afreq", QString::number(s->audio_frequency));
|
||||
stream.writeAttribute("alayout", QString::number(s->audio_layout));
|
||||
if (s == sequence) {
|
||||
stream.writeAttribute("open", "1");
|
||||
}
|
||||
if (c->closing_transition != NULL) {
|
||||
stream.writeAttribute("closing", QString::number(c->closing_transition->id));
|
||||
if (s->using_workarea) {
|
||||
stream.writeAttribute("workareaIn", QString::number(s->workarea_in));
|
||||
stream.writeAttribute("workareaOut", QString::number(s->workarea_out));
|
||||
}
|
||||
stream.writeAttribute("r", QString::number(c->color_r));
|
||||
stream.writeAttribute("g", QString::number(c->color_g));
|
||||
stream.writeAttribute("b", QString::number(c->color_b));
|
||||
stream.writeAttribute("media", QString::number(c->media->save_id));
|
||||
stream.writeAttribute("stream", QString::number(c->media_stream));
|
||||
for (int j=0;j<s->clip_count();j++) {
|
||||
Clip* c = s->get_clip(j);
|
||||
if (c != NULL) {
|
||||
stream.writeStartElement("clip"); // clip
|
||||
stream.writeAttribute("id", QString::number(j));
|
||||
stream.writeAttribute("name", c->name);
|
||||
stream.writeAttribute("clipin", QString::number(c->clip_in));
|
||||
stream.writeAttribute("in", QString::number(c->timeline_in));
|
||||
stream.writeAttribute("out", QString::number(c->timeline_out));
|
||||
stream.writeAttribute("track", QString::number(c->track));
|
||||
if (c->opening_transition != NULL) {
|
||||
stream.writeAttribute("opening", QString::number(c->opening_transition->id));
|
||||
}
|
||||
if (c->closing_transition != NULL) {
|
||||
stream.writeAttribute("closing", QString::number(c->closing_transition->id));
|
||||
}
|
||||
stream.writeAttribute("r", QString::number(c->color_r));
|
||||
stream.writeAttribute("g", QString::number(c->color_g));
|
||||
stream.writeAttribute("b", QString::number(c->color_b));
|
||||
|
||||
stream.writeStartElement("linked"); // linked
|
||||
for (int k=0;k<c->linked.size();k++) {
|
||||
stream.writeStartElement("link"); // link
|
||||
stream.writeAttribute("id", QString::number(c->linked.at(k)));
|
||||
stream.writeEndElement(); // link
|
||||
}
|
||||
stream.writeEndElement(); // linked
|
||||
stream.writeAttribute("type", QString::number(c->media_type));
|
||||
switch (c->media_type) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
stream.writeAttribute("media", QString::number(static_cast<Media*>(c->media)->save_id));
|
||||
stream.writeAttribute("stream", QString::number(c->media_stream));
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
stream.writeAttribute("sequence", QString::number(static_cast<Sequence*>(c->media)->save_id));
|
||||
break;
|
||||
}
|
||||
|
||||
stream.writeStartElement("effects"); // effects
|
||||
for (int k=0;k<c->effects.size();k++) {
|
||||
stream.writeStartElement("effect"); // effect
|
||||
Effect* e = c->effects.at(k);
|
||||
stream.writeAttribute("id", QString::number(e->id));
|
||||
e->save(&stream);
|
||||
stream.writeEndElement(); // effect
|
||||
stream.writeStartElement("linked"); // linked
|
||||
for (int k=0;k<c->linked.size();k++) {
|
||||
stream.writeStartElement("link"); // link
|
||||
stream.writeAttribute("id", QString::number(c->linked.at(k)));
|
||||
stream.writeEndElement(); // link
|
||||
}
|
||||
stream.writeEndElement(); // linked
|
||||
|
||||
stream.writeStartElement("effects"); // effects
|
||||
for (int k=0;k<c->effects.size();k++) {
|
||||
stream.writeStartElement("effect"); // effect
|
||||
Effect* e = c->effects.at(k);
|
||||
stream.writeAttribute("id", QString::number(e->id));
|
||||
e->save(&stream);
|
||||
stream.writeEndElement(); // effect
|
||||
}
|
||||
stream.writeEndElement(); // effects
|
||||
stream.writeEndElement(); // clip
|
||||
}
|
||||
}
|
||||
stream.writeEndElement(); // effects
|
||||
stream.writeEndElement(); // clip
|
||||
stream.writeEndElement();
|
||||
}
|
||||
}
|
||||
stream.writeEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -945,7 +997,8 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int
|
||||
|
||||
void Project::save_project(bool autorecovery) {
|
||||
folder_id = 1;
|
||||
media_id = 0;
|
||||
media_id = 1;
|
||||
sequence_id = 1;
|
||||
|
||||
QFile file(autorecovery ? autorecovery_filename : project_url);
|
||||
if (!file.open(QIODevice::WriteOnly/* | QIODevice::Text*/)) {
|
||||
@@ -961,18 +1014,20 @@ void Project::save_project(bool autorecovery) {
|
||||
|
||||
stream.writeTextElement("version", SAVE_VERSION);
|
||||
|
||||
save_folder(stream, NULL, SAVE_SET_FOLDER_IDS);
|
||||
save_folder(stream, NULL, MEDIA_TYPE_FOLDER, true);
|
||||
|
||||
stream.writeStartElement("folders"); // folders
|
||||
save_folder(stream, NULL, MEDIA_TYPE_FOLDER);
|
||||
save_folder(stream, NULL, MEDIA_TYPE_FOLDER, false);
|
||||
stream.writeEndElement(); // folders
|
||||
|
||||
stream.writeStartElement("media"); // media
|
||||
save_folder(stream, NULL, MEDIA_TYPE_FOOTAGE);
|
||||
save_folder(stream, NULL, MEDIA_TYPE_FOOTAGE, false);
|
||||
stream.writeEndElement(); // media
|
||||
|
||||
save_folder(stream, NULL, MEDIA_TYPE_SEQUENCE, true);
|
||||
|
||||
stream.writeStartElement("sequences"); // sequences
|
||||
save_folder(stream, NULL, MEDIA_TYPE_SEQUENCE);
|
||||
save_folder(stream, NULL, MEDIA_TYPE_SEQUENCE, false);
|
||||
stream.writeEndElement();// sequences
|
||||
|
||||
stream.writeEndElement(); // project
|
||||
@@ -1027,6 +1082,24 @@ void Project::add_recent_project(QString url) {
|
||||
save_recent_projects();
|
||||
}
|
||||
|
||||
void Project::list_all_sequences_worker(QVector<Sequence*>* list, QTreeWidgetItem* parent) {
|
||||
int len = (parent == NULL) ? ui->treeWidget->topLevelItemCount() : parent->childCount();
|
||||
for (int i=0;i<len;i++) {
|
||||
QTreeWidgetItem* item = (parent == NULL) ? ui->treeWidget->topLevelItem(i) : parent->child(i);
|
||||
if (get_type_from_tree(item) == MEDIA_TYPE_SEQUENCE) {
|
||||
list->append(get_sequence_from_tree(item));
|
||||
} else if (get_type_from_tree(item) == MEDIA_TYPE_FOLDER) {
|
||||
list_all_sequences_worker(list, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<Sequence*> Project::list_all_project_sequences() {
|
||||
QVector<Sequence*> list;
|
||||
list_all_sequences_worker(&list, NULL);
|
||||
return list;
|
||||
}
|
||||
|
||||
#define THROBBER_LIMIT 20
|
||||
#define THROBBER_SIZE 50
|
||||
|
||||
@@ -1048,11 +1121,30 @@ void MediaThrobber::animation_update() {
|
||||
|
||||
void MediaThrobber::stop(int icon_type) {
|
||||
animator.stop();
|
||||
|
||||
switch (icon_type) {
|
||||
case ICON_TYPE_VIDEO: item->setIcon(0, QIcon(":/icons/videosource.png")); break;
|
||||
case ICON_TYPE_AUDIO: item->setIcon(0, QIcon(":/icons/audiosource.png")); break;
|
||||
case ICON_TYPE_ERROR: item->setIcon(0, QIcon::fromTheme("dialog-error")); break;
|
||||
}
|
||||
|
||||
// re-init all effects on all clips
|
||||
QVector<Sequence*> sequences = panel_project->list_all_project_sequences();
|
||||
for (int i=0;i<sequences.size();i++) {
|
||||
Sequence* s = sequences.at(i);
|
||||
for (int j=0;j<s->clip_count();j++) {
|
||||
Clip* c = s->get_clip(j);
|
||||
if (c != NULL) {
|
||||
for (int k=0;k<c->effects.size();k++) {
|
||||
c->effects.at(k)->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// redraw clips
|
||||
panel_timeline->redraw_all_clips(false);
|
||||
|
||||
panel_project->source_table->viewport()->update();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
+8
-2
@@ -7,6 +7,7 @@
|
||||
|
||||
struct Media;
|
||||
struct Sequence;
|
||||
struct Clip;
|
||||
class Timeline;
|
||||
class Viewer;
|
||||
class SourceTable;
|
||||
@@ -21,7 +22,6 @@ class QFile;
|
||||
#define MEDIA_TYPE_SOLID 3
|
||||
|
||||
#define LOAD_TYPE_VERSION 69
|
||||
#define SAVE_SET_FOLDER_IDS 70
|
||||
|
||||
class TimelineAction;
|
||||
|
||||
@@ -65,6 +65,8 @@ public:
|
||||
|
||||
void save_recent_projects();
|
||||
|
||||
QVector<Sequence*> list_all_project_sequences();
|
||||
|
||||
SourceTable* source_table;
|
||||
public slots:
|
||||
void import_dialog();
|
||||
@@ -74,16 +76,20 @@ private:
|
||||
Ui::Project *ui;
|
||||
QTreeWidgetItem* new_item();
|
||||
bool load_worker(QFile& f, QXmlStreamReader& stream, int type);
|
||||
void save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int type);
|
||||
void save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int type, bool set_ids_only);
|
||||
QString error_str;
|
||||
int folder_id;
|
||||
int media_id;
|
||||
int sequence_id;
|
||||
QVector<QTreeWidgetItem*> loaded_folders;
|
||||
QVector<Media*> loaded_media;
|
||||
QVector<Clip*> loaded_clips;
|
||||
QVector<Sequence*> loaded_sequences;
|
||||
QTreeWidgetItem* find_loaded_folder_by_id(int id);
|
||||
void add_recent_project(QString url);
|
||||
void get_media_from_table(QList<QTreeWidgetItem*> items, QList<QTreeWidgetItem*>& list, int type);
|
||||
void start_preview_generator(QTreeWidgetItem* item, Media* media);
|
||||
void list_all_sequences_worker(QVector<Sequence*>* list, QTreeWidgetItem* parent);
|
||||
private slots:
|
||||
void rename_media(QTreeWidgetItem* item, int column);
|
||||
void clear_recent_projects();
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#include <QScrollBar>
|
||||
#include <QtMath>
|
||||
|
||||
long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) {
|
||||
return qRound(((double)framenumber/source_frame_rate)*target_frame_rate);
|
||||
}
|
||||
|
||||
Timeline::Timeline(QWidget *parent) :
|
||||
QDockWidget(parent),
|
||||
selecting(false),
|
||||
|
||||
+3
-1
@@ -17,6 +17,7 @@ struct Media;
|
||||
struct MediaStream;
|
||||
|
||||
int lerp(int a, int b, double t);
|
||||
long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
|
||||
|
||||
struct Ghost {
|
||||
int clip;
|
||||
@@ -31,7 +32,8 @@ struct Ghost {
|
||||
long old_clip_in;
|
||||
|
||||
// importing variables
|
||||
Media* media;
|
||||
void* media;
|
||||
int media_type;
|
||||
int media_stream;
|
||||
|
||||
// other variables
|
||||
|
||||
+5
-4
@@ -151,7 +151,7 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) {
|
||||
|
||||
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
|
||||
MediaStream* ms = c->media->get_stream_from_file_index(c->media_stream);
|
||||
MediaStream* ms = static_cast<Media*>(c->media)->get_stream_from_file_index(c->media_stream);
|
||||
if (ms->infinite_length) {
|
||||
// if this clip is a still image, we only need one frame
|
||||
if (!c->cache_A.written) {
|
||||
@@ -197,9 +197,10 @@ 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();
|
||||
Media* m = static_cast<Media*>(clip->media);
|
||||
QByteArray ba = m->url.toUtf8();
|
||||
const char* filename = ba.constData();
|
||||
MediaStream* ms = clip->media->get_stream_from_file_index(clip->media_stream);
|
||||
MediaStream* ms = m->get_stream_from_file_index(clip->media_stream);
|
||||
|
||||
int errCode = avformat_open_input(
|
||||
&clip->formatCtx,
|
||||
@@ -361,7 +362,7 @@ void cache_clip_worker(Clip* clip, long playhead, bool write_A, bool write_B, bo
|
||||
|
||||
void close_clip_worker(Clip* clip) {
|
||||
// closes ffmpeg file handle and frees any memory used for caching
|
||||
MediaStream* ms = clip->media->get_stream_from_file_index(clip->media_stream);
|
||||
MediaStream* ms = static_cast<Media*>(clip->media)->get_stream_from_file_index(clip->media_stream);
|
||||
if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
sws_freeContext(clip->sws_ctx);
|
||||
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
|
||||
@@ -77,7 +77,7 @@ void get_clip_frame(Clip* c, long playhead) {
|
||||
long clip_time = seconds_to_clip_frame(c, playhead_to_seconds(c, playhead));
|
||||
|
||||
// do we need to update the texture?
|
||||
MediaStream* ms = c->media->get_stream_from_file_index(c->media_stream);
|
||||
MediaStream* ms = static_cast<Media*>(c->media)->get_stream_from_file_index(c->media_stream);
|
||||
if ((!ms->infinite_length && c->texture_frame != clip_time) ||
|
||||
(ms->infinite_length && c->texture_frame == -1)) {
|
||||
AVFrame* current_frame = NULL;
|
||||
|
||||
+22
-12
@@ -12,19 +12,21 @@ extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
Clip::Clip(Sequence* s) : sequence(s) {
|
||||
Clip::Clip(Sequence* s) :
|
||||
sequence(s),
|
||||
enabled(true),
|
||||
clip_in(0),
|
||||
timeline_in(0),
|
||||
timeline_out(0),
|
||||
track(0),
|
||||
undeletable(0),
|
||||
texture(NULL),
|
||||
opening_transition(NULL),
|
||||
closing_transition(NULL),
|
||||
media(NULL),
|
||||
pkt(new AVPacket())
|
||||
{
|
||||
reset();
|
||||
enabled = true;
|
||||
clip_in = 0;
|
||||
timeline_in = 0;
|
||||
timeline_out = 0;
|
||||
track = 0;
|
||||
undeletable = 0;
|
||||
texture = NULL;
|
||||
opening_transition = NULL;
|
||||
closing_transition = NULL;
|
||||
media = NULL;
|
||||
pkt = new AVPacket();
|
||||
}
|
||||
|
||||
Clip* Clip::copy(Sequence* s) {
|
||||
@@ -41,6 +43,7 @@ Clip* Clip::copy(Sequence* s) {
|
||||
copy->color_b = color_b;
|
||||
copy->sequence = s;
|
||||
copy->media = media;
|
||||
copy->media_type = media_type;
|
||||
copy->media_stream = media_stream;
|
||||
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
@@ -80,6 +83,13 @@ void Clip::reset() {
|
||||
cache_B.frames = NULL;
|
||||
}
|
||||
|
||||
void Clip::refresh() {
|
||||
// reinitializes all effects... just in case
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
effects.at(i)->init();
|
||||
}
|
||||
}
|
||||
|
||||
Clip::~Clip() {
|
||||
if (open) {
|
||||
close_clip(this);
|
||||
|
||||
+3
-1
@@ -40,6 +40,7 @@ struct Clip
|
||||
~Clip();
|
||||
Clip* copy(Sequence* s);
|
||||
void reset();
|
||||
void refresh();
|
||||
bool undeletable;
|
||||
|
||||
// timeline variables
|
||||
@@ -56,7 +57,8 @@ struct Clip
|
||||
quint8 color_g;
|
||||
quint8 color_b;
|
||||
long getLength();
|
||||
Media* media; // attached media
|
||||
void* media; // attached media
|
||||
int media_type;
|
||||
int media_stream;
|
||||
Sequence* sequence;
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ public:
|
||||
bool using_workarea;
|
||||
long workarea_in;
|
||||
long workarea_out;
|
||||
|
||||
int save_id;
|
||||
private:
|
||||
QVector<Clip*> clips;
|
||||
};
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
#include "project/sequence.h"
|
||||
#include "panels/panels.h"
|
||||
#include "panels/project.h"
|
||||
#include "panels/effectcontrols.h"
|
||||
#include "playback/playback.h"
|
||||
#include "ui/sourcetable.h"
|
||||
#include "effects/effects.h"
|
||||
|
||||
QUndoStack undo_stack;
|
||||
|
||||
@@ -23,6 +25,7 @@ QUndoStack undo_stack;
|
||||
#define TA_ADD_OUT 6
|
||||
#define TA_ADD_CLIP_IN 7
|
||||
#define TA_ADD_TRACK 8
|
||||
#define TA_ADD_EFFECT 9
|
||||
|
||||
TimelineAction::TimelineAction() :
|
||||
done(false),
|
||||
@@ -139,6 +142,10 @@ void TimelineAction::ripple(Sequence* s, long point, long length) {
|
||||
ripple(s, point, length, i);
|
||||
}
|
||||
|
||||
void TimelineAction::add_effect(Sequence* s, int clip, int effect) {
|
||||
new_action(s, TA_ADD_EFFECT, clip, 0, effect);
|
||||
}
|
||||
|
||||
void TimelineAction::set_in_out(Sequence* s, bool enabled, long in, long out) {
|
||||
change_in_out = true;
|
||||
change_in_out_sequence = s;
|
||||
@@ -211,6 +218,12 @@ void TimelineAction::undo() {
|
||||
case TA_ADD_TRACK:
|
||||
sequences.at(i)->get_clip(clips.at(i))->track -= new_values.at(i);
|
||||
break;
|
||||
case TA_ADD_EFFECT:
|
||||
Clip* c = sequences.at(i)->get_clip(clips.at(i));
|
||||
Effect* effect = c->effects.at(old_values.at(i));
|
||||
c->effects.removeAt(old_values.at(i));
|
||||
delete effect;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,6 +359,13 @@ void TimelineAction::redo() {
|
||||
sequences.at(i)->get_clip(clips.at(i))->track += new_values.at(i);
|
||||
}
|
||||
break;
|
||||
case TA_ADD_EFFECT:
|
||||
{
|
||||
Clip* c = sequences.at(i)->get_clip(clips.at(i));
|
||||
old_values[i] = c->effects.size();
|
||||
c->effects.append(create_effect(new_values.at(i), c));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ public:
|
||||
void ripple(Sequence* s, long point, long length);
|
||||
void ripple(Sequence* s, long point, long length, QVector<int> &ignore);
|
||||
void set_in_out(Sequence* s, bool enabled, long in, long out);
|
||||
void add_effect(Sequence* s, int clip, int effect);
|
||||
void undo();
|
||||
void redo();
|
||||
private:
|
||||
|
||||
+14
-9
@@ -6,19 +6,20 @@
|
||||
#include <QInputDialog>
|
||||
#include <QApplication>
|
||||
|
||||
LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent)
|
||||
{
|
||||
LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) {
|
||||
drag_start = false;
|
||||
min_enabled = false;
|
||||
max_enabled = false;
|
||||
setStyleSheet("QLabel{color:#ffc000;text-decoration:underline;}QLabel:disabled{color:#808080;}");
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
internal_value = -1;
|
||||
set_value(0);
|
||||
set_default_value(0);
|
||||
set_value(0);
|
||||
set = false;
|
||||
}
|
||||
|
||||
void LabelSlider::set_value(float v) {
|
||||
void LabelSlider::set_value(double v) {
|
||||
set = true;
|
||||
if (v != internal_value) {
|
||||
if (min_enabled && v < min_value) {
|
||||
internal_value = min_value;
|
||||
@@ -33,21 +34,25 @@ void LabelSlider::set_value(float v) {
|
||||
}
|
||||
}
|
||||
|
||||
float LabelSlider::value() {
|
||||
bool LabelSlider::is_set() {
|
||||
return set;
|
||||
}
|
||||
|
||||
double LabelSlider::value() {
|
||||
return internal_value;
|
||||
}
|
||||
|
||||
void LabelSlider::set_default_value(float v) {
|
||||
void LabelSlider::set_default_value(double v) {
|
||||
default_value = v;
|
||||
set_value(v);
|
||||
if (!set) set_value(v);
|
||||
}
|
||||
|
||||
void LabelSlider::set_minimum_value(float v) {
|
||||
void LabelSlider::set_minimum_value(double v) {
|
||||
min_value = v;
|
||||
min_enabled = true;
|
||||
}
|
||||
|
||||
void LabelSlider::set_maximum_value(float v) {
|
||||
void LabelSlider::set_maximum_value(double v) {
|
||||
max_value = v;
|
||||
max_enabled = true;
|
||||
}
|
||||
|
||||
+13
-10
@@ -9,29 +9,32 @@ class LabelSlider : public QLabel
|
||||
Q_OBJECT
|
||||
public:
|
||||
LabelSlider(QWidget* parent = 0);
|
||||
void set_value(float v);
|
||||
void set_default_value(float v);
|
||||
void set_minimum_value(float v);
|
||||
void set_maximum_value(float v);
|
||||
float value();
|
||||
void set_value(double v);
|
||||
void set_default_value(double v);
|
||||
void set_minimum_value(double v);
|
||||
void set_maximum_value(double v);
|
||||
double value();
|
||||
bool is_set();
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *ev);
|
||||
void mouseMoveEvent(QMouseEvent *ev);
|
||||
void mouseReleaseEvent(QMouseEvent *ev);
|
||||
private:
|
||||
float default_value;
|
||||
float internal_value;
|
||||
float drag_start_value;
|
||||
double default_value;
|
||||
double internal_value;
|
||||
double drag_start_value;
|
||||
|
||||
bool min_enabled;
|
||||
float min_value;
|
||||
double min_value;
|
||||
bool max_enabled;
|
||||
float max_value;
|
||||
double max_value;
|
||||
|
||||
bool drag_start;
|
||||
bool drag_proc;
|
||||
int drag_start_x;
|
||||
int drag_start_y;
|
||||
|
||||
bool set;
|
||||
signals:
|
||||
void valueChanged();
|
||||
};
|
||||
|
||||
+156
-86
@@ -113,21 +113,48 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
|
||||
}
|
||||
for (int i=0;i<items.size();i++) {
|
||||
QTreeWidgetItem* item = items.at(i);
|
||||
if (get_type_from_tree(item) == MEDIA_TYPE_FOOTAGE) {
|
||||
Media* m = get_media_from_tree(item);
|
||||
if (m->ready) {
|
||||
Ghost g;
|
||||
g.clip = -1;
|
||||
g.media = m;
|
||||
g.old_clip_in = g.clip_in = 0;
|
||||
g.in = entry_point;
|
||||
int item_type = get_type_from_tree(item);
|
||||
bool can_import = true;
|
||||
|
||||
Media* m = NULL;
|
||||
Sequence* s = NULL;
|
||||
void* media = NULL;
|
||||
long sequence_length;
|
||||
|
||||
switch (item_type) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
m = get_media_from_tree(item);
|
||||
media = m;
|
||||
can_import = m->ready;
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
s = get_sequence_from_tree(item);
|
||||
sequence_length = s->getEndFrame();
|
||||
media = s;
|
||||
can_import = (s != sequence && sequence_length != 0);
|
||||
break;
|
||||
default:
|
||||
can_import = false;
|
||||
}
|
||||
|
||||
if (can_import) {
|
||||
Ghost g;
|
||||
g.clip = -1;
|
||||
g.media_type = item_type;
|
||||
g.trimming = false;
|
||||
g.old_clip_in = g.clip_in = 0;
|
||||
g.media = media;
|
||||
g.in = entry_point;
|
||||
|
||||
// is video source a still image?
|
||||
switch (item_type) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
if (m->video_tracks.size() > 0 && m->video_tracks[0]->infinite_length && m->audio_tracks.size() == 0) {
|
||||
g.out = g.in + 100;
|
||||
} else {
|
||||
g.out = entry_point + m->get_length_in_frames(predicted_new_frame_rate);
|
||||
}
|
||||
entry_point = g.out;
|
||||
g.trimming = false;
|
||||
|
||||
for (int j=0;j<m->audio_tracks.size();j++) {
|
||||
g.track = j;
|
||||
g.media_stream = m->audio_tracks.at(j)->file_index;
|
||||
@@ -140,7 +167,20 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
|
||||
panel_timeline->ghosts.append(g);
|
||||
panel_timeline->video_ghosts = true;
|
||||
}
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
g.out = entry_point + sequence_length;
|
||||
|
||||
g.track = -1;
|
||||
panel_timeline->ghosts.append(g);
|
||||
g.track = 0;
|
||||
panel_timeline->ghosts.append(g);
|
||||
|
||||
panel_timeline->video_ghosts = true;
|
||||
panel_timeline->audio_ghosts = true;
|
||||
break;
|
||||
}
|
||||
entry_point = g.out;
|
||||
}
|
||||
}
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
@@ -178,6 +218,8 @@ void TimelineWidget::dropEvent(QDropEvent* event) {
|
||||
QVector<Clip*> added_clips;
|
||||
|
||||
Sequence* s = sequence;
|
||||
|
||||
// if we're dropping into nothing, create a new sequences based on the clip being dragged
|
||||
if (s == NULL) {
|
||||
s = new Sequence();
|
||||
|
||||
@@ -210,41 +252,46 @@ void TimelineWidget::dropEvent(QDropEvent* event) {
|
||||
|
||||
Clip* c = new Clip(s);
|
||||
c->media = g.media;
|
||||
c->media_type = g.media_type;
|
||||
c->media_stream = g.media_stream;
|
||||
c->timeline_in = g.in;
|
||||
c->timeline_out = g.out;
|
||||
c->clip_in = g.clip_in;
|
||||
if (c->media->video_tracks.size() == 0) {
|
||||
// audio only (greenish)
|
||||
c->color_r = 128;
|
||||
c->color_g = 192;
|
||||
c->color_b = 128;
|
||||
} else if (c->media->audio_tracks.size() == 0) {
|
||||
// video only (orangeish)
|
||||
if (c->media_type == MEDIA_TYPE_FOOTAGE) {
|
||||
Media* m = static_cast<Media*>(c->media);
|
||||
if (m->video_tracks.size() == 0) {
|
||||
// audio only (greenish)
|
||||
c->color_r = 128;
|
||||
c->color_g = 192;
|
||||
c->color_b = 128;
|
||||
} else if (m->audio_tracks.size() == 0) {
|
||||
// video only (orangeish)
|
||||
c->color_r = 192;
|
||||
c->color_g = 160;
|
||||
c->color_b = 128;
|
||||
} else {
|
||||
// video and audio (blueish)
|
||||
c->color_r = 128;
|
||||
c->color_g = 128;
|
||||
c->color_b = 192;
|
||||
}
|
||||
c->name = m->name;
|
||||
} else if (c->media_type == MEDIA_TYPE_SEQUENCE) {
|
||||
// sequence (red?ish?)
|
||||
c->color_r = 192;
|
||||
c->color_g = 160;
|
||||
c->color_b = 128;
|
||||
} else {
|
||||
// video and audio (blueish)
|
||||
c->color_r = 128;
|
||||
c->color_g = 128;
|
||||
c->color_b = 192;
|
||||
}
|
||||
c->track = g.track;
|
||||
c->name = c->media->name;
|
||||
c->color_b = 128;
|
||||
|
||||
if (c->track < 0) {
|
||||
// add default video effects
|
||||
c->effects.append(create_effect(VIDEO_TRANSFORM_EFFECT, c));
|
||||
} else {
|
||||
// add default audio effects
|
||||
c->effects.append(create_effect(AUDIO_VOLUME_EFFECT, c));
|
||||
c->effects.append(create_effect(AUDIO_PAN_EFFECT, c));
|
||||
c->name = static_cast<Sequence*>(c->media)->name;
|
||||
}
|
||||
|
||||
c->track = g.track;
|
||||
|
||||
added_clips.append(c);
|
||||
}
|
||||
|
||||
ta->add_clips(s, added_clips);
|
||||
|
||||
// link clips from the same media
|
||||
for (int i=0;i<added_clips.size();i++) {
|
||||
Clip* c = added_clips.at(i);
|
||||
@@ -254,9 +301,18 @@ void TimelineWidget::dropEvent(QDropEvent* event) {
|
||||
c->linked.append(j);
|
||||
}
|
||||
}
|
||||
|
||||
// DUMB HACKY CODE THAT MIGHT NOT WORK TO ADD EFFECTS
|
||||
if (c->track < 0) {
|
||||
// add default video effects
|
||||
ta->add_effect(s, i + sequence->clip_count(), VIDEO_TRANSFORM_EFFECT);
|
||||
} else {
|
||||
// add default audio effects
|
||||
ta->add_effect(s, i + sequence->clip_count(), AUDIO_VOLUME_EFFECT);
|
||||
ta->add_effect(s, i + sequence->clip_count(), AUDIO_PAN_EFFECT);
|
||||
}
|
||||
}
|
||||
|
||||
ta->add_clips(s, added_clips);
|
||||
|
||||
panel_timeline->ghosts.clear();
|
||||
panel_timeline->importing = false;
|
||||
@@ -624,7 +680,15 @@ void TimelineWidget::init_ghosts() {
|
||||
|
||||
if (panel_timeline->trim_target > -1 || panel_timeline->tool == TIMELINE_TOOL_SLIP || panel_timeline->tool == TIMELINE_TOOL_SLIDE) {
|
||||
// used for trim ops
|
||||
g.media_length = sequence->get_clip(g.clip)->media->get_length_in_frames(sequence->frame_rate);
|
||||
switch (c->media_type) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
g.media_length = static_cast<Media*>(c->media)->get_length_in_frames(sequence->frame_rate);
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
Sequence* s = static_cast<Sequence*>(c->media);
|
||||
g.media_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, sequence->frame_rate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i=0;i<panel_timeline->selections.size();i++) {
|
||||
@@ -702,7 +766,8 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
|
||||
|
||||
// validate ghosts for trimming
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_SLIP) {
|
||||
if (!c->media->get_stream_from_file_index(c->media_stream)->infinite_length) {
|
||||
if (c->media_type == MEDIA_TYPE_SEQUENCE
|
||||
|| (c->media_type == MEDIA_TYPE_FOOTAGE && !static_cast<Media*>(c->media)->get_stream_from_file_index(c->media_stream)->infinite_length)) {
|
||||
// prevent slip moving a clip below 0 clip_in
|
||||
validator = g.old_clip_in - frame_diff;
|
||||
if (validator < 0) frame_diff += validator;
|
||||
@@ -722,7 +787,8 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
|
||||
if (validator < 0) frame_diff -= validator;
|
||||
|
||||
// prevent clip_in from going below 0
|
||||
if (!c->media->get_stream_from_file_index(c->media_stream)->infinite_length) {
|
||||
if (c->media_type == MEDIA_TYPE_SEQUENCE
|
||||
|| (c->media_type == MEDIA_TYPE_FOOTAGE && !static_cast<Media*>(c->media)->get_stream_from_file_index(c->media_stream)->infinite_length)) {
|
||||
validator = g.old_clip_in + frame_diff;
|
||||
if (validator < 0) frame_diff -= validator;
|
||||
}
|
||||
@@ -732,7 +798,8 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) {
|
||||
if (validator < 1) frame_diff += (1 - validator);
|
||||
|
||||
// prevent clip length exceeding media length
|
||||
if (!c->media->get_stream_from_file_index(c->media_stream)->infinite_length) {
|
||||
if (c->media_type == MEDIA_TYPE_SEQUENCE
|
||||
|| (c->media_type == MEDIA_TYPE_FOOTAGE && !static_cast<Media*>(c->media)->get_stream_from_file_index(c->media_stream)->infinite_length)) {
|
||||
validator = g.old_clip_in + g.ghost_length + frame_diff;
|
||||
if (validator > g.media_length) frame_diff -= validator - g.media_length;
|
||||
}
|
||||
@@ -1335,60 +1402,63 @@ void TimelineWidget::redraw_clips() {
|
||||
}
|
||||
}
|
||||
|
||||
MediaStream* ms = clip->media->get_stream_from_file_index(clip->media_stream);
|
||||
if (ms == NULL) {
|
||||
// draw "error lines" if media stream is missing
|
||||
clip_painter.setPen(QPen(QColor(64, 64, 64), 2));
|
||||
int limit = clip_rect.width();
|
||||
int clip_height = clip_rect.bottom()-clip_rect.top();
|
||||
for (int j=-clip_height;j<limit;j+=15) {
|
||||
int lines_start_x = clip_rect.left()+j;
|
||||
int lines_start_y = clip_rect.bottom();
|
||||
int lines_end_x = lines_start_x + clip_height;
|
||||
int lines_end_y = clip_rect.top();
|
||||
if (lines_start_x < clip_rect.left()) {
|
||||
lines_start_y -= (clip_rect.left() - lines_start_x);
|
||||
lines_start_x = clip_rect.left();
|
||||
if (clip->media_type == MEDIA_TYPE_FOOTAGE) {
|
||||
Media* m = static_cast<Media*>(clip->media);
|
||||
MediaStream* ms = m->get_stream_from_file_index(clip->media_stream);
|
||||
if (ms == NULL) {
|
||||
// draw "error lines" if media stream is missing
|
||||
clip_painter.setPen(QPen(QColor(64, 64, 64), 2));
|
||||
int limit = clip_rect.width();
|
||||
int clip_height = clip_rect.bottom()-clip_rect.top();
|
||||
for (int j=-clip_height;j<limit;j+=15) {
|
||||
int lines_start_x = clip_rect.left()+j;
|
||||
int lines_start_y = clip_rect.bottom();
|
||||
int lines_end_x = lines_start_x + clip_height;
|
||||
int lines_end_y = clip_rect.top();
|
||||
if (lines_start_x < clip_rect.left()) {
|
||||
lines_start_y -= (clip_rect.left() - lines_start_x);
|
||||
lines_start_x = clip_rect.left();
|
||||
}
|
||||
if (lines_end_x > clip_rect.right()) {
|
||||
lines_end_y -= (clip_rect.right() - lines_end_x);
|
||||
lines_end_x = clip_rect.right();
|
||||
}
|
||||
clip_painter.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y);
|
||||
}
|
||||
if (lines_end_x > clip_rect.right()) {
|
||||
lines_end_y -= (clip_rect.right() - lines_end_x);
|
||||
lines_end_x = clip_rect.right();
|
||||
}
|
||||
clip_painter.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y);
|
||||
}
|
||||
} else if (ms->preview_done) {
|
||||
// draw thumbnail/waveform
|
||||
if (clip->track < 0) {
|
||||
int thumb_y = clip_painter.fontMetrics().height()+CLIP_TEXT_PADDING+CLIP_TEXT_PADDING;
|
||||
int thumb_height = clip_rect.height()-thumb_y;
|
||||
int thumb_width = (thumb_height*((double)ms->video_preview.width()/(double)ms->video_preview.height()));
|
||||
if (thumb_height > thumb_y && text_rect.width() + CLIP_TEXT_PADDING > thumb_width) { // at small clip heights, don't even draw it
|
||||
QRect thumb_rect(thumb_x, clip_rect.y()+thumb_y, thumb_width, thumb_height);
|
||||
clip_painter.drawImage(thumb_rect, ms->video_preview);
|
||||
}
|
||||
} else if (clip_rect.height() > TRACK_MIN_HEIGHT) {
|
||||
int divider = ms->audio_channels*2;
|
||||
} else if (ms->preview_done) {
|
||||
// draw thumbnail/waveform
|
||||
if (clip->track < 0) {
|
||||
int thumb_y = clip_painter.fontMetrics().height()+CLIP_TEXT_PADDING+CLIP_TEXT_PADDING;
|
||||
int thumb_height = clip_rect.height()-thumb_y;
|
||||
int thumb_width = (thumb_height*((double)ms->video_preview.width()/(double)ms->video_preview.height()));
|
||||
if (thumb_height > thumb_y && text_rect.width() + CLIP_TEXT_PADDING > thumb_width) { // at small clip heights, don't even draw it
|
||||
QRect thumb_rect(thumb_x, clip_rect.y()+thumb_y, thumb_width, thumb_height);
|
||||
clip_painter.drawImage(thumb_rect, ms->video_preview);
|
||||
}
|
||||
} else if (clip_rect.height() > TRACK_MIN_HEIGHT) {
|
||||
int divider = ms->audio_channels*2;
|
||||
|
||||
clip_painter.setPen(QColor(80, 80, 80));
|
||||
int channel_height = clip_rect.height()/ms->audio_channels;
|
||||
long media_length = clip->media->get_length_in_frames(clip->sequence->frame_rate);
|
||||
for (int i=0;i<clip_rect.width();i++) {
|
||||
int waveform_index = qFloor((((clip->clip_in + ((double) i/panel_timeline->zoom))/media_length) * ms->audio_preview.size())/divider)*divider;
|
||||
clip_painter.setPen(QColor(80, 80, 80));
|
||||
int channel_height = clip_rect.height()/ms->audio_channels;
|
||||
long media_length = m->get_length_in_frames(clip->sequence->frame_rate);
|
||||
for (int i=0;i<clip_rect.width();i++) {
|
||||
int waveform_index = qFloor((((clip->clip_in + ((double) i/panel_timeline->zoom))/media_length) * ms->audio_preview.size())/divider)*divider;
|
||||
|
||||
for (int j=0;j<ms->audio_channels;j++) {
|
||||
int mid = clip_rect.top()+channel_height*j+(channel_height/2);
|
||||
int offset = waveform_index+(j*2);
|
||||
for (int j=0;j<ms->audio_channels;j++) {
|
||||
int mid = clip_rect.top()+channel_height*j+(channel_height/2);
|
||||
int offset = waveform_index+(j*2);
|
||||
|
||||
qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2);
|
||||
qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2);
|
||||
clip_painter.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max);
|
||||
qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2);
|
||||
qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2);
|
||||
clip_painter.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max);
|
||||
|
||||
/*if (offset >= 0 && offset < ms->audio_preview.size()) {
|
||||
/*if (offset >= 0 && offset < ms->audio_preview.size()) {
|
||||
|
||||
} else {
|
||||
QMessageBox::critical(this, "AAAAAAAAAAAAA", "Here's that terrible, no-good bug again!!! I've stepped around it but plz report the following to Matt:\n\n" + QString::number(offset) + " vs " + QString::number(clip->media_stream->audio_preview.size()), QMessageBox::Ok);
|
||||
break;
|
||||
}*/
|
||||
} else {
|
||||
QMessageBox::critical(this, "AAAAAAAAAAAAA", "Here's that terrible, no-good bug again!!! I've stepped around it but plz report the following to Matt:\n\n" + QString::number(offset) + " vs " + QString::number(clip->media_stream->audio_preview.size()), QMessageBox::Ok);
|
||||
break;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+74
-66
@@ -3,6 +3,7 @@
|
||||
#include "panels/panels.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "panels/project.h"
|
||||
#include "project/sequence.h"
|
||||
#include "project/effect.h"
|
||||
#include "effects/transition.h"
|
||||
@@ -92,9 +93,10 @@ void ViewerWidget::compose_sequence(Sequence *s, bool render_audio) {
|
||||
Clip* c = s->get_clip(i);
|
||||
|
||||
// if clip starts within one second and/or hasn't finished yet
|
||||
if (c != NULL) {
|
||||
if (c->media->ready
|
||||
&& c->media->get_stream_from_file_index(c->media_stream) != NULL
|
||||
if (c != NULL && c->media_type == MEDIA_TYPE_FOOTAGE) {
|
||||
Media* m = static_cast<Media*>(c->media);
|
||||
if (m->ready
|
||||
&& m->get_stream_from_file_index(c->media_stream) != NULL
|
||||
&& is_clip_active(c, panel_timeline->playhead)) {
|
||||
// if thread is already working, we don't want to touch this,
|
||||
// but we also don't want to hang the UI thread
|
||||
@@ -126,77 +128,83 @@ void ViewerWidget::compose_sequence(Sequence *s, bool render_audio) {
|
||||
qDebug() << "[WARNING] Tried to display clip" << i << "but it's closed";
|
||||
texture_failed = true;
|
||||
} else if (is_clip_active(c, panel_timeline->playhead)) {
|
||||
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
// start preparing cache
|
||||
get_clip_frame(c, panel_timeline->playhead);
|
||||
switch (c->media_type) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
// start preparing cache
|
||||
get_clip_frame(c, panel_timeline->playhead);
|
||||
|
||||
if (c->texture == NULL) {
|
||||
qDebug() << "[WARNING] Texture hasn't been created yet";
|
||||
texture_failed = true;
|
||||
} else if (panel_timeline->playhead >= c->timeline_in) {
|
||||
MediaStream* ms = c->media->get_stream_from_file_index(c->media_stream);
|
||||
if (c->texture == NULL) {
|
||||
qDebug() << "[WARNING] Texture hasn't been created yet";
|
||||
texture_failed = true;
|
||||
} else if (panel_timeline->playhead >= c->timeline_in) {
|
||||
MediaStream* ms = static_cast<Media*>(c->media)->get_stream_from_file_index(c->media_stream);
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glColor4f(1.0, 1.0, 1.0, 1.0);
|
||||
glLoadIdentity();
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glColor4f(1.0, 1.0, 1.0, 1.0);
|
||||
glLoadIdentity();
|
||||
|
||||
int half_width = s->width/2;
|
||||
int half_height = s->height/2;
|
||||
if (flip) {
|
||||
glOrtho(-half_width, half_width, -half_height, half_height, -1, 1);
|
||||
} else {
|
||||
glOrtho(-half_width, half_width, half_height, -half_height, -1, 1);
|
||||
}
|
||||
int anchor_x = ms->video_width/2;
|
||||
int anchor_y = ms->video_height/2;
|
||||
int half_width = s->width/2;
|
||||
int half_height = s->height/2;
|
||||
if (flip) {
|
||||
glOrtho(-half_width, half_width, -half_height, half_height, -1, 1);
|
||||
} else {
|
||||
glOrtho(-half_width, half_width, half_height, -half_height, -1, 1);
|
||||
}
|
||||
int anchor_x = ms->video_width/2;
|
||||
int anchor_y = ms->video_height/2;
|
||||
|
||||
// perform all transform effects
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
if (c->effects.at(j)->is_enabled()) c->effects.at(j)->process_gl(&anchor_x, &anchor_y);
|
||||
}
|
||||
// perform all transform effects
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
if (c->effects.at(j)->is_enabled()) c->effects.at(j)->process_gl(&anchor_x, &anchor_y);
|
||||
}
|
||||
|
||||
if (c->opening_transition != NULL) {
|
||||
int transition_progress = panel_timeline->playhead-c->timeline_in;
|
||||
if (transition_progress < c->opening_transition->length) {
|
||||
c->opening_transition->process_transition((float)transition_progress/(float)c->opening_transition->length);
|
||||
if (c->opening_transition != NULL) {
|
||||
int transition_progress = panel_timeline->playhead-c->timeline_in;
|
||||
if (transition_progress < c->opening_transition->length) {
|
||||
c->opening_transition->process_transition((float)transition_progress/(float)c->opening_transition->length);
|
||||
}
|
||||
}
|
||||
if (c->closing_transition != NULL) {
|
||||
int transition_progress = c->closing_transition->length-(panel_timeline->playhead-c->timeline_in-c->getLength()+c->closing_transition->length);
|
||||
if (transition_progress < c->closing_transition->length) {
|
||||
c->closing_transition->process_transition((float)transition_progress/(float)c->closing_transition->length);
|
||||
}
|
||||
}
|
||||
|
||||
int anchor_right = ms->video_width - anchor_x;
|
||||
int anchor_bottom = ms->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();
|
||||
|
||||
// perform all transform effects
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
if (c->effects.at(j)->is_enabled()) c->effects.at(j)->post_gl();
|
||||
}
|
||||
}
|
||||
if (c->closing_transition != NULL) {
|
||||
int transition_progress = c->closing_transition->length-(panel_timeline->playhead-c->timeline_in-c->getLength()+c->closing_transition->length);
|
||||
if (transition_progress < c->closing_transition->length) {
|
||||
c->closing_transition->process_transition((float)transition_progress/(float)c->closing_transition->length);
|
||||
}
|
||||
}
|
||||
|
||||
int anchor_right = ms->video_width - anchor_x;
|
||||
int anchor_bottom = ms->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();
|
||||
|
||||
// perform all transform effects
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
if (c->effects.at(j)->is_enabled()) c->effects.at(j)->post_gl();
|
||||
}
|
||||
} else if (render_audio &&
|
||||
c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
|
||||
c->lock.tryLock()) {
|
||||
// clip is not caching, start caching audio
|
||||
cache_clip(c, panel_timeline->playhead, false, false, c->reset_audio);
|
||||
c->lock.unlock();
|
||||
}
|
||||
} else if (render_audio &&
|
||||
c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
|
||||
c->lock.tryLock()) {
|
||||
// clip is not caching, start caching audio
|
||||
cache_clip(c, panel_timeline->playhead, false, false, c->reset_audio);
|
||||
c->lock.unlock();
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user