mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
Revert behavior of MediaPlayer position to normal and instead fixed the
GUI to match the [start end] range of timeline (instead of shifting position in MediaPlayer). Fixed Loop mode for bi-directional and stop modes to react according to Timeline gaps.
This commit is contained in:
@@ -286,7 +286,7 @@ void ImGuiToolkit::HelpMarker(const char* desc)
|
|||||||
#define NUM_MARKS 10
|
#define NUM_MARKS 10
|
||||||
#define LARGE_TICK_INCREMENT 1
|
#define LARGE_TICK_INCREMENT 1
|
||||||
#define LABEL_TICK_INCREMENT 3
|
#define LABEL_TICK_INCREMENT 3
|
||||||
bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 duration, guint64 step, const float width)
|
bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 start, guint64 end, guint64 step, const float width)
|
||||||
{
|
{
|
||||||
static guint64 optimal_tick_marks[NUM_MARKS + LABEL_TICK_INCREMENT] = { 100 * MILISECOND, 500 * MILISECOND, 1 * SECOND, 2 * SECOND, 5 * SECOND, 10 * SECOND, 20 * SECOND, 1 * MINUTE, 2 * MINUTE, 5 * MINUTE, 10 * MINUTE, 60 * MINUTE, 60 * MINUTE };
|
static guint64 optimal_tick_marks[NUM_MARKS + LABEL_TICK_INCREMENT] = { 100 * MILISECOND, 500 * MILISECOND, 1 * SECOND, 2 * SECOND, 5 * SECOND, 10 * SECOND, 20 * SECOND, 1 * MINUTE, 2 * MINUTE, 5 * MINUTE, 10 * MINUTE, 60 * MINUTE, 60 * MINUTE };
|
||||||
|
|
||||||
@@ -326,8 +326,8 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 dura
|
|||||||
ImRect slider_bbox( timeline_bbox.GetTL() + ImVec2(-cursor_width + 2.f, cursor_width + 4.f ), timeline_bbox.GetBR() + ImVec2( cursor_width - 2.f, 0.f ) );
|
ImRect slider_bbox( timeline_bbox.GetTL() + ImVec2(-cursor_width + 2.f, cursor_width + 4.f ), timeline_bbox.GetBR() + ImVec2( cursor_width - 2.f, 0.f ) );
|
||||||
|
|
||||||
// units conversion: from time to float (calculation made with higher precision first)
|
// units conversion: from time to float (calculation made with higher precision first)
|
||||||
float time_ = static_cast<float> ( static_cast<double>(*time) / static_cast<double>(duration) );
|
float time_ = static_cast<float> ( static_cast<double>(*time - start) / static_cast<double>(end) );
|
||||||
float step_ = static_cast<float> ( static_cast<double>(step) / static_cast<double>(duration) );
|
float step_ = static_cast<float> ( static_cast<double>(step) / static_cast<double>(end) );
|
||||||
|
|
||||||
//
|
//
|
||||||
// SECOND GET USER INPUT AND PERFORM CHANGES AND DECISIONS
|
// SECOND GET USER INPUT AND PERFORM CHANGES AND DECISIONS
|
||||||
@@ -359,7 +359,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 dura
|
|||||||
&time_end, "%.2f", 1.f, ImGuiSliderFlags_None, &grab_slider_bb);
|
&time_end, "%.2f", 1.f, ImGuiSliderFlags_None, &grab_slider_bb);
|
||||||
if (value_changed){
|
if (value_changed){
|
||||||
// g_print("slider %f %ld \n", time_slider, static_cast<guint64> ( static_cast<double>(time_slider) * static_cast<double>(duration) ));
|
// g_print("slider %f %ld \n", time_slider, static_cast<guint64> ( static_cast<double>(time_slider) * static_cast<double>(duration) ));
|
||||||
*time = static_cast<guint64> ( 0.1 * static_cast<double>(time_slider) * static_cast<double>(duration) );
|
*time = static_cast<guint64> ( 0.1 * static_cast<double>(time_slider) * static_cast<double>(end) ) + start;
|
||||||
grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrabActive);
|
grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrabActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,7 +393,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 dura
|
|||||||
tick_step = optimal_tick_marks[i];
|
tick_step = optimal_tick_marks[i];
|
||||||
large_tick_step = optimal_tick_marks[i+LARGE_TICK_INCREMENT];
|
large_tick_step = optimal_tick_marks[i+LARGE_TICK_INCREMENT];
|
||||||
label_tick_step = optimal_tick_marks[i+LABEL_TICK_INCREMENT];
|
label_tick_step = optimal_tick_marks[i+LABEL_TICK_INCREMENT];
|
||||||
tick_step_pixels = timeline_bbox.GetWidth() * static_cast<float> ( static_cast<double>(tick_step) / static_cast<double>(duration) );
|
tick_step_pixels = timeline_bbox.GetWidth() * static_cast<float> ( static_cast<double>(tick_step) / static_cast<double>(end) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,14 +409,14 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 dura
|
|||||||
|
|
||||||
// render text duration
|
// render text duration
|
||||||
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s",
|
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s",
|
||||||
GstToolkit::time_to_string(duration, GstToolkit::TIME_STRING_MINIMAL).c_str());
|
GstToolkit::time_to_string(end, GstToolkit::TIME_STRING_MINIMAL).c_str());
|
||||||
overlay_size = ImGui::CalcTextSize(overlay_buf, NULL);
|
overlay_size = ImGui::CalcTextSize(overlay_buf, NULL);
|
||||||
ImVec2 duration_label = bbox.GetBR() - overlay_size - ImVec2(3.f, 3.f);
|
ImVec2 duration_label = bbox.GetBR() - overlay_size - ImVec2(3.f, 3.f);
|
||||||
if (overlay_size.x > 0.0f)
|
if (overlay_size.x > 0.0f)
|
||||||
ImGui::RenderTextClipped( duration_label, bbox.Max, overlay_buf, NULL, &overlay_size);
|
ImGui::RenderTextClipped( duration_label, bbox.Max, overlay_buf, NULL, &overlay_size);
|
||||||
|
|
||||||
// render tick marks
|
// render tick marks
|
||||||
while ( tick < duration)
|
while ( tick < end)
|
||||||
{
|
{
|
||||||
// large tick mark
|
// large tick mark
|
||||||
float tick_length = !(tick%large_tick_step) ? fontsize - style.FramePadding.y : style.FramePadding.y;
|
float tick_length = !(tick%large_tick_step) ? fontsize - style.FramePadding.y : style.FramePadding.y;
|
||||||
@@ -440,7 +440,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 dura
|
|||||||
|
|
||||||
// next tick
|
// next tick
|
||||||
tick += tick_step;
|
tick += tick_step;
|
||||||
tick_percent = static_cast<float> ( static_cast<double>(tick) / static_cast<double>(duration) );
|
tick_percent = static_cast<float> ( static_cast<double>(tick) / static_cast<double>(end) );
|
||||||
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
|
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace ImGuiToolkit
|
|||||||
|
|
||||||
// utility sliders
|
// utility sliders
|
||||||
void Bar (float value, float in, float out, float min, float max, const char* title, bool expand);
|
void Bar (float value, float in, float out, float min, float max, const char* title, bool expand);
|
||||||
bool TimelineSlider (const char* label, guint64 *time, guint64 duration, guint64 step, const float width);
|
bool TimelineSlider (const char* label, guint64 *time, guint64 start, guint64 end, guint64 step, const float width);
|
||||||
bool InvisibleSliderInt(const char* label, uint *index, uint min, uint max, const ImVec2 size);
|
bool InvisibleSliderInt(const char* label, uint *index, uint min, uint max, const ImVec2 size);
|
||||||
|
|
||||||
// fonts from ressources 'fonts/'
|
// fonts from ressources 'fonts/'
|
||||||
|
|||||||
@@ -387,15 +387,13 @@ float MediaPlayer::aspectRatio() const
|
|||||||
|
|
||||||
GstClockTime MediaPlayer::position()
|
GstClockTime MediaPlayer::position()
|
||||||
{
|
{
|
||||||
GstClockTime pos = position_;
|
if (position_ == GST_CLOCK_TIME_NONE && pipeline_ != nullptr) {
|
||||||
|
|
||||||
if (pos == GST_CLOCK_TIME_NONE && pipeline_ != nullptr) {
|
|
||||||
gint64 p = GST_CLOCK_TIME_NONE;
|
gint64 p = GST_CLOCK_TIME_NONE;
|
||||||
if ( gst_element_query_position (pipeline_, GST_FORMAT_TIME, &p) )
|
if ( gst_element_query_position (pipeline_, GST_FORMAT_TIME, &p) )
|
||||||
pos = p;
|
position_ = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pos - media_.timeline.start();
|
return position_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPlayer::enable(bool on)
|
void MediaPlayer::enable(bool on)
|
||||||
@@ -457,7 +455,8 @@ void MediaPlayer::play(bool on)
|
|||||||
|
|
||||||
// requesting to play, but stopped at end of stream : rewind first !
|
// requesting to play, but stopped at end of stream : rewind first !
|
||||||
if ( desired_state_ == GST_STATE_PLAYING) {
|
if ( desired_state_ == GST_STATE_PLAYING) {
|
||||||
if ( ( rate_>0.0 ? media_.timeline.end() - position() : position() ) < 2 * media_.timeline.step() )
|
if ( ( rate_ < 0.0 && position_ <= media_.timeline.next(0) )
|
||||||
|
|| ( rate_ > 0.0 && position_ >= media_.timeline.previous(media_.timeline.last()) ) )
|
||||||
rewind();
|
rewind();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,12 +510,18 @@ void MediaPlayer::rewind()
|
|||||||
if (!enabled_ || !media_.seekable)
|
if (!enabled_ || !media_.seekable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (rate_ > 0.0)
|
// playing forward, loop to begin
|
||||||
// playing forward, loop to begin
|
if (rate_ > 0.0) {
|
||||||
execute_seek_command(0);
|
// begin is the end of a gab which includes the first PTS (if exists)
|
||||||
else
|
// normal case, begin is zero
|
||||||
// playing backward, loop to end
|
execute_seek_command( media_.timeline.next(0) );
|
||||||
execute_seek_command(media_.timeline.end() - media_.timeline.step());
|
}
|
||||||
|
// playing backward, loop to endTimeInterval gap;
|
||||||
|
else {
|
||||||
|
// end is the start of a gab which includes the last PTS (if exists)
|
||||||
|
// normal case, end is last frame
|
||||||
|
execute_seek_command( media_.timeline.previous(media_.timeline.last()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -526,7 +531,8 @@ void MediaPlayer::step()
|
|||||||
if (!enabled_ || isPlaying())
|
if (!enabled_ || isPlaying())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( ( rate_ < 0.0 && position_ <= media_.timeline.start() ) || ( rate_ > 0.0 && position_ >= media_.timeline.end() ) )
|
if ( ( rate_ < 0.0 && position_ <= media_.timeline.next(0) )
|
||||||
|
|| ( rate_ > 0.0 && position_ >= media_.timeline.previous(media_.timeline.last()) ) )
|
||||||
rewind();
|
rewind();
|
||||||
|
|
||||||
// step
|
// step
|
||||||
@@ -539,8 +545,7 @@ void MediaPlayer::seek(GstClockTime pos)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// apply seek
|
// apply seek
|
||||||
GstClockTime target = CLAMP(pos, 0, media_.timeline.end());
|
GstClockTime target = CLAMP(pos, media_.timeline.start(), media_.timeline.end());
|
||||||
// GstClockTime target = CLAMP(pos, timeline.start(), timeline.end());
|
|
||||||
execute_seek_command(target);
|
execute_seek_command(target);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -690,6 +695,13 @@ void MediaPlayer::update()
|
|||||||
index_lock_.lock();
|
index_lock_.lock();
|
||||||
// get the last frame filled from fill_frame()
|
// get the last frame filled from fill_frame()
|
||||||
read_index = last_index_;
|
read_index = last_index_;
|
||||||
|
// Do NOT miss and jump directly (after seek) to a pre-roll
|
||||||
|
for (guint i = 0; i < N_VFRAME; ++i) {
|
||||||
|
if (frame_[i].status == PREROLL) {
|
||||||
|
read_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
// unlock access to index change
|
// unlock access to index change
|
||||||
index_lock_.unlock();
|
index_lock_.unlock();
|
||||||
|
|
||||||
@@ -738,22 +750,28 @@ void MediaPlayer::update()
|
|||||||
seeking_ = false;
|
seeking_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// manage timeline
|
||||||
|
TimeInterval gap;
|
||||||
|
if (position_ != GST_CLOCK_TIME_NONE && media_.timeline.gapAt(position_, gap)) {
|
||||||
|
|
||||||
|
if (gap.is_valid()) {
|
||||||
|
|
||||||
|
GstClockTime jumpPts = (rate_>0.f) ? gap.end : gap.begin;
|
||||||
|
|
||||||
|
if (jumpPts > media_.timeline.first() && jumpPts < media_.timeline.last())
|
||||||
|
seek( jumpPts);
|
||||||
|
else
|
||||||
|
need_loop = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// manage loop mode
|
// manage loop mode
|
||||||
if (need_loop) {
|
if (need_loop) {
|
||||||
execute_loop_command();
|
execute_loop_command();
|
||||||
}
|
}
|
||||||
|
|
||||||
// manage timeline
|
|
||||||
TimeInterval gap;
|
|
||||||
if (position_ != GST_CLOCK_TIME_NONE && media_.timeline.gapAt(position_, gap)) {
|
|
||||||
|
|
||||||
|
|
||||||
if (gap.is_valid())
|
|
||||||
seek( (rate_>0.f) ? gap.end : gap.begin);
|
|
||||||
|
|
||||||
// TODO : manage loop when jumping out of timeline
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -783,9 +801,9 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
|
|||||||
// no target given
|
// no target given
|
||||||
if (target == GST_CLOCK_TIME_NONE)
|
if (target == GST_CLOCK_TIME_NONE)
|
||||||
// create seek event with current position (rate changed ?)
|
// create seek event with current position (rate changed ?)
|
||||||
seek_pos = position();
|
seek_pos = position_;
|
||||||
// target is given but useless
|
// target is given but useless
|
||||||
else if ( ABS_DIFF(target, position()) < media_.timeline.step()) {
|
else if ( ABS_DIFF(target, position_) < media_.timeline.step()) {
|
||||||
// ignore request
|
// ignore request
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -887,7 +905,7 @@ bool MediaPlayer::fill_frame(GstBuffer *buf, FrameStatus status)
|
|||||||
{
|
{
|
||||||
// Do NOT overwrite an unread EOS
|
// Do NOT overwrite an unread EOS
|
||||||
if ( frame_[write_index_].status == EOS )
|
if ( frame_[write_index_].status == EOS )
|
||||||
return true;
|
write_index_ = (write_index_ + 1) % N_VFRAME;
|
||||||
|
|
||||||
// lock access to frame
|
// lock access to frame
|
||||||
frame_[write_index_].access.lock();
|
frame_[write_index_].access.lock();
|
||||||
@@ -925,8 +943,8 @@ bool MediaPlayer::fill_frame(GstBuffer *buf, FrameStatus status)
|
|||||||
|
|
||||||
// set the start position (i.e. pts of first frame we got)
|
// set the start position (i.e. pts of first frame we got)
|
||||||
if (media_.timeline.start() == GST_CLOCK_TIME_NONE) {
|
if (media_.timeline.start() == GST_CLOCK_TIME_NONE) {
|
||||||
media_.timeline.setStart(buf->pts);
|
media_.timeline.setFirst(buf->pts);
|
||||||
Log::Info("Timeline %ld [%ld %ld]", media_.timeline.numFrames(), media_.timeline.start(), media_.timeline.end());
|
Log::Info("Timeline %ld [%ld %ld]", media_.timeline.numFrames(), media_.timeline.first(), media_.timeline.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// full but invalid frame : will be deleted next iteration
|
// full but invalid frame : will be deleted next iteration
|
||||||
@@ -987,7 +1005,7 @@ GstFlowReturn MediaPlayer::callback_new_preroll (GstAppSink *sink, gpointer p)
|
|||||||
if ( !m->fill_frame(buf, MediaPlayer::PREROLL) )
|
if ( !m->fill_frame(buf, MediaPlayer::PREROLL) )
|
||||||
ret = GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
// loop negative rate: emulate an EOS
|
// loop negative rate: emulate an EOS
|
||||||
else if (m->playSpeed() < 0.f && buf->pts <= m->media_.timeline.start()) {
|
else if (m->playSpeed() < 0.f && !(buf->pts > 0) ) {
|
||||||
m->fill_frame(NULL, MediaPlayer::EOS);
|
m->fill_frame(NULL, MediaPlayer::EOS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1021,7 +1039,7 @@ GstFlowReturn MediaPlayer::callback_new_sample (GstAppSink *sink, gpointer p)
|
|||||||
if ( !m->fill_frame(buf, MediaPlayer::SAMPLE) )
|
if ( !m->fill_frame(buf, MediaPlayer::SAMPLE) )
|
||||||
ret = GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
// loop negative rate: emulate an EOS
|
// loop negative rate: emulate an EOS
|
||||||
else if (m->playSpeed() < 0.f && buf->pts <= m->media_.timeline.start()) {
|
else if (m->playSpeed() < 0.f && !(buf->pts > 0) ) {
|
||||||
m->fill_frame(NULL, MediaPlayer::EOS);
|
m->fill_frame(NULL, MediaPlayer::EOS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
82
Timeline.cpp
82
Timeline.cpp
@@ -44,6 +44,7 @@ void Timeline::reset()
|
|||||||
{
|
{
|
||||||
// reset timing
|
// reset timing
|
||||||
timing_.reset();
|
timing_.reset();
|
||||||
|
first_ = GST_CLOCK_TIME_NONE;
|
||||||
step_ = GST_CLOCK_TIME_NONE;
|
step_ = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
// clear gaps
|
// clear gaps
|
||||||
@@ -55,9 +56,10 @@ bool Timeline::is_valid()
|
|||||||
return timing_.is_valid() && step_ != GST_CLOCK_TIME_NONE;
|
return timing_.is_valid() && step_ != GST_CLOCK_TIME_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::setStart(GstClockTime start)
|
void Timeline::setFirst(GstClockTime first)
|
||||||
{
|
{
|
||||||
timing_.begin = start;
|
timing_.begin = 0;
|
||||||
|
first_ = first;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::setEnd(GstClockTime end)
|
void Timeline::setEnd(GstClockTime end)
|
||||||
@@ -70,6 +72,28 @@ void Timeline::setStep(GstClockTime dt)
|
|||||||
step_ = dt;
|
step_ = dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
void Timeline::updateGapsFromArray(float *array_, size_t array_size_)
|
void Timeline::updateGapsFromArray(float *array_, size_t array_size_)
|
||||||
{
|
{
|
||||||
// reset gaps
|
// reset gaps
|
||||||
@@ -123,7 +147,7 @@ size_t Timeline::numGaps()
|
|||||||
return gaps_.size();
|
return gaps_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timeline::gapAt(const GstClockTime t, TimeInterval &gap)
|
bool Timeline::gapAt(const GstClockTime t, TimeInterval &gap) const
|
||||||
{
|
{
|
||||||
TimeIntervalSet::const_iterator g = std::find_if(gaps_.begin(), gaps_.end(), includesTime(t));
|
TimeIntervalSet::const_iterator g = std::find_if(gaps_.begin(), gaps_.end(), includesTime(t));
|
||||||
|
|
||||||
@@ -148,37 +172,37 @@ bool Timeline::addGap(TimeInterval s)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::toggleGaps(GstClockTime from, GstClockTime to)
|
//void Timeline::toggleGaps(GstClockTime from, GstClockTime to)
|
||||||
{
|
//{
|
||||||
TimeInterval interval(from, to);
|
// TimeInterval interval(from, to);
|
||||||
TimeInterval gap;
|
// TimeInterval gap;
|
||||||
bool is_a_gap_ = gapAt(from, gap);
|
// bool is_a_gap_ = gapAt(from, gap);
|
||||||
|
|
||||||
if (interval.is_valid())
|
// if (interval.is_valid())
|
||||||
{
|
// {
|
||||||
// fill gap
|
// // fill gap
|
||||||
if (is_a_gap_) {
|
// if (is_a_gap_) {
|
||||||
|
|
||||||
}
|
// }
|
||||||
// else create gap (from time is not in a gap)
|
// // else create gap (from time is not in a gap)
|
||||||
else {
|
// else {
|
||||||
|
|
||||||
TimeIntervalSet::iterator g = std::find_if(gaps_.begin(), gaps_.end(), includesTime(to));
|
// TimeIntervalSet::iterator g = std::find_if(gaps_.begin(), gaps_.end(), includesTime(to));
|
||||||
// if there is a gap overlap with [from to] (or [to from]), expand the gap
|
// // if there is a gap overlap with [from to] (or [to from]), expand the gap
|
||||||
if ( g != gaps_.end() ) {
|
// if ( g != gaps_.end() ) {
|
||||||
interval.begin = MIN( (*g).begin, interval.begin);
|
// interval.begin = MIN( (*g).begin, interval.begin);
|
||||||
interval.end = MAX( (*g).end , interval.end);
|
// interval.end = MAX( (*g).end , interval.end);
|
||||||
gaps_.erase(g);
|
// gaps_.erase(g);
|
||||||
}
|
// }
|
||||||
// add the new gap
|
// // add the new gap
|
||||||
addGap(interval);
|
// addGap(interval);
|
||||||
Log::Info("add gap [ %ld %ld ]", interval.begin, interval.end);
|
// Log::Info("add gap [ %ld %ld ]", interval.begin, interval.end);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
}
|
// }
|
||||||
Log::Info("%d gaps in timeline", numGaps());
|
// Log::Info("%d gaps in timeline", numGaps());
|
||||||
}
|
//}
|
||||||
|
|
||||||
bool Timeline::removeGaptAt(GstClockTime t)
|
bool Timeline::removeGaptAt(GstClockTime t)
|
||||||
{
|
{
|
||||||
|
|||||||
14
Timeline.h
14
Timeline.h
@@ -58,7 +58,7 @@ struct TimeInterval
|
|||||||
}
|
}
|
||||||
inline bool includes(const GstClockTime t) const
|
inline bool includes(const GstClockTime t) const
|
||||||
{
|
{
|
||||||
return (is_valid() && t != GST_CLOCK_TIME_NONE && t > this->begin && t < this->end);
|
return (is_valid() && t != GST_CLOCK_TIME_NONE && !(t < this->begin) && !(t > this->end) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,27 +86,32 @@ public:
|
|||||||
|
|
||||||
// global properties of the timeline
|
// global properties of the timeline
|
||||||
// timeline is invalid untill all 3 are set
|
// timeline is invalid untill all 3 are set
|
||||||
void setStart(GstClockTime start);
|
void setFirst(GstClockTime first);
|
||||||
void setEnd(GstClockTime end);
|
void setEnd(GstClockTime end);
|
||||||
void setStep(GstClockTime dt);
|
void setStep(GstClockTime dt);
|
||||||
|
|
||||||
// get properties
|
// get properties
|
||||||
inline GstClockTime start() const { return timing_.begin; }
|
inline GstClockTime start() const { return timing_.begin; }
|
||||||
inline GstClockTime end() const { return timing_.end; }
|
inline GstClockTime end() const { return timing_.end; }
|
||||||
|
inline GstClockTime first() const { return first_; }
|
||||||
|
inline GstClockTime last() const { return timing_.end - step_; }
|
||||||
inline GstClockTime step() const { return step_; }
|
inline GstClockTime step() const { return step_; }
|
||||||
inline GstClockTime duration() const { return timing_.duration(); }
|
inline GstClockTime duration() const { return timing_.duration(); }
|
||||||
inline size_t numFrames() const { return duration() / step_; }
|
inline size_t numFrames() const { return duration() / step_; }
|
||||||
|
|
||||||
|
GstClockTime next(GstClockTime time) const;
|
||||||
|
GstClockTime previous(GstClockTime time) const;
|
||||||
|
|
||||||
// Add / remove gaps in the timeline
|
// Add / remove gaps in the timeline
|
||||||
bool addGap(TimeInterval s);
|
bool addGap(TimeInterval s);
|
||||||
bool addGap(GstClockTime begin, GstClockTime end);
|
bool addGap(GstClockTime begin, GstClockTime end);
|
||||||
bool removeGaptAt(GstClockTime t);
|
bool removeGaptAt(GstClockTime t);
|
||||||
void clearGaps();
|
void clearGaps();
|
||||||
void toggleGaps(GstClockTime from, GstClockTime to);
|
// void toggleGaps(GstClockTime from, GstClockTime to);
|
||||||
|
|
||||||
// get gaps
|
// get gaps
|
||||||
size_t numGaps();
|
size_t numGaps();
|
||||||
bool gapAt(const GstClockTime t, TimeInterval &gap);
|
bool gapAt(const GstClockTime t, TimeInterval &gap) const;
|
||||||
std::list< std::pair<guint64, guint64> > gaps() const;
|
std::list< std::pair<guint64, guint64> > gaps() const;
|
||||||
|
|
||||||
// synchronize data structures
|
// synchronize data structures
|
||||||
@@ -117,6 +122,7 @@ private:
|
|||||||
|
|
||||||
// global information on the timeline
|
// global information on the timeline
|
||||||
TimeInterval timing_;
|
TimeInterval timing_;
|
||||||
|
GstClockTime first_;
|
||||||
GstClockTime step_;
|
GstClockTime step_;
|
||||||
|
|
||||||
// main data structure containing list of gaps in the timeline
|
// main data structure containing list of gaps in the timeline
|
||||||
|
|||||||
@@ -1330,7 +1330,7 @@ void MediaController::Render()
|
|||||||
// bool interval_slider_pressed = ImGuiToolkit::InvisibleSliderInt("##TimelinePicking", &interval_time_current, 0, mp_->timeline().end(), size);
|
// bool interval_slider_pressed = ImGuiToolkit::InvisibleSliderInt("##TimelinePicking", &interval_time_current, 0, mp_->timeline().end(), size);
|
||||||
|
|
||||||
//
|
//
|
||||||
if (timeline_mp != mp_) {
|
if (timeline_mp != mp_ || !working_timeline.is_valid()) {
|
||||||
timeline_mp = mp_;
|
timeline_mp = mp_;
|
||||||
working_timeline = timeline_mp->timeline();
|
working_timeline = timeline_mp->timeline();
|
||||||
working_timeline.fillArrayFromGaps(array, array_size);
|
working_timeline.fillArrayFromGaps(array, array_size);
|
||||||
@@ -1383,7 +1383,7 @@ void MediaController::Render()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// custom timeline slider
|
// custom timeline slider
|
||||||
slider_pressed_ = ImGuiToolkit::TimelineSlider("##timeline", &seek_t,
|
slider_pressed_ = ImGuiToolkit::TimelineSlider("##timeline", &seek_t, mp_->timeline().first(),
|
||||||
mp_->timeline().end(), mp_->timeline().step(), size.x);
|
mp_->timeline().end(), mp_->timeline().step(), size.x);
|
||||||
|
|
||||||
ImGui::PopStyleVar(2);
|
ImGui::PopStyleVar(2);
|
||||||
@@ -1397,7 +1397,7 @@ void MediaController::Render()
|
|||||||
|
|
||||||
// if the seek target time is different from the current position time
|
// if the seek target time is different from the current position time
|
||||||
// (i.e. the difference is less than one frame)
|
// (i.e. the difference is less than one frame)
|
||||||
if ( ABS_DIFF (current_t, seek_t) > mp_->timeline().step() ) {
|
if ( ABS_DIFF (current_t, seek_t) > 2 * mp_->timeline().step() ) {
|
||||||
// request seek (ASYNC)
|
// request seek (ASYNC)
|
||||||
mp_->seek(seek_t);
|
mp_->seek(seek_t);
|
||||||
slider_pressed_ = false;
|
slider_pressed_ = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user