#include #include #include "defines.h" #include "Log.h" #include "Timeline.h" struct includesTime: public std::unary_function { inline bool operator()(const TimeInterval s) const { return s.includes(_t); } includesTime(GstClockTime t) : _t(t) { } private: GstClockTime _t; }; Timeline::Timeline() { reset(); } Timeline::~Timeline() { } Timeline& Timeline::operator = (const Timeline& b) { if (this != &b) { this->timing_ = b.timing_; this->step_ = b.step_; this->gaps_ = b.gaps_; this->gaps_array_need_update_ = b.gaps_array_need_update_; memcpy( this->gapsArray_, b.gapsArray_, MAX_TIMELINE_ARRAY * sizeof(float)); memcpy( this->fadingArray_, b.fadingArray_, MAX_TIMELINE_ARRAY * sizeof(float)); } return *this; } void Timeline::reset() { // reset timing timing_.reset(); timing_.begin = 0; first_ = 0; step_ = GST_CLOCK_TIME_NONE; clearGaps(); clearFading(); } bool Timeline::is_valid() { return timing_.is_valid() && step_ != GST_CLOCK_TIME_NONE; } void Timeline::setFirst(GstClockTime first) { first_ = first; } void Timeline::setEnd(GstClockTime end) { timing_.end = end; } void Timeline::setStep(GstClockTime dt) { step_ = dt; } void Timeline::setTiming(TimeInterval interval, GstClockTime step) { timing_ = interval; if (step != GST_CLOCK_TIME_NONE) step_ = step; } GstClockTime Timeline::next(GstClockTime time) const { GstClockTime next_time = time; TimeInterval gap; if (gapAt(time, gap) && gap.is_valid()) next_time = gap.end; return next_time; } GstClockTime Timeline::previous(GstClockTime time) const { GstClockTime prev_time = time; TimeInterval gap; if (gapAt(time, gap) && gap.is_valid()) prev_time = gap.begin; return prev_time; } float *Timeline::gapsArray() { if (gaps_array_need_update_) { fillArrayFromGaps(gapsArray_, MAX_TIMELINE_ARRAY); } return gapsArray_; } void Timeline::update() { updateGapsFromArray(gapsArray_, MAX_TIMELINE_ARRAY); gaps_array_need_update_ = false; } bool Timeline::gapAt(const GstClockTime t, TimeInterval &gap) const { TimeIntervalSet::const_iterator g = std::find_if(gaps_.begin(), gaps_.end(), includesTime(t)); if ( g != gaps_.end() ) { gap = (*g); return true; } return false; } bool Timeline::addGap(GstClockTime begin, GstClockTime end) { return addGap( TimeInterval(begin, end) ); } bool Timeline::addGap(TimeInterval s) { if ( s.is_valid() ) { gaps_array_need_update_ = true; return gaps_.insert(s).second; } return false; } void Timeline::setGaps(TimeIntervalSet g) { gaps_array_need_update_ = true; gaps_ = g; } bool Timeline::removeGaptAt(GstClockTime t) { TimeIntervalSet::const_iterator s = std::find_if(gaps_.begin(), gaps_.end(), includesTime(t)); if ( s != gaps_.end() ) { gaps_.erase(s); gaps_array_need_update_ = true; return true; } return false; } TimeIntervalSet Timeline::sections() const { TimeIntervalSet sec; GstClockTime begin_sec = timing_.begin; if (gaps_.size() > 0) { auto it = gaps_.begin(); if ((*it).begin == begin_sec) { begin_sec = (*it).end; ++it; } for (; it != gaps_.end(); ++it) { sec.insert( TimeInterval(begin_sec, (*it).begin) ); begin_sec = (*it).end; } } if (begin_sec != timing_.end) sec.insert( TimeInterval(begin_sec, timing_.end) ); return sec; } void Timeline::clearGaps() { gaps_.clear(); for(int i=0;i(MAX_TIMELINE_ARRAY) * static_cast(t)) / static_cast(timing_.end); double previous_index = floor(true_index); float percent = static_cast(true_index - previous_index); size_t keyframe_index = CLAMP( static_cast(previous_index), 0, MAX_TIMELINE_ARRAY-1); size_t keyframe_next_index = CLAMP( keyframe_index+1, 0, MAX_TIMELINE_ARRAY-1); float v = fadingArray_[keyframe_index]; v += percent * (fadingArray_[keyframe_next_index] - fadingArray_[keyframe_index]); return v; } void Timeline::clearFading() { for(int i=0;i -1 && k < MAX_TIMELINE_ARRAY-1) { tmparray[i] += fadingArray_[k] * kernel[j]; divider += kernel[j]; } } tmparray[i] *= 1.f / divider; } memcpy( fadingArray_, tmparray, MAX_TIMELINE_ARRAY * sizeof(float)); } } void Timeline::autoFading(uint milisecond) { GstClockTime stepduration = timing_.end / MAX_TIMELINE_ARRAY; stepduration = GST_TIME_AS_MSECONDS(stepduration); uint N = milisecond / stepduration; // reset all to zero for(int i=0;i(i-s) / static_cast(n); // plateau for (; i < e-n; ++i) fadingArray_[i] = 1.f; // linear fade out ending at e for (; i < e; ++i) fadingArray_[i] = static_cast(e-i) / static_cast(n); } } void Timeline::updateGapsFromArray(float *array, size_t array_size) { // reset gaps gaps_.clear(); // fill the gaps from array if (array != nullptr && array_size > 0 && timing_.is_valid()) { // loop over the array to detect gaps float status = 0.f; GstClockTime begin_gap = GST_CLOCK_TIME_NONE; for (size_t i = 0; i < array_size; ++i) { // detect a change of value between two slots if ( array[i] != status) { // compute time of the event in array GstClockTime t = (timing_.duration() * i) / array_size; // change from 0.f to 1.f : begin of a gap if (array[i] > 0.f) { begin_gap = t; } // change from 1.f to 0.f : end of a gap else { addGap( begin_gap, t ); begin_gap = GST_CLOCK_TIME_NONE; } // swap status = array[i]; } } // end a potentially pending gap if reached end of array with no end of gap if (begin_gap != GST_CLOCK_TIME_NONE) addGap( begin_gap, timing_.end ); } } void Timeline::fillArrayFromGaps(float *array, size_t array_size) { // fill the array from gaps if (array != nullptr && array_size > 0 && timing_.is_valid()) { for(int i=0;i