improved file saving/loading

This commit is contained in:
itsmattkc
2018-07-27 12:47:25 +01:00
parent 5ea746a053
commit 5862242111
23 changed files with 633 additions and 415 deletions
+2 -2
View File
@@ -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));
+8 -8
View File
@@ -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
View File
@@ -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()) {
+1 -1
View File
@@ -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
View File
@@ -3,7 +3,7 @@
#include <QString>
#define SAVE_VERSION "180722"
#define SAVE_VERSION "180727"
struct Config {
Config();
+1 -1
View File
@@ -162,7 +162,7 @@ void MainWindow::on_action_Import_triggered()
void MainWindow::on_actionExit_triggered()
{
QApplication::quit();
close();
}
void MainWindow::on_actionAbout_triggered()
+5 -38
View File
@@ -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() {
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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();
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+2
View File
@@ -27,6 +27,8 @@ public:
bool using_workarea;
long workarea_in;
long workarea_out;
int save_id;
private:
QVector<Clip*> clips;
};
+20
View File
@@ -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;
}
}
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
}