1 /***
2
3 Olive - Non-Linear Video Editor
4 Copyright (C) 2019 Olive Team
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 ***/
20
21 #include "clip.h"
22
23 #include <QtMath>
24
25 #include "effects/effect.h"
26 #include "effects/transition.h"
27 #include "project/footage.h"
28 #include "global/config.h"
29 #include "rendering/cacher.h"
30 #include "rendering/renderfunctions.h"
31 #include "panels/project.h"
32 #include "timeline/sequence.h"
33 #include "panels/timeline.h"
34 #include "project/media.h"
35 #include "project/clipboard.h"
36 #include "undo/undo.h"
37 #include "global/debug.h"
38
39 const int kRGBAComponentCount = 4;
40
Clip(Sequence * s)41 Clip::Clip(Sequence* s) :
42 sequence(s),
43 cacher(this),
44 enabled_(true),
45 clip_in_(0),
46 timeline_in_(0),
47 timeline_out_(0),
48 track_(0),
49 media_(nullptr),
50 reverse_(false),
51 autoscale_(olive::CurrentConfig.autoscale_by_default),
52 opening_transition(nullptr),
53 closing_transition(nullptr),
54 undeletable(false),
55 replaced(false),
56 fbo(nullptr),
57 open_(false),
58 texture(nullptr)
59 {
60 }
61
copy(Sequence * s)62 ClipPtr Clip::copy(Sequence* s) {
63 ClipPtr copy = std::make_shared<Clip>(s);
64
65 copy->set_enabled(enabled());
66 copy->set_name(name());
67 copy->set_clip_in(clip_in());
68 copy->set_timeline_in(timeline_in());
69 copy->set_timeline_out(timeline_out());
70 copy->set_track(track());
71 copy->set_color(color());
72 copy->set_media(media(), media_stream_index());
73 copy->set_autoscaled(autoscaled());
74 copy->set_speed(speed());
75 copy->set_reversed(reversed());
76
77 for (int i=0;i<effects.size();i++) {
78 copy->effects.append(effects.at(i)->copy(copy.get()));
79 }
80
81 copy->set_cached_frame_rate((this->sequence == nullptr) ? cached_frame_rate() : this->sequence->frame_rate);
82
83 copy->refresh();
84
85 return copy;
86 }
87
IsActiveAt(long timecode)88 bool Clip::IsActiveAt(long timecode)
89 {
90 // these buffers allow clips to be opened and prepared well before they're displayed
91 // as well as closed a little after they're not needed anymore
92 int open_buffer = qCeil(this->sequence->frame_rate*2);
93 int close_buffer = qCeil(this->sequence->frame_rate);
94
95
96 return enabled()
97 && timeline_in(true) < timecode + open_buffer
98 && timeline_out(true) > timecode - close_buffer
99 && timecode - timeline_in(true) + clip_in(true) < media_length();
100 }
101
IsSelected(bool containing)102 bool Clip::IsSelected(bool containing)
103 {
104 if (this->sequence == nullptr) {
105 return false;
106 }
107
108 return this->sequence->IsClipSelected(this, containing);
109 }
110
color()111 const QColor &Clip::color()
112 {
113 return color_;
114 }
115
set_color(int r,int g,int b)116 void Clip::set_color(int r, int g, int b)
117 {
118 color_.setRed(r);
119 color_.setGreen(g);
120 color_.setBlue(b);
121 }
122
set_color(const QColor & c)123 void Clip::set_color(const QColor &c)
124 {
125 color_ = c;
126 }
127
media()128 Media *Clip::media()
129 {
130 return media_;
131 }
132
media_stream()133 FootageStream *Clip::media_stream()
134 {
135 if (media() != nullptr
136 && media()->get_type() == MEDIA_TYPE_FOOTAGE) {
137 return media()->to_footage()->get_stream_from_file_index(track() < 0, media_stream_index());
138 }
139
140 return nullptr;
141 }
142
media_stream_index()143 int Clip::media_stream_index()
144 {
145 return media_stream_;
146 }
147
set_media(Media * m,int s)148 void Clip::set_media(Media *m, int s)
149 {
150 media_ = m;
151 media_stream_ = s;
152 }
153
enabled()154 bool Clip::enabled()
155 {
156 return enabled_;
157 }
158
set_enabled(bool e)159 void Clip::set_enabled(bool e)
160 {
161 enabled_ = e;
162 }
163
move(ComboAction * ca,long iin,long iout,long iclip_in,int itrack,bool verify_transitions,bool relative)164 void Clip::move(ComboAction* ca, long iin, long iout, long iclip_in, int itrack, bool verify_transitions, bool relative)
165 {
166 ca->append(new MoveClipAction(this, iin, iout, iclip_in, itrack, relative));
167
168 if (verify_transitions) {
169
170 // if this is a shared transition, and the corresponding clip will be moved away somehow
171 if (opening_transition != nullptr
172 && opening_transition->secondary_clip != nullptr
173 && opening_transition->secondary_clip->timeline_out() != iin) {
174 // separate transition
175 ca->append(new SetPointer(reinterpret_cast<void**>(&opening_transition->secondary_clip), nullptr));
176 ca->append(new AddTransitionCommand(nullptr,
177 opening_transition->secondary_clip,
178 opening_transition,
179 nullptr,
180 0));
181 }
182
183 if (closing_transition != nullptr
184 && closing_transition->secondary_clip != nullptr
185 && closing_transition->parent_clip->timeline_in() != iout) {
186 // separate transition
187 ca->append(new SetPointer(reinterpret_cast<void**>(&closing_transition->secondary_clip), nullptr));
188 ca->append(new AddTransitionCommand(nullptr,
189 this,
190 closing_transition,
191 nullptr,
192 0));
193 }
194 }
195 }
196
reset_audio()197 void Clip::reset_audio() {
198 if (UsesCacher()) {
199 cacher.ResetAudio();
200 }
201 if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) {
202 Sequence* nested_sequence = media()->to_sequence().get();
203 for (int i=0;i<nested_sequence->clips.size();i++) {
204 Clip* c = nested_sequence->clips.at(i).get();
205 if (c != nullptr) {
206 c->reset_audio();
207 }
208 }
209 }
210 }
211
refresh()212 void Clip::refresh() {
213 // validates media if it was replaced
214 if (replaced && media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE) {
215 Footage* m = media()->to_footage();
216
217 if (track() < 0 && m->video_tracks.size() > 0) {
218 set_media(media(), m->video_tracks.at(0).file_index);
219 } else if (track() >= 0 && m->audio_tracks.size() > 0) {
220 set_media(media(), m->audio_tracks.at(0).file_index);
221 }
222 }
223 replaced = false;
224
225 // reinitializes all effects... just in case
226 for (int i=0;i<effects.size();i++) {
227 effects.at(i)->refresh();
228 }
229 }
230
get_markers()231 QVector<Marker> &Clip::get_markers() {
232 if (media() != nullptr) {
233 return media()->get_markers();
234 }
235 return markers;
236 }
237
IndexOfEffect(Effect * e)238 int Clip::IndexOfEffect(Effect *e)
239 {
240 for (int i=0;i<effects.size();i++) {
241 if (effects.at(i).get() == e) {
242 return i;
243 }
244 }
245 return -1;
246 }
247
~Clip()248 Clip::~Clip() {
249 if (IsOpen()) {
250 Close(true);
251 }
252
253 effects.clear();
254 }
255
clip_in(bool with_transition)256 long Clip::clip_in(bool with_transition) {
257 if (with_transition && opening_transition != nullptr && opening_transition->secondary_clip != nullptr) {
258 // we must be the secondary clip, so return (timeline in - length)
259 return clip_in_ - opening_transition->get_true_length();
260 }
261 return clip_in_;
262 }
263
set_clip_in(long c)264 void Clip::set_clip_in(long c)
265 {
266 clip_in_ = c;
267 }
268
timeline_in(bool with_transition)269 long Clip::timeline_in(bool with_transition) {
270 if (with_transition && opening_transition != nullptr && opening_transition->secondary_clip != nullptr) {
271 // we must be the secondary clip, so return (timeline in - length)
272 return timeline_in_ - opening_transition->get_true_length();
273 }
274 return timeline_in_;
275 }
276
set_timeline_in(long t)277 void Clip::set_timeline_in(long t)
278 {
279 timeline_in_ = t;
280 }
281
timeline_out(bool with_transitions)282 long Clip::timeline_out(bool with_transitions) {
283 if (with_transitions && closing_transition != nullptr && closing_transition->secondary_clip != nullptr) {
284 // we must be the primary clip, so return (timeline out + length2)
285 return timeline_out_ + closing_transition->get_true_length();
286 } else {
287 return timeline_out_;
288 }
289 }
290
set_timeline_out(long t)291 void Clip::set_timeline_out(long t)
292 {
293 timeline_out_ = t;
294 }
295
reversed()296 bool Clip::reversed()
297 {
298 return reverse_;
299 }
300
set_reversed(bool r)301 void Clip::set_reversed(bool r)
302 {
303 reverse_ = r;
304 }
305
autoscaled()306 bool Clip::autoscaled()
307 {
308 return autoscale_;
309 }
310
set_autoscaled(bool b)311 void Clip::set_autoscaled(bool b)
312 {
313 autoscale_ = b;
314 }
315
cached_frame_rate()316 double Clip::cached_frame_rate()
317 {
318 return cached_fr_;
319 }
320
set_cached_frame_rate(double d)321 void Clip::set_cached_frame_rate(double d)
322 {
323 cached_fr_ = d;
324 }
325
name()326 const QString &Clip::name()
327 {
328 return name_;
329 }
330
set_name(const QString & s)331 void Clip::set_name(const QString &s)
332 {
333 name_ = s;
334 }
335
speed()336 const ClipSpeed& Clip::speed()
337 {
338 return speed_;
339 }
340
set_speed(const ClipSpeed & d)341 void Clip::set_speed(const ClipSpeed& d)
342 {
343 speed_ = d;
344 }
345
time_base()346 AVRational Clip::time_base()
347 {
348 return cacher.media_time_base();
349 }
350
track()351 int Clip::track()
352 {
353 return track_;
354 }
355
set_track(int t)356 void Clip::set_track(int t)
357 {
358 track_ = t;
359 }
360
361 // timeline functions
length()362 long Clip::length() {
363 return timeline_out_ - timeline_in_;
364 }
365
media_frame_rate()366 double Clip::media_frame_rate() {
367 Q_ASSERT(track_ < 0);
368 if (media_ != nullptr) {
369 double rate = media_->get_frame_rate(media_stream_index());
370 if (!qIsNaN(rate)) return rate;
371 }
372 if (sequence != nullptr) return sequence->frame_rate;
373 return qSNaN();
374 }
375
media_length()376 long Clip::media_length() {
377 if (this->sequence != nullptr) {
378 double fr = this->sequence->frame_rate;
379
380 fr /= speed_.value;
381
382 if (media_ == nullptr) {
383 return LONG_MAX;
384 } else {
385 switch (media_->get_type()) {
386 case MEDIA_TYPE_FOOTAGE:
387 {
388 Footage* m = media_->to_footage();
389 const FootageStream* ms = m->get_stream_from_file_index(track_ < 0, media_stream_index());
390 if (ms != nullptr && ms->infinite_length) {
391 return LONG_MAX;
392 } else {
393 return m->get_length_in_frames(fr);
394 }
395 }
396 case MEDIA_TYPE_SEQUENCE:
397 {
398 Sequence* s = media_->to_sequence().get();
399 return rescale_frame_number(s->getEndFrame(), s->frame_rate, fr);
400 }
401 }
402 }
403 }
404 return 0;
405 }
406
media_width()407 int Clip::media_width() {
408 if (media_ == nullptr && sequence != nullptr) return sequence->width;
409 switch (media_->get_type()) {
410 case MEDIA_TYPE_FOOTAGE:
411 {
412 const FootageStream* ms = media_stream();
413 if (ms != nullptr) return ms->video_width;
414 if (sequence != nullptr) return sequence->width;
415 break;
416 }
417 case MEDIA_TYPE_SEQUENCE:
418 {
419 Sequence* s = media_->to_sequence().get();
420 return s->width;
421 }
422 }
423 return 0;
424 }
425
media_height()426 int Clip::media_height() {
427 if (media_ == nullptr && sequence != nullptr) return sequence->height;
428 switch (media_->get_type()) {
429 case MEDIA_TYPE_FOOTAGE:
430 {
431 const FootageStream* ms = media_stream();
432 if (ms != nullptr) return ms->video_height;
433 if (sequence != nullptr) return sequence->height;
434 }
435 break;
436 case MEDIA_TYPE_SEQUENCE:
437 {
438 Sequence* s = media_->to_sequence().get();
439 return s->height;
440 }
441 }
442 return 0;
443 }
444
refactor_frame_rate(ComboAction * ca,double multiplier,bool change_timeline_points)445 void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points) {
446 if (change_timeline_points) {
447 this->move(ca,
448 qRound(double(timeline_in_) * multiplier),
449 qRound(double(timeline_out_) * multiplier),
450 qRound(double(clip_in_) * multiplier),
451 track_);
452 }
453
454 // move keyframes
455 for (int i=0;i<effects.size();i++) {
456 EffectPtr e = effects.at(i);
457 for (int j=0;j<e->row_count();j++) {
458 EffectRow* r = e->row(j);
459 for (int l=0;l<r->FieldCount();l++) {
460 EffectField* f = r->Field(l);
461 for (int k=0;k<f->keyframes.size();k++) {
462 ca->append(new SetLong(&f->keyframes[k].time, f->keyframes[k].time, qRound(f->keyframes[k].time * multiplier)));
463 }
464 }
465 }
466 }
467 }
468
Open()469 void Clip::Open() {
470 if (!open_ && state_change_lock.tryLock()) {
471 open_ = true;
472
473 for (int i=0;i<effects.size();i++) {
474 effects.at(i)->open();
475 }
476
477 // reset variable used to optimize uploading frame data
478 texture_frame = -1;
479
480 if (UsesCacher()) {
481 // cacher will unlock open_lock
482 cacher.Open();
483 } else {
484 // this media doesn't use a cacher, so we unlock here
485 state_change_lock.unlock();
486 }
487 }
488 }
489
Close(bool wait)490 void Clip::Close(bool wait) {
491 // thread safety, prevents Close() running from two separate threads simultaneously
492 if (open_ && state_change_lock.tryLock()) {
493 open_ = false;
494
495 if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) {
496 close_active_clips(media()->to_sequence().get());
497 }
498
499 // destroy opengl texture in main thread
500 delete texture;
501 texture = nullptr;
502
503 // close all effects
504 for (int i=0;i<effects.size();i++) {
505 if (effects.at(i)->is_open()) {
506 effects.at(i)->close();
507 }
508 }
509
510 // delete framebuffers
511 if (fbo != nullptr) {
512 // delete 3 fbos for nested sequences, 2 for most clips
513 int fbo_count = (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) ? 3 : 2;
514
515 for (int j=0;j<fbo_count;j++) {
516 delete fbo[j];
517 }
518
519 delete [] fbo;
520
521 fbo = nullptr;
522 }
523
524 if (UsesCacher()) {
525 cacher.Close(wait);
526 } else {
527 state_change_lock.unlock();
528 }
529 }
530 }
531
IsOpen()532 bool Clip::IsOpen()
533 {
534 return open_;
535 }
536
Cache(long playhead,bool scrubbing,QVector<Clip * > & nests,int playback_speed)537 void Clip::Cache(long playhead, bool scrubbing, QVector<Clip*>& nests, int playback_speed) {
538 cacher.Cache(playhead, scrubbing, nests, playback_speed);
539 cacher_frame = playhead;
540 }
541
Retrieve()542 bool Clip::Retrieve()
543 {
544 bool ret = false;
545
546 if (UsesCacher()) {
547
548 // Retrieve the frame from the cacher that we requested in Cache().
549 AVFrame* frame = cacher.Retrieve();
550
551 // Wait for exclusive control of the queue to avoid any threading collisions
552 cacher.queue()->lock();
553
554 // Check if we retrieved a frame (nullptr) and if the queue still contains this frame.
555 //
556 // `nullptr` is returned if the cacher failed to get any sort of frame and is uncommon, but we do need
557 // to handle it.
558 //
559 // We check the queue because in some situations (e.g. intensive scrubbing), in the time it took to gain
560 // exclusive control of the queue, the cacher may have deleted the frame.
561 // Therefore we check to ensure the queue still contains the frame now that we have exclusive control,
562 // to avoid any attempt to utilize now-freed memory.
563
564 if (frame != nullptr && cacher.queue()->contains(frame)) {
565
566 // check if the opengl texture exists yet, create it if not
567 if (texture == nullptr) {
568 texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
569
570 // the raw frame size may differ from the one we're using (e.g. a lower resolution proxy), so we make sure
571 // the texture is using the correct dimensions, but then treat it as if it's the original resolution in the
572 // composition
573 texture->setSize(cacher.media_width(), cacher.media_height());
574
575 texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
576 texture->setMipLevels(texture->maximumMipLevels());
577 texture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
578 texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
579 }
580
581 glPixelStorei(GL_UNPACK_ROW_LENGTH, frame->linesize[0]/kRGBAComponentCount);
582
583 // 2 data buffers to ping-pong between
584 bool using_db_1 = true;
585 uint8_t* data_buffer_1 = frame->data[0];
586 uint8_t* data_buffer_2 = nullptr;
587
588 int frame_size = frame->linesize[0]*frame->height;
589
590 for (int i=0;i<effects.size();i++) {
591 Effect* e = effects.at(i).get();
592 if ((e->Flags() & Effect::ImageFlag) && e->IsEnabled()) {
593 if (data_buffer_1 == frame->data[0]) {
594 data_buffer_1 = new uint8_t[frame_size];
595 data_buffer_2 = new uint8_t[frame_size];
596
597 memcpy(data_buffer_1, frame->data[0], frame_size);
598 }
599
600 e->process_image(get_timecode(this, cacher_frame),
601 using_db_1 ? data_buffer_1 : data_buffer_2,
602 using_db_1 ? data_buffer_2 : data_buffer_1,
603 frame_size
604 );
605
606 using_db_1 = !using_db_1;
607 }
608 }
609
610 texture->setData(QOpenGLTexture::RGBA,
611 QOpenGLTexture::UInt8,
612 const_cast<const uint8_t*>(using_db_1 ? data_buffer_1 : data_buffer_2));
613
614 if (data_buffer_1 != frame->data[0]) {
615 delete [] data_buffer_1;
616 delete [] data_buffer_2;
617 }
618
619 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
620
621 ret = true;
622 } else {
623 qCritical() << "Failed to retrieve frame for clip" << name();
624 }
625
626 cacher.queue()->unlock();
627 }
628
629 return ret;
630 }
631
UsesCacher()632 bool Clip::UsesCacher()
633 {
634 return track() >= 0 || (media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE);
635 }
636
ClipSpeed()637 ClipSpeed::ClipSpeed() :
638 value(1.0),
639 maintain_audio_pitch(false)
640 {
641 }
642