SEVERAL bug fixes

This commit is contained in:
itsmattkc
2018-10-12 18:48:14 +11:00
parent caee50a943
commit cdbec85a81
30 changed files with 444 additions and 149 deletions
+35
View File
@@ -0,0 +1,35 @@
#include "mediapropertiesdialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
#include <QLineEdit>
#include <QDialogButtonBox>
#include "io/media.h"
#include "panels/project.h"
MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent) {
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QGridLayout* grid = new QGridLayout();
setLayout(grid);
interlacing_box = new QComboBox();
interlacing_box->addItem(get_interlacing_name(VIDEO_PROGRESSIVE), VIDEO_PROGRESSIVE);
interlacing_box->addItem(get_interlacing_name(VIDEO_TOP_FIELD_FIRST), VIDEO_TOP_FIELD_FIRST);
interlacing_box->addItem(get_interlacing_name(VIDEO_BOTTOM_FIELD_FIRST), VIDEO_BOTTOM_FIELD_FIRST);
grid->addWidget(new QLabel("Interlacing:"), 0, 0);
grid->addWidget(interlacing_box, 0, 1);
grid->addWidget(new QLabel("Name:"), 1, 0);
grid->addWidget(new QLineEdit("h"), 1, 1);
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttons->setCenterButtons(true);
grid->addWidget(buttons, 2, 0, 1, 2);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
}
+16
View File
@@ -0,0 +1,16 @@
#ifndef MEDIAPROPERTIESDIALOG_H
#define MEDIAPROPERTIESDIALOG_H
#include <QDialog>
class QComboBox;
class MediaPropertiesDialog : public QDialog {
Q_OBJECT
public:
explicit MediaPropertiesDialog(QWidget *parent = 0);
private:
QComboBox* interlacing_box;
};
#endif // MEDIAPROPERTIESDIALOG_H
+32 -7
View File
@@ -15,6 +15,7 @@ extern "C" {
NewSequenceDialog::NewSequenceDialog(QWidget *parent) :
QDialog(parent),
existing_sequence(NULL),
ui(new Ui::NewSequenceDialog)
{
ui->setupUi(this);
@@ -51,20 +52,44 @@ void NewSequenceDialog::set_sequence_name(const QString& s) {
ui->lineEdit->setText(s);
}
void NewSequenceDialog::on_buttonBox_accepted()
{
Sequence* s = new Sequence();
void NewSequenceDialog::showEvent(QShowEvent *) {
if (existing_sequence != NULL) {
ui->width_numeric->setValue(existing_sequence->width);
ui->height_numeric->setValue(existing_sequence->height);
int comp_rate = qRound(existing_sequence->frame_rate*100);
for (int i=0;i<ui->frame_rate_combobox->count();i++) {
if (qRound(ui->frame_rate_combobox->itemData(i).toDouble()*100) == comp_rate) {
ui->frame_rate_combobox->setCurrentIndex(i);
break;
}
}
ui->lineEdit->setText(existing_sequence->name);
for (int i=0;i<ui->audio_frequency_combobox->count();i++) {
if (ui->audio_frequency_combobox->itemData(i) == existing_sequence->audio_frequency) {
ui->audio_frequency_combobox->setCurrentIndex(i);
break;
}
}
}
}
void NewSequenceDialog::on_buttonBox_accepted() {
Sequence* s = (existing_sequence != NULL) ? existing_sequence : new Sequence();
s->name = ui->lineEdit->text();
s->width = ui->width_numeric->value();
s->height = ui->height_numeric->value();
s->frame_rate = ui->frame_rate_combobox->currentData().toDouble();
s->frame_rate = ui->frame_rate_combobox->currentData().toDouble();
s->audio_frequency = ui->audio_frequency_combobox->currentData().toInt();
s->audio_layout = AV_CH_LAYOUT_STEREO;
ComboAction* ca = new ComboAction();
panel_project->new_sequence(ca, s, true, NULL);
undo_stack.push(ca);
if (existing_sequence == NULL) {
ComboAction* ca = new ComboAction();
panel_project->new_sequence(ca, s, true, NULL);
undo_stack.push(ca);
} else {
// TODO make editing undoable
}
}
void NewSequenceDialog::on_comboBox_currentIndexChanged(int index)
+5
View File
@@ -4,6 +4,7 @@
#include <QDialog>
class Project;
struct Sequence;
namespace Ui {
class NewSequenceDialog;
@@ -16,8 +17,12 @@ class NewSequenceDialog : public QDialog
public:
explicit NewSequenceDialog(QWidget *parent = 0);
~NewSequenceDialog();
Sequence* existing_sequence;
void set_sequence_name(const QString& s);
protected:
void showEvent(QShowEvent *);
private slots:
void on_buttonBox_accepted();
+2 -1
View File
@@ -320,7 +320,8 @@ void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, lo
for (int j=0;j<e->row_count();j++) {
EffectRow* r = e->row(j);
for (int k=0;k<r->keyframe_times.size();k++) {
long new_pos = r->keyframe_times.at(k) / speed;
long new_pos = r->keyframe_times.at(k) * c->speed / speed;
qDebug() << "old key" << r->keyframe_times.at(k) << "new key" << new_pos;
KeyframeMove* km = new KeyframeMove();
km->movement = new_pos - r->keyframe_times.at(k);
km->rows.append(r);
+5 -3
View File
@@ -1,6 +1,7 @@
#include "audionoiseeffect.h"
#include <QDateTime>
#include <QtMath>
AudioNoiseEffect::AudioNoiseEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_NOISE_EFFECT) {
amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE);
@@ -26,11 +27,12 @@ void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end,
qint16 right_noise_sample = rand();
// set noise volume
left_noise_sample *= amount_val->get_double_value(timecode)*0.01;
right_noise_sample *= amount_val->get_double_value(timecode)*0.01;
double vol = qSqrt(amount_val->get_double_value(timecode, true)*0.01);
left_noise_sample *= vol;
right_noise_sample *= vol;
// mix with source audio
if (mix_val->get_bool_value(timecode)) {
if (mix_val->get_bool_value(timecode, true)) {
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));
left_noise_sample = mix_audio_sample(left_noise_sample, left_sample);
+4 -5
View File
@@ -23,17 +23,16 @@ PanEffect::PanEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_PAN_EFFECT) {
void PanEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
double interval = (timecode_end - timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=4) {
double pval = pan_val->get_double_value(timecode_start+(interval*i));
double pval = qSqrt(pan_val->get_double_value(timecode_start+(interval*i), true)*0.01);
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));
double val = qPow(pval*0.01, 3);
if (val < 0) {
if (pval < 0) {
// affect right channel
right_sample *= (1-std::abs(val));
right_sample *= (1-std::abs(pval));
} else {
// affect left channel
left_sample *= (1-val);
left_sample *= (1-pval);
}
samples[i+3] = (quint8) (right_sample >> 8);
+4 -4
View File
@@ -7,7 +7,7 @@
#include "project/clip.h"
#include "project/sequence.h"
ToneEffect::ToneEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_TONE_EFFECT), sinX(0) {
ToneEffect::ToneEffect(Clip* c) : Effect(c, EFFECT_TYPE_AUDIO, AUDIO_TONE_EFFECT), sinX(INT_MIN) {
type_val = add_row("Type:")->add_field(EFFECT_FIELD_COMBO);
type_val->add_combo_item("Sine", TONE_TYPE_SINE);
@@ -34,12 +34,12 @@ void ToneEffect::process_audio(double timecode_start, double timecode_end, quint
for (int i=0;i<nb_bytes;i+=4) {
double timecode = timecode_start+(interval*i);
qint16 left_tone_sample = qSin((2*M_PI*sinX*freq_val->get_double_value(timecode))/parent_clip->sequence->audio_frequency)*(amount_val->get_double_value(timecode)*0.01)*INT16_MAX;
qint16 left_tone_sample = qSin((2*M_PI*sinX*freq_val->get_double_value(timecode, true))/parent_clip->sequence->audio_frequency)*qSqrt((amount_val->get_double_value(timecode, true)*0.01))*INT16_MAX;
qint16 right_tone_sample = left_tone_sample;
// mix with source audio
if (mix_val->get_bool_value(timecode)) {
if (mix_val->get_bool_value(timecode, true)) {
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));
left_tone_sample = mix_audio_sample(left_tone_sample, left_sample);
@@ -54,7 +54,7 @@ void ToneEffect::process_audio(double timecode_start, double timecode_end, quint
int presin = sinX;
sinX++;
if (sinX < presin) {
qDebug() << "overflowed";
qDebug() << "[WARNING] Tone effect overflowed";
}
}
}
+2 -4
View File
@@ -25,11 +25,9 @@ void VolumeEffect::process_audio(double timecode_start, double timecode_end, qui
// qDebug() << timecode_start << timecode_end;
double interval = (timecode_end-timecode_start)/nb_bytes;
for (int i=0;i<nb_bytes;i+=2) {
double vol_val = volume_val->get_double_value(timecode_start+(interval*i));
// qDebug() << timecode_start+(interval*i);
double vol_val = qSqrt(volume_val->get_double_value(timecode_start+(interval*i), true)*0.01);
qint32 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
double val = qPow(vol_val*0.01, 3);
samp *= val;
samp *= vol_val;
if (samp > INT16_MAX) {
samp = INT16_MAX;
} else if (samp < INT16_MIN) {
+58 -17
View File
@@ -699,7 +699,7 @@ QVariant EffectField::get_current_data() {
switch (type) {
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->value(); break;
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->get_color(); break;
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->toPlainText(); break;
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPlainTextEx(); break;
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->isChecked(); break;
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->currentIndex(); break;
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->currentText(); break;
@@ -765,8 +765,12 @@ void EffectField::get_keyframe_data(double timecode, int &before, int &after, do
}
}
void EffectField::validate_keyframe_data(double timecode) {
if (parent_row->isKeyframing() && keyframe_data.size() > 0) {
bool EffectField::hasKeyframes() {
return (parent_row->isKeyframing() && keyframe_data.size() > 0);
}
QVariant EffectField::validate_keyframe_data(double timecode, bool async) {
if (hasKeyframes()) {
int before_keyframe;
int after_keyframe;
double progress;
@@ -784,7 +788,10 @@ void EffectField::validate_keyframe_data(double timecode) {
double after_dbl = keyframe_data.at(after_keyframe).toDouble();
value = double_lerp(before_dbl, after_dbl, progress);
}
static_cast<LabelSlider*>(ui_element)->set_value(value, false);
if (async) {
return value;
}
static_cast<LabelSlider*>(ui_element)->set_value(value, false);
}
break;
case EFFECT_FIELD_COLOR:
@@ -797,23 +804,39 @@ void EffectField::validate_keyframe_data(double timecode) {
QColor after_data = keyframe_data.at(after_keyframe).value<QColor>();
value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress));
}
return static_cast<ColorButton*>(ui_element)->set_color(value);
if (async) {
return value;
}
static_cast<ColorButton*>(ui_element)->set_color(value);
}
break;
case EFFECT_FIELD_STRING:
if (async) {
return before_data;
}
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(before_data.toString());
break;
case EFFECT_FIELD_BOOL:
static_cast<QCheckBox*>(ui_element)->setChecked(before_data.toBool());
if (async) {
return before_data;
}
static_cast<QCheckBox*>(ui_element)->setChecked(before_data.toBool());
break;
case EFFECT_FIELD_COMBO:
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(before_data.toInt());
if (async) {
return before_data;
}
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(before_data.toInt());
break;
case EFFECT_FIELD_FONT:
static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(before_data.toString());
if (async) {
return before_data;
}
static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(before_data.toString());
break;
}
}
}
return QVariant();
}
void EffectField::uiElementChange() {
@@ -835,9 +858,12 @@ void EffectField::set_enabled(bool e) {
ui_element->setEnabled(e);
}
double EffectField::get_double_value(double timecode) {
double EffectField::get_double_value(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).toDouble();
}
validate_keyframe_data(timecode);
return static_cast<LabelSlider*>(ui_element)->value();
return static_cast<LabelSlider*>(ui_element)->value();
}
void EffectField::set_double_value(double v) {
@@ -860,7 +886,10 @@ void EffectField::add_combo_item(const QString& name, const QVariant& data) {
static_cast<ComboBoxEx*>(ui_element)->addItem(name, data);
}
int EffectField::get_combo_index(double timecode) {
int EffectField::get_combo_index(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).toInt();
}
validate_keyframe_data(timecode);
return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
}
@@ -883,7 +912,10 @@ void EffectField::set_combo_string(const QString& s) {
static_cast<ComboBoxEx*>(ui_element)->setCurrentTextEx(s);
}
bool EffectField::get_bool_value(double timecode) {
bool EffectField::get_bool_value(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).toBool();
}
validate_keyframe_data(timecode);
return static_cast<QCheckBox*>(ui_element)->isChecked();
}
@@ -892,16 +924,22 @@ void EffectField::set_bool_value(bool b) {
return static_cast<QCheckBox*>(ui_element)->setChecked(b);
}
const QString EffectField::get_string_value(double timecode) {
const QString EffectField::get_string_value(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).toString();
}
validate_keyframe_data(timecode);
return static_cast<TextEditEx*>(ui_element)->toPlainText();
return static_cast<TextEditEx*>(ui_element)->getPlainTextEx();
}
void EffectField::set_string_value(const QString& s) {
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(s);
}
const QString EffectField::get_font_name(double timecode) {
const QString EffectField::get_font_name(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).toString();
}
validate_keyframe_data(timecode);
return static_cast<FontCombobox*>(ui_element)->currentText();
}
@@ -910,7 +948,10 @@ void EffectField::set_font_name(const QString& s) {
static_cast<FontCombobox*>(ui_element)->setCurrentText(s);
}
QColor EffectField::get_color_value(double timecode) {
QColor EffectField::get_color_value(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).value<QColor>();
}
validate_keyframe_data(timecode);
return static_cast<ColorButton*>(ui_element)->get_color();
}
+8 -9
View File
@@ -99,33 +99,31 @@ public:
long timecodeToFrame(double timecode);
void set_current_data(const QVariant&);
void get_keyframe_data(double timecode, int& before, int& after, double& d);
void validate_keyframe_data(double timecode);
// QVariant get_keyframe_data(long p);
// bool is_keyframed(long p);
QVariant validate_keyframe_data(double timecode, bool async = false);
double get_double_value(double timecode);
double get_double_value(double timecode, bool async = false);
void set_double_value(double v);
void set_double_default_value(double v);
void set_double_minimum_value(double v);
void set_double_maximum_value(double v);
const QString get_string_value(double timecode);
const QString get_string_value(double timecode, bool async = false);
void set_string_value(const QString &s);
void add_combo_item(const QString& name, const QVariant &data);
int get_combo_index(double timecode);
int get_combo_index(double timecode, bool async = false);
const QVariant get_combo_data(double timecode);
const QString get_combo_string(double timecode);
void set_combo_index(int index);
void set_combo_string(const QString& s);
bool get_bool_value(double timecode);
bool get_bool_value(double timecode, bool async = false);
void set_bool_value(bool b);
const QString get_font_name(double timecode);
const QString get_font_name(double timecode, bool async = false);
void set_font_name(const QString& s);
QColor get_color_value(double timecode);
QColor get_color_value(double timecode, bool async = false);
void set_color_value(QColor color);
QWidget* get_ui_element();
@@ -133,6 +131,7 @@ public:
QVector<QVariant> keyframe_data;
QWidget* ui_element;
private:
bool hasKeyframes();
private slots:
void uiElementChange();
signals:
+61 -4
View File
@@ -2,6 +2,7 @@
#include "media.h"
#include "panels/viewer.h"
#include "panels/project.h"
#include "io/config.h"
#include <QPainter>
@@ -301,19 +302,20 @@ void PreviewGenerator::run() {
char* filename = new char[ba.size()+1];
strcpy(filename, ba.data());
QString errorStr;
bool error = false;
int errCode = avformat_open_input(&fmt_ctx, filename, NULL, NULL);
if(errCode != 0) {
char err[1024];
av_strerror(errCode, err, 1024);
item->setToolTip(0, "Could not open file - " + QString(err));
errorStr = "Could not open file - " + QString(err);
error = true;
} else {
errCode = avformat_find_stream_info(fmt_ctx, NULL);
if (errCode < 0) {
char err[1024];
av_strerror(errCode, err, 1024);
item->setToolTip(0, "Could not find stream information - " + QString(err));
errorStr = "Could not find stream information - " + QString(err);
error = true;
} else {
av_dump_format(fmt_ctx, 0, filename, 0);
@@ -321,12 +323,67 @@ void PreviewGenerator::run() {
generate_waveform();
}
avformat_close_input(&fmt_ctx);
}
}
QString tooltip = "Name: " + media->name + "\nFilename: " + media->url + "\n";
if (error) {
tooltip += errorStr;
emit set_icon(ICON_TYPE_ERROR, replace);
} else {
item->setToolTip(0, QString());
// tooltip += "Video Tracks: " + QString::number(media->video_tracks.size()) + "\nAudio Tracks: " + QString::number(media->audio_tracks.size()) + "\n";
if (media->video_tracks.size() > 0) {
tooltip += "Video Dimensions: ";
for (int i=0;i<media->video_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
tooltip += QString::number(media->video_tracks.at(i)->video_width) + "x" + QString::number(media->video_tracks.at(i)->video_height);
}
tooltip += "\n";
tooltip += "Frame Rate: ";
for (int i=0;i<media->video_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
tooltip += QString::number(media->video_tracks.at(i)->video_frame_rate);
if (media->video_tracks.at(i)->video_interlacing != VIDEO_PROGRESSIVE) {
tooltip += " fields (" + QString::number(media->video_tracks.at(i)->video_frame_rate*0.5) + " frames)";
}
}
tooltip += "\n";
tooltip += "Interlacing: ";
for (int i=0;i<media->video_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
tooltip += get_interlacing_name(media->video_tracks.at(i)->video_interlacing);
}
tooltip += "\n";
}
if (media->audio_tracks.size() > 0) {
tooltip += "Audio Frequency: ";
for (int i=0;i<media->audio_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
tooltip += QString::number(media->audio_tracks.at(i)->audio_frequency);
}
tooltip += "\n";
tooltip += "Audio Channels: ";
for (int i=0;i<media->audio_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
tooltip += get_channel_layout_name(media->audio_tracks.at(i)->audio_channels, media->audio_tracks.at(i)->audio_layout);
}
// tooltip += "\n";
}
}
item->setToolTip(0, tooltip);
delete [] filename;
media->preview_gen = NULL;
}
+4 -2
View File
@@ -81,7 +81,8 @@ SOURCES += \
dialogs/demonotice.cpp \
effects/audio/toneeffect.cpp \
project/marker.cpp \
dialogs/speeddialog.cpp
dialogs/speeddialog.cpp \
dialogs/mediapropertiesdialog.cpp
HEADERS += \
mainwindow.h \
@@ -141,7 +142,8 @@ HEADERS += \
project/marker.h \
project/selection.h \
dialogs/speeddialog.h \
dialogs/speeddialog.h
dialogs/speeddialog.h \
dialogs/mediapropertiesdialog.h
FORMS += \
mainwindow.ui \
+65 -2
View File
@@ -18,6 +18,8 @@
#include "playback/cacher.h"
#include "dialogs/replaceclipmediadialog.h"
#include "panels/effectcontrols.h"
#include "dialogs/newsequencedialog.h"
#include "dialogs/mediapropertiesdialog.h"
#include <QFileDialog>
#include <QString>
@@ -28,6 +30,7 @@
#include <QDropEvent>
#include <QMimeData>
#include <QPushButton>
#include <QInputDialog>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
@@ -140,6 +143,39 @@ void Project::replace_clip_media() {
}
}
void Project::open_properties() {
if (ui->treeWidget->selectedItems().size() == 1) {
QTreeWidgetItem* item = ui->treeWidget->selectedItems().at(0);
switch (get_type_from_tree(item)) {
case MEDIA_TYPE_FOOTAGE:
{
MediaPropertiesDialog mpd(this);
mpd.exec();
}
break;
case MEDIA_TYPE_SEQUENCE:
{
NewSequenceDialog nsd(this);
Sequence* s = get_sequence_from_tree(item);
nsd.existing_sequence = s;
if (nsd.exec() == QDialog::Accepted) {
set_sequence_of_tree(item, s);
panel_timeline->repaint_timeline(true);
}
}
break;
default:
{
// fall back to renaming
QString new_name = QInputDialog::getText(this, "Rename '" + item->text(0) + "'", "Enter new name:");
if (!new_name.isEmpty()) {
item->setText(0, new_name);
}
}
}
}
}
void Project::new_sequence(ComboAction *ca, Sequence *s, bool open, QTreeWidgetItem* parent) {
QTreeWidgetItem* item = new_item();
item->setText(0, s->name);
@@ -521,9 +557,27 @@ Sequence* get_sequence_from_tree(QTreeWidgetItem* item) {
return reinterpret_cast<Sequence*>(item->data(0, Qt::UserRole + 2).value<quintptr>());
}
void set_sequence_of_tree(QTreeWidgetItem* item, Sequence* sequence) {
QString get_channel_layout_name(int channels, int layout) {
switch (channels) {
case 0: return "Invalid"; break;
case 1: return "Mono"; break;
case 2: return "Stereo"; break;
default: {
char buf[50];
av_get_channel_layout_string(buf, sizeof(buf), channels, layout);
return QString(buf);
}
}
}
void set_sequence_of_tree(QTreeWidgetItem* item, Sequence* s) {
item->setData(0, Qt::UserRole + 1, MEDIA_TYPE_SEQUENCE);
item->setData(0, Qt::UserRole + 2, QVariant::fromValue(reinterpret_cast<quintptr>(sequence)));
item->setData(0, Qt::UserRole + 2, QVariant::fromValue(reinterpret_cast<quintptr>(s)));
item->setToolTip(0, "Name: " + s->name
+ "\nVideo Dimensions: " + QString::number(s->width) + "x" + QString::number(s->height)
+ "\nFrame Rate: " + QString::number(s->frame_rate)
+ "\nAudio Frequency: " + QString::number(s->audio_frequency)
+ "\nAudio Layout: " + get_channel_layout_name(av_get_channel_layout_nb_channels(s->audio_layout), s->audio_layout));
}
int get_type_from_tree(QTreeWidgetItem* item) {
@@ -1294,3 +1348,12 @@ void MediaThrobber::stop(int icon_type, bool replace) {
panel_project->source_table->viewport()->update();
deleteLater();
}
QString get_interlacing_name(int interlacing) {
switch (interlacing) {
case VIDEO_PROGRESSIVE: return "None (Progressive)";
case VIDEO_TOP_FIELD_FIRST: return "Top Field First";
case VIDEO_BOTTOM_FIELD_FIRST: return "Bottom Field First";
default: return "Invalid";
}
}
+4
View File
@@ -36,6 +36,9 @@ Sequence* get_sequence_from_tree(QTreeWidgetItem* item);
void set_sequence_of_tree(QTreeWidgetItem* item, Sequence* sequence);
void set_item_to_folder(QTreeWidgetItem* item);
QString get_channel_layout_name(int channels, int layout);
QString get_interlacing_name(int interlacing);
class Project : public QDockWidget
{
Q_OBJECT
@@ -70,6 +73,7 @@ public slots:
void delete_clips_using_selected_media();
void replace_selected_file();
void replace_clip_media();
void open_properties();
private:
Ui::Project *ui;
QTreeWidgetItem* new_item();
+2 -2
View File
@@ -260,7 +260,7 @@ void cache_audio_worker(Clip* c, Clip* nest) {
// apply any audio effects to the data
if (nb_bytes == INT_MAX) nb_bytes = frame->nb_samples * av_get_bytes_per_sample(static_cast<AVSampleFormat>(frame->format)) * frame->channels;
if (new_frame) {
apply_audio_effects(c, bytes_to_seconds(c->audio_buffer_write, 2, sequence->audio_frequency) + audio_ibuffer_timecode, frame, nb_bytes);
apply_audio_effects(c, bytes_to_seconds(c->audio_buffer_write, 2, sequence->audio_frequency) + audio_ibuffer_timecode + ((double) (c->clip_in - c->timeline_in)/sequence->frame_rate), frame, nb_bytes);
}
}
break;
@@ -431,7 +431,7 @@ void reset_cache(Clip* c, long target_frame) {
// seeks to nearest keyframe (target_frame represents internal clip frame)
int64_t seek_ts = qRound(clip_frame_to_seconds(c, target_frame) / timebase);
av_seek_frame(c->formatCtx, ms->file_index, seek_ts - (av_q2d(av_inv_q(c->stream->time_base))), AVSEEK_FLAG_BACKWARD);
av_seek_frame(c->formatCtx, ms->file_index, seek_ts/* - (av_q2d(av_inv_q(c->stream->time_base)))*/, AVSEEK_FLAG_BACKWARD);
// play up to the frame we actually want
int ret;
+22 -20
View File
@@ -109,7 +109,7 @@ bool get_clip_frame(Clip* c, long playhead) {
// do we need to update the texture?
MediaStream* ms = static_cast<Media*>(c->media)->get_stream_from_file_index(c->track < 0, c->media_stream);
long sequence_clip_time = playhead - c->timeline_in + c->clip_in;
long sequence_clip_time = qMax(0L, playhead - c->timeline_in + c->clip_in);
if (c->reverse && !ms->infinite_length) {
sequence_clip_time = c->getMaximumLength() - sequence_clip_time - 1;
@@ -117,7 +117,7 @@ bool get_clip_frame(Clip* c, long playhead) {
double rate = c->getMediaFrameRate();
if (c->skip_type == SKIP_TYPE_DISCARD) rate *= c->speed;
long clip_time = qMax(0L, refactor_frame_number(sequence_clip_time, c->sequence->frame_rate, rate));
long clip_time = refactor_frame_number(sequence_clip_time, c->sequence->frame_rate, rate);
AVFrame* current_frame = NULL;
bool no_frame = false;
@@ -206,25 +206,27 @@ bool get_clip_frame(Clip* c, long playhead) {
}
}
if (current_frame != NULL) {
// set up opengl texture
if (c->texture == NULL) {
c->texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
c->texture->setSize(current_frame->width, current_frame->height);
c->texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
c->texture->setMipLevels(c->texture->maximumMipLevels());
c->texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
c->texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
}
if (playhead >= c->timeline_in) {
if (current_frame != NULL) {
// set up opengl texture
if (c->texture == NULL) {
c->texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
c->texture->setSize(current_frame->width, current_frame->height);
c->texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
c->texture->setMipLevels(c->texture->maximumMipLevels());
c->texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
c->texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, current_frame->linesize[0]/4);
c->texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, current_frame->data[0]);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
c->texture_frame = clip_time;
return true;
} else {
texture_failed = true;
qDebug() << "[ERROR] Failed to retrieve frame from cache (R:" << clip_time << "| A:" << c->cache_A.offset << "-" << c->cache_A.offset+c->cache_size-1 << "| B:" << c->cache_B.offset << "-" << c->cache_B.offset+c->cache_size-1 << "| WA:" << c->cache_A.written << "| WB:" << c->cache_B.written << ")";
glPixelStorei(GL_UNPACK_ROW_LENGTH, current_frame->linesize[0]/4);
c->texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, current_frame->data[0]);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
c->texture_frame = clip_time;
return true;
} else {
texture_failed = true;
qDebug() << "[ERROR] Failed to retrieve frame from cache (R:" << clip_time << "| A:" << c->cache_A.offset << "-" << c->cache_A.offset+c->cache_size-1 << "| B:" << c->cache_B.offset << "-" << c->cache_B.offset+c->cache_size-1 << "| WA:" << c->cache_A.written << "| WB:" << c->cache_B.written << ")";
}
}
}
return false;
+25 -23
View File
@@ -178,33 +178,35 @@ long Clip::getLength() {
}
void Clip::recalculateMaxLength() {
double fr = this->sequence->frame_rate;
if (sequence != NULL) {
double fr = this->sequence->frame_rate;
fr /= speed;
fr /= speed;
switch (media_type) {
case MEDIA_TYPE_FOOTAGE:
{
Media* m = static_cast<Media*>(media);
MediaStream* ms = m->get_stream_from_file_index(track < 0, media_stream);
if (ms != NULL && ms->infinite_length) {
switch (media_type) {
case MEDIA_TYPE_FOOTAGE:
{
Media* m = static_cast<Media*>(media);
MediaStream* ms = m->get_stream_from_file_index(track < 0, media_stream);
if (ms != NULL && ms->infinite_length) {
calculated_length = LONG_MAX;
} else {
calculated_length = m->get_length_in_frames(fr);
}
}
break;
case MEDIA_TYPE_SEQUENCE:
{
Sequence* s = static_cast<Sequence*>(media);
calculated_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, fr);
}
break;
/*case MEDIA_TYPE_SOLID:
case MEDIA_TYPE_TONE:*/
default:
calculated_length = LONG_MAX;
} else {
calculated_length = m->get_length_in_frames(fr);
break;
}
}
break;
case MEDIA_TYPE_SEQUENCE:
{
Sequence* s = static_cast<Sequence*>(media);
calculated_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, fr);
}
break;
/*case MEDIA_TYPE_SOLID:
case MEDIA_TYPE_TONE:*/
default:
calculated_length = LONG_MAX;
break;
}
}
+1 -3
View File
@@ -8,7 +8,6 @@
#include "project/selection.h"
struct Sequence {
public:
Sequence();
~Sequence();
Sequence* copy();
@@ -31,8 +30,7 @@ public:
int save_id;
QVector<Marker> markers;
QVector<Clip*> clips;
private:
QVector<Clip*> clips;
};
// static variable for the currently active sequence
+7 -3
View File
@@ -352,8 +352,10 @@ DeleteMediaCommand::DeleteMediaCommand(QTreeWidgetItem* i) :
{}
DeleteMediaCommand::~DeleteMediaCommand() {
panel_project->delete_media(item);
delete item;
if (done) {
panel_project->delete_media(item);
delete item;
}
}
void DeleteMediaCommand::undo() {
@@ -364,6 +366,7 @@ void DeleteMediaCommand::undo() {
}
mainWindow->setWindowModified(old_project_changed);
done = false;
}
void DeleteMediaCommand::redo() {
@@ -373,9 +376,10 @@ void DeleteMediaCommand::redo() {
panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item));
} else {
parent->removeChild(item);
}
}
mainWindow->setWindowModified(true);
done = true;
}
RippleCommand::RippleCommand(Sequence *s, long ipoint, long ilength) :
+1
View File
@@ -193,6 +193,7 @@ private:
QTreeWidgetItem* item;
QTreeWidgetItem* parent;
bool old_project_changed;
bool done;
};
class RippleCommand : public QUndoCommand {
+15 -8
View File
@@ -81,6 +81,10 @@ void KeyframeView::paintEvent(QPaintEvent*) {
visible_out = effects_out;
int max_width = getScreenPointFromFrame(panel_effect_controls->zoom, visible_out - visible_in);
qDebug() << max_width << width();
if (max_width < width()) {
p.fillRect(QRect(max_width, 0, width(), height()), QColor(0, 0, 0, 64));
}
panel_effect_controls->ui->horizontalScrollBar->setMaximum(qMax(max_width - width(), 0));
header->set_visible_in(effects_in);
@@ -152,11 +156,13 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
int row_index = -1;
int keyframe_index = -1;
long frame_diff = 0;
long frame_min = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x()-KEYFRAME_SIZE);
drag_frame_start = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x());
long frame_max = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x()+KEYFRAME_SIZE);
int mouse_x = event->x() + x_scroll;
int mouse_y = event->y();
long frame_min = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x-KEYFRAME_SIZE);
drag_frame_start = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x);
long frame_max = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x+KEYFRAME_SIZE);
for (int i=0;i<rowY.size();i++) {
if (event->y() > rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && event->y() < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) {
if (mouse_y > rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && mouse_y < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) {
EffectRow* row = rows.at(i);
for (int j=0;j<row->keyframe_times.size();j++) {
long eval_keyframe_time = row->keyframe_times.at(j)-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in);
@@ -199,9 +205,10 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
if (mousedown) {
int mouse_x = event->x() + x_scroll;
if (keys_selected) {
// move keyframes
frame_diff = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x()) - drag_frame_start;
frame_diff = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x) - drag_frame_start;
// snapping to playhead
if (panel_timeline->snapping) {
@@ -210,7 +217,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
Clip* c = row->parent_effect->parent_clip;
long key_time = row->keyframe_times.at(selected_keyframes.at(i)) + frame_diff - c->clip_in + c->timeline_in;
long key_eval = key_time;
if (panel_timeline->snap_to_timeline(&key_eval, true, true, true)) {
if (panel_timeline->snap_to_point(sequence->playhead, &key_eval)) {
frame_diff += (key_eval - key_time);
break;
}
@@ -245,8 +252,8 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
int min_row = qMin(rect_select_y, event->y())-KEYFRAME_SIZE;
int max_row = qMax(rect_select_y, event->y())+KEYFRAME_SIZE;
long frame_start = getFrameFromScreenPoint(panel_effect_controls->zoom, rect_select_x);
long frame_end = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x());
long frame_start = getFrameFromScreenPoint(panel_effect_controls->zoom, rect_select_x+x_scroll);
long frame_end = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x);
long min_frame = qMin(frame_start, frame_end)-KEYFRAME_SIZE;
long max_frame = qMax(frame_start, frame_end)+KEYFRAME_SIZE;
+1
View File
@@ -8,6 +8,7 @@
#include <QMouseEvent>
#include <QInputDialog>
#include <QApplication>
#include <QDebug>
LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) {
decimal_places = 1;
+1 -1
View File
@@ -22,7 +22,7 @@ public:
bool is_set();
double get_drag_start_value();
bool is_dragging();
virtual QString valueToString(double v);
QString valueToString(double v);
double getPreviousValue();
int decimal_places;
protected:
+8 -3
View File
@@ -24,10 +24,10 @@ SourceTable::SourceTable(QWidget* parent) : QTreeWidget(parent) {
connect(&rename_timer, SIGNAL(timeout()), this, SLOT(rename_interval()));
connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(item_click(QTreeWidgetItem*,int)));
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(item_renamed(QTreeWidgetItem*)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu()));
}
void SourceTable::show_context_menu(const QPoint& pos) {
void SourceTable::show_context_menu() {
QMenu menu(this);
if (selectedItems().size() == 0) {
@@ -75,9 +75,14 @@ void SourceTable::show_context_menu(const QPoint& pos) {
// delete media
QAction* delete_action = menu.addAction("Delete");
connect(delete_action, SIGNAL(triggered(bool)), panel_project, SLOT(delete_selected_media()));
if (selectedItems().size() == 1) {
QAction* properties_action = menu.addAction("Properties...");
connect(properties_action, SIGNAL(triggered(bool)), panel_project, SLOT(open_properties()));
}
}
menu.exec(mapToGlobal(pos));
menu.exec(QCursor::pos());
}
void SourceTable::item_renamed(QTreeWidgetItem* item) {
+1 -1
View File
@@ -27,7 +27,7 @@ private slots:
void item_click(QTreeWidgetItem* item, int column);
void stop_rename_timer();
void item_renamed(QTreeWidgetItem *item);
void show_context_menu(const QPoint& pos);
void show_context_menu();
};
#endif // SOURCETABLE_H
+22 -13
View File
@@ -5,22 +5,17 @@
TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) {
setUndoRedoEnabled(false);
connect(this, SIGNAL(textChanged()), this, SLOT(updateInternals()));
connect(this, SIGNAL(updateSelf()), this, SLOT(updateText()));
}
void TextEditEx::setPlainTextEx(const QString &text) {
blockSignals(true);
const QString& TextEditEx::getPlainTextEx() {
return text;
}
int pos = textCursor().position();
setPlainText(text);
QTextCursor newCursor(document());
newCursor.setPosition(pos);
setTextCursor(newCursor);
updateInternals();
blockSignals(false);
void TextEditEx::setPlainTextEx(const QString &t) {
previousText = text;
text = t;
emit updateSelf();
}
const QString &TextEditEx::getPreviousValue() {
@@ -31,3 +26,17 @@ void TextEditEx::updateInternals() {
previousText = text;
text = toPlainText();
}
void TextEditEx::updateText() {
blockSignals(true);
int pos = textCursor().position();
setPlainText(text);
QTextCursor newCursor(document());
newCursor.setPosition(pos);
setTextCursor(newCursor);
blockSignals(false);
}
+4
View File
@@ -9,8 +9,12 @@ public:
TextEditEx(QWidget* parent = 0);
void setPlainTextEx(const QString &text);
const QString& getPreviousValue();
const QString& getPlainTextEx();
signals:
void updateSelf();
private slots:
void updateInternals();
void updateText();
private:
QString previousText;
QString text;
+1 -1
View File
@@ -1947,7 +1947,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
for (int i=0;i<2;i++) {
Transition* t = (i == 0) ? clip->opening_transition : clip->closing_transition;
if (t != NULL) {
int transition_width = panel_timeline->getTimelineScreenPointFromFrame(t->length);
int transition_width = getScreenPointFromFrame(panel_timeline->zoom, t->length);
int transition_height = clip_rect.height();
int tr_y = clip_rect.y();
int tr_x = 0;
+28 -13
View File
@@ -85,7 +85,7 @@ void ViewerWidget::drawTitleSafeArea() {
glLoadIdentity();
glOrtho(-halfWidth, halfWidth, halfHeight, -halfHeight, -1, 1);
glColor4f(0.5, 0.5, 0.5, 1.0);
glColor4f(0.66f, 0.66f, 0.66f, 1.0f);
glBegin(GL_LINES);
// action safe rectangle
@@ -378,6 +378,8 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
glVertex2f(coords.vertexBottomLeftX, coords.vertexBottomLeftY); // bottom left
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
if (nest != NULL) {
nest->fbo[0]->release();
if (default_fbo != NULL) default_fbo->bind();
@@ -386,19 +388,32 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
glPopMatrix();
} else {
switch (c->media_type) {
case MEDIA_TYPE_FOOTAGE:
case MEDIA_TYPE_TONE:
if (render_audio
&& c->lock.tryLock()) {
// clip is not caching, start caching audio
cache_clip(c, playhead, false, false, c->audio_reset, nest);
c->lock.unlock();
if (render_audio) {
switch (c->media_type) {
case MEDIA_TYPE_FOOTAGE:
case MEDIA_TYPE_TONE:
if (c->lock.tryLock()) {
// clip is not caching, start caching audio
cache_clip(c, playhead, false, false, c->audio_reset, nest);
c->lock.unlock();
}
break;
case MEDIA_TYPE_SEQUENCE:
compose_sequence(c, render_audio);
break;
}
}
// visually update all the keyframe values
double ts = (playhead - c->timeline_in + c->clip_in)/sequence->frame_rate;
for (int i=0;i<c->effects.size();i++) {
Effect* e = c->effects.at(i);
for (int j=0;j<e->row_count();j++) {
EffectRow* r = e->row(j);
for (int k=0;k<r->fieldCount();k++) {
r->field(k)->validate_keyframe_data(ts);
}
}
break;
case MEDIA_TYPE_SEQUENCE:
compose_sequence(c, render_audio);
break;
}
}
}