giant rendering overhaul and many small fixes
This commit is contained in:
+409
-142
@@ -20,12 +20,14 @@
|
||||
|
||||
#include "clip.h"
|
||||
|
||||
#include <QtMath>
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "project/transition.h"
|
||||
#include "project/footage.h"
|
||||
#include "io/config.h"
|
||||
#include "playback/playback.h"
|
||||
#include "playback/cacher.h"
|
||||
#include "rendering/cacher.h"
|
||||
#include "rendering/renderfunctions.h"
|
||||
#include "panels/project.h"
|
||||
#include "project/sequence.h"
|
||||
#include "panels/timeline.h"
|
||||
@@ -34,86 +36,133 @@
|
||||
#include "undo.h"
|
||||
#include "debug.h"
|
||||
|
||||
const int kRGBAComponentCount = 4;
|
||||
|
||||
Clip::Clip(SequencePtr s) :
|
||||
sequence(s),
|
||||
enabled(true),
|
||||
clip_in(0),
|
||||
timeline_in(0),
|
||||
timeline_out(0),
|
||||
track(0),
|
||||
media(nullptr),
|
||||
speed(1.0),
|
||||
reverse(false),
|
||||
maintain_audio_pitch(false),
|
||||
autoscale(olive::CurrentConfig.autoscale_by_default),
|
||||
opening_transition(nullptr),
|
||||
closing_transition(nullptr),
|
||||
undeletable(false),
|
||||
replaced(false),
|
||||
ignore_reverse(false),
|
||||
use_existing_frame(false),
|
||||
filter_graph(nullptr),
|
||||
fbo(nullptr),
|
||||
opts(nullptr)
|
||||
cacher(ClipPtr(this))
|
||||
{
|
||||
pkt = av_packet_alloc();
|
||||
enabled_ = true;
|
||||
clip_in_ = 0;
|
||||
timeline_in_ = 0;
|
||||
timeline_out_ = 0;
|
||||
track_ = 0;
|
||||
media_ = nullptr;
|
||||
speed_.value = 1.0;
|
||||
speed_.maintain_audio_pitch = false;
|
||||
reverse_ = false;
|
||||
autoscale_ = olive::CurrentConfig.autoscale_by_default;
|
||||
opening_transition = nullptr;
|
||||
closing_transition = nullptr;
|
||||
undeletable = false;
|
||||
replaced = false;
|
||||
fbo = nullptr;
|
||||
open_ = false;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
ClipPtr Clip::copy(SequencePtr s) {
|
||||
ClipPtr copy(new Clip(s));
|
||||
|
||||
copy->enabled = enabled;
|
||||
copy->name = QString(name);
|
||||
copy->clip_in = clip_in;
|
||||
copy->timeline_in = timeline_in;
|
||||
copy->timeline_out = timeline_out;
|
||||
copy->track = track;
|
||||
copy->color_r = color_r;
|
||||
copy->color_g = color_g;
|
||||
copy->color_b = color_b;
|
||||
copy->media = media;
|
||||
copy->media_stream = media_stream;
|
||||
copy->autoscale = autoscale;
|
||||
copy->speed = speed;
|
||||
copy->maintain_audio_pitch = maintain_audio_pitch;
|
||||
copy->reverse = reverse;
|
||||
copy->set_enabled(enabled());
|
||||
copy->set_name(name());
|
||||
copy->set_clip_in(clip_in());
|
||||
copy->set_timeline_in(timeline_in());
|
||||
copy->set_timeline_out(timeline_out());
|
||||
copy->set_track(track());
|
||||
copy->set_color(color());
|
||||
copy->set_media(media(), media_stream_index());
|
||||
copy->set_autoscaled(autoscaled());
|
||||
copy->set_speed(speed());
|
||||
copy->set_reversed(reversed());
|
||||
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
copy->effects.append(effects.at(i)->copy(copy));
|
||||
}
|
||||
|
||||
copy->cached_fr = (this->sequence == nullptr) ? cached_fr : this->sequence->frame_rate;
|
||||
copy->set_cached_frame_rate((this->sequence == nullptr) ? cached_frame_rate() : this->sequence->frame_rate);
|
||||
|
||||
copy->recalculateMaxLength();
|
||||
copy->refresh();
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
bool Clip::IsActiveAt(long timecode)
|
||||
{
|
||||
// these buffers allow clips to be opened and prepared well before they're displayed
|
||||
// as well as closed a little after they're not needed anymore
|
||||
int open_buffer = qCeil(this->sequence->frame_rate*2);
|
||||
int close_buffer = qCeil(this->sequence->frame_rate);
|
||||
|
||||
|
||||
return enabled()
|
||||
&& timeline_in(true) < timecode + open_buffer
|
||||
&& timeline_out(true) > timecode - close_buffer
|
||||
&& timecode - timeline_in(true) + clip_in(true) < media_length();
|
||||
}
|
||||
|
||||
const QColor &Clip::color()
|
||||
{
|
||||
return color_;
|
||||
}
|
||||
|
||||
void Clip::set_color(int r, int g, int b)
|
||||
{
|
||||
color_.setRed(r);
|
||||
color_.setGreen(g);
|
||||
color_.setBlue(b);
|
||||
}
|
||||
|
||||
void Clip::set_color(const QColor &c)
|
||||
{
|
||||
color_ = c;
|
||||
}
|
||||
|
||||
Media *Clip::media()
|
||||
{
|
||||
return media_;
|
||||
}
|
||||
|
||||
FootageStream *Clip::media_stream()
|
||||
{
|
||||
if (media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
return media()->to_footage()->get_stream_from_file_index(track() < 0, media_stream_index());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Clip::media_stream_index()
|
||||
{
|
||||
return media_stream_;
|
||||
}
|
||||
|
||||
void Clip::set_media(Media *m, int s)
|
||||
{
|
||||
media_ = m;
|
||||
media_stream_ = s;
|
||||
}
|
||||
|
||||
bool Clip::enabled()
|
||||
{
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
void Clip::set_enabled(bool e)
|
||||
{
|
||||
enabled_ = e;
|
||||
}
|
||||
|
||||
void Clip::reset() {
|
||||
audio_just_reset = false;
|
||||
open = false;
|
||||
finished_opening = false;
|
||||
pkt_written = false;
|
||||
audio_reset = false;
|
||||
frame_sample_index = -1;
|
||||
audio_buffer_write = false;
|
||||
texture_frame = -1;
|
||||
formatCtx = nullptr;
|
||||
stream = nullptr;
|
||||
codec = nullptr;
|
||||
codecCtx = nullptr;
|
||||
texture = nullptr;
|
||||
last_invalid_ts = -1;
|
||||
}
|
||||
|
||||
void Clip::reset_audio() {
|
||||
if (media == nullptr || media->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
audio_reset = true;
|
||||
frame_sample_index = -1;
|
||||
audio_buffer_write = 0;
|
||||
} else if (media->get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
SequencePtr nested_sequence = media->to_sequence();
|
||||
if (UsesCacher()) {
|
||||
cacher.ResetAudio();
|
||||
}
|
||||
if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
SequencePtr nested_sequence = media()->to_sequence();
|
||||
for (int i=0;i<nested_sequence->clips.size();i++) {
|
||||
ClipPtr c = nested_sequence->clips.at(i);
|
||||
if (c != nullptr) c->reset_audio();
|
||||
@@ -123,13 +172,13 @@ void Clip::reset_audio() {
|
||||
|
||||
void Clip::refresh() {
|
||||
// validates media if it was replaced
|
||||
if (replaced && media != nullptr && media->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
FootagePtr m = media->to_footage();
|
||||
if (replaced && media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
FootagePtr m = media()->to_footage();
|
||||
|
||||
if (track < 0 && m->video_tracks.size() > 0) {
|
||||
media_stream = m->video_tracks.at(0).file_index;
|
||||
} else if (track >= 0 && m->audio_tracks.size() > 0) {
|
||||
media_stream = m->audio_tracks.at(0).file_index;
|
||||
if (track() < 0 && m->video_tracks.size() > 0) {
|
||||
set_media(media(), m->video_tracks.at(0).file_index);
|
||||
} else if (track() >= 0 && m->audio_tracks.size() > 0) {
|
||||
set_media(media(), m->audio_tracks.at(0).file_index);
|
||||
}
|
||||
}
|
||||
replaced = false;
|
||||
@@ -138,153 +187,206 @@ void Clip::refresh() {
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
effects.at(i)->refresh();
|
||||
}
|
||||
|
||||
recalculateMaxLength();
|
||||
}
|
||||
|
||||
void Clip::queue_clear() {
|
||||
while (queue.size() > 0) {
|
||||
av_frame_free(&queue.first());
|
||||
queue.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
void Clip::queue_remove_earliest() {
|
||||
int earliest_frame = 0;
|
||||
for (int i=1;i<queue.size();i++) {
|
||||
// TODO/NOTE: this will not work on sped up AND reversed video
|
||||
if (queue.at(i)->pts < queue.at(earliest_frame)->pts) {
|
||||
earliest_frame = i;
|
||||
}
|
||||
}
|
||||
av_frame_free(&queue[earliest_frame]);
|
||||
queue.removeAt(earliest_frame);
|
||||
}
|
||||
|
||||
QVector<Marker> &Clip::get_markers() {
|
||||
if (media != nullptr) {
|
||||
return media->get_markers();
|
||||
if (media() != nullptr) {
|
||||
return media()->get_markers();
|
||||
}
|
||||
return markers;
|
||||
}
|
||||
|
||||
Clip::~Clip() {
|
||||
if (open) {
|
||||
close_clip(ClipPtr(this), true);
|
||||
if (IsOpen()) {
|
||||
Close(true);
|
||||
}
|
||||
|
||||
effects.clear();
|
||||
av_packet_free(&pkt);
|
||||
}
|
||||
|
||||
long Clip::get_clip_in_with_transition() {
|
||||
if (opening_transition != nullptr && opening_transition->secondary_clip != nullptr) {
|
||||
long Clip::clip_in(bool with_transition) {
|
||||
if (with_transition && opening_transition != nullptr && opening_transition->secondary_clip != nullptr) {
|
||||
// we must be the secondary clip, so return (timeline in - length)
|
||||
return clip_in - opening_transition->get_true_length();
|
||||
return clip_in_ - opening_transition->get_true_length();
|
||||
}
|
||||
return clip_in;
|
||||
return clip_in_;
|
||||
}
|
||||
|
||||
long Clip::get_timeline_in_with_transition() {
|
||||
if (opening_transition != nullptr && opening_transition->secondary_clip != nullptr) {
|
||||
void Clip::set_clip_in(long c)
|
||||
{
|
||||
clip_in_ = c;
|
||||
}
|
||||
|
||||
long Clip::timeline_in(bool with_transition) {
|
||||
if (with_transition && opening_transition != nullptr && opening_transition->secondary_clip != nullptr) {
|
||||
// we must be the secondary clip, so return (timeline in - length)
|
||||
return timeline_in - opening_transition->get_true_length();
|
||||
return timeline_in_ - opening_transition->get_true_length();
|
||||
}
|
||||
return timeline_in;
|
||||
return timeline_in_;
|
||||
}
|
||||
|
||||
long Clip::get_timeline_out_with_transition() {
|
||||
if (closing_transition != nullptr && closing_transition->secondary_clip != nullptr) {
|
||||
void Clip::set_timeline_in(long t)
|
||||
{
|
||||
timeline_in_ = t;
|
||||
}
|
||||
|
||||
long Clip::timeline_out(bool with_transitions) {
|
||||
if (with_transitions && closing_transition != nullptr && closing_transition->secondary_clip != nullptr) {
|
||||
// we must be the primary clip, so return (timeline out + length2)
|
||||
return timeline_out + closing_transition->get_true_length();
|
||||
return timeline_out_ + closing_transition->get_true_length();
|
||||
} else {
|
||||
return timeline_out;
|
||||
return timeline_out_;
|
||||
}
|
||||
}
|
||||
|
||||
void Clip::set_timeline_out(long t)
|
||||
{
|
||||
timeline_out_ = t;
|
||||
}
|
||||
|
||||
bool Clip::reversed()
|
||||
{
|
||||
return reverse_;
|
||||
}
|
||||
|
||||
void Clip::set_reversed(bool r)
|
||||
{
|
||||
reverse_ = r;
|
||||
}
|
||||
|
||||
bool Clip::autoscaled()
|
||||
{
|
||||
return autoscale_;
|
||||
}
|
||||
|
||||
void Clip::set_autoscaled(bool b)
|
||||
{
|
||||
autoscale_ = b;
|
||||
}
|
||||
|
||||
double Clip::cached_frame_rate()
|
||||
{
|
||||
return cached_fr_;
|
||||
}
|
||||
|
||||
void Clip::set_cached_frame_rate(double d)
|
||||
{
|
||||
cached_fr_ = d;
|
||||
}
|
||||
|
||||
const QString &Clip::name()
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
void Clip::set_name(const QString &s)
|
||||
{
|
||||
name_ = s;
|
||||
}
|
||||
|
||||
const ClipSpeed& Clip::speed()
|
||||
{
|
||||
return speed_;
|
||||
}
|
||||
|
||||
void Clip::set_speed(const ClipSpeed& d)
|
||||
{
|
||||
speed_ = d;
|
||||
}
|
||||
|
||||
AVRational Clip::time_base()
|
||||
{
|
||||
return cacher.media_time_base();
|
||||
}
|
||||
|
||||
int Clip::track()
|
||||
{
|
||||
return track_;
|
||||
}
|
||||
|
||||
void Clip::set_track(int t)
|
||||
{
|
||||
track_ = t;
|
||||
}
|
||||
|
||||
// timeline functions
|
||||
long Clip::getLength() {
|
||||
return timeline_out - timeline_in;
|
||||
long Clip::length() {
|
||||
return timeline_out_ - timeline_in_;
|
||||
}
|
||||
|
||||
double Clip::getMediaFrameRate() {
|
||||
Q_ASSERT(track < 0);
|
||||
if (media != nullptr) {
|
||||
double rate = media->get_frame_rate(media_stream);
|
||||
double Clip::media_frame_rate() {
|
||||
Q_ASSERT(track_ < 0);
|
||||
if (media_ != nullptr) {
|
||||
double rate = media_->get_frame_rate(media_stream_index());
|
||||
if (!qIsNaN(rate)) return rate;
|
||||
}
|
||||
if (sequence != nullptr) return sequence->frame_rate;
|
||||
return qSNaN();
|
||||
}
|
||||
|
||||
void Clip::recalculateMaxLength() {
|
||||
long Clip::media_length() {
|
||||
if (this->sequence != nullptr) {
|
||||
double fr = this->sequence->frame_rate;
|
||||
|
||||
fr /= speed;
|
||||
fr /= speed_.value;
|
||||
|
||||
calculated_length = LONG_MAX;
|
||||
|
||||
if (media != nullptr) {
|
||||
switch (media->get_type()) {
|
||||
if (media_ == nullptr) {
|
||||
return LONG_MAX;
|
||||
} else {
|
||||
switch (media_->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
FootagePtr m = media->to_footage();
|
||||
const FootageStream* ms = m->get_stream_from_file_index(track < 0, media_stream);
|
||||
FootagePtr m = media_->to_footage();
|
||||
const FootageStream* ms = m->get_stream_from_file_index(track_ < 0, media_stream_index());
|
||||
if (ms != nullptr && ms->infinite_length) {
|
||||
calculated_length = LONG_MAX;
|
||||
return LONG_MAX;
|
||||
} else {
|
||||
calculated_length = m->get_length_in_frames(fr);
|
||||
return m->get_length_in_frames(fr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
{
|
||||
SequencePtr s = media->to_sequence();
|
||||
calculated_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, fr);
|
||||
SequencePtr s = media_->to_sequence();
|
||||
return rescale_frame_number(s->getEndFrame(), s->frame_rate, fr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long Clip::getMaximumLength() {
|
||||
return calculated_length;
|
||||
}
|
||||
|
||||
int Clip::getWidth() {
|
||||
if (media == nullptr && sequence != nullptr) return sequence->width;
|
||||
switch (media->get_type()) {
|
||||
int Clip::media_width() {
|
||||
if (media_ == nullptr && sequence != nullptr) return sequence->width;
|
||||
switch (media_->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
const FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream);
|
||||
const FootageStream* ms = media_stream();
|
||||
if (ms != nullptr) return ms->video_width;
|
||||
if (sequence != nullptr) return sequence->width;
|
||||
break;
|
||||
}
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
{
|
||||
SequencePtr s = media->to_sequence();
|
||||
SequencePtr s = media_->to_sequence();
|
||||
return s->width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Clip::getHeight() {
|
||||
if (media == nullptr && sequence != nullptr) return sequence->height;
|
||||
switch (media->get_type()) {
|
||||
int Clip::media_height() {
|
||||
if (media_ == nullptr && sequence != nullptr) return sequence->height;
|
||||
switch (media_->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
const FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream);
|
||||
const FootageStream* ms = media_stream();
|
||||
if (ms != nullptr) return ms->video_height;
|
||||
if (sequence != nullptr) return sequence->height;
|
||||
}
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
{
|
||||
SequencePtr s = media->to_sequence();
|
||||
SequencePtr s = media_->to_sequence();
|
||||
return s->height;
|
||||
}
|
||||
}
|
||||
@@ -294,10 +396,10 @@ int Clip::getHeight() {
|
||||
void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points) {
|
||||
if (change_timeline_points) {
|
||||
move_clip(ca, ClipPtr(this),
|
||||
qRound((double) timeline_in * multiplier),
|
||||
qRound((double) timeline_out * multiplier),
|
||||
qRound((double) clip_in * multiplier),
|
||||
track);
|
||||
qRound(double(timeline_in_) * multiplier),
|
||||
qRound(double(timeline_out_) * multiplier),
|
||||
qRound(double(clip_in_) * multiplier),
|
||||
track_);
|
||||
}
|
||||
|
||||
// move keyframes
|
||||
@@ -308,9 +410,174 @@ void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_t
|
||||
for (int l=0;l<r->fieldCount();l++) {
|
||||
EffectField* f = r->field(l);
|
||||
for (int k=0;k<f->keyframes.size();k++) {
|
||||
ca->append(new SetLong(&f->keyframes[k].time, f->keyframes[k].time, f->keyframes[k].time * multiplier));
|
||||
ca->append(new SetLong(&f->keyframes[k].time, f->keyframes[k].time, qRound(f->keyframes[k].time * multiplier)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Clip::Open() {
|
||||
if (!open_ && state_change_lock.tryLock()) {
|
||||
open_ = true;
|
||||
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
effects.at(i)->open();
|
||||
}
|
||||
|
||||
// reset variable used to optimize uploading frame data
|
||||
texture_frame = -1;
|
||||
|
||||
if (UsesCacher()) {
|
||||
// cacher will unlock open_lock
|
||||
cacher.Open();
|
||||
} else {
|
||||
// this media doesn't use a cacher, so we unlock here
|
||||
state_change_lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Clip::Close(bool wait) {
|
||||
// thread safety, prevents Close() running from two separate threads simultaneously
|
||||
if (open_ && state_change_lock.tryLock()) {
|
||||
open_ = false;
|
||||
|
||||
if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
close_active_clips(media()->to_sequence());
|
||||
}
|
||||
|
||||
// destroy opengl texture in main thread
|
||||
delete texture;
|
||||
texture = nullptr;
|
||||
|
||||
// close all effects
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
if (effects.at(i)->is_open()) {
|
||||
effects.at(i)->close();
|
||||
}
|
||||
}
|
||||
|
||||
// delete framebuffers
|
||||
if (fbo != nullptr) {
|
||||
// delete 3 fbos for nested sequences, 2 for most clips
|
||||
int fbo_count = (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) ? 3 : 2;
|
||||
|
||||
for (int j=0;j<fbo_count;j++) {
|
||||
delete fbo[j];
|
||||
}
|
||||
|
||||
delete [] fbo;
|
||||
|
||||
fbo = nullptr;
|
||||
}
|
||||
|
||||
if (UsesCacher()) {
|
||||
cacher.Close(wait);
|
||||
} else {
|
||||
state_change_lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Clip::IsOpen()
|
||||
{
|
||||
return open_;
|
||||
}
|
||||
|
||||
void Clip::Cache(long playhead, bool scrubbing, QVector<ClipPtr>& nests, int playback_speed) {
|
||||
// qint64 time = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
cacher.Cache(playhead, scrubbing, nests, playback_speed);
|
||||
cacher_frame = playhead;
|
||||
|
||||
// qDebug() << "Clip::Cache took" << (QDateTime::currentMSecsSinceEpoch() - time);
|
||||
}
|
||||
|
||||
bool Clip::Retrieve()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (UsesCacher()) {
|
||||
|
||||
// qint64 time = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
AVFrame* frame = cacher.Retrieve();
|
||||
|
||||
cacher.QueueLock();
|
||||
|
||||
if (frame != nullptr) {
|
||||
|
||||
// check if the opengl texture exists yet, create it if not
|
||||
if (texture == nullptr) {
|
||||
texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
||||
|
||||
// the raw frame size may differ from the one we're using (e.g. a lower resolution proxy), so we make sure
|
||||
// the texture is using the correct dimensions, but then treat it as if it's the original resolution in the
|
||||
// composition
|
||||
texture->setSize(cacher.media_width(), cacher.media_height());
|
||||
|
||||
texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
|
||||
texture->setMipLevels(texture->maximumMipLevels());
|
||||
texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
|
||||
texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
|
||||
}
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame->linesize[0]/kRGBAComponentCount);
|
||||
|
||||
// 2 data buffers to ping-pong between
|
||||
bool using_db_1 = true;
|
||||
uint8_t* data_buffer_1 = frame->data[0];
|
||||
uint8_t* data_buffer_2 = nullptr;
|
||||
|
||||
int frame_size = frame->linesize[0]*frame->height;
|
||||
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
EffectPtr e = effects.at(i);
|
||||
if (e->enable_image && e->is_enabled()) {
|
||||
if (data_buffer_1 == frame->data[0]) {
|
||||
data_buffer_1 = new uint8_t[frame_size];
|
||||
data_buffer_2 = new uint8_t[frame_size];
|
||||
|
||||
memcpy(data_buffer_1, frame->data[0], frame_size);
|
||||
}
|
||||
|
||||
e->process_image(get_timecode(ClipPtr(this), cacher_frame),
|
||||
using_db_1 ? data_buffer_1 : data_buffer_2,
|
||||
using_db_1 ? data_buffer_2 : data_buffer_1,
|
||||
frame_size
|
||||
);
|
||||
|
||||
using_db_1 = !using_db_1;
|
||||
}
|
||||
}
|
||||
|
||||
texture->setData(QOpenGLTexture::RGBA,
|
||||
QOpenGLTexture::UInt8,
|
||||
const_cast<const uint8_t*>(using_db_1 ? data_buffer_1 : data_buffer_2));
|
||||
|
||||
if (data_buffer_1 != frame->data[0]) {
|
||||
qDebug() << data_buffer_1 << frame->data[0];
|
||||
delete [] data_buffer_1;
|
||||
delete [] data_buffer_2;
|
||||
}
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
// qDebug() << "Clip::Retrieve took" << (QDateTime::currentMSecsSinceEpoch() - time);
|
||||
|
||||
ret = true;
|
||||
} else {
|
||||
qCritical() << "Failed to retrieve frame for clip" << name();
|
||||
}
|
||||
|
||||
cacher.QueueUnlock();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Clip::UsesCacher()
|
||||
{
|
||||
return track() >= 0 || (media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE);
|
||||
}
|
||||
|
||||
+86
-69
@@ -28,7 +28,7 @@
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QOpenGLTexture>
|
||||
|
||||
#include "playback/cacher.h"
|
||||
#include "rendering/cacher.h"
|
||||
|
||||
#include "project/effect.h"
|
||||
#include "project/transition.h"
|
||||
@@ -43,6 +43,11 @@ extern "C" {
|
||||
#include <libavfilter/avfilter.h>
|
||||
}
|
||||
|
||||
struct ClipSpeed {
|
||||
double value;
|
||||
bool maintain_audio_pitch;
|
||||
};
|
||||
|
||||
using ClipPtr = std::shared_ptr<Clip>;
|
||||
|
||||
class Sequence;
|
||||
@@ -53,43 +58,63 @@ public:
|
||||
Clip(SequencePtr s);
|
||||
~Clip();
|
||||
ClipPtr copy(SequencePtr s);
|
||||
|
||||
bool IsActiveAt(long timecode);
|
||||
|
||||
const QColor& color();
|
||||
void set_color(int r, int g, int b);
|
||||
void set_color(const QColor& c);
|
||||
|
||||
Media* media();
|
||||
FootageStream* media_stream();
|
||||
int media_stream_index();
|
||||
int media_width();
|
||||
int media_height();
|
||||
double media_frame_rate();
|
||||
long media_length();
|
||||
void set_media(Media* m, int s);
|
||||
|
||||
bool enabled();
|
||||
void set_enabled(bool e);
|
||||
|
||||
long clip_in(bool with_transition = false);
|
||||
void set_clip_in(long c);
|
||||
|
||||
long timeline_in(bool with_transition = false);
|
||||
void set_timeline_in(long t);
|
||||
|
||||
long timeline_out(bool with_transition = false);
|
||||
void set_timeline_out(long t);
|
||||
|
||||
int track();
|
||||
void set_track(int t);
|
||||
|
||||
bool reversed();
|
||||
void set_reversed(bool r);
|
||||
|
||||
bool autoscaled();
|
||||
void set_autoscaled(bool b);
|
||||
|
||||
double cached_frame_rate();
|
||||
void set_cached_frame_rate(double d);
|
||||
|
||||
const QString& name();
|
||||
void set_name(const QString& s);
|
||||
|
||||
const ClipSpeed& speed();
|
||||
void set_speed(const ClipSpeed& s);
|
||||
|
||||
AVRational time_base();
|
||||
|
||||
void reset_audio();
|
||||
void reset();
|
||||
void refresh();
|
||||
long get_clip_in_with_transition();
|
||||
long get_timeline_in_with_transition();
|
||||
long get_timeline_out_with_transition();
|
||||
long getLength();
|
||||
double getMediaFrameRate();
|
||||
long getMaximumLength();
|
||||
void recalculateMaxLength();
|
||||
int getWidth();
|
||||
int getHeight();
|
||||
|
||||
long length();
|
||||
|
||||
void refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points);
|
||||
SequencePtr sequence;
|
||||
|
||||
// queue functions
|
||||
void queue_clear();
|
||||
void queue_remove_earliest();
|
||||
|
||||
// timeline variables (should be copied in copy())
|
||||
bool enabled;
|
||||
long clip_in;
|
||||
long timeline_in;
|
||||
long timeline_out;
|
||||
int track;
|
||||
QString name;
|
||||
quint8 color_r;
|
||||
quint8 color_g;
|
||||
quint8 color_b;
|
||||
Media* media;
|
||||
int media_stream;
|
||||
double speed;
|
||||
double cached_fr;
|
||||
bool reverse;
|
||||
bool maintain_audio_pitch;
|
||||
bool autoscale;
|
||||
|
||||
// markers
|
||||
QVector<Marker>& get_markers();
|
||||
|
||||
@@ -99,58 +124,50 @@ public:
|
||||
TransitionPtr opening_transition;
|
||||
TransitionPtr closing_transition;
|
||||
|
||||
// media handling
|
||||
AVFormatContext* formatCtx;
|
||||
AVStream* stream;
|
||||
AVCodec* codec;
|
||||
AVCodecContext* codecCtx;
|
||||
AVPacket* pkt;
|
||||
AVFrame* frame;
|
||||
AVDictionary* opts;
|
||||
long calculated_length;
|
||||
// playback functions
|
||||
void Open();
|
||||
void Cache(long playhead, bool scrubbing, QVector<ClipPtr> &nests, int playback_speed);
|
||||
bool Retrieve();
|
||||
void Close(bool wait);
|
||||
bool IsOpen();
|
||||
|
||||
bool UsesCacher();
|
||||
|
||||
// temporary variables
|
||||
int load_id;
|
||||
bool undeletable;
|
||||
bool reached_end;
|
||||
bool pkt_written;
|
||||
bool open;
|
||||
bool finished_opening;
|
||||
bool replaced;
|
||||
bool ignore_reverse;
|
||||
int pix_fmt;
|
||||
|
||||
// caching functions
|
||||
bool use_existing_frame;
|
||||
bool multithreaded;
|
||||
Cacher* cacher;
|
||||
QWaitCondition can_cache;
|
||||
QVector<AVFrame*> queue;
|
||||
QMutex queue_lock;
|
||||
QMutex render_lock;
|
||||
QMutex lock;
|
||||
QMutex open_lock;
|
||||
int64_t last_invalid_ts;
|
||||
|
||||
// converters/filters
|
||||
AVFilterGraph* filter_graph;
|
||||
AVFilterContext* buffersink_ctx;
|
||||
AVFilterContext* buffersrc_ctx;
|
||||
QMutex state_change_lock;
|
||||
QMutex cache_lock;
|
||||
|
||||
// video playback variables
|
||||
QOpenGLFramebufferObject** fbo;
|
||||
QOpenGLTexture* texture;
|
||||
long texture_frame;
|
||||
|
||||
// audio playback variables
|
||||
int64_t reverse_target;
|
||||
int frame_sample_index;
|
||||
qint64 audio_buffer_write;
|
||||
bool audio_reset;
|
||||
bool audio_just_reset;
|
||||
long audio_target_frame;
|
||||
private:
|
||||
// timeline variables (should be copied in copy())
|
||||
bool enabled_;
|
||||
long clip_in_;
|
||||
long timeline_in_;
|
||||
long timeline_out_;
|
||||
int track_;
|
||||
QString name_;
|
||||
Media* media_;
|
||||
int media_stream_;
|
||||
ClipSpeed speed_;
|
||||
double cached_fr_;
|
||||
bool reverse_;
|
||||
bool autoscale_;
|
||||
|
||||
Cacher cacher;
|
||||
long cacher_frame;
|
||||
|
||||
QVector<Marker> markers;
|
||||
QColor color_;
|
||||
bool open_;
|
||||
};
|
||||
|
||||
#endif // CLIP_H
|
||||
|
||||
+5
-5
@@ -862,7 +862,7 @@ EffectPtr Effect::copy(ClipPtr c) {
|
||||
}
|
||||
|
||||
void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) {
|
||||
glslProgram->setUniformValue("resolution", parent_clip->getWidth(), parent_clip->getHeight());
|
||||
glslProgram->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height());
|
||||
glslProgram->setUniformValue("time", GLfloat(timecode));
|
||||
glslProgram->setUniformValue("iteration", iteration);
|
||||
|
||||
@@ -904,8 +904,8 @@ GLuint Effect::process_superimpose(double timecode) {
|
||||
bool dimensions_changed = false;
|
||||
bool redrew_image = false;
|
||||
|
||||
int width = parent_clip->getWidth();
|
||||
int height = parent_clip->getHeight();
|
||||
int width = parent_clip->media_width();
|
||||
int height = parent_clip->media_height();
|
||||
|
||||
if (width != img.width() || height != img.height()) {
|
||||
img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied);
|
||||
@@ -1003,8 +1003,8 @@ void Effect::redraw(double) {
|
||||
painter_wrapper.painter = &p;
|
||||
|
||||
jsEngine.globalObject().setProperty("painter", wrapper_obj);
|
||||
jsEngine.globalObject().setProperty("width", parent_clip->getWidth());
|
||||
jsEngine.globalObject().setProperty("height", parent_clip->getHeight());
|
||||
jsEngine.globalObject().setProperty("width", parent_clip->media_width());
|
||||
jsEngine.globalObject().setProperty("height", parent_clip->media_height());
|
||||
|
||||
for (int i=0;i<rows.size();i++) {
|
||||
EffectRow* row = rows.at(i);
|
||||
|
||||
@@ -120,7 +120,7 @@ void EffectRow::goto_previous_key() {
|
||||
for (int i=0;i<fieldCount();i++) {
|
||||
EffectField* f = field(i);
|
||||
for (int j=0;j<f->keyframes.size();j++) {
|
||||
long comp = f->keyframes.at(j).time - c->clip_in + c->timeline_in;
|
||||
long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in();
|
||||
if (comp < olive::ActiveSequence->playhead) {
|
||||
key = qMax(comp, key);
|
||||
}
|
||||
@@ -136,7 +136,7 @@ void EffectRow::toggle_key() {
|
||||
for (int j=0;j<fieldCount();j++) {
|
||||
EffectField* f = field(j);
|
||||
for (int i=0;i<f->keyframes.size();i++) {
|
||||
long comp = c->timeline_in - c->clip_in + f->keyframes.at(i).time;
|
||||
long comp = c->timeline_in() - c->clip_in() + f->keyframes.at(i).time;
|
||||
if (comp == olive::ActiveSequence->playhead) {
|
||||
key_fields.append(f);
|
||||
key_field_index.append(i);
|
||||
@@ -163,7 +163,7 @@ void EffectRow::goto_next_key() {
|
||||
for (int i=0;i<fieldCount();i++) {
|
||||
EffectField* f = field(i);
|
||||
for (int j=0;j<f->keyframes.size();j++) {
|
||||
long comp = f->keyframes.at(j).time - c->clip_in + c->timeline_in;
|
||||
long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in();
|
||||
if (comp > olive::ActiveSequence->playhead) {
|
||||
key = qMin(comp, key);
|
||||
}
|
||||
@@ -194,7 +194,9 @@ void EffectRow::add_widget(QWidget* w) {
|
||||
}
|
||||
|
||||
void EffectRow::set_keyframe_now(ComboAction* ca) {
|
||||
long time = olive::ActiveSequence->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in;
|
||||
long time = olive::ActiveSequence->playhead
|
||||
- parent_effect->parent_clip->timeline_in()
|
||||
+ parent_effect->parent_clip->clip_in();
|
||||
|
||||
if (!just_made_unsafe_keyframe) {
|
||||
EffectKeyframe key;
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
#include <QPainter>
|
||||
#include "io/previewgenerator.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
#include "project/clip.h"
|
||||
|
||||
Footage::Footage() :
|
||||
|
||||
+53
-49
@@ -21,6 +21,10 @@
|
||||
#ifndef FOOTAGE_H
|
||||
#define FOOTAGE_H
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
#include <memory>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
@@ -33,9 +37,9 @@
|
||||
#include "project/marker.h"
|
||||
|
||||
enum VideoInterlacingMode {
|
||||
VIDEO_PROGRESSIVE,
|
||||
VIDEO_TOP_FIELD_FIRST,
|
||||
VIDEO_BOTTOM_FIELD_FIRST
|
||||
VIDEO_PROGRESSIVE,
|
||||
VIDEO_TOP_FIELD_FIRST,
|
||||
VIDEO_BOTTOM_FIELD_FIRST
|
||||
};
|
||||
|
||||
class Sequence;
|
||||
@@ -43,62 +47,62 @@ class Clip;
|
||||
class PreviewGenerator;
|
||||
|
||||
struct FootageStream {
|
||||
int file_index;
|
||||
int video_width;
|
||||
int video_height;
|
||||
bool infinite_length;
|
||||
double video_frame_rate;
|
||||
int video_interlacing;
|
||||
int video_auto_interlacing;
|
||||
int audio_channels;
|
||||
int audio_layout;
|
||||
int audio_frequency;
|
||||
bool enabled;
|
||||
int file_index;
|
||||
int video_width;
|
||||
int video_height;
|
||||
bool infinite_length;
|
||||
double video_frame_rate;
|
||||
int video_interlacing;
|
||||
int video_auto_interlacing;
|
||||
int audio_channels;
|
||||
int audio_layout;
|
||||
int audio_frequency;
|
||||
bool enabled;
|
||||
|
||||
// preview thumbnail/waveform
|
||||
bool preview_done;
|
||||
QImage video_preview;
|
||||
QIcon video_preview_square;
|
||||
QVector<char> audio_preview;
|
||||
void make_square_thumb();
|
||||
// preview thumbnail/waveform
|
||||
bool preview_done;
|
||||
QImage video_preview;
|
||||
QIcon video_preview_square;
|
||||
QVector<char> audio_preview;
|
||||
void make_square_thumb();
|
||||
};
|
||||
|
||||
struct Footage {
|
||||
Footage();
|
||||
~Footage();
|
||||
Footage();
|
||||
~Footage();
|
||||
|
||||
// footage metadata
|
||||
QString url;
|
||||
QString name;
|
||||
int64_t length;
|
||||
QVector<FootageStream> video_tracks;
|
||||
QVector<FootageStream> audio_tracks;
|
||||
int save_id;
|
||||
bool ready;
|
||||
bool invalid;
|
||||
double speed;
|
||||
bool alpha_is_premultiplied;
|
||||
// footage metadata
|
||||
QString url;
|
||||
QString name;
|
||||
int64_t length;
|
||||
QVector<FootageStream> video_tracks;
|
||||
QVector<FootageStream> audio_tracks;
|
||||
int save_id;
|
||||
bool ready;
|
||||
bool invalid;
|
||||
double speed;
|
||||
bool alpha_is_premultiplied;
|
||||
|
||||
// proxy config
|
||||
bool proxy;
|
||||
QString proxy_path;
|
||||
// proxy config
|
||||
bool proxy;
|
||||
QString proxy_path;
|
||||
|
||||
// thumbnail/waveform generation
|
||||
PreviewGenerator* preview_gen;
|
||||
QMutex ready_lock;
|
||||
// thumbnail/waveform generation
|
||||
PreviewGenerator* preview_gen;
|
||||
QMutex ready_lock;
|
||||
|
||||
// in/out points
|
||||
bool using_inout;
|
||||
long in;
|
||||
long out;
|
||||
// in/out points
|
||||
bool using_inout;
|
||||
long in;
|
||||
long out;
|
||||
|
||||
// markers
|
||||
QVector<Marker> markers;
|
||||
// markers
|
||||
QVector<Marker> markers;
|
||||
|
||||
// functions
|
||||
long get_length_in_frames(double frame_rate);
|
||||
FootageStream *get_stream_from_file_index(bool video, int index);
|
||||
void reset();
|
||||
// functions
|
||||
long get_length_in_frames(double frame_rate);
|
||||
FootageStream *get_stream_from_file_index(bool video, int index);
|
||||
void reset();
|
||||
};
|
||||
|
||||
using FootagePtr = std::shared_ptr<Footage>;
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ void set_marker_internal(SequencePtr seq, const QVector<int>& clips) {
|
||||
foreach (int i, clips) {
|
||||
ClipPtr c = seq->clips.at(i);
|
||||
ca->append(new AddMarkerAction(&c->get_markers(),
|
||||
seq->playhead - c->timeline_in + c->clip_in,
|
||||
seq->playhead - c->timeline_in() + c->clip_in(),
|
||||
marker_name));
|
||||
}
|
||||
|
||||
|
||||
+231
-231
@@ -34,332 +34,332 @@
|
||||
#include "debug.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
|
||||
QString get_interlacing_name(int interlacing) {
|
||||
switch (interlacing) {
|
||||
case VIDEO_PROGRESSIVE: return QCoreApplication::translate("InterlacingName", "None (Progressive)");
|
||||
case VIDEO_TOP_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Top Field First");
|
||||
case VIDEO_BOTTOM_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Bottom Field First");
|
||||
default: return QCoreApplication::translate("InterlacingName", "Invalid");
|
||||
}
|
||||
switch (interlacing) {
|
||||
case VIDEO_PROGRESSIVE: return QCoreApplication::translate("InterlacingName", "None (Progressive)");
|
||||
case VIDEO_TOP_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Top Field First");
|
||||
case VIDEO_BOTTOM_FIELD_FIRST: return QCoreApplication::translate("InterlacingName", "Bottom Field First");
|
||||
default: return QCoreApplication::translate("InterlacingName", "Invalid");
|
||||
}
|
||||
}
|
||||
|
||||
QString get_channel_layout_name(int channels, uint64_t layout) {
|
||||
switch (channels) {
|
||||
case 0: return QCoreApplication::translate("ChannelLayoutName", "Invalid");
|
||||
case 1: return QCoreApplication::translate("ChannelLayoutName", "Mono");
|
||||
case 2: return QCoreApplication::translate("ChannelLayoutName", "Stereo");
|
||||
default: {
|
||||
char buf[50];
|
||||
av_get_channel_layout_string(buf, sizeof(buf), channels, layout);
|
||||
return QString(buf);
|
||||
}
|
||||
}
|
||||
switch (channels) {
|
||||
case 0: return QCoreApplication::translate("ChannelLayoutName", "Invalid");
|
||||
case 1: return QCoreApplication::translate("ChannelLayoutName", "Mono");
|
||||
case 2: return QCoreApplication::translate("ChannelLayoutName", "Stereo");
|
||||
default: {
|
||||
char buf[50];
|
||||
av_get_channel_layout_string(buf, sizeof(buf), channels, layout);
|
||||
return QString(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Media::Media(Media* iparent) {
|
||||
parent = iparent;
|
||||
root = false;
|
||||
type = -1;
|
||||
parent = iparent;
|
||||
root = false;
|
||||
type = -1;
|
||||
}
|
||||
|
||||
Media::~Media() {
|
||||
for (int i=0;i<children.size();i++) {
|
||||
delete children.at(i);
|
||||
}
|
||||
for (int i=0;i<children.size();i++) {
|
||||
delete children.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
FootagePtr Media::to_footage() {
|
||||
return std::static_pointer_cast<Footage>(object);
|
||||
return std::static_pointer_cast<Footage>(object);
|
||||
}
|
||||
|
||||
SequencePtr Media::to_sequence() {
|
||||
return std::static_pointer_cast<Sequence>(object);
|
||||
return std::static_pointer_cast<Sequence>(object);
|
||||
}
|
||||
|
||||
void Media::set_footage(FootagePtr f) {
|
||||
type = MEDIA_TYPE_FOOTAGE;
|
||||
object = VoidPtr(f);
|
||||
type = MEDIA_TYPE_FOOTAGE;
|
||||
object = VoidPtr(f);
|
||||
}
|
||||
|
||||
void Media::set_sequence(SequencePtr s) {
|
||||
set_icon(QIcon(":/icons/sequence.png"));
|
||||
type = MEDIA_TYPE_SEQUENCE;
|
||||
object = VoidPtr(s);
|
||||
if (s != nullptr) update_tooltip();
|
||||
set_icon(QIcon(":/icons/sequence.png"));
|
||||
type = MEDIA_TYPE_SEQUENCE;
|
||||
object = VoidPtr(s);
|
||||
if (s != nullptr) update_tooltip();
|
||||
}
|
||||
|
||||
void Media::set_folder() {
|
||||
if (folder_name.isEmpty()) folder_name = QCoreApplication::translate("Media", "New Folder");
|
||||
set_icon(QIcon(":/icons/folder.png"));
|
||||
type = MEDIA_TYPE_FOLDER;
|
||||
object = nullptr;
|
||||
if (folder_name.isEmpty()) folder_name = QCoreApplication::translate("Media", "New Folder");
|
||||
set_icon(QIcon(":/icons/folder.png"));
|
||||
type = MEDIA_TYPE_FOLDER;
|
||||
object = nullptr;
|
||||
}
|
||||
|
||||
void Media::set_icon(const QIcon &ico) {
|
||||
icon = ico;
|
||||
icon = ico;
|
||||
}
|
||||
|
||||
void Media::set_parent(Media *p) {
|
||||
parent = p;
|
||||
parent = p;
|
||||
}
|
||||
|
||||
void Media::update_tooltip(const QString& error) {
|
||||
switch (type) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
FootagePtr f = to_footage();
|
||||
tooltip = QCoreApplication::translate("Media", "Name:") + " " + f->name + "\n" + QCoreApplication::translate("Media", "Filename:") + " " + f->url + "\n";
|
||||
switch (type) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
FootagePtr f = to_footage();
|
||||
tooltip = QCoreApplication::translate("Media", "Name:") + " " + f->name + "\n" + QCoreApplication::translate("Media", "Filename:") + " " + f->url + "\n";
|
||||
|
||||
if (error.isEmpty()) {
|
||||
if (f->video_tracks.size() > 0) {
|
||||
tooltip += QCoreApplication::translate("Media", "Video Dimensions:") + " ";
|
||||
for (int i=0;i<f->video_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
tooltip += QString::number(f->video_tracks.at(i).video_width) + "x" + QString::number(f->video_tracks.at(i).video_height);
|
||||
}
|
||||
tooltip += "\n";
|
||||
if (error.isEmpty()) {
|
||||
if (f->video_tracks.size() > 0) {
|
||||
tooltip += QCoreApplication::translate("Media", "Video Dimensions:") + " ";
|
||||
for (int i=0;i<f->video_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
tooltip += QString::number(f->video_tracks.at(i).video_width) + "x" + QString::number(f->video_tracks.at(i).video_height);
|
||||
}
|
||||
tooltip += "\n";
|
||||
|
||||
if (!f->video_tracks.at(0).infinite_length) {
|
||||
tooltip += QCoreApplication::translate("Media", "Frame Rate:") + " ";
|
||||
for (int i=0;i<f->video_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
if (f->video_tracks.at(i).video_interlacing == VIDEO_PROGRESSIVE) {
|
||||
tooltip += QString::number(f->video_tracks.at(i).video_frame_rate * f->speed);
|
||||
} else {
|
||||
double adjusted_rate = f->video_tracks.at(i).video_frame_rate * f->speed;
|
||||
if (!f->video_tracks.at(0).infinite_length) {
|
||||
tooltip += QCoreApplication::translate("Media", "Frame Rate:") + " ";
|
||||
for (int i=0;i<f->video_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
if (f->video_tracks.at(i).video_interlacing == VIDEO_PROGRESSIVE) {
|
||||
tooltip += QString::number(f->video_tracks.at(i).video_frame_rate * f->speed);
|
||||
} else {
|
||||
double adjusted_rate = f->video_tracks.at(i).video_frame_rate * f->speed;
|
||||
|
||||
tooltip += QCoreApplication::translate("Media", "%1 field(s) (%2 frame(s))").arg(
|
||||
QString::number(adjusted_rate*2.0),
|
||||
QString::number(adjusted_rate)
|
||||
);
|
||||
}
|
||||
}
|
||||
tooltip += "\n";
|
||||
}
|
||||
tooltip += QCoreApplication::translate("Media", "%1 field(s) (%2 frame(s))").arg(
|
||||
QString::number(adjusted_rate*2.0),
|
||||
QString::number(adjusted_rate)
|
||||
);
|
||||
}
|
||||
}
|
||||
tooltip += "\n";
|
||||
}
|
||||
|
||||
tooltip += QCoreApplication::translate("Media", "Interlacing:") + " ";
|
||||
for (int i=0;i<f->video_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
tooltip += get_interlacing_name(f->video_tracks.at(i).video_interlacing);
|
||||
}
|
||||
}
|
||||
tooltip += QCoreApplication::translate("Media", "Interlacing:") + " ";
|
||||
for (int i=0;i<f->video_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
tooltip += get_interlacing_name(f->video_tracks.at(i).video_interlacing);
|
||||
}
|
||||
}
|
||||
|
||||
if (f->audio_tracks.size() > 0) {
|
||||
tooltip += "\n";
|
||||
if (f->audio_tracks.size() > 0) {
|
||||
tooltip += "\n";
|
||||
|
||||
tooltip += QCoreApplication::translate("Media", "Audio Frequency:") + " ";
|
||||
for (int i=0;i<f->audio_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
tooltip += QString::number(f->audio_tracks.at(i).audio_frequency * f->speed);
|
||||
}
|
||||
tooltip += "\n";
|
||||
tooltip += QCoreApplication::translate("Media", "Audio Frequency:") + " ";
|
||||
for (int i=0;i<f->audio_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
tooltip += QString::number(f->audio_tracks.at(i).audio_frequency * f->speed);
|
||||
}
|
||||
tooltip += "\n";
|
||||
|
||||
tooltip += QCoreApplication::translate("Media", "Audio Channels:") + " ";
|
||||
for (int i=0;i<f->audio_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
tooltip += get_channel_layout_name(f->audio_tracks.at(i).audio_channels, f->audio_tracks.at(i).audio_layout);
|
||||
}
|
||||
// tooltip += "\n";
|
||||
}
|
||||
} else {
|
||||
tooltip += error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
{
|
||||
SequencePtr s = to_sequence();
|
||||
tooltip += QCoreApplication::translate("Media", "Audio Channels:") + " ";
|
||||
for (int i=0;i<f->audio_tracks.size();i++) {
|
||||
if (i > 0) {
|
||||
tooltip += ", ";
|
||||
}
|
||||
tooltip += get_channel_layout_name(f->audio_tracks.at(i).audio_channels, f->audio_tracks.at(i).audio_layout);
|
||||
}
|
||||
// tooltip += "\n";
|
||||
}
|
||||
} else {
|
||||
tooltip += error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
{
|
||||
SequencePtr s = to_sequence();
|
||||
|
||||
tooltip = QCoreApplication::translate("Media", "Name: %1"
|
||||
"\nVideo Dimensions: %2x%3"
|
||||
"\nFrame Rate: %4"
|
||||
"\nAudio Frequency: %5"
|
||||
"\nAudio Layout: %6").arg(
|
||||
s->name,
|
||||
QString::number(s->width),
|
||||
QString::number(s->height),
|
||||
QString::number(s->frame_rate),
|
||||
QString::number(s->audio_frequency),
|
||||
get_channel_layout_name(av_get_channel_layout_nb_channels(s->audio_layout), s->audio_layout)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
tooltip = QCoreApplication::translate("Media", "Name: %1"
|
||||
"\nVideo Dimensions: %2x%3"
|
||||
"\nFrame Rate: %4"
|
||||
"\nAudio Frequency: %5"
|
||||
"\nAudio Layout: %6").arg(
|
||||
s->name,
|
||||
QString::number(s->width),
|
||||
QString::number(s->height),
|
||||
QString::number(s->frame_rate),
|
||||
QString::number(s->audio_frequency),
|
||||
get_channel_layout_name(av_get_channel_layout_nb_channels(s->audio_layout), s->audio_layout)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VoidPtr Media::to_object() {
|
||||
return object;
|
||||
return object;
|
||||
}
|
||||
|
||||
int Media::get_type() {
|
||||
return type;
|
||||
return type;
|
||||
}
|
||||
|
||||
const QString &Media::get_name() {
|
||||
switch (type) {
|
||||
case MEDIA_TYPE_FOOTAGE: return to_footage()->name;
|
||||
case MEDIA_TYPE_SEQUENCE: return to_sequence()->name;
|
||||
default: return folder_name;
|
||||
}
|
||||
switch (type) {
|
||||
case MEDIA_TYPE_FOOTAGE: return to_footage()->name;
|
||||
case MEDIA_TYPE_SEQUENCE: return to_sequence()->name;
|
||||
default: return folder_name;
|
||||
}
|
||||
}
|
||||
|
||||
void Media::set_name(const QString &n) {
|
||||
switch (type) {
|
||||
case MEDIA_TYPE_FOOTAGE: to_footage()->name = n; break;
|
||||
case MEDIA_TYPE_SEQUENCE: to_sequence()->name = n; break;
|
||||
case MEDIA_TYPE_FOLDER: folder_name = n; break;
|
||||
}
|
||||
switch (type) {
|
||||
case MEDIA_TYPE_FOOTAGE: to_footage()->name = n; break;
|
||||
case MEDIA_TYPE_SEQUENCE: to_sequence()->name = n; break;
|
||||
case MEDIA_TYPE_FOLDER: folder_name = n; break;
|
||||
}
|
||||
}
|
||||
|
||||
double Media::get_frame_rate(int stream) {
|
||||
switch (get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
FootagePtr f = to_footage();
|
||||
if (stream < 0) return f->video_tracks.at(0).video_frame_rate * f->speed;
|
||||
return f->get_stream_from_file_index(true, stream)->video_frame_rate * f->speed;
|
||||
}
|
||||
case MEDIA_TYPE_SEQUENCE: return to_sequence()->frame_rate;
|
||||
}
|
||||
return 0;
|
||||
switch (get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
FootagePtr f = to_footage();
|
||||
if (stream < 0) return f->video_tracks.at(0).video_frame_rate * f->speed;
|
||||
return f->get_stream_from_file_index(true, stream)->video_frame_rate * f->speed;
|
||||
}
|
||||
case MEDIA_TYPE_SEQUENCE: return to_sequence()->frame_rate;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Media::get_sampling_rate(int stream) {
|
||||
switch (get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
FootagePtr f = to_footage();
|
||||
if (stream < 0) return f->audio_tracks.at(0).audio_frequency * f->speed;
|
||||
return to_footage()->get_stream_from_file_index(false, stream)->audio_frequency * f->speed;
|
||||
}
|
||||
case MEDIA_TYPE_SEQUENCE: return to_sequence()->audio_frequency;
|
||||
}
|
||||
return 0;
|
||||
switch (get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
FootagePtr f = to_footage();
|
||||
if (stream < 0) return f->audio_tracks.at(0).audio_frequency * f->speed;
|
||||
return to_footage()->get_stream_from_file_index(false, stream)->audio_frequency * f->speed;
|
||||
}
|
||||
case MEDIA_TYPE_SEQUENCE: return to_sequence()->audio_frequency;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Media::appendChild(Media *child) {
|
||||
child->set_parent(this);
|
||||
children.append(child);
|
||||
child->set_parent(this);
|
||||
children.append(child);
|
||||
}
|
||||
|
||||
bool Media::setData(int col, const QVariant &value) {
|
||||
if (col == 0) {
|
||||
QString n = value.toString();
|
||||
if (!n.isEmpty() && get_name() != n) {
|
||||
olive::UndoStack.push(new MediaRename(this, value.toString()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (col == 0) {
|
||||
QString n = value.toString();
|
||||
if (!n.isEmpty() && get_name() != n) {
|
||||
olive::UndoStack.push(new MediaRename(this, value.toString()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Media *Media::child(int row) {
|
||||
return children.value(row);
|
||||
return children.value(row);
|
||||
}
|
||||
|
||||
int Media::childCount() const {
|
||||
return children.count();
|
||||
return children.count();
|
||||
}
|
||||
|
||||
int Media::columnCount() const {
|
||||
return 3;
|
||||
return 3;
|
||||
}
|
||||
|
||||
QVariant Media::data(int column, int role) {
|
||||
switch (role) {
|
||||
case Qt::DecorationRole:
|
||||
if (column == 0) {
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
FootagePtr f = to_footage();
|
||||
if (f->video_tracks.size() > 0
|
||||
&& f->video_tracks.at(0).preview_done) {
|
||||
return f->video_tracks.at(0).video_preview_square;
|
||||
}
|
||||
}
|
||||
switch (role) {
|
||||
case Qt::DecorationRole:
|
||||
if (column == 0) {
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
FootagePtr f = to_footage();
|
||||
if (f->video_tracks.size() > 0
|
||||
&& f->video_tracks.at(0).preview_done) {
|
||||
return f->video_tracks.at(0).video_preview_square;
|
||||
}
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
break;
|
||||
case Qt::DisplayRole:
|
||||
switch (column) {
|
||||
case 0: return (root) ? QCoreApplication::translate("Media", "Name") : get_name();
|
||||
case 1:
|
||||
if (root) return QCoreApplication::translate("Media", "Duration");
|
||||
if (get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
SequencePtr s = to_sequence();
|
||||
return frame_to_timecode(s->getEndFrame(), olive::CurrentConfig.timecode_view, s->frame_rate);
|
||||
}
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
FootagePtr f = to_footage();
|
||||
double r = 30;
|
||||
return icon;
|
||||
}
|
||||
break;
|
||||
case Qt::DisplayRole:
|
||||
switch (column) {
|
||||
case 0: return (root) ? QCoreApplication::translate("Media", "Name") : get_name();
|
||||
case 1:
|
||||
if (root) return QCoreApplication::translate("Media", "Duration");
|
||||
if (get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
SequencePtr s = to_sequence();
|
||||
return frame_to_timecode(s->getEndFrame(), olive::CurrentConfig.timecode_view, s->frame_rate);
|
||||
}
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
FootagePtr f = to_footage();
|
||||
double r = 30;
|
||||
|
||||
if (f->video_tracks.size() > 0 && !qIsNull(f->video_tracks.at(0).video_frame_rate))
|
||||
r = f->video_tracks.at(0).video_frame_rate * f->speed;
|
||||
if (f->video_tracks.size() > 0 && !qIsNull(f->video_tracks.at(0).video_frame_rate))
|
||||
r = f->video_tracks.at(0).video_frame_rate * f->speed;
|
||||
|
||||
long len = f->get_length_in_frames(r);
|
||||
if (len > 0) return frame_to_timecode(len, olive::CurrentConfig.timecode_view, r);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (root) return QCoreApplication::translate("Media", "Rate");
|
||||
if (get_type() == MEDIA_TYPE_SEQUENCE) return QString::number(get_frame_rate()) + " FPS";
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
FootagePtr f = to_footage();
|
||||
double r;
|
||||
if (f->video_tracks.size() > 0 && !qIsNull(r = get_frame_rate())) {
|
||||
return QString::number(get_frame_rate()) + " FPS";
|
||||
} else if (f->audio_tracks.size() > 0) {
|
||||
return QString::number(get_sampling_rate()) + " Hz";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Qt::ToolTipRole:
|
||||
return tooltip;
|
||||
}
|
||||
return QVariant();
|
||||
long len = f->get_length_in_frames(r);
|
||||
if (len > 0) return frame_to_timecode(len, olive::CurrentConfig.timecode_view, r);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (root) return QCoreApplication::translate("Media", "Rate");
|
||||
if (get_type() == MEDIA_TYPE_SEQUENCE) return QString::number(get_frame_rate()) + " FPS";
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
FootagePtr f = to_footage();
|
||||
double r;
|
||||
if (f->video_tracks.size() > 0 && !qIsNull(r = get_frame_rate())) {
|
||||
return QString::number(get_frame_rate()) + " FPS";
|
||||
} else if (f->audio_tracks.size() > 0) {
|
||||
return QString::number(get_sampling_rate()) + " Hz";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Qt::ToolTipRole:
|
||||
return tooltip;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int Media::row() const {
|
||||
if (parent) {
|
||||
return parent->children.indexOf(const_cast<Media*>(this));
|
||||
}
|
||||
return 0;
|
||||
if (parent) {
|
||||
return parent->children.indexOf(const_cast<Media*>(this));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Media *Media::parentItem() {
|
||||
return parent;
|
||||
return parent;
|
||||
}
|
||||
|
||||
void Media::removeChild(int i) {
|
||||
children.removeAt(i);
|
||||
children.removeAt(i);
|
||||
}
|
||||
|
||||
QVector<Marker> &Media::get_markers() {
|
||||
// returns the marker array from the internal object
|
||||
//
|
||||
// NOTE: if this media object is not footage or a sequence, the result is
|
||||
// undefined - most likely a crash
|
||||
// returns the marker array from the internal object
|
||||
//
|
||||
// NOTE: if this media object is not footage or a sequence, the result is
|
||||
// undefined - most likely a crash
|
||||
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
return to_footage()->markers;
|
||||
} else {
|
||||
return to_sequence()->markers;
|
||||
}
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
return to_footage()->markers;
|
||||
} else {
|
||||
return to_sequence()->markers;
|
||||
}
|
||||
}
|
||||
|
||||
+42
-42
@@ -29,9 +29,9 @@
|
||||
#include "project/footage.h"
|
||||
|
||||
enum MediaType {
|
||||
MEDIA_TYPE_FOOTAGE,
|
||||
MEDIA_TYPE_SEQUENCE,
|
||||
MEDIA_TYPE_FOLDER
|
||||
MEDIA_TYPE_FOOTAGE,
|
||||
MEDIA_TYPE_SEQUENCE,
|
||||
MEDIA_TYPE_FOLDER
|
||||
};
|
||||
|
||||
class Sequence;
|
||||
@@ -42,51 +42,51 @@ using VoidPtr = std::shared_ptr<void>;
|
||||
class Media
|
||||
{
|
||||
public:
|
||||
Media(Media* iparent);
|
||||
~Media();
|
||||
FootagePtr to_footage();
|
||||
SequencePtr to_sequence();
|
||||
void set_footage(FootagePtr f);
|
||||
void set_sequence(SequencePtr s);
|
||||
void set_folder();
|
||||
void set_icon(const QIcon &ico);
|
||||
void set_parent(Media* p);
|
||||
void update_tooltip(const QString& error = 0);
|
||||
VoidPtr to_object();
|
||||
int get_type();
|
||||
const QString& get_name();
|
||||
void set_name(const QString& n);
|
||||
Media(Media* iparent);
|
||||
~Media();
|
||||
FootagePtr to_footage();
|
||||
SequencePtr to_sequence();
|
||||
void set_footage(FootagePtr f);
|
||||
void set_sequence(SequencePtr s);
|
||||
void set_folder();
|
||||
void set_icon(const QIcon &ico);
|
||||
void set_parent(Media* p);
|
||||
void update_tooltip(const QString& error = 0);
|
||||
VoidPtr to_object();
|
||||
int get_type();
|
||||
const QString& get_name();
|
||||
void set_name(const QString& n);
|
||||
|
||||
double get_frame_rate(int stream = -1);
|
||||
int get_sampling_rate(int stream = -1);
|
||||
double get_frame_rate(int stream = -1);
|
||||
int get_sampling_rate(int stream = -1);
|
||||
|
||||
// item functions
|
||||
void appendChild(Media *child);
|
||||
bool setData(int col, const QVariant &value);
|
||||
Media *child(int row);
|
||||
int childCount() const;
|
||||
int columnCount() const;
|
||||
QVariant data(int column, int role);
|
||||
int row() const;
|
||||
Media *parentItem();
|
||||
void removeChild(int i);
|
||||
// item functions
|
||||
void appendChild(Media *child);
|
||||
bool setData(int col, const QVariant &value);
|
||||
Media *child(int row);
|
||||
int childCount() const;
|
||||
int columnCount() const;
|
||||
QVariant data(int column, int role);
|
||||
int row() const;
|
||||
Media *parentItem();
|
||||
void removeChild(int i);
|
||||
|
||||
// get markers from internal object
|
||||
QVector<Marker>& get_markers();
|
||||
// get markers from internal object
|
||||
QVector<Marker>& get_markers();
|
||||
|
||||
bool root;
|
||||
int temp_id;
|
||||
int temp_id2;
|
||||
bool root;
|
||||
int temp_id;
|
||||
int temp_id2;
|
||||
private:
|
||||
int type;
|
||||
VoidPtr object;
|
||||
int type;
|
||||
VoidPtr object;
|
||||
|
||||
// item functions
|
||||
QList<Media*> children;
|
||||
Media* parent;
|
||||
QString folder_name;
|
||||
QString tooltip;
|
||||
QIcon icon;
|
||||
// item functions
|
||||
QList<Media*> children;
|
||||
Media* parent;
|
||||
QString folder_name;
|
||||
QString tooltip;
|
||||
QIcon icon;
|
||||
};
|
||||
|
||||
#endif // MEDIA_H
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
#ifndef PROJECTELEMENTS_H
|
||||
#define PROJECTELEMENTS_H
|
||||
|
||||
/**
|
||||
|
||||
Simple header to include all classes used for an Olive project file
|
||||
|
||||
*/
|
||||
|
||||
// includes elements the user can use in a project
|
||||
#include "media.h"
|
||||
#include "footage.h"
|
||||
|
||||
+47
-46
@@ -25,45 +25,45 @@
|
||||
#include "debug.h"
|
||||
|
||||
Sequence::Sequence() {
|
||||
playhead = 0;
|
||||
using_workarea = false;
|
||||
workarea_in = 0;
|
||||
workarea_out = 0;
|
||||
wrapper_sequence = false;
|
||||
playhead = 0;
|
||||
using_workarea = false;
|
||||
workarea_in = 0;
|
||||
workarea_out = 0;
|
||||
wrapper_sequence = false;
|
||||
}
|
||||
|
||||
Sequence::~Sequence() {}
|
||||
|
||||
SequencePtr Sequence::copy() {
|
||||
SequencePtr s(new Sequence());
|
||||
s->name = QCoreApplication::translate("Sequence", "%1 (copy)").arg(name);
|
||||
s->width = width;
|
||||
s->height = height;
|
||||
s->frame_rate = frame_rate;
|
||||
s->audio_frequency = audio_frequency;
|
||||
s->audio_layout = audio_layout;
|
||||
s->clips.resize(clips.size());
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
ClipPtr c = clips.at(i);
|
||||
if (c == nullptr) {
|
||||
s->clips[i] = nullptr;
|
||||
} else {
|
||||
ClipPtr copy = c->copy(s);
|
||||
copy->linked = c->linked;
|
||||
s->clips[i] = copy;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
SequencePtr s(new Sequence());
|
||||
s->name = QCoreApplication::translate("Sequence", "%1 (copy)").arg(name);
|
||||
s->width = width;
|
||||
s->height = height;
|
||||
s->frame_rate = frame_rate;
|
||||
s->audio_frequency = audio_frequency;
|
||||
s->audio_layout = audio_layout;
|
||||
s->clips.resize(clips.size());
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
ClipPtr c = clips.at(i);
|
||||
if (c == nullptr) {
|
||||
s->clips[i] = nullptr;
|
||||
} else {
|
||||
ClipPtr copy = c->copy(s);
|
||||
copy->linked = c->linked;
|
||||
s->clips[i] = copy;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
long Sequence::getEndFrame() {
|
||||
long end = 0;
|
||||
for (int j=0;j<clips.size();j++) {
|
||||
ClipPtr c = clips.at(j);
|
||||
if (c != nullptr && c->timeline_out > end) {
|
||||
end = c->timeline_out;
|
||||
}
|
||||
}
|
||||
long end = 0;
|
||||
for (int j=0;j<clips.size();j++) {
|
||||
ClipPtr c = clips.at(j);
|
||||
if (c != nullptr && c->timeline_out() > end) {
|
||||
end = c->timeline_out();
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
@@ -72,27 +72,28 @@ void Sequence::RefreshClips(Media *m) {
|
||||
ClipPtr c = clips.at(i);
|
||||
|
||||
if (c != nullptr
|
||||
&& (m == nullptr || c->media == m)) {
|
||||
&& (m == nullptr || c->media() == m)) {
|
||||
c->Close(true);
|
||||
c->refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sequence::getTrackLimits(int* video_tracks, int* audio_tracks) {
|
||||
int vt = 0;
|
||||
int at = 0;
|
||||
for (int j=0;j<clips.size();j++) {
|
||||
ClipPtr c = clips.at(j);
|
||||
if (c != nullptr) {
|
||||
if (c->track < 0 && c->track < vt) { // video clip
|
||||
vt = c->track;
|
||||
} else if (c->track > at) {
|
||||
at = c->track;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (video_tracks != nullptr) *video_tracks = vt;
|
||||
if (audio_tracks != nullptr) *audio_tracks = at;
|
||||
int vt = 0;
|
||||
int at = 0;
|
||||
for (int j=0;j<clips.size();j++) {
|
||||
ClipPtr c = clips.at(j);
|
||||
if (c != nullptr) {
|
||||
if (c->track() < 0 && c->track() < vt) { // video clip
|
||||
vt = c->track();
|
||||
} else if (c->track() > at) {
|
||||
at = c->track();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (video_tracks != nullptr) *video_tracks = vt;
|
||||
if (audio_tracks != nullptr) *audio_tracks = at;
|
||||
}
|
||||
|
||||
// static variable for the currently active sequence
|
||||
|
||||
+279
-276
@@ -23,7 +23,7 @@
|
||||
#include "panels/panels.h"
|
||||
#include "project/media.h"
|
||||
#include "project/undo.h"
|
||||
#include "playback/playback.h"
|
||||
#include "rendering/renderfunctions.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "panels/project.h"
|
||||
#include "project/footage.h"
|
||||
@@ -47,173 +47,176 @@
|
||||
#include <QDebug>
|
||||
|
||||
SourcesCommon::SourcesCommon(Project* parent) :
|
||||
editing_item(nullptr),
|
||||
project_parent(parent)
|
||||
editing_item(nullptr),
|
||||
project_parent(parent)
|
||||
{
|
||||
rename_timer.setInterval(1000);
|
||||
connect(&rename_timer, SIGNAL(timeout()), this, SLOT(rename_interval()));
|
||||
rename_timer.setInterval(1000);
|
||||
connect(&rename_timer, SIGNAL(timeout()), this, SLOT(rename_interval()));
|
||||
}
|
||||
|
||||
void SourcesCommon::create_seq_from_selected() {
|
||||
if (!selected_items.isEmpty()) {
|
||||
QVector<Media*> media_list;
|
||||
for (int i=0;i<selected_items.size();i++) {
|
||||
media_list.append(project_parent->item_to_media(selected_items.at(i)));
|
||||
}
|
||||
if (!selected_items.isEmpty()) {
|
||||
QVector<Media*> media_list;
|
||||
for (int i=0;i<selected_items.size();i++) {
|
||||
media_list.append(project_parent->item_to_media(selected_items.at(i)));
|
||||
}
|
||||
|
||||
ComboAction* ca = new ComboAction();
|
||||
SequencePtr s = create_sequence_from_media(media_list);
|
||||
ComboAction* ca = new ComboAction();
|
||||
SequencePtr s = create_sequence_from_media(media_list);
|
||||
|
||||
// add clips to it
|
||||
panel_timeline->create_ghosts_from_media(s, 0, media_list);
|
||||
panel_timeline->add_clips_from_ghosts(ca, s);
|
||||
// add clips to it
|
||||
panel_timeline->create_ghosts_from_media(s, 0, media_list);
|
||||
panel_timeline->add_clips_from_ghosts(ca, s);
|
||||
|
||||
project_parent->create_sequence_internal(ca, s, true, nullptr);
|
||||
olive::UndoStack.push(ca);
|
||||
}
|
||||
project_parent->create_sequence_internal(ca, s, true, nullptr);
|
||||
olive::UndoStack.push(ca);
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::show_context_menu(QWidget* parent, const QModelIndexList& items) {
|
||||
QMenu menu(parent);
|
||||
QMenu menu(parent);
|
||||
|
||||
selected_items = items;
|
||||
selected_items = items;
|
||||
|
||||
QAction* import_action = menu.addAction(tr("Import..."));
|
||||
QObject::connect(import_action, SIGNAL(triggered(bool)), project_parent, SLOT(import_dialog()));
|
||||
QAction* import_action = menu.addAction(tr("Import..."));
|
||||
QObject::connect(import_action, SIGNAL(triggered(bool)), project_parent, SLOT(import_dialog()));
|
||||
|
||||
QMenu* new_menu = menu.addMenu(tr("New"));
|
||||
olive::MenuHelper.make_new_menu(new_menu);
|
||||
QMenu* new_menu = menu.addMenu(tr("New"));
|
||||
olive::MenuHelper.make_new_menu(new_menu);
|
||||
|
||||
QMenu* view_menu = menu.addMenu(tr("View"));
|
||||
QMenu* view_menu = menu.addMenu(tr("View"));
|
||||
|
||||
QAction* tree_view_action = view_menu->addAction(tr("Tree View"));
|
||||
connect(tree_view_action, SIGNAL(triggered(bool)), project_parent, SLOT(set_tree_view()));
|
||||
QAction* tree_view_action = view_menu->addAction(tr("Tree View"));
|
||||
connect(tree_view_action, SIGNAL(triggered(bool)), project_parent, SLOT(set_tree_view()));
|
||||
|
||||
QAction* icon_view_action = view_menu->addAction(tr("Icon View"));
|
||||
connect(icon_view_action, SIGNAL(triggered(bool)), project_parent, SLOT(set_icon_view()));
|
||||
QAction* icon_view_action = view_menu->addAction(tr("Icon View"));
|
||||
connect(icon_view_action, SIGNAL(triggered(bool)), project_parent, SLOT(set_icon_view()));
|
||||
|
||||
QAction* toolbar_action = view_menu->addAction(tr("Show Toolbar"));
|
||||
toolbar_action->setCheckable(true);
|
||||
toolbar_action->setChecked(project_parent->toolbar_widget->isVisible());
|
||||
connect(toolbar_action, SIGNAL(triggered(bool)), project_parent->toolbar_widget, SLOT(setVisible(bool)));
|
||||
QAction* toolbar_action = view_menu->addAction(tr("Show Toolbar"));
|
||||
toolbar_action->setCheckable(true);
|
||||
toolbar_action->setChecked(project_parent->toolbar_widget->isVisible());
|
||||
connect(toolbar_action, SIGNAL(triggered(bool)), project_parent->toolbar_widget, SLOT(setVisible(bool)));
|
||||
|
||||
QAction* show_sequences = view_menu->addAction(tr("Show Sequences"));
|
||||
show_sequences->setCheckable(true);
|
||||
show_sequences->setChecked(panel_project->sorter->get_show_sequences());
|
||||
connect(show_sequences, SIGNAL(triggered(bool)), panel_project->sorter, SLOT(set_show_sequences(bool)));
|
||||
QAction* show_sequences = view_menu->addAction(tr("Show Sequences"));
|
||||
show_sequences->setCheckable(true);
|
||||
show_sequences->setChecked(panel_project->sorter->get_show_sequences());
|
||||
connect(show_sequences, SIGNAL(triggered(bool)), panel_project->sorter, SLOT(set_show_sequences(bool)));
|
||||
|
||||
if (items.size() > 0) {
|
||||
if (items.size() == 1) {
|
||||
Media* first_media = project_parent->item_to_media(items.at(0));
|
||||
if (items.size() > 0) {
|
||||
if (items.size() == 1) {
|
||||
Media* first_media = project_parent->item_to_media(items.at(0));
|
||||
|
||||
// replace footage
|
||||
int type = first_media->get_type();
|
||||
if (type == MEDIA_TYPE_FOOTAGE) {
|
||||
QAction* replace_action = menu.addAction(tr("Replace/Relink Media"));
|
||||
QObject::connect(replace_action, SIGNAL(triggered(bool)), project_parent, SLOT(replace_selected_file()));
|
||||
// replace footage
|
||||
int type = first_media->get_type();
|
||||
if (type == MEDIA_TYPE_FOOTAGE) {
|
||||
QAction* replace_action = menu.addAction(tr("Replace/Relink Media"));
|
||||
QObject::connect(replace_action, SIGNAL(triggered(bool)), project_parent, SLOT(replace_selected_file()));
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
QAction* reveal_in_explorer = menu.addAction(tr("Reveal in Explorer"));
|
||||
QAction* reveal_in_explorer = menu.addAction(tr("Reveal in Explorer"));
|
||||
#elif defined(Q_OS_MAC)
|
||||
QAction* reveal_in_explorer = menu.addAction(tr("Reveal in Finder"));
|
||||
QAction* reveal_in_explorer = menu.addAction(tr("Reveal in Finder"));
|
||||
#else
|
||||
QAction* reveal_in_explorer = menu.addAction(tr("Reveal in File Manager"));
|
||||
QAction* reveal_in_explorer = menu.addAction(tr("Reveal in File Manager"));
|
||||
#endif
|
||||
QObject::connect(reveal_in_explorer, SIGNAL(triggered(bool)), this, SLOT(reveal_in_browser()));
|
||||
}
|
||||
if (type != MEDIA_TYPE_FOLDER) {
|
||||
QAction* replace_clip_media = menu.addAction(tr("Replace Clips Using This Media"));
|
||||
QObject::connect(replace_clip_media, SIGNAL(triggered(bool)), project_parent, SLOT(replace_clip_media()));
|
||||
}
|
||||
}
|
||||
QObject::connect(reveal_in_explorer, SIGNAL(triggered(bool)), this, SLOT(reveal_in_browser()));
|
||||
}
|
||||
if (type != MEDIA_TYPE_FOLDER) {
|
||||
QAction* replace_clip_media = menu.addAction(tr("Replace Clips Using This Media"));
|
||||
QObject::connect(replace_clip_media, SIGNAL(triggered(bool)), project_parent, SLOT(replace_clip_media()));
|
||||
}
|
||||
}
|
||||
|
||||
// analyze selected footage types
|
||||
bool all_sequences = true;
|
||||
bool all_footage = true;
|
||||
// analyze selected footage types
|
||||
bool all_sequences = true;
|
||||
bool all_footage = true;
|
||||
|
||||
cached_selected_footage.clear();
|
||||
for (int i=0;i<items.size();i++) {
|
||||
Media* m = project_parent->item_to_media(items.at(i));
|
||||
if (m->get_type() != MEDIA_TYPE_SEQUENCE) {
|
||||
all_sequences = false;
|
||||
}
|
||||
if (m->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
cached_selected_footage.append(m->to_footage());
|
||||
} else {
|
||||
all_footage = false;
|
||||
}
|
||||
}
|
||||
cached_selected_footage.clear();
|
||||
for (int i=0;i<items.size();i++) {
|
||||
Media* m = project_parent->item_to_media(items.at(i));
|
||||
if (m->get_type() != MEDIA_TYPE_SEQUENCE) {
|
||||
all_sequences = false;
|
||||
}
|
||||
if (m->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
cached_selected_footage.append(m);
|
||||
} else {
|
||||
all_footage = false;
|
||||
}
|
||||
}
|
||||
|
||||
// create sequence from
|
||||
QAction* create_seq_from = menu.addAction(tr("Create Sequence With This Media"));
|
||||
QObject::connect(create_seq_from, SIGNAL(triggered(bool)), this, SLOT(create_seq_from_selected()));
|
||||
// create sequence from
|
||||
QAction* create_seq_from = menu.addAction(tr("Create Sequence With This Media"));
|
||||
QObject::connect(create_seq_from, SIGNAL(triggered(bool)), this, SLOT(create_seq_from_selected()));
|
||||
|
||||
// ONLY sequences are selected
|
||||
if (all_sequences) {
|
||||
// ONLY sequences are selected
|
||||
QAction* duplicate_action = menu.addAction(tr("Duplicate"));
|
||||
QObject::connect(duplicate_action, SIGNAL(triggered(bool)), project_parent, SLOT(duplicate_selected()));
|
||||
}
|
||||
// ONLY sequences are selected
|
||||
if (all_sequences) {
|
||||
// ONLY sequences are selected
|
||||
QAction* duplicate_action = menu.addAction(tr("Duplicate"));
|
||||
QObject::connect(duplicate_action, SIGNAL(triggered(bool)), project_parent, SLOT(duplicate_selected()));
|
||||
}
|
||||
|
||||
// ONLY footage is selected
|
||||
if (all_footage) {
|
||||
QAction* delete_footage_from_sequences = menu.addAction(tr("Delete All Clips Using This Media"));
|
||||
QObject::connect(delete_footage_from_sequences, SIGNAL(triggered(bool)), project_parent, SLOT(delete_clips_using_selected_media()));
|
||||
// ONLY footage is selected
|
||||
if (all_footage) {
|
||||
QAction* delete_footage_from_sequences = menu.addAction(tr("Delete All Clips Using This Media"));
|
||||
QObject::connect(delete_footage_from_sequences, SIGNAL(triggered(bool)), project_parent, SLOT(delete_clips_using_selected_media()));
|
||||
|
||||
QMenu* proxies = menu.addMenu(tr("Proxy"));
|
||||
QMenu* proxies = menu.addMenu(tr("Proxy"));
|
||||
|
||||
// special case if one footage item is selected and its proxy is currently being generated
|
||||
if (cached_selected_footage.size() == 1
|
||||
&& cached_selected_footage.at(0)->proxy
|
||||
&& cached_selected_footage.at(0)->proxy_path.isEmpty()) {
|
||||
QAction* action = proxies->addAction(tr("Generating proxy: %1% complete").arg(proxy_generator.get_proxy_progress(cached_selected_footage.at(0))));
|
||||
action->setEnabled(false);
|
||||
} else {
|
||||
// determine whether any selected footage has or doesn't have proxies
|
||||
bool footage_without_proxies_exists = false;
|
||||
bool footage_with_proxies_exists = false;
|
||||
// special case if one footage item is selected and its proxy is currently being generated
|
||||
if (cached_selected_footage.size() == 1
|
||||
&& cached_selected_footage.at(0)->to_footage()->proxy
|
||||
&& cached_selected_footage.at(0)->to_footage()->proxy_path.isEmpty()) {
|
||||
QAction* action = proxies->addAction(tr("Generating proxy: %1% complete").arg(
|
||||
olive::proxy_generator.get_proxy_progress(cached_selected_footage.at(0))
|
||||
)
|
||||
);
|
||||
action->setEnabled(false);
|
||||
} else {
|
||||
// determine whether any selected footage has or doesn't have proxies
|
||||
bool footage_without_proxies_exists = false;
|
||||
bool footage_with_proxies_exists = false;
|
||||
|
||||
for (int i=0;i<cached_selected_footage.size();i++) {
|
||||
if (cached_selected_footage.at(i)->proxy) {
|
||||
footage_with_proxies_exists = true;
|
||||
} else {
|
||||
footage_without_proxies_exists = true;
|
||||
}
|
||||
}
|
||||
for (int i=0;i<cached_selected_footage.size();i++) {
|
||||
if (cached_selected_footage.at(i)->to_footage()->proxy) {
|
||||
footage_with_proxies_exists = true;
|
||||
} else {
|
||||
footage_without_proxies_exists = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if footage was selected WITHOUT proxies
|
||||
if (footage_without_proxies_exists) {
|
||||
QString create_proxy_text;
|
||||
// if footage was selected WITHOUT proxies
|
||||
if (footage_without_proxies_exists) {
|
||||
QString create_proxy_text;
|
||||
|
||||
if (footage_with_proxies_exists) {
|
||||
// some of the footage already has proxies, so we use a different string
|
||||
create_proxy_text = tr("Create/Modify Proxy");
|
||||
} else {
|
||||
// none of the footage has proxies
|
||||
create_proxy_text = tr("Create Proxy");
|
||||
}
|
||||
if (footage_with_proxies_exists) {
|
||||
// some of the footage already has proxies, so we use a different string
|
||||
create_proxy_text = tr("Create/Modify Proxy");
|
||||
} else {
|
||||
// none of the footage has proxies
|
||||
create_proxy_text = tr("Create Proxy");
|
||||
}
|
||||
|
||||
proxies->addAction(create_proxy_text, this, SLOT(open_create_proxy_dialog()));
|
||||
}
|
||||
proxies->addAction(create_proxy_text, this, SLOT(open_create_proxy_dialog()));
|
||||
}
|
||||
|
||||
// if footage was selected WITH proxies
|
||||
if (footage_with_proxies_exists) {
|
||||
// if footage was selected WITH proxies
|
||||
if (footage_with_proxies_exists) {
|
||||
|
||||
if (!footage_without_proxies_exists) {
|
||||
// if all the footage has proxies, we didn't make a "Create/Modify" above, so we create one here (but only "modify")
|
||||
proxies->addAction(tr("Modify Proxy"), this, SLOT(open_create_proxy_dialog()));
|
||||
}
|
||||
if (!footage_without_proxies_exists) {
|
||||
// if all the footage has proxies, we didn't make a "Create/Modify" above, so we create one here (but only "modify")
|
||||
proxies->addAction(tr("Modify Proxy"), this, SLOT(open_create_proxy_dialog()));
|
||||
}
|
||||
|
||||
proxies->addAction(tr("Restore Original"), this, SLOT(clear_proxies_from_selected()));
|
||||
}
|
||||
}
|
||||
}
|
||||
proxies->addAction(tr("Restore Original"), this, SLOT(clear_proxies_from_selected()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete media
|
||||
QAction* delete_action = menu.addAction(tr("Delete"));
|
||||
QObject::connect(delete_action, SIGNAL(triggered(bool)), project_parent, SLOT(delete_selected_media()));
|
||||
// delete media
|
||||
QAction* delete_action = menu.addAction(tr("Delete"));
|
||||
QObject::connect(delete_action, SIGNAL(triggered(bool)), project_parent, SLOT(delete_selected_media()));
|
||||
|
||||
if (items.size() == 1) {
|
||||
if (items.size() == 1) {
|
||||
Media* media_item = project_parent->item_to_media(items.at(0));
|
||||
|
||||
if (media_item->get_type() != MEDIA_TYPE_FOLDER) {
|
||||
@@ -223,160 +226,160 @@ void SourcesCommon::show_context_menu(QWidget* parent, const QModelIndexList& it
|
||||
preview_in_media_viewer_action->setData(reinterpret_cast<quintptr>(media_item));
|
||||
}
|
||||
|
||||
QAction* properties_action = menu.addAction(tr("Properties..."));
|
||||
QObject::connect(properties_action, SIGNAL(triggered(bool)), project_parent, SLOT(open_properties()));
|
||||
}
|
||||
}
|
||||
QAction* properties_action = menu.addAction(tr("Properties..."));
|
||||
QObject::connect(properties_action, SIGNAL(triggered(bool)), project_parent, SLOT(open_properties()));
|
||||
}
|
||||
}
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void SourcesCommon::mousePressEvent(QMouseEvent *) {
|
||||
stop_rename_timer();
|
||||
stop_rename_timer();
|
||||
}
|
||||
|
||||
void SourcesCommon::item_click(Media *m, const QModelIndex& index) {
|
||||
if (editing_item == m) {
|
||||
rename_timer.start();
|
||||
} else {
|
||||
editing_item = m;
|
||||
editing_index = index;
|
||||
}
|
||||
if (editing_item == m) {
|
||||
rename_timer.start();
|
||||
} else {
|
||||
editing_item = m;
|
||||
editing_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::mouseDoubleClickEvent(const QModelIndexList& selected_items) {
|
||||
stop_rename_timer();
|
||||
if (selected_items.size() == 0) {
|
||||
project_parent->import_dialog();
|
||||
} else if (selected_items.size() == 1) {
|
||||
stop_rename_timer();
|
||||
if (selected_items.size() == 0) {
|
||||
project_parent->import_dialog();
|
||||
} else if (selected_items.size() == 1) {
|
||||
Media* media = project_parent->item_to_media(selected_items.at(0));
|
||||
if (media->get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
olive::UndoStack.push(new ChangeSequenceAction(media->to_sequence()));
|
||||
} else {
|
||||
OpenSelectedMediaInMediaViewer(project_parent->item_to_media(selected_items.at(0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::dropEvent(QWidget* parent, QDropEvent *event, const QModelIndex& drop_item, const QModelIndexList& items) {
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
Media* m = project_parent->item_to_media(drop_item);
|
||||
if (mimeData->hasUrls()) {
|
||||
// drag files in from outside
|
||||
QList<QUrl> urls = mimeData->urls();
|
||||
if (!urls.isEmpty()) {
|
||||
QStringList paths;
|
||||
for (int i=0;i<urls.size();i++) {
|
||||
paths.append(urls.at(i).toLocalFile());
|
||||
}
|
||||
bool replace = false;
|
||||
if (urls.size() == 1
|
||||
&& drop_item.isValid()
|
||||
&& m->get_type() == MEDIA_TYPE_FOOTAGE
|
||||
&& !QFileInfo(paths.at(0)).isDir()
|
||||
&& olive::CurrentConfig.drop_on_media_to_replace
|
||||
&& QMessageBox::question(
|
||||
parent,
|
||||
tr("Replace Media"),
|
||||
tr("You dropped a file onto '%1'. Would you like to replace it with the dropped file?").arg(m->get_name()),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
|
||||
replace = true;
|
||||
project_parent->replace_media(m, paths.at(0));
|
||||
}
|
||||
if (!replace) {
|
||||
QModelIndex parent;
|
||||
if (drop_item.isValid()) {
|
||||
if (m->get_type() == MEDIA_TYPE_FOLDER) {
|
||||
parent = drop_item;
|
||||
} else {
|
||||
parent = drop_item.parent();
|
||||
}
|
||||
}
|
||||
project_parent->process_file_list(paths, false, nullptr, panel_project->item_to_media(parent));
|
||||
}
|
||||
}
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
event->ignore();
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
Media* m = project_parent->item_to_media(drop_item);
|
||||
if (mimeData->hasUrls()) {
|
||||
// drag files in from outside
|
||||
QList<QUrl> urls = mimeData->urls();
|
||||
if (!urls.isEmpty()) {
|
||||
QStringList paths;
|
||||
for (int i=0;i<urls.size();i++) {
|
||||
paths.append(urls.at(i).toLocalFile());
|
||||
}
|
||||
bool replace = false;
|
||||
if (urls.size() == 1
|
||||
&& drop_item.isValid()
|
||||
&& m->get_type() == MEDIA_TYPE_FOOTAGE
|
||||
&& !QFileInfo(paths.at(0)).isDir()
|
||||
&& olive::CurrentConfig.drop_on_media_to_replace
|
||||
&& QMessageBox::question(
|
||||
parent,
|
||||
tr("Replace Media"),
|
||||
tr("You dropped a file onto '%1'. Would you like to replace it with the dropped file?").arg(m->get_name()),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
|
||||
replace = true;
|
||||
project_parent->replace_media(m, paths.at(0));
|
||||
}
|
||||
if (!replace) {
|
||||
QModelIndex parent;
|
||||
if (drop_item.isValid()) {
|
||||
if (m->get_type() == MEDIA_TYPE_FOLDER) {
|
||||
parent = drop_item;
|
||||
} else {
|
||||
parent = drop_item.parent();
|
||||
}
|
||||
}
|
||||
project_parent->process_file_list(paths, false, nullptr, panel_project->item_to_media(parent));
|
||||
}
|
||||
}
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
event->ignore();
|
||||
|
||||
// dragging files within project
|
||||
// if we dragged to the root OR dragged to a folder
|
||||
if (!drop_item.isValid() || m->get_type() == MEDIA_TYPE_FOLDER) {
|
||||
QVector<Media*> move_items;
|
||||
for (int i=0;i<items.size();i++) {
|
||||
const QModelIndex& item = items.at(i);
|
||||
const QModelIndex& parent = item.parent();
|
||||
Media* s = project_parent->item_to_media(item);
|
||||
if (parent != drop_item && item != drop_item) {
|
||||
bool ignore = false;
|
||||
if (parent.isValid()) {
|
||||
// if child belongs to a selected parent, assume the user is just moving the parent and ignore the child
|
||||
QModelIndex par = parent;
|
||||
while (par.isValid() && !ignore) {
|
||||
for (int j=0;j<items.size();j++) {
|
||||
if (par == items.at(j)) {
|
||||
ignore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
par = par.parent();
|
||||
}
|
||||
}
|
||||
if (!ignore) {
|
||||
move_items.append(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (move_items.size() > 0) {
|
||||
MediaMove* mm = new MediaMove();
|
||||
mm->to = m;
|
||||
mm->items = move_items;
|
||||
olive::UndoStack.push(mm);
|
||||
}
|
||||
}
|
||||
}
|
||||
// dragging files within project
|
||||
// if we dragged to the root OR dragged to a folder
|
||||
if (!drop_item.isValid() || m->get_type() == MEDIA_TYPE_FOLDER) {
|
||||
QVector<Media*> move_items;
|
||||
for (int i=0;i<items.size();i++) {
|
||||
const QModelIndex& item = items.at(i);
|
||||
const QModelIndex& parent = item.parent();
|
||||
Media* s = project_parent->item_to_media(item);
|
||||
if (parent != drop_item && item != drop_item) {
|
||||
bool ignore = false;
|
||||
if (parent.isValid()) {
|
||||
// if child belongs to a selected parent, assume the user is just moving the parent and ignore the child
|
||||
QModelIndex par = parent;
|
||||
while (par.isValid() && !ignore) {
|
||||
for (int j=0;j<items.size();j++) {
|
||||
if (par == items.at(j)) {
|
||||
ignore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
par = par.parent();
|
||||
}
|
||||
}
|
||||
if (!ignore) {
|
||||
move_items.append(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (move_items.size() > 0) {
|
||||
MediaMove* mm = new MediaMove();
|
||||
mm->to = m;
|
||||
mm->items = move_items;
|
||||
olive::UndoStack.push(mm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::reveal_in_browser() {
|
||||
Media* media = project_parent->item_to_media(selected_items.at(0));
|
||||
FootagePtr m = media->to_footage();
|
||||
Media* media = project_parent->item_to_media(selected_items.at(0));
|
||||
FootagePtr m = media->to_footage();
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
QStringList args;
|
||||
args << "/select," << QDir::toNativeSeparators(m->url);
|
||||
QProcess::startDetached("explorer", args);
|
||||
QStringList args;
|
||||
args << "/select," << QDir::toNativeSeparators(m->url);
|
||||
QProcess::startDetached("explorer", args);
|
||||
#elif defined(Q_OS_MAC)
|
||||
QStringList args;
|
||||
args << "-e";
|
||||
args << "tell application \"Finder\"";
|
||||
args << "-e";
|
||||
args << "activate";
|
||||
args << "-e";
|
||||
args << "select POSIX file \""+m->url+"\"";
|
||||
args << "-e";
|
||||
args << "end tell";
|
||||
QProcess::startDetached("osascript", args);
|
||||
QStringList args;
|
||||
args << "-e";
|
||||
args << "tell application \"Finder\"";
|
||||
args << "-e";
|
||||
args << "activate";
|
||||
args << "-e";
|
||||
args << "select POSIX file \""+m->url+"\"";
|
||||
args << "-e";
|
||||
args << "end tell";
|
||||
QProcess::startDetached("osascript", args);
|
||||
#else
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(m->url.left(m->url.lastIndexOf('/'))));
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(m->url.left(m->url.lastIndexOf('/'))));
|
||||
#endif
|
||||
}
|
||||
|
||||
void SourcesCommon::stop_rename_timer() {
|
||||
rename_timer.stop();
|
||||
rename_timer.stop();
|
||||
}
|
||||
|
||||
void SourcesCommon::rename_interval() {
|
||||
stop_rename_timer();
|
||||
if (view->hasFocus() && editing_item != nullptr) {
|
||||
view->edit(editing_index);
|
||||
}
|
||||
stop_rename_timer();
|
||||
if (view->hasFocus() && editing_item != nullptr) {
|
||||
view->edit(editing_index);
|
||||
}
|
||||
}
|
||||
|
||||
void SourcesCommon::item_renamed(Media* item) {
|
||||
if (editing_item == item) {
|
||||
MediaRename* mr = new MediaRename(item, "idk");
|
||||
olive::UndoStack.push(mr);
|
||||
editing_item = nullptr;
|
||||
if (editing_item == item) {
|
||||
MediaRename* mr = new MediaRename(item, "idk");
|
||||
olive::UndoStack.push(mr);
|
||||
editing_item = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,46 +396,46 @@ void SourcesCommon::OpenSelectedMediaInMediaViewer(Media* item) {
|
||||
}
|
||||
|
||||
void SourcesCommon::open_create_proxy_dialog() {
|
||||
// open the proxy dialog and send it a list of currently selected footage
|
||||
ProxyDialog pd(olive::MainWindow, cached_selected_footage);
|
||||
pd.exec();
|
||||
// open the proxy dialog and send it a list of currently selected footage
|
||||
ProxyDialog pd(olive::MainWindow, cached_selected_footage);
|
||||
pd.exec();
|
||||
}
|
||||
|
||||
void SourcesCommon::clear_proxies_from_selected() {
|
||||
QList<QString> delete_list;
|
||||
QList<QString> delete_list;
|
||||
|
||||
for (int i=0;i<cached_selected_footage.size();i++) {
|
||||
FootagePtr f = cached_selected_footage.at(i);
|
||||
for (int i=0;i<cached_selected_footage.size();i++) {
|
||||
FootagePtr f = cached_selected_footage.at(i)->to_footage();
|
||||
|
||||
if (f->proxy && !f->proxy_path.isEmpty()) {
|
||||
if (QFileInfo::exists(f->proxy_path)) {
|
||||
if (QMessageBox::question(olive::MainWindow,
|
||||
tr("Delete proxy"),
|
||||
tr("Would you like to delete the proxy file \"%1\" as well?").arg(f->proxy_path),
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
delete_list.append(f->proxy_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f->proxy && !f->proxy_path.isEmpty()) {
|
||||
if (QFileInfo::exists(f->proxy_path)) {
|
||||
if (QMessageBox::question(olive::MainWindow,
|
||||
tr("Delete proxy"),
|
||||
tr("Would you like to delete the proxy file \"%1\" as well?").arg(f->proxy_path),
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
delete_list.append(f->proxy_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f->proxy = false;
|
||||
f->proxy_path.clear();
|
||||
}
|
||||
f->proxy = false;
|
||||
f->proxy_path.clear();
|
||||
}
|
||||
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
// close all clips so we can delete any proxies requested to be deleted
|
||||
closeActiveClips(olive::ActiveSequence);
|
||||
}
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
// close all clips so we can delete any proxies requested to be deleted
|
||||
close_active_clips(olive::ActiveSequence);
|
||||
}
|
||||
|
||||
// delete proxies requested to be deleted
|
||||
for (int i=0;i<delete_list.size();i++) {
|
||||
QFile::remove(delete_list.at(i));
|
||||
}
|
||||
// delete proxies requested to be deleted
|
||||
for (int i=0;i<delete_list.size();i++) {
|
||||
QFile::remove(delete_list.at(i));
|
||||
}
|
||||
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
// update viewer (will re-open active clips with original media)
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
}
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
// update viewer (will re-open active clips with original media)
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
}
|
||||
|
||||
olive::MainWindow->setWindowModified(true);
|
||||
olive::MainWindow->setWindowModified(true);
|
||||
}
|
||||
|
||||
+22
-22
@@ -36,38 +36,38 @@ class QDropEvent;
|
||||
struct Footage;
|
||||
|
||||
class SourcesCommon : public QObject {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
SourcesCommon(Project *parent);
|
||||
QAbstractItemView* view;
|
||||
void show_context_menu(QWidget* parent, const QModelIndexList &items);
|
||||
SourcesCommon(Project *parent);
|
||||
QAbstractItemView* view;
|
||||
void show_context_menu(QWidget* parent, const QModelIndexList &items);
|
||||
|
||||
void mousePressEvent(QMouseEvent* e);
|
||||
void mousePressEvent(QMouseEvent* e);
|
||||
void mouseDoubleClickEvent(const QModelIndexList& selected_items);
|
||||
void dropEvent(QWidget *parent, QDropEvent* e, const QModelIndex& drop_item, const QModelIndexList &items);
|
||||
void dropEvent(QWidget *parent, QDropEvent* e, const QModelIndex& drop_item, const QModelIndexList &items);
|
||||
|
||||
void item_click(Media* m, const QModelIndex &index);
|
||||
void item_click(Media* m, const QModelIndex &index);
|
||||
private slots:
|
||||
void create_seq_from_selected();
|
||||
void reveal_in_browser();
|
||||
void rename_interval();
|
||||
void item_renamed(Media *item);
|
||||
void create_seq_from_selected();
|
||||
void reveal_in_browser();
|
||||
void rename_interval();
|
||||
void item_renamed(Media *item);
|
||||
void OpenSelectedMediaInMediaViewerFromAction();
|
||||
void OpenSelectedMediaInMediaViewer(Media* item);
|
||||
|
||||
// proxy functions
|
||||
void open_create_proxy_dialog();
|
||||
void clear_proxies_from_selected();
|
||||
// proxy functions
|
||||
void open_create_proxy_dialog();
|
||||
void clear_proxies_from_selected();
|
||||
private:
|
||||
Media* editing_item;
|
||||
QModelIndex editing_index;
|
||||
QModelIndexList selected_items;
|
||||
Project* project_parent;
|
||||
void stop_rename_timer();
|
||||
QTimer rename_timer;
|
||||
Media* editing_item;
|
||||
QModelIndex editing_index;
|
||||
QModelIndexList selected_items;
|
||||
Project* project_parent;
|
||||
void stop_rename_timer();
|
||||
QTimer rename_timer;
|
||||
|
||||
// we cache the selected footage items for open_create_proxy_dialog()
|
||||
QVector<FootagePtr> cached_selected_footage;
|
||||
// we cache the selected footage items for open_create_proxy_dialog()
|
||||
QVector<Media*> cached_selected_footage;
|
||||
};
|
||||
|
||||
#endif // SOURCESCOMMON_H
|
||||
|
||||
@@ -52,7 +52,7 @@ Transition::Transition(ClipPtr c, ClipPtr s, const EffectMeta* em) :
|
||||
|
||||
LabelSlider* length_ui_ele = static_cast<LabelSlider*>(length_field->ui_element);
|
||||
length_ui_ele->set_display_type(LABELSLIDER_FRAMENUMBER);
|
||||
length_ui_ele->set_frame_rate(parent_clip->sequence == nullptr ? parent_clip->cached_fr : parent_clip->sequence->frame_rate);
|
||||
length_ui_ele->set_frame_rate(parent_clip->sequence == nullptr ? parent_clip->cached_frame_rate() : parent_clip->sequence->frame_rate);
|
||||
}
|
||||
|
||||
TransitionPtr Transition::copy(ClipPtr c, ClipPtr s) {
|
||||
|
||||
+116
-62
@@ -32,12 +32,13 @@
|
||||
#include "panels/effectcontrols.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "playback/playback.h"
|
||||
#include "ui/sourcetable.h"
|
||||
#include "project/effect.h"
|
||||
#include "project/transition.h"
|
||||
#include "project/footage.h"
|
||||
#include "playback/cacher.h"
|
||||
#include "rendering/renderfunctions.h"
|
||||
#include "rendering/cacher.h"
|
||||
#include "io/previewgenerator.h"
|
||||
#include "ui/labelslider.h"
|
||||
#include "ui/viewerwidget.h"
|
||||
#include "project/marker.h"
|
||||
@@ -45,16 +46,17 @@
|
||||
#include "io/clipboard.h"
|
||||
#include "project/media.h"
|
||||
#include "debug.h"
|
||||
#include "oliveglobal.h"
|
||||
|
||||
QUndoStack olive::UndoStack;
|
||||
|
||||
MoveClipAction::MoveClipAction(ClipPtr c, long iin, long iout, long iclip_in, int itrack, bool irelative) {
|
||||
clip = c;
|
||||
|
||||
old_in = c->timeline_in;
|
||||
old_out = c->timeline_out;
|
||||
old_clip_in = c->clip_in;
|
||||
old_track = c->track;
|
||||
old_in = c->timeline_in();
|
||||
old_out = c->timeline_out();
|
||||
old_clip_in = c->clip_in();
|
||||
old_track = c->track();
|
||||
|
||||
new_in = iin;
|
||||
new_out = iout;
|
||||
@@ -66,29 +68,29 @@ MoveClipAction::MoveClipAction(ClipPtr c, long iin, long iout, long iclip_in, in
|
||||
|
||||
void MoveClipAction::doUndo() {
|
||||
if (relative) {
|
||||
clip->timeline_in -= new_in;
|
||||
clip->timeline_out -= new_out;
|
||||
clip->clip_in -= new_clip_in;
|
||||
clip->track -= new_track;
|
||||
clip->set_timeline_in (clip->timeline_in() - new_in);
|
||||
clip->set_timeline_out (clip->timeline_out() - new_out);
|
||||
clip->set_clip_in (clip->clip_in() - new_clip_in);
|
||||
clip->set_track (clip->track() - new_track);
|
||||
} else {
|
||||
clip->timeline_in = old_in;
|
||||
clip->timeline_out = old_out;
|
||||
clip->clip_in = old_clip_in;
|
||||
clip->track = old_track;
|
||||
clip->set_timeline_in(old_in);
|
||||
clip->set_timeline_out(old_out);
|
||||
clip->set_clip_in(old_clip_in);
|
||||
clip->set_track(old_track);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveClipAction::doRedo() {
|
||||
if (relative) {
|
||||
clip->timeline_in += new_in;
|
||||
clip->timeline_out += new_out;
|
||||
clip->clip_in += new_clip_in;
|
||||
clip->track += new_track;
|
||||
clip->set_timeline_in(clip->timeline_in() + new_in);
|
||||
clip->set_timeline_out(clip->timeline_out() + new_out);
|
||||
clip->set_clip_in(clip->clip_in() + new_clip_in);
|
||||
clip->set_track(clip->track() + new_track);
|
||||
} else {
|
||||
clip->timeline_in = new_in;
|
||||
clip->timeline_out = new_out;
|
||||
clip->clip_in = new_clip_in;
|
||||
clip->track = new_track;
|
||||
clip->set_timeline_in(new_in);
|
||||
clip->set_timeline_out(new_out);
|
||||
clip->set_clip_in(new_clip_in);
|
||||
clip->set_track(new_track);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,8 +118,8 @@ void DeleteClipAction::doUndo() {
|
||||
void DeleteClipAction::doRedo() {
|
||||
// remove ref to clip
|
||||
ref = seq->clips.at(index);
|
||||
if (ref->open) {
|
||||
close_clip(ref, true);
|
||||
if (ref->IsOpen()) {
|
||||
ref->Close(true);
|
||||
}
|
||||
seq->clips[index] = nullptr;
|
||||
|
||||
@@ -143,12 +145,12 @@ ChangeSequenceAction::ChangeSequenceAction(SequencePtr s) {
|
||||
}
|
||||
|
||||
void ChangeSequenceAction::doUndo() {
|
||||
set_sequence(old_sequence);
|
||||
olive::Global->set_sequence(old_sequence);
|
||||
}
|
||||
|
||||
void ChangeSequenceAction::doRedo() {
|
||||
old_sequence = olive::ActiveSequence;
|
||||
set_sequence(new_sequence);
|
||||
olive::Global->set_sequence(new_sequence);
|
||||
}
|
||||
|
||||
SetTimelineInOutCommand::SetTimelineInOutCommand(SequencePtr s, bool enabled, long in, long out) {
|
||||
@@ -165,7 +167,7 @@ void SetTimelineInOutCommand::doUndo() {
|
||||
|
||||
// footage viewer functions
|
||||
if (seq->wrapper_sequence) {
|
||||
FootagePtr m = seq->clips.at(0)->media->to_footage();
|
||||
FootagePtr m = seq->clips.at(0)->media()->to_footage();
|
||||
m->using_inout = old_enabled;
|
||||
m->in = old_in;
|
||||
m->out = old_out;
|
||||
@@ -183,7 +185,7 @@ void SetTimelineInOutCommand::doRedo() {
|
||||
|
||||
// footage viewer functions
|
||||
if (seq->wrapper_sequence) {
|
||||
FootagePtr m = seq->clips.at(0)->media->to_footage();
|
||||
FootagePtr m = seq->clips.at(0)->media()->to_footage();
|
||||
m->using_inout = new_enabled;
|
||||
m->in = new_in;
|
||||
m->out = new_out;
|
||||
@@ -417,11 +419,11 @@ void AddClipCommand::doUndo() {
|
||||
}
|
||||
|
||||
// deselect the area occupied by this clip
|
||||
panel_timeline->deselect_area(c->timeline_in, c->timeline_out, c->track);
|
||||
panel_timeline->deselect_area(c->timeline_in(), c->timeline_out(), c->track());
|
||||
|
||||
// if the clip is open, close it
|
||||
if (c->open) {
|
||||
close_clip(c, true);
|
||||
if (c->IsOpen()) {
|
||||
c->Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,7 +470,6 @@ void LinkCommand::doUndo() {
|
||||
void LinkCommand::doRedo() {
|
||||
old_links.clear();
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
dout << clips.at(i);
|
||||
ClipPtr c = s->clips.at(clips.at(i));
|
||||
if (link) {
|
||||
for (int j=0;j<clips.size();j++) {
|
||||
@@ -516,8 +517,8 @@ void ReplaceMediaCommand::replace(QString& filename) {
|
||||
SequencePtr s = all_sequences.at(i)->to_sequence();
|
||||
for (int j=0;j<s->clips.size();j++) {
|
||||
ClipPtr c = s->clips.at(j);
|
||||
if (c != nullptr && c->media == item && c->open) {
|
||||
close_clip(c, true);
|
||||
if (c != nullptr && c->media() == item && c->IsOpen()) {
|
||||
c->Close(true);
|
||||
c->replaced = true;
|
||||
}
|
||||
}
|
||||
@@ -526,8 +527,8 @@ void ReplaceMediaCommand::replace(QString& filename) {
|
||||
// replace media
|
||||
QStringList files;
|
||||
files.append(filename);
|
||||
item->to_footage()->ready_lock.lock();
|
||||
panel_project->process_file_list(files, false, item, nullptr);
|
||||
PreviewGenerator* pg = new PreviewGenerator(item);
|
||||
}
|
||||
|
||||
void ReplaceMediaCommand::doUndo() {
|
||||
@@ -553,23 +554,23 @@ void ReplaceClipMediaCommand::replace(bool undo) {
|
||||
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
ClipPtr c = clips.at(i);
|
||||
if (c->open) {
|
||||
close_clip(c, true);
|
||||
if (c->IsOpen()) {
|
||||
c->Close(true);
|
||||
}
|
||||
|
||||
if (undo) {
|
||||
if (!preserve_clip_ins) {
|
||||
c->clip_in = old_clip_ins.at(i);
|
||||
c->set_clip_in(old_clip_ins.at(i));
|
||||
}
|
||||
|
||||
c->media = old_media;
|
||||
c->set_media(old_media, c->media_stream_index());
|
||||
} else {
|
||||
if (!preserve_clip_ins) {
|
||||
old_clip_ins.append(c->clip_in);
|
||||
c->clip_in = 0;
|
||||
old_clip_ins.append(c->clip_in());
|
||||
c->set_clip_in(0);
|
||||
}
|
||||
|
||||
c->media = new_media;
|
||||
c->set_media(new_media, c->media_stream_index());
|
||||
}
|
||||
|
||||
c->replaced = true;
|
||||
@@ -685,20 +686,68 @@ void EffectFieldUndo::doRedo() {
|
||||
}
|
||||
}
|
||||
|
||||
SetAutoscaleAction::SetAutoscaleAction() {}
|
||||
SetClipProperty::SetClipProperty(SetClipPropertyType type) : type_(type)
|
||||
{}
|
||||
|
||||
void SetAutoscaleAction::doUndo() {
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
clips.at(i)->autoscale = !clips.at(i)->autoscale;
|
||||
void SetClipProperty::AddSetting(ClipPtr c, bool setting)
|
||||
{
|
||||
clips_.append(c);
|
||||
setting_.append(setting);
|
||||
|
||||
// store current setting for undoing
|
||||
bool old_setting = false;
|
||||
switch (type_) {
|
||||
case kSetClipPropertyAutoscale:
|
||||
old_setting = c->autoscaled();
|
||||
break;
|
||||
case kSetClipPropertyReversed:
|
||||
old_setting = c->reversed();
|
||||
break;
|
||||
case kSetClipPropertyMaintainAudioPitch:
|
||||
old_setting = c->speed().maintain_audio_pitch;
|
||||
break;
|
||||
case kSetClipPropertyEnabled:
|
||||
old_setting = c->enabled();
|
||||
break;
|
||||
}
|
||||
old_setting_.append(old_setting);
|
||||
}
|
||||
|
||||
void SetClipProperty::MainLoop(bool undo)
|
||||
{
|
||||
for (int i=0;i<clips_.size();i++) {
|
||||
|
||||
bool setting = (undo) ? old_setting_.at(i) : setting_.at(i);
|
||||
|
||||
switch (type_) {
|
||||
case kSetClipPropertyAutoscale:
|
||||
clips_.at(i)->set_autoscaled(setting);
|
||||
break;
|
||||
case kSetClipPropertyReversed:
|
||||
clips_.at(i)->set_reversed(setting);
|
||||
break;
|
||||
case kSetClipPropertyMaintainAudioPitch:
|
||||
{
|
||||
ClipSpeed s = clips_.at(i)->speed();
|
||||
s.maintain_audio_pitch = setting;
|
||||
clips_.at(i)->set_speed(s);
|
||||
}
|
||||
break;
|
||||
case kSetClipPropertyEnabled:
|
||||
clips_.at(i)->set_enabled(setting);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetClipProperty::doUndo() {
|
||||
MainLoop(true);
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
|
||||
}
|
||||
|
||||
void SetAutoscaleAction::doRedo() {
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
clips.at(i)->autoscale = !clips.at(i)->autoscale;
|
||||
}
|
||||
void SetClipProperty::doRedo() {
|
||||
MainLoop(false);
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
}
|
||||
|
||||
@@ -782,19 +831,24 @@ void DeleteMarkerAction::doRedo() {
|
||||
|
||||
SetSpeedAction::SetSpeedAction(ClipPtr c, double speed) {
|
||||
clip = c;
|
||||
old_speed = c->speed;
|
||||
old_speed = c->speed().value;
|
||||
new_speed = speed;
|
||||
}
|
||||
|
||||
void SetSpeedAction::doUndo() {
|
||||
clip->speed = old_speed;
|
||||
clip->recalculateMaxLength();
|
||||
ClipSpeed cs = clip->speed();
|
||||
|
||||
cs.value = old_speed;
|
||||
|
||||
clip->set_speed(cs);
|
||||
}
|
||||
|
||||
void SetSpeedAction::doRedo() {
|
||||
clip->speed = new_speed;
|
||||
clip->recalculateMaxLength();
|
||||
ClipSpeed cs = clip->speed();
|
||||
|
||||
cs.value = new_speed;
|
||||
|
||||
clip->set_speed(cs);
|
||||
}
|
||||
|
||||
SetBool::SetBool(bool* b, bool setting) {
|
||||
@@ -868,7 +922,7 @@ void EditSequenceCommand::update() {
|
||||
}
|
||||
|
||||
if (olive::ActiveSequence == seq) {
|
||||
set_sequence(seq);
|
||||
olive::Global->set_sequence(seq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,7 +961,7 @@ void CloseAllClipsCommand::doUndo() {
|
||||
}
|
||||
|
||||
void CloseAllClipsCommand::doRedo() {
|
||||
closeActiveClips(olive::ActiveSequence);
|
||||
close_active_clips(olive::ActiveSequence);
|
||||
}
|
||||
|
||||
UpdateFootageTooltip::UpdateFootageTooltip(Media *i) {
|
||||
@@ -955,15 +1009,15 @@ RenameClipCommand::RenameClipCommand() {}
|
||||
|
||||
void RenameClipCommand::doUndo() {
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
clips.at(i)->name = old_names.at(i);
|
||||
clips.at(i)->set_name(old_names.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
void RenameClipCommand::doRedo() {
|
||||
old_names.resize(clips.size());
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
old_names[i] = clips.at(i)->name;
|
||||
clips.at(i)->name = new_name;
|
||||
old_names[i] = clips.at(i)->name();
|
||||
clips.at(i)->set_name(new_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1007,7 +1061,7 @@ void RippleAction::doRedo() {
|
||||
if (!ignore.contains(i)) {
|
||||
ClipPtr c = s->clips.at(i);
|
||||
if (c != nullptr) {
|
||||
if (c->timeline_in >= point) {
|
||||
if (c->timeline_in() >= point) {
|
||||
move_clip(ca, c, length, length, 0, 0, true, true);
|
||||
}
|
||||
}
|
||||
@@ -1108,7 +1162,7 @@ void RefreshClips::doRedo() {
|
||||
SequencePtr s = all_sequences.at(i)->to_sequence();
|
||||
for (int j=0;j<s->clips.size();j++) {
|
||||
ClipPtr c = s->clips.at(j);
|
||||
if (c != nullptr && c->media == media) {
|
||||
if (c != nullptr && c->media() == media) {
|
||||
c->replaced = true;
|
||||
c->refresh();
|
||||
}
|
||||
|
||||
+16
-3
@@ -362,12 +362,25 @@ private:
|
||||
bool done;
|
||||
};
|
||||
|
||||
class SetAutoscaleAction : public OliveAction {
|
||||
enum SetClipPropertyType {
|
||||
kSetClipPropertyAutoscale,
|
||||
kSetClipPropertyReversed,
|
||||
kSetClipPropertyMaintainAudioPitch,
|
||||
kSetClipPropertyEnabled
|
||||
};
|
||||
|
||||
class SetClipProperty : public OliveAction {
|
||||
public:
|
||||
SetAutoscaleAction();
|
||||
SetClipProperty(SetClipPropertyType type);
|
||||
virtual void doUndo() override;
|
||||
virtual void doRedo() override;
|
||||
QVector<ClipPtr> clips;
|
||||
void AddSetting(ClipPtr c, bool setting);
|
||||
private:
|
||||
SetClipPropertyType type_;
|
||||
QVector<ClipPtr> clips_;
|
||||
QVector<bool> setting_;
|
||||
QVector<bool> old_setting_;
|
||||
void MainLoop(bool undo);
|
||||
};
|
||||
|
||||
class AddMarkerAction : public OliveAction {
|
||||
|
||||
Reference in New Issue
Block a user