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