merge of long discussed new pipeline
This commit is contained in:
+239
-160
@@ -1,20 +1,20 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 Olive Team
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include <QtMath>
|
||||
|
||||
#include "effects/effect.h"
|
||||
#include "nodes/node.h"
|
||||
#include "effects/transition.h"
|
||||
#include "project/footage.h"
|
||||
#include "global/config.h"
|
||||
@@ -32,34 +32,31 @@
|
||||
#include "timeline/sequence.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "project/media.h"
|
||||
#include "project/clipboard.h"
|
||||
#include "undo/undo.h"
|
||||
#include "global/clipboard.h"
|
||||
#include "global/debug.h"
|
||||
#include "global/timing.h"
|
||||
|
||||
const int kRGBAComponentCount = 4;
|
||||
|
||||
Clip::Clip(Sequence* s) :
|
||||
sequence(s),
|
||||
Clip::Clip(Track *s) :
|
||||
track_(s),
|
||||
cacher(this),
|
||||
enabled_(true),
|
||||
clip_in_(0),
|
||||
timeline_in_(0),
|
||||
timeline_out_(0),
|
||||
track_(0),
|
||||
media_(nullptr),
|
||||
reverse_(false),
|
||||
autoscale_(olive::CurrentConfig.autoscale_by_default),
|
||||
autoscale_(olive::config.autoscale_by_default),
|
||||
opening_transition(nullptr),
|
||||
closing_transition(nullptr),
|
||||
undeletable(false),
|
||||
replaced(false),
|
||||
fbo(nullptr),
|
||||
open_(false),
|
||||
texture(nullptr)
|
||||
texture(0)
|
||||
{
|
||||
}
|
||||
|
||||
ClipPtr Clip::copy(Sequence* s) {
|
||||
ClipPtr Clip::copy(Track* s) {
|
||||
ClipPtr copy = std::make_shared<Clip>(s);
|
||||
|
||||
copy->set_enabled(enabled());
|
||||
@@ -67,7 +64,6 @@ ClipPtr Clip::copy(Sequence* s) {
|
||||
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());
|
||||
@@ -78,7 +74,7 @@ ClipPtr Clip::copy(Sequence* s) {
|
||||
copy->effects.append(effects.at(i)->copy(copy.get()));
|
||||
}
|
||||
|
||||
copy->set_cached_frame_rate((this->sequence == nullptr) ? cached_frame_rate() : this->sequence->frame_rate);
|
||||
copy->set_cached_frame_rate((this->track_ == nullptr) ? cached_frame_rate() : this->track_->sequence()->frame_rate);
|
||||
|
||||
copy->refresh();
|
||||
|
||||
@@ -87,25 +83,42 @@ ClipPtr Clip::copy(Sequence* s) {
|
||||
|
||||
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();
|
||||
&& timeline_in(true) <= timecode
|
||||
&& timeline_out(true) > timecode
|
||||
&& timecode - timeline_in(true) + clip_in(true) < media_length()
|
||||
&& !track()->IsEffectivelyMuted();
|
||||
}
|
||||
|
||||
bool Clip::IsSelected(bool containing)
|
||||
{
|
||||
if (this->sequence == nullptr) {
|
||||
if (this->track_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->sequence->IsClipSelected(this, containing);
|
||||
return this->track_->IsClipSelected(this, containing);
|
||||
}
|
||||
|
||||
bool Clip::IsTransitionSelected(TransitionType type)
|
||||
{
|
||||
switch (type) {
|
||||
case kTransitionOpening:
|
||||
return track_->IsTransitionSelected(opening_transition.get());
|
||||
case kTransitionClosing:
|
||||
return track_->IsTransitionSelected(closing_transition.get());
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Selection Clip::ToSelection()
|
||||
{
|
||||
return Selection(timeline_in(), timeline_out(), track());
|
||||
}
|
||||
|
||||
olive::TrackType Clip::type()
|
||||
{
|
||||
return track()->type();
|
||||
}
|
||||
|
||||
const QColor &Clip::color()
|
||||
@@ -134,7 +147,7 @@ FootageStream *Clip::media_stream()
|
||||
{
|
||||
if (media() != nullptr
|
||||
&& media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
return media()->to_footage()->get_stream_from_file_index(track() < 0, media_stream_index());
|
||||
return media()->to_footage()->get_stream_from_file_index(type() == olive::kTypeVideo, media_stream_index());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -151,6 +164,11 @@ void Clip::set_media(Media *m, int s)
|
||||
media_stream_ = s;
|
||||
}
|
||||
|
||||
void Clip::Move(ComboAction *ca, long iin, long iout, long iclip_in, Track *itrack, bool verify_transitions, bool relative)
|
||||
{
|
||||
track()->sequence()->MoveClip(this, ca, iin, iout, iclip_in, itrack, verify_transitions, relative);
|
||||
}
|
||||
|
||||
bool Clip::enabled()
|
||||
{
|
||||
return enabled_;
|
||||
@@ -161,51 +179,18 @@ void Clip::set_enabled(bool e)
|
||||
enabled_ = e;
|
||||
}
|
||||
|
||||
void Clip::move(ComboAction* ca, long iin, long iout, long iclip_in, int itrack, bool verify_transitions, bool relative)
|
||||
{
|
||||
ca->append(new MoveClipAction(this, iin, iout, iclip_in, itrack, relative));
|
||||
|
||||
if (verify_transitions) {
|
||||
|
||||
// if this is a shared transition, and the corresponding clip will be moved away somehow
|
||||
if (opening_transition != nullptr
|
||||
&& opening_transition->secondary_clip != nullptr
|
||||
&& opening_transition->secondary_clip->timeline_out() != iin) {
|
||||
// separate transition
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&opening_transition->secondary_clip), nullptr));
|
||||
ca->append(new AddTransitionCommand(nullptr,
|
||||
opening_transition->secondary_clip,
|
||||
opening_transition,
|
||||
nullptr,
|
||||
0));
|
||||
}
|
||||
|
||||
if (closing_transition != nullptr
|
||||
&& closing_transition->secondary_clip != nullptr
|
||||
&& closing_transition->parent_clip->timeline_in() != iout) {
|
||||
// separate transition
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&closing_transition->secondary_clip), nullptr));
|
||||
ca->append(new AddTransitionCommand(nullptr,
|
||||
this,
|
||||
closing_transition,
|
||||
nullptr,
|
||||
0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Clip::reset_audio() {
|
||||
if (UsesCacher()) {
|
||||
cacher.ResetAudio();
|
||||
}
|
||||
if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
Sequence* nested_sequence = media()->to_sequence().get();
|
||||
for (int i=0;i<nested_sequence->clips.size();i++) {
|
||||
Clip* c = nested_sequence->clips.at(i).get();
|
||||
if (c != nullptr) {
|
||||
c->reset_audio();
|
||||
}
|
||||
|
||||
QVector<Clip*> nested_sequence_clips = media()->to_sequence()->GetAllClips();
|
||||
|
||||
for (int i=0;i<nested_sequence_clips.size();i++) {
|
||||
nested_sequence_clips.at(i)->reset_audio();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,9 +199,9 @@ void Clip::refresh() {
|
||||
if (replaced && media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
Footage* m = media()->to_footage();
|
||||
|
||||
if (track() < 0 && m->video_tracks.size() > 0) {
|
||||
if (type() == olive::kTypeVideo && m->video_tracks.size() > 0) {
|
||||
set_media(media(), m->video_tracks.at(0).file_index);
|
||||
} else if (track() >= 0 && m->audio_tracks.size() > 0) {
|
||||
} else if (type() == olive::kTypeAudio && m->audio_tracks.size() > 0) {
|
||||
set_media(media(), m->audio_tracks.at(0).file_index);
|
||||
}
|
||||
}
|
||||
@@ -235,7 +220,7 @@ QVector<Marker> &Clip::get_markers() {
|
||||
return markers;
|
||||
}
|
||||
|
||||
int Clip::IndexOfEffect(Effect *e)
|
||||
int Clip::IndexOfEffect(Node *e)
|
||||
{
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
if (effects.at(i).get() == e) {
|
||||
@@ -249,13 +234,91 @@ Clip::~Clip() {
|
||||
if (IsOpen()) {
|
||||
Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
effects.clear();
|
||||
void Clip::Save(QXmlStreamWriter &stream)
|
||||
{
|
||||
stream.writeStartElement("clip");
|
||||
stream.writeAttribute("id", QString::number(load_id));
|
||||
|
||||
stream.writeAttribute("enabled", QString::number(enabled()));
|
||||
stream.writeAttribute("name", name());
|
||||
stream.writeAttribute("clipin", QString::number(clip_in()));
|
||||
stream.writeAttribute("in", QString::number(timeline_in()));
|
||||
stream.writeAttribute("out", QString::number(timeline_out()));
|
||||
|
||||
stream.writeAttribute("r", QString::number(color().red()));
|
||||
stream.writeAttribute("g", QString::number(color().green()));
|
||||
stream.writeAttribute("b", QString::number(color().blue()));
|
||||
|
||||
stream.writeAttribute("autoscale", QString::number(autoscaled()));
|
||||
stream.writeAttribute("speed", QString::number(speed().value, 'f', 10));
|
||||
stream.writeAttribute("maintainpitch", QString::number(speed().maintain_audio_pitch));
|
||||
stream.writeAttribute("reverse", QString::number(reversed()));
|
||||
|
||||
if (media() != nullptr) {
|
||||
stream.writeAttribute("type", QString::number(media()->get_type()));
|
||||
switch (media()->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
stream.writeAttribute("media", QString::number(media()->to_footage()->save_id));
|
||||
stream.writeAttribute("stream", QString::number(media_stream_index()));
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
stream.writeAttribute("sequence", QString::number(media()->to_sequence()->save_id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// save markers
|
||||
// only necessary for null media clips, since media has its own markers
|
||||
if (media() == nullptr) {
|
||||
for (int k=0;k<get_markers().size();k++) {
|
||||
get_markers().at(k).Save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// save clip links
|
||||
stream.writeStartElement("linked"); // linked
|
||||
for (int k=0;k<linked.size();k++) {
|
||||
stream.writeStartElement("link"); // link
|
||||
stream.writeAttribute("id", QString::number(linked.at(k)->load_id));
|
||||
stream.writeEndElement(); // link
|
||||
}
|
||||
stream.writeEndElement(); // linked
|
||||
|
||||
// save opening and closing transitions
|
||||
for (int t=kTransitionOpening;t<=kTransitionClosing;t++) {
|
||||
TransitionPtr transition = (t == kTransitionOpening) ? opening_transition : closing_transition;
|
||||
|
||||
if (transition != nullptr) {
|
||||
stream.writeStartElement((t == kTransitionOpening) ? "opening" : "closing");
|
||||
|
||||
// check if this is a shared transition
|
||||
if (this == transition->secondary_clip) {
|
||||
// if so, just save a reference to the other clip
|
||||
stream.writeAttribute("shared",
|
||||
QString::number(transition->parent_clip->load_id));
|
||||
} else {
|
||||
// otherwise save the whole transition
|
||||
transition->save(stream);
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // opening/closing
|
||||
}
|
||||
}
|
||||
|
||||
for (int k=0;k<effects.size();k++) {
|
||||
stream.writeStartElement("effect"); // effect
|
||||
effects.at(k)->save(stream);
|
||||
stream.writeEndElement(); // effect
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // clip
|
||||
}
|
||||
|
||||
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)
|
||||
// we must be the secondary clip, so return (clip in - length)
|
||||
return clip_in_ - opening_transition->get_true_length();
|
||||
}
|
||||
return clip_in_;
|
||||
@@ -281,7 +344,7 @@ void Clip::set_timeline_in(long 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)
|
||||
// we must be the primary clip, so return (timeline out + length)
|
||||
return timeline_out_ + closing_transition->get_true_length();
|
||||
} else {
|
||||
return timeline_out_;
|
||||
@@ -348,12 +411,12 @@ AVRational Clip::time_base()
|
||||
return cacher.media_time_base();
|
||||
}
|
||||
|
||||
int Clip::track()
|
||||
Track *Clip::track()
|
||||
{
|
||||
return track_;
|
||||
}
|
||||
|
||||
void Clip::set_track(int t)
|
||||
void Clip::set_track(Track *t)
|
||||
{
|
||||
track_ = t;
|
||||
}
|
||||
@@ -364,18 +427,18 @@ long Clip::length() {
|
||||
}
|
||||
|
||||
double Clip::media_frame_rate() {
|
||||
Q_ASSERT(track_ < 0);
|
||||
Q_ASSERT(type() == olive::kTypeVideo);
|
||||
if (media_ != nullptr) {
|
||||
double rate = media_->get_frame_rate(media_stream_index());
|
||||
if (!qIsNaN(rate)) return rate;
|
||||
}
|
||||
if (sequence != nullptr) return sequence->frame_rate;
|
||||
if (track() != nullptr) return track()->sequence()->frame_rate;
|
||||
return qSNaN();
|
||||
}
|
||||
|
||||
long Clip::media_length() {
|
||||
if (this->sequence != nullptr) {
|
||||
double fr = this->sequence->frame_rate;
|
||||
if (this->track() != nullptr) {
|
||||
double fr = this->track()->sequence()->frame_rate;
|
||||
|
||||
fr /= speed_.value;
|
||||
|
||||
@@ -386,7 +449,7 @@ long Clip::media_length() {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
Footage* m = media_->to_footage();
|
||||
const FootageStream* ms = m->get_stream_from_file_index(track_ < 0, media_stream_index());
|
||||
const FootageStream* ms = m->get_stream_from_file_index(type() == olive::kTypeVideo, media_stream_index());
|
||||
if (ms != nullptr && ms->infinite_length) {
|
||||
return LONG_MAX;
|
||||
} else {
|
||||
@@ -396,7 +459,7 @@ long Clip::media_length() {
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
{
|
||||
Sequence* s = media_->to_sequence().get();
|
||||
return rescale_frame_number(s->getEndFrame(), s->frame_rate, fr);
|
||||
return rescale_frame_number(s->GetEndFrame(), s->frame_rate, fr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -405,13 +468,13 @@ long Clip::media_length() {
|
||||
}
|
||||
|
||||
int Clip::media_width() {
|
||||
if (media_ == nullptr && sequence != nullptr) return sequence->width;
|
||||
if (media_ == nullptr && track() != nullptr) return track()->sequence()->width;
|
||||
switch (media_->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
const FootageStream* ms = media_stream();
|
||||
if (ms != nullptr) return ms->video_width;
|
||||
if (sequence != nullptr) return sequence->width;
|
||||
if (track() != nullptr) return track()->sequence()->width;
|
||||
break;
|
||||
}
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
@@ -424,13 +487,13 @@ int Clip::media_width() {
|
||||
}
|
||||
|
||||
int Clip::media_height() {
|
||||
if (media_ == nullptr && sequence != nullptr) return sequence->height;
|
||||
if (media_ == nullptr && track() != nullptr) return track()->sequence()->height;
|
||||
switch (media_->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
const FootageStream* ms = media_stream();
|
||||
if (ms != nullptr) return ms->video_height;
|
||||
if (sequence != nullptr) return sequence->height;
|
||||
if (track() != nullptr) return track()->sequence()->height;
|
||||
}
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
@@ -444,16 +507,17 @@ int Clip::media_height() {
|
||||
|
||||
void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points) {
|
||||
if (change_timeline_points) {
|
||||
this->move(ca,
|
||||
qRound(double(timeline_in_) * multiplier),
|
||||
qRound(double(timeline_out_) * multiplier),
|
||||
qRound(double(clip_in_) * multiplier),
|
||||
track_);
|
||||
track()->sequence()->MoveClip(this,
|
||||
ca,
|
||||
qRound(double(timeline_in_) * multiplier),
|
||||
qRound(double(timeline_out_) * multiplier),
|
||||
qRound(double(clip_in_) * multiplier),
|
||||
track_);
|
||||
}
|
||||
|
||||
// move keyframes
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
EffectPtr e = effects.at(i);
|
||||
NodePtr e = effects.at(i);
|
||||
for (int j=0;j<e->row_count();j++) {
|
||||
EffectRow* r = e->row(j);
|
||||
for (int l=0;l<r->FieldCount();l++) {
|
||||
@@ -475,7 +539,7 @@ void Clip::Open() {
|
||||
}
|
||||
|
||||
// reset variable used to optimize uploading frame data
|
||||
texture_frame = -1;
|
||||
texture_timestamp = -1;
|
||||
|
||||
if (UsesCacher()) {
|
||||
// cacher will unlock open_lock
|
||||
@@ -493,12 +557,14 @@ void Clip::Close(bool wait) {
|
||||
open_ = false;
|
||||
|
||||
if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
close_active_clips(media()->to_sequence().get());
|
||||
media()->to_sequence()->Close();
|
||||
}
|
||||
|
||||
// destroy opengl texture in main thread
|
||||
delete texture;
|
||||
texture = nullptr;
|
||||
if (texture > 0) {
|
||||
QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &texture);
|
||||
texture = 0;
|
||||
}
|
||||
|
||||
// close all effects
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
@@ -508,18 +574,10 @@ void Clip::Close(bool wait) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
fbo.clear();
|
||||
|
||||
for (int j=0;j<fbo_count;j++) {
|
||||
delete fbo[j];
|
||||
}
|
||||
|
||||
delete [] fbo;
|
||||
|
||||
fbo = nullptr;
|
||||
}
|
||||
// delete OCIO shader
|
||||
ocio_shader = nullptr;
|
||||
|
||||
if (UsesCacher()) {
|
||||
cacher.Close(wait);
|
||||
@@ -563,60 +621,81 @@ bool Clip::Retrieve()
|
||||
|
||||
if (frame != nullptr && cacher.queue()->contains(frame)) {
|
||||
|
||||
//if (frame->pts != texture_timestamp) {
|
||||
|
||||
bool allocate_data = false;
|
||||
|
||||
QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions();
|
||||
|
||||
// check if the opengl texture exists yet, create it if not
|
||||
if (texture == nullptr) {
|
||||
texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
||||
if (texture == 0) {
|
||||
|
||||
// create texture object
|
||||
f->glGenTextures(1, &texture);
|
||||
|
||||
f->glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
// set texture filtering to bilinear
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// set texture wrapping to clamp
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// queue an allocation ahead
|
||||
allocate_data = true;
|
||||
|
||||
} else {
|
||||
|
||||
f->glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
}
|
||||
|
||||
int video_width = cacher.media_width();
|
||||
int video_height = cacher.media_height();
|
||||
|
||||
const olive::PixelFormatInfo& pix_fmt_info = olive::pixel_formats.at(cacher.media_pixel_format());
|
||||
|
||||
f->glPixelStorei(GL_UNPACK_ROW_LENGTH, frame->linesize[0]/pix_fmt_info.bytes_per_pixel);
|
||||
|
||||
if (allocate_data) {
|
||||
|
||||
// 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());
|
||||
f->glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
pix_fmt_info.internal_format,
|
||||
video_width,
|
||||
video_height,
|
||||
0,
|
||||
pix_fmt_info.pixel_format,
|
||||
pix_fmt_info.pixel_type,
|
||||
frame->data[0]
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
f->glTexSubImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
video_width,
|
||||
video_height,
|
||||
pix_fmt_info.pixel_format,
|
||||
pix_fmt_info.pixel_type,
|
||||
frame->data[0]
|
||||
);
|
||||
|
||||
texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
|
||||
texture->setMipLevels(texture->maximumMipLevels());
|
||||
texture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
|
||||
texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
|
||||
}
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, frame->linesize[0]/kRGBAComponentCount);
|
||||
f->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// 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;
|
||||
f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
int frame_size = frame->linesize[0]*frame->height;
|
||||
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
Effect* e = effects.at(i).get();
|
||||
if ((e->Flags() & Effect::ImageFlag) && e->IsEnabled()) {
|
||||
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(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]) {
|
||||
delete [] data_buffer_1;
|
||||
delete [] data_buffer_2;
|
||||
}
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
texture_timestamp = frame->pts;
|
||||
|
||||
ret = true;
|
||||
} else {
|
||||
@@ -631,7 +710,7 @@ bool Clip::Retrieve()
|
||||
|
||||
bool Clip::UsesCacher()
|
||||
{
|
||||
return track() >= 0 || (media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE);
|
||||
return type() == olive::kTypeAudio || (media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE);
|
||||
}
|
||||
|
||||
ClipSpeed::ClipSpeed() :
|
||||
|
||||
Reference in New Issue
Block a user