diff --git a/ImGuiToolkit.cpp b/ImGuiToolkit.cpp index d8106ea..2e8a1dc 100644 --- a/ImGuiToolkit.cpp +++ b/ImGuiToolkit.cpp @@ -475,8 +475,9 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 star 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) - float time_ = static_cast ( static_cast(*time - start) / static_cast(end) ); - float step_ = static_cast ( static_cast(step) / static_cast(end) ); + guint64 duration = end - start; + float time_ = static_cast ( static_cast(*time - start) / static_cast(duration) ); + float step_ = static_cast ( static_cast(step) / static_cast(duration) ); // // SECOND GET USER INPUT AND PERFORM CHANGES AND DECISIONS @@ -548,7 +549,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 star tick_step = optimal_tick_marks[i]; large_tick_step = optimal_tick_marks[i+LARGE_TICK_INCREMENT]; label_tick_step = optimal_tick_marks[i+LABEL_TICK_INCREMENT]; - tick_step_pixels = timeline_bbox.GetWidth() * static_cast ( static_cast(tick_step) / static_cast(end) ); + tick_step_pixels = timeline_bbox.GetWidth() * static_cast ( static_cast(tick_step) / static_cast(duration) ); } } @@ -567,7 +568,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 star ImGui::RenderTextClipped( duration_label, bbox.Max, overlay_buf, NULL, &overlay_size); // render tick marks - while ( tick < end) + while ( tick < duration ) { // large tick mark float tick_length = !(tick%large_tick_step) ? fontsize - style.FramePadding.y : style.FramePadding.y; @@ -575,7 +576,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 star // label tick mark if ( !(tick%label_tick_step) ) { tick_length = fontsize; - guint64 ticklabel = 100 * (guint64) round( (double)( tick ) / 100.0); // round value to avoid '0.99' and alike + guint64 ticklabel = 100 * (guint64) round( (double)( tick + start ) / 100.0); // round value to avoid '0.99' and alike ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s", GstToolkit::time_to_string(ticklabel, GstToolkit::TIME_STRING_MINIMAL).c_str()); overlay_size = ImGui::CalcTextSize(overlay_buf, NULL); @@ -591,7 +592,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 star // next tick tick += tick_step; - float tick_percent = static_cast ( static_cast(tick) / static_cast(end) ); + float tick_percent = static_cast ( static_cast(tick) / static_cast(duration) ); pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent); } @@ -656,8 +657,9 @@ void ImGuiToolkit::Timeline (const char* label, guint64 time, guint64 start, gui // 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) - float time_ = static_cast ( static_cast(time - start) / static_cast(end) ); - float step_ = static_cast ( static_cast(step) / static_cast(end) ); + guint64 duration = end - start; + float time_ = static_cast ( static_cast(time - start) / static_cast(duration) ); + float step_ = static_cast ( static_cast(step) / static_cast(duration) ); // // THIRD RENDER @@ -695,7 +697,7 @@ void ImGuiToolkit::Timeline (const char* label, guint64 time, guint64 start, gui tick_step = optimal_tick_marks[i]; large_tick_step = optimal_tick_marks[i+LARGE_TICK_INCREMENT]; label_tick_step = optimal_tick_marks[i+LABEL_TICK_INCREMENT]; - tick_step_pixels = timeline_bbox.GetWidth() * static_cast ( static_cast(tick_step) / static_cast(end) ); + tick_step_pixels = timeline_bbox.GetWidth() * static_cast ( static_cast(tick_step) / static_cast(duration) ); } } @@ -709,12 +711,12 @@ void ImGuiToolkit::Timeline (const char* label, guint64 time, guint64 start, gui ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s", GstToolkit::time_to_string(end, GstToolkit::TIME_STRING_MINIMAL).c_str()); ImVec2 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, 5.f); if (overlay_size.x > 0.0f) ImGui::RenderTextClipped( duration_label, bbox.Max, overlay_buf, NULL, &overlay_size); // render tick marks - while ( tick < end) + while ( tick < duration ) { // large tick mark float tick_length = !(tick%large_tick_step) ? fontsize - style.FramePadding.y : style.FramePadding.y; @@ -722,7 +724,7 @@ void ImGuiToolkit::Timeline (const char* label, guint64 time, guint64 start, gui // label tick mark if ( !(tick%label_tick_step) ) { tick_length = fontsize; - guint64 ticklabel = 100 * (guint64) round( (double)( tick ) / 100.0); // round value to avoid '0.99' and alike + guint64 ticklabel = 100 * (guint64) round( (double)( tick + start) / 100.0); // round value to avoid '0.99' and alike ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s", GstToolkit::time_to_string(ticklabel, GstToolkit::TIME_STRING_MINIMAL).c_str()); overlay_size = ImGui::CalcTextSize(overlay_buf, NULL); @@ -738,7 +740,7 @@ void ImGuiToolkit::Timeline (const char* label, guint64 time, guint64 start, gui // next tick tick += tick_step; - float tick_percent = static_cast ( static_cast(tick) / static_cast(end) ); + float tick_percent = static_cast ( static_cast(tick) / static_cast(duration) ); pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent); } @@ -758,7 +760,7 @@ void ImGuiToolkit::Timeline (const char* label, guint64 time, guint64 start, gui // } // draw the cursor - if ( time_ > 0.f && time_ < 1.f ) { + if ( time_ > -FLT_EPSILON && time_ < 1.f ) { color = ImGui::GetColorU32(style.Colors[ImGuiCol_SliderGrab]); pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), time_) - ImVec2(cursor_width, 2.f); ImGui::RenderArrow(window->DrawList, pos, color, ImGuiDir_Up, cursor_scale); @@ -984,12 +986,12 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array, // keep active area while mouse is pressed static bool active = false; - static uint previous_index = UINT32_MAX; + static size_t previous_index = UINT32_MAX; if (mouse_press) { float x = (float) values_count * (mouse_pos_in_canvas.x - _h_space) / (size.x - 2.f * _h_space); - uint index = CLAMP( (int) floor(x), 0, values_count-1); + size_t index = CLAMP( (int) floor(x), 0, values_count); float y = mouse_pos_in_canvas.y / bbox.GetHeight(); y = CLAMP( (y * (values_max-values_min)) + values_min, values_min, values_max); @@ -997,8 +999,8 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array, if (previous_index == UINT32_MAX) previous_index = index; - const uint left = MIN(previous_index, index); - const uint right = MAX(previous_index, index); + const size_t left = MIN(previous_index, index); + const size_t right = MAX(previous_index, index); if (edit_histogram){ static float target_value = values_min; @@ -1009,13 +1011,13 @@ bool ImGuiToolkit::EditPlotHistoLines(const char* label, float *histogram_array, active = true; } - for (uint i = left; i < right; ++i) + for (size_t i = left; i < right; ++i) histogram_array[i] = target_value; } else { const float target_value = values_max - y; - for (uint i = left; i < right; ++i) + for (size_t i = left; i < right; ++i) lines_array[i] = target_value; } diff --git a/Timeline.cpp b/Timeline.cpp index 6fcb6ca..aeba084 100644 --- a/Timeline.cpp +++ b/Timeline.cpp @@ -120,6 +120,11 @@ void Timeline::update() gaps_array_need_update_ = false; } +void Timeline::refresh() +{ + fillArrayFromGaps(gapsArray_, MAX_TIMELINE_ARRAY); +} + bool Timeline::gapAt(const GstClockTime t, TimeInterval &gap) const { TimeIntervalSet::const_iterator g = std::find_if(gaps_.begin(), gaps_.end(), includesTime(t)); @@ -354,8 +359,10 @@ void Timeline::autoFading(uint milisecond) { // get index of begining of section size_t s = ( (*it).begin * MAX_TIMELINE_ARRAY ) / timing_.end; + s += 1; // get index of ending of section size_t e = ( (*it).end * MAX_TIMELINE_ARRAY ) / timing_.end; + e -= 1; // calculate size of the smooth transition in [s e] interval uint n = MIN( (e-s)/3, N ); @@ -405,14 +412,16 @@ void Timeline::updateGapsFromArray(float *array, size_t array_size) // 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; + GstClockTime t = (timing_.duration() * i) / (array_size-1); // 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 ); + TimeInterval d (begin_gap, t) ; + if (d.is_valid() && d.duration() > step_) + addGap(d); begin_gap = GST_CLOCK_TIME_NONE; } // swap @@ -420,10 +429,14 @@ void Timeline::updateGapsFromArray(float *array, size_t array_size) } } // 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 ); + if (begin_gap != GST_CLOCK_TIME_NONE) { + TimeInterval d (begin_gap, timing_.end) ; + if (d.is_valid() && d.duration() > step_) + addGap(d); + } } + } void Timeline::fillArrayFromGaps(float *array, size_t array_size) @@ -435,10 +448,11 @@ void Timeline::fillArrayFromGaps(float *array, size_t array_size) memcpy(gapsArray_, empty_gaps, MAX_TIMELINE_ARRAY * sizeof(float)); // for each gap + GstClockTime d = timing_.duration(); for (auto it = gaps_.begin(); it != gaps_.end(); ++it) { - size_t s = ( (*it).begin * array_size ) / timing_.end; - size_t e = ( (*it).end * array_size ) / timing_.end; + size_t s = ( (*it).begin * array_size ) / d; + size_t e = ( (*it).end * array_size ) / d; // fill with 1 where there is a gap for (size_t i = s; i < e; ++i) { diff --git a/Timeline.h b/Timeline.h index c201f41..d842b2b 100644 --- a/Timeline.h +++ b/Timeline.h @@ -85,6 +85,7 @@ public: bool is_valid(); void update(); + void refresh(); // global properties of the timeline // timeline is valid only if all 3 are set diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index 7badc53..a0b4d95 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -2147,7 +2147,6 @@ void SourceController::RenderSelection(size_t i) // size_t numsteps = tl->fillSectionsArrays(gaps, fade) - 1; ImVec2 size(rendersize.x - framesize.x - _h_space - _scrollbar, 1.5f * _timeline_height); - GstClockTime playtime = 0; // GstClockTime d = tl->sectionsDuration(); // size.x = size.x * d / ( maxduration * mp->playSpeed() ); @@ -2155,6 +2154,7 @@ void SourceController::RenderSelection(size_t i) // ImGuiToolkit::ShowPlotHistoLines("##TimelineArray2", gaps, fade, numsteps, 0.f, 1.f, size); TimeIntervalSet se = tl->sections(); + GstClockTime playtime = tl->sectionsDuration(); for (auto section = se.begin(); section != se.end(); ++section) { GstClockTime d = section->duration(); @@ -2162,7 +2162,7 @@ void SourceController::RenderSelection(size_t i) ImGuiToolkit::Timeline("##timeline2", mp->position(), section->begin, section->end, tl->step(), w); ImGui::SameLine(0,1); - playtime += d; + } // ImGuiToolkit::Timeline("##timeline2", mp->position(), tl->begin(), tl->end(), tl->step(), size.x); @@ -2170,7 +2170,9 @@ void SourceController::RenderSelection(size_t i) // text below timeline to show info ImGui::SetCursorPos(image_top + ImVec2( framesize.x + _h_space, 1.5f * _timeline_height + _v_space)); GstClockTime t = (GstClockTime) ( (double) playtime / mp->playSpeed() ); - ImGui::Text("%s play time / %.2f speed = %s (effective duration)", GstToolkit::time_to_string(playtime).c_str(), mp->playSpeed(), GstToolkit::time_to_string(t).c_str()); + ImGui::Text("%d sections, %s play time / %.2f speed = %s (effective duration)", + se.size(), GstToolkit::time_to_string(playtime).c_str(), + mp->playSpeed(), GstToolkit::time_to_string(t).c_str()); } // next line position @@ -2516,16 +2518,23 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp) ImGui::SetCursorScreenPos(top + ImVec2(framesize.x - ImGui::GetTextLineHeightWithSpacing(), _v_space)); ImGui::Text(ICON_FA_INFO_CIRCLE); if (ImGui::IsItemHovered()){ + // information visitor mp->accept(info_); - float tooltip_height = 3.f * ImGui::GetTextLineHeightWithSpacing(); ImDrawList* draw_list = ImGui::GetWindowDrawList(); draw_list->AddRectFilled(top, top + ImVec2(framesize.x, tooltip_height), IMGUI_COLOR_OVERLAY); ImGui::SetCursorScreenPos(top + ImVec2(_h_space, _v_space)); ImGui::Text("%s", info_.str().c_str()); - if (mp->isPlaying()) { - ImGui::SetCursorScreenPos(top + ImVec2( framesize.x - 1.5f * _buttons_height, 0.666f * tooltip_height)); + // Icon to inform hardware decoding + if ( !mp->hardwareDecoderName().empty()) { + ImGui::SetCursorScreenPos(top + ImVec2( framesize.x - ImGui::GetTextLineHeightWithSpacing(), 0.35f * tooltip_height)); + ImGui::Text(ICON_FA_MICROCHIP); + } + + // refresh frequency + if ( mp->isPlaying()) { + ImGui::SetCursorScreenPos(top + ImVec2( framesize.x - 1.5f * _buttons_height, 0.667f * tooltip_height)); ImGui::Text("%.1f Hz", mp->updateFrameRate()); } } @@ -2599,40 +2608,29 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp) ImGui::OpenPopup( "MenuTimeline" ); if (ImGui::BeginPopup( "MenuTimeline" )) { - if (ImGui::MenuItem("Reset Speed" )){ + if (ImGui::MenuItem(UNICODE_MULTIPLY " " ICON_FA_CARET_RIGHT " Reset Speed" )){ speed = 1.f; mp->setPlaySpeed( static_cast(speed) ); } - if (ImGui::MenuItem( "Reset Timeline" )){ + if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset Timeline" )){ timeline_zoom = 1.f; mp->timeline()->clearFading(); mp->timeline()->clearGaps(); Action::manager().store("Timeline Reset"); } -// if (ImGui::BeginMenu("Smooth curve")) -// { -// const char* names[] = { "Just a little", "A bit more", "Quite a lot"}; -// for (int i = 0; i < IM_ARRAYSIZE(names); ++i) { -// if (ImGui::MenuItem(names[i])) { -// mp->timeline()->smoothFading( 10 * (int) pow(4, i) ); -// Action::manager().store("Timeline Smooth curve"); -// } -// } -// ImGui::EndMenu(); -// } - if (ImGui::BeginMenu("Auto fading")) + if (ImGui::BeginMenu(ICON_FA_RANDOM " Auto fading")) { const char* names[] = { "250 ms", "500 ms", "1 second", "2 seconds"}; for (int i = 0; i < IM_ARRAYSIZE(names); ++i) { if (ImGui::MenuItem(names[i])) { mp->timeline()->autoFading( 250 * (int ) pow(2, i) ); - mp->timeline()->smoothFading( 10 * (i + 1) ); + mp->timeline()->smoothFading( 2 * (i + 1) ); Action::manager().store("Timeline Auto fading"); } } ImGui::EndMenu(); } - if (Settings::application.render.gpu_decoding && ImGui::BeginMenu("Hardware Decoding")) + if (Settings::application.render.gpu_decoding && ImGui::BeginMenu(ICON_FA_MICROCHIP " Hardware Decoding")) { bool hwdec = !mp->softwareDecodingForced(); if (ImGui::MenuItem("Auto", "", &hwdec )) @@ -2669,16 +2667,18 @@ void SourceController::RenderMediaPlayer(MediaPlayer *mp) ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), _timeline_height -1); size.x *= timeline_zoom; - bool released = false; Timeline *tl = mp->timeline(); if (tl->is_valid()) { + bool released = false; if ( ImGuiToolkit::EditPlotHistoLines("##TimelineArray", tl->gapsArray(), tl->fadingArray(), MAX_TIMELINE_ARRAY, 0.f, 1.f, Settings::application.widget.timeline_editmode, &released, size) ) { tl->update(); } - else if (released) { + else if (released) + { + tl->refresh(); Action::manager().store("Timeline change"); } @@ -3990,7 +3990,7 @@ void Navigator::RenderMainPannelSettings() change |= ImGuiToolkit::ButtonSwitch( "Vertical synchronization", &vsync); change |= ImGuiToolkit::ButtonSwitch( "Blit framebuffer", &blit); change |= ImGuiToolkit::ButtonSwitch( "Antialiasing framebuffer", &multi); - change |= ImGuiToolkit::ButtonSwitch( "Hardware video decoding", &gpu); + change |= ImGuiToolkit::ButtonSwitch( ICON_FA_MICROCHIP " Hardware video decoding", &gpu); if (change) { need_restart = ( vsync != (Settings::application.render.vsync > 0) ||