mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-12 02:40:00 +01:00
work in progress cleanum memory leak and crash :(
This commit is contained in:
@@ -234,6 +234,7 @@ set(VMIX_SRCS
|
|||||||
Screenshot.cpp
|
Screenshot.cpp
|
||||||
Resource.cpp
|
Resource.cpp
|
||||||
FileDialog.cpp
|
FileDialog.cpp
|
||||||
|
Timeline.cpp
|
||||||
MediaPlayer.cpp
|
MediaPlayer.cpp
|
||||||
MediaSource.cpp
|
MediaSource.cpp
|
||||||
FrameBuffer.cpp
|
FrameBuffer.cpp
|
||||||
|
|||||||
213
ImGuiToolkit.cpp
213
ImGuiToolkit.cpp
@@ -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, float scale)
|
bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 duration, 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 };
|
||||||
|
|
||||||
@@ -308,8 +308,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 dura
|
|||||||
// widget bounding box
|
// widget bounding box
|
||||||
const float height = 2.f * (fontsize + style.FramePadding.y);
|
const float height = 2.f * (fontsize + style.FramePadding.y);
|
||||||
ImVec2 pos = window->DC.CursorPos;
|
ImVec2 pos = window->DC.CursorPos;
|
||||||
ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), height);
|
ImVec2 size = ImVec2(width, height);
|
||||||
size.x *= scale;
|
|
||||||
ImRect bbox(pos, pos + size);
|
ImRect bbox(pos, pos + size);
|
||||||
ImGui::ItemSize(size, style.FramePadding.y);
|
ImGui::ItemSize(size, style.FramePadding.y);
|
||||||
if (!ImGui::ItemAdd(bbox, id))
|
if (!ImGui::ItemAdd(bbox, id))
|
||||||
@@ -380,7 +379,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 dura
|
|||||||
// how many pixels to represent one frame step?
|
// how many pixels to represent one frame step?
|
||||||
float tick_step_pixels = timeline_bbox.GetWidth() * step_;
|
float tick_step_pixels = timeline_bbox.GetWidth() * step_;
|
||||||
|
|
||||||
// tick at each step: add a label every 30 frames (1 second?)
|
// tick at each step: add a label every 0 frames
|
||||||
if (tick_step_pixels > 5.f)
|
if (tick_step_pixels > 5.f)
|
||||||
{
|
{
|
||||||
large_tick_step = 10 * step;
|
large_tick_step = 10 * step;
|
||||||
@@ -468,212 +467,6 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 dura
|
|||||||
return left_mouse_press;
|
return left_mouse_press;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draws a timeline showing
|
|
||||||
// 1) a cursor at position *time in the range [0 duration]
|
|
||||||
// 2) a line of tick marks indicating time, every step if possible
|
|
||||||
// 3) a slider handle below the cursor: user can move the slider
|
|
||||||
// 4) different blocs for each time segment [first second] of the list of segments
|
|
||||||
// Behavior
|
|
||||||
// a) Returns TRUE if the left mouse button LMB is pressed over the timeline
|
|
||||||
// b) the value of *time is changed to the position of the slider handle from user input (LMB)
|
|
||||||
// c) the list segments is replaced with the list of new segments created by user (empty list otherwise)
|
|
||||||
|
|
||||||
bool ImGuiToolkit::TimelineSliderEdit(const char* label, guint64 *time, guint64 duration, guint64 step,
|
|
||||||
std::list<std::pair<guint64, guint64> >& segments)
|
|
||||||
{
|
|
||||||
static guint64 optimal_tick_marks[12] = { 100 * MILISECOND, 500 * MILISECOND, 1 * SECOND, 2 * SECOND, 5 * SECOND, 10 * SECOND, 20 * SECOND, 1 * MINUTE, 2 * MINUTE, 5 * MINUTE, 10 * MINUTE, 60 * MINUTE };
|
|
||||||
|
|
||||||
// get window
|
|
||||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
|
||||||
if (window->SkipItems)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// get style & id
|
|
||||||
const ImGuiStyle& style = ImGui::GetStyle();
|
|
||||||
const float fontsize = ImGui::GetFontSize();
|
|
||||||
ImGuiContext& g = *GImGui;
|
|
||||||
const ImGuiID id = window->GetID(label);
|
|
||||||
|
|
||||||
//
|
|
||||||
// FIRST PREPARE ALL data structures
|
|
||||||
//
|
|
||||||
|
|
||||||
// widget bounding box
|
|
||||||
const float height = 2.f * (fontsize + style.FramePadding.y);
|
|
||||||
ImVec2 pos = window->DC.CursorPos;
|
|
||||||
ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), height);
|
|
||||||
ImRect bbox(pos, pos + size);
|
|
||||||
ImGui::ItemSize(size, style.FramePadding.y);
|
|
||||||
if (!ImGui::ItemAdd(bbox, id))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// cursor size
|
|
||||||
const float cursor_scale = 1.f;
|
|
||||||
const float cursor_width = 0.5f * fontsize * cursor_scale;
|
|
||||||
|
|
||||||
// TIMELINE is inside the bbox, in a slightly smaller bounding box
|
|
||||||
ImRect timeline_bbox(bbox);
|
|
||||||
timeline_bbox.Expand( ImVec2(-cursor_width, -style.FramePadding.y) );
|
|
||||||
|
|
||||||
// SLIDER is inside the timeline
|
|
||||||
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<float> ( static_cast<double>(*time) / static_cast<double>(duration) );
|
|
||||||
float step_ = static_cast<float> ( static_cast<double>(step) / static_cast<double>(duration) );
|
|
||||||
|
|
||||||
//
|
|
||||||
// SECOND GET USER INPUT AND PERFORM CHANGES AND DECISIONS
|
|
||||||
//
|
|
||||||
|
|
||||||
// read user input from system
|
|
||||||
bool left_mouse_press = false;
|
|
||||||
bool right_mouse_press = false;
|
|
||||||
const bool hovered = ImGui::ItemHoverable(bbox, id);
|
|
||||||
bool temp_input_is_active = ImGui::TempInputIsActive(id);
|
|
||||||
if (!temp_input_is_active)
|
|
||||||
{
|
|
||||||
const bool focus_requested = ImGui::FocusableItemRegister(window, id);
|
|
||||||
left_mouse_press = hovered && ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
|
||||||
right_mouse_press = hovered && ImGui::IsMouseDown(ImGuiMouseButton_Right);
|
|
||||||
if (focus_requested || left_mouse_press || right_mouse_press || g.NavActivateId == id || g.NavInputId == id)
|
|
||||||
{
|
|
||||||
ImGui::SetActiveID(id, window);
|
|
||||||
ImGui::SetFocusID(id, window);
|
|
||||||
ImGui::FocusWindow(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// active slider if inside bb
|
|
||||||
ImRect grab_slider_bb;
|
|
||||||
ImU32 grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrab);
|
|
||||||
ImGuiID slider_id = window->GetID("werwerwsdvcsdgfdghdfsgagewrgsvdfhfdghkjfghsdgsdtgewfszdvgfkjfg"); // FIXME: cleaner way to create a valid but useless id that is never active
|
|
||||||
if ( slider_bbox.Contains(g.IO.MousePos) ) {
|
|
||||||
slider_id = id; // active id
|
|
||||||
grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrabActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
// time Slider behavior
|
|
||||||
float time_slider = time_ * 10.f; // x 10 precision on grab
|
|
||||||
float time_zero = 0.f;
|
|
||||||
float time_end = 10.f;
|
|
||||||
bool value_changed = ImGui::SliderBehavior(slider_bbox, slider_id, ImGuiDataType_Float, &time_slider, &time_zero,
|
|
||||||
&time_end, "%.2f", 1.f, ImGuiSliderFlags_None, &grab_slider_bb);
|
|
||||||
if (value_changed){
|
|
||||||
// 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) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// segments behavior
|
|
||||||
float time_segment_begin = 0.f;
|
|
||||||
// float time_segment_end = 0.f;
|
|
||||||
if (right_mouse_press) {
|
|
||||||
time_segment_begin = 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// THIRD RENDER
|
|
||||||
//
|
|
||||||
|
|
||||||
// Render the bounding box
|
|
||||||
const ImU32 frame_col = ImGui::GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
|
|
||||||
ImGui::RenderFrame(bbox.Min, bbox.Max, frame_col, true, style.FrameRounding);
|
|
||||||
|
|
||||||
// by default, put a tick mark at every frame step and a large mark every second
|
|
||||||
guint64 tick_step = step;
|
|
||||||
guint64 large_tick_step = SECOND;
|
|
||||||
|
|
||||||
// how many pixels to represent one frame step?
|
|
||||||
float tick_step_pixels = timeline_bbox.GetWidth() * step_;
|
|
||||||
// while there is less than 3 pixels between two tick marks (or at last optimal tick mark)
|
|
||||||
for ( int i=0; i<10 && tick_step_pixels < 3.f; ++i )
|
|
||||||
{
|
|
||||||
// try to use the optimal tick marks pre-defined
|
|
||||||
tick_step = optimal_tick_marks[i];
|
|
||||||
large_tick_step = optimal_tick_marks[i+1];
|
|
||||||
tick_step_pixels = timeline_bbox.GetWidth() * static_cast<float> ( static_cast<double>(tick_step) / static_cast<double>(duration) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// render the tick marks along TIMELINE
|
|
||||||
ImU32 color_in = ImGui::GetColorU32( style.Colors[ImGuiCol_Text] );
|
|
||||||
ImU32 color_out = ImGui::GetColorU32( style.Colors[ImGuiCol_TextDisabled] );
|
|
||||||
ImU32 color = color_in;
|
|
||||||
pos = timeline_bbox.GetTL();
|
|
||||||
guint64 tick = 0;
|
|
||||||
float tick_percent = 0.f;
|
|
||||||
std::list< std::pair<guint64, guint64> >::iterator it = segments.begin();
|
|
||||||
while ( tick < duration)
|
|
||||||
{
|
|
||||||
// large tick mark every large tick
|
|
||||||
float tick_length = !(tick%large_tick_step) ? fontsize : style.FramePadding.y;
|
|
||||||
|
|
||||||
// different colors for inside and outside [begin end] of segments
|
|
||||||
if ( it != segments.end() ) {
|
|
||||||
|
|
||||||
if ( tick < it->first )
|
|
||||||
color = color_out;
|
|
||||||
else if ( tick > it->second ){
|
|
||||||
color = color_out;
|
|
||||||
it ++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
color = color_in;
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw a tick mark each step
|
|
||||||
window->DrawList->AddLine( pos, pos + ImVec2(0.f, tick_length), color);
|
|
||||||
|
|
||||||
// next tick
|
|
||||||
tick += tick_step;
|
|
||||||
tick_percent = static_cast<float> ( static_cast<double>(tick) / static_cast<double>(duration) );
|
|
||||||
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop over segments and EMPTY the list
|
|
||||||
// ticks for segments begin & end
|
|
||||||
for (std::list< std::pair<guint64, guint64> >::iterator s = segments.begin(); s != segments.end(); s++){
|
|
||||||
tick_percent = static_cast<float> ( static_cast<double>(s->first) / static_cast<double>(duration) );
|
|
||||||
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
|
|
||||||
window->DrawList->AddLine( pos, pos + ImVec2(0.f, timeline_bbox.GetHeight()), color_in);
|
|
||||||
tick_percent = static_cast<float> ( static_cast<double>(s->second) / static_cast<double>(duration) );
|
|
||||||
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
|
|
||||||
window->DrawList->AddLine( pos, pos + ImVec2(0.f, timeline_bbox.GetHeight()), color_in);
|
|
||||||
}
|
|
||||||
segments.clear();
|
|
||||||
|
|
||||||
// tick EOF
|
|
||||||
window->DrawList->AddLine( timeline_bbox.GetTR(), timeline_bbox.GetTR() + ImVec2(0.f, fontsize), color_in);
|
|
||||||
|
|
||||||
// render text : duration and current time
|
|
||||||
char overlay_buf[24];
|
|
||||||
ImVec2 overlay_size = ImVec2(0.f, 0.f);
|
|
||||||
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s", GstToolkit::time_to_string(duration).c_str());
|
|
||||||
overlay_size = ImGui::CalcTextSize(overlay_buf, NULL);
|
|
||||||
overlay_size += ImVec2(3.f, 3.f);
|
|
||||||
if (overlay_size.x > 0.0f)
|
|
||||||
ImGui::RenderTextClipped( bbox.GetBR() - overlay_size, bbox.Max, overlay_buf, NULL, &overlay_size);
|
|
||||||
|
|
||||||
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s", GstToolkit::time_to_string(*time).c_str());
|
|
||||||
overlay_size = ImGui::CalcTextSize(overlay_buf, NULL);
|
|
||||||
overlay_size = ImVec2(3.f, -3.f - overlay_size.y);
|
|
||||||
if (overlay_size.x > 0.0f)
|
|
||||||
ImGui::RenderTextClipped( bbox.GetBL() + overlay_size, bbox.Max, overlay_buf, NULL, &overlay_size);
|
|
||||||
|
|
||||||
|
|
||||||
// draw slider grab handle
|
|
||||||
if (grab_slider_bb.Max.x > grab_slider_bb.Min.x) {
|
|
||||||
window->DrawList->AddRectFilled(grab_slider_bb.Min, grab_slider_bb.Max, grab_slider_color, style.GrabRounding);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw the cursor
|
|
||||||
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);
|
|
||||||
|
|
||||||
return left_mouse_press;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ImGuiToolkit::Bar(float value, float in, float out, float min, float max, const char* title, bool expand)
|
void ImGuiToolkit::Bar(float value, float in, float out, float min, float max, const char* title, bool expand)
|
||||||
{
|
{
|
||||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||||
|
|||||||
@@ -27,11 +27,8 @@ 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, float scale = 1.f);
|
bool TimelineSlider (const char* label, guint64 *time, guint64 duration, guint64 step, const float width);
|
||||||
bool TimelineSliderEdit (const char* label, guint64 *time, guint64 duration, guint64 step,
|
bool InvisibleSliderInt(const char* label, uint *index, int min, int max, const ImVec2 size);
|
||||||
std::list<std::pair<guint64, guint64> >& segments);
|
|
||||||
bool InvisibleSliderInt(const char* label, uint *index, int min, int max, ImVec2 size);
|
|
||||||
|
|
||||||
|
|
||||||
// fonts from ressources 'fonts/'
|
// fonts from ressources 'fonts/'
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ void ImGuiVisitor::visit (Source& s)
|
|||||||
|
|
||||||
void ImGuiVisitor::visit (MediaSource& s)
|
void ImGuiVisitor::visit (MediaSource& s)
|
||||||
{
|
{
|
||||||
if ( s.mediaplayer()->duration() == GST_CLOCK_TIME_NONE) {
|
if ( s.mediaplayer()->isImage() ) {
|
||||||
ImGuiToolkit::Icon(2,9);
|
ImGuiToolkit::Icon(2,9);
|
||||||
ImGui::SameLine(0, 10);
|
ImGui::SameLine(0, 10);
|
||||||
ImGui::Text("Image File");
|
ImGui::Text("Image File");
|
||||||
|
|||||||
212
MediaPlayer.cpp
212
MediaPlayer.cpp
@@ -42,9 +42,9 @@ MediaPlayer::MediaPlayer(string name) : id_(name)
|
|||||||
width_ = par_width_ = 640;
|
width_ = par_width_ = 640;
|
||||||
height_ = 480;
|
height_ = 480;
|
||||||
position_ = GST_CLOCK_TIME_NONE;
|
position_ = GST_CLOCK_TIME_NONE;
|
||||||
duration_ = GST_CLOCK_TIME_NONE;
|
// duration_ = GST_CLOCK_TIME_NONE;
|
||||||
start_position_ = GST_CLOCK_TIME_NONE;
|
// start_position_ = GST_CLOCK_TIME_NONE;
|
||||||
frame_duration_ = GST_CLOCK_TIME_NONE;
|
// frame_duration_ = GST_CLOCK_TIME_NONE;
|
||||||
desired_state_ = GST_STATE_PAUSED;
|
desired_state_ = GST_STATE_PAUSED;
|
||||||
loop_ = LoopMode::LOOP_REWIND;
|
loop_ = LoopMode::LOOP_REWIND;
|
||||||
|
|
||||||
@@ -82,14 +82,16 @@ void MediaPlayer::open(string path)
|
|||||||
{
|
{
|
||||||
// set uri to open
|
// set uri to open
|
||||||
filename_ = path;
|
filename_ = path;
|
||||||
uri_ = string( gst_uri_construct("file", path.c_str()) );
|
gchar *uritmp = gst_filename_to_uri(path.c_str(), NULL);
|
||||||
|
uri_ = string( uritmp );
|
||||||
|
g_free(uritmp);
|
||||||
|
|
||||||
// reset
|
// reset
|
||||||
ready_ = false;
|
ready_ = false;
|
||||||
|
|
||||||
/* Instantiate the Discoverer */
|
/* Instantiate the Discoverer */
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
discoverer_ = gst_discoverer_new (5 * GST_SECOND, &err);
|
discoverer_ = gst_discoverer_new (45 * GST_SECOND, &err);
|
||||||
if (!discoverer_) {
|
if (!discoverer_) {
|
||||||
Log::Warning("MediaPlayer Error creating discoverer instance: %s\n", err->message);
|
Log::Warning("MediaPlayer Error creating discoverer instance: %s\n", err->message);
|
||||||
g_clear_error (&err);
|
g_clear_error (&err);
|
||||||
@@ -169,19 +171,26 @@ void MediaPlayer::execute_open()
|
|||||||
gst_app_sink_set_max_buffers( GST_APP_SINK(sink), 100);
|
gst_app_sink_set_max_buffers( GST_APP_SINK(sink), 100);
|
||||||
gst_app_sink_set_drop (GST_APP_SINK(sink), true);
|
gst_app_sink_set_drop (GST_APP_SINK(sink), true);
|
||||||
|
|
||||||
// set the callbacks
|
// // set the callbacks
|
||||||
GstAppSinkCallbacks callbacks;
|
// GstAppSinkCallbacks callbacks;
|
||||||
callbacks.new_preroll = callback_new_preroll;
|
// callbacks.new_preroll = callback_new_preroll;
|
||||||
if (isimage_) {
|
// if (isimage_) {
|
||||||
callbacks.eos = NULL;
|
// callbacks.eos = NULL;
|
||||||
callbacks.new_sample = NULL;
|
// callbacks.new_sample = NULL;
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
callbacks.eos = callback_end_of_stream;
|
// callbacks.eos = callback_end_of_stream;
|
||||||
callbacks.new_sample = callback_new_sample;
|
// callbacks.new_sample = callback_new_sample;
|
||||||
}
|
// }
|
||||||
gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, this, NULL);
|
// gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, this, NULL);
|
||||||
gst_app_sink_set_emit_signals (GST_APP_SINK(sink), false);
|
// gst_app_sink_set_emit_signals (GST_APP_SINK(sink), false);
|
||||||
|
|
||||||
|
// connect callbacks
|
||||||
|
g_signal_connect(G_OBJECT(sink), "new-sample", G_CALLBACK (callback_new_sample), this);
|
||||||
|
g_signal_connect(G_OBJECT(sink), "new-preroll", G_CALLBACK (callback_new_preroll), this);
|
||||||
|
g_signal_connect(G_OBJECT(sink), "eos", G_CALLBACK (callback_end_of_stream), this);
|
||||||
|
gst_app_sink_set_emit_signals (GST_APP_SINK(sink), true);
|
||||||
|
|
||||||
|
|
||||||
// done with ref to sink
|
// done with ref to sink
|
||||||
gst_object_unref (sink);
|
gst_object_unref (sink);
|
||||||
@@ -204,13 +213,18 @@ void MediaPlayer::execute_open()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create & init segment array
|
|
||||||
|
|
||||||
|
|
||||||
// all good
|
// all good
|
||||||
Log::Info("MediaPlayer %s Open %s (%s %d x %d)", id_.c_str(), uri_.c_str(), codec_name_.c_str(), width_, height_);
|
Log::Info("MediaPlayer %s Open %s (%s %d x %d)", id_.c_str(), uri_.c_str(), codec_name_.c_str(), width_, height_);
|
||||||
ready_ = true;
|
ready_ = true;
|
||||||
|
|
||||||
|
// // in case discoverer failed to get duration
|
||||||
|
// if (timeline.end() == GST_CLOCK_TIME_NONE) {
|
||||||
|
// gint64 d = GST_CLOCK_TIME_NONE;
|
||||||
|
// if ( gst_element_query_duration(pipeline_, GST_FORMAT_TIME, &d) )
|
||||||
|
// timeline.setEnd(d);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// register media player
|
||||||
MediaPlayer::registered_.push_back(this);
|
MediaPlayer::registered_.push_back(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,62 +247,51 @@ void MediaPlayer::close()
|
|||||||
discoverer_ = nullptr;
|
discoverer_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// not openned? nothing to close!
|
||||||
if (!ready_)
|
if (!ready_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// un-ready the media player
|
||||||
|
ready_ = false;
|
||||||
|
|
||||||
|
// reset timeline
|
||||||
|
timeline.reset();
|
||||||
|
|
||||||
// clean up GST
|
// clean up GST
|
||||||
if (pipeline_ != nullptr) {
|
if (pipeline_ != nullptr) {
|
||||||
gst_element_set_state (pipeline_, GST_STATE_NULL);
|
GstStateChangeReturn ret = gst_element_set_state (pipeline_, GST_STATE_NULL);
|
||||||
|
if (ret == GST_STATE_CHANGE_ASYNC) {
|
||||||
|
GstState state;
|
||||||
|
gst_element_get_state (pipeline_, &state, NULL, GST_CLOCK_TIME_NONE);
|
||||||
|
}
|
||||||
gst_object_unref (pipeline_);
|
gst_object_unref (pipeline_);
|
||||||
pipeline_ = nullptr;
|
pipeline_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup eventual remaining frame related memory
|
// // cleanup eventual remaining frame related memory
|
||||||
for(guint i = 0; i < N_VFRAME; i++){
|
// for(guint i = 0; i < N_VFRAME; i++){
|
||||||
frame_[i].access.lock();
|
//// frame_[i].access.lock();
|
||||||
if (frame_[i].vframe.buffer)
|
// if (frame_[i].vframe.buffer)
|
||||||
gst_video_frame_unmap(&frame_[i].vframe);
|
// gst_video_frame_unmap(&frame_[i].vframe);
|
||||||
frame_[i].status = EMPTY;
|
// frame_[i].status = EMPTY;
|
||||||
frame_[i].access.unlock();
|
//// frame_[i].access.unlock();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// cleanup opengl texture
|
// cleanup opengl texture
|
||||||
if (textureindex_)
|
if (textureindex_)
|
||||||
glDeleteTextures(1, &textureindex_);
|
glDeleteTextures(1, &textureindex_);
|
||||||
textureindex_ = 0;
|
textureindex_ = 0;
|
||||||
|
|
||||||
// delete picture buffer
|
// cleanup picture buffer
|
||||||
if (pbo_[0])
|
if (pbo_[0])
|
||||||
glDeleteBuffers(2, pbo_);
|
glDeleteBuffers(2, pbo_);
|
||||||
pbo_size_ = 0;
|
pbo_size_ = 0;
|
||||||
|
|
||||||
// un-ready the media player
|
// unregister media player
|
||||||
ready_ = false;
|
|
||||||
|
|
||||||
MediaPlayer::registered_.remove(this);
|
MediaPlayer::registered_.remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GstClockTime MediaPlayer::duration()
|
|
||||||
{
|
|
||||||
// cannot play an image
|
|
||||||
if (isimage_)
|
|
||||||
return GST_CLOCK_TIME_NONE;
|
|
||||||
|
|
||||||
if (duration_ == GST_CLOCK_TIME_NONE && pipeline_ != nullptr) {
|
|
||||||
gint64 d = GST_CLOCK_TIME_NONE;
|
|
||||||
if ( gst_element_query_duration(pipeline_, GST_FORMAT_TIME, &d) )
|
|
||||||
duration_ = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
return duration_;
|
|
||||||
}
|
|
||||||
|
|
||||||
GstClockTime MediaPlayer::frameDuration()
|
|
||||||
{
|
|
||||||
return frame_duration_;
|
|
||||||
}
|
|
||||||
|
|
||||||
guint MediaPlayer::width() const
|
guint MediaPlayer::width() const
|
||||||
{
|
{
|
||||||
return width_;
|
return width_;
|
||||||
@@ -314,7 +317,7 @@ GstClockTime MediaPlayer::position()
|
|||||||
pos = p;
|
pos = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pos - start_position_;
|
return pos - timeline.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPlayer::enable(bool on)
|
void MediaPlayer::enable(bool on)
|
||||||
@@ -347,6 +350,12 @@ bool MediaPlayer::isEnabled() const
|
|||||||
return enabled_;
|
return enabled_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MediaPlayer::isImage() const
|
||||||
|
{
|
||||||
|
return isimage_;
|
||||||
|
}
|
||||||
|
|
||||||
void MediaPlayer::play(bool on)
|
void MediaPlayer::play(bool on)
|
||||||
{
|
{
|
||||||
// cannot play an image
|
// cannot play an image
|
||||||
@@ -369,7 +378,7 @@ 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 ? duration_ - position() : position() ) < 2 * frame_duration_ )
|
if ( ( rate_>0.0 ? timeline.end() - position() : position() ) < 2 * timeline.step() )
|
||||||
rewind();
|
rewind();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +438,7 @@ void MediaPlayer::rewind()
|
|||||||
execute_seek_command(0);
|
execute_seek_command(0);
|
||||||
else
|
else
|
||||||
// playing backward, loop to end
|
// playing backward, loop to end
|
||||||
execute_seek_command(duration_ - frame_duration_);
|
execute_seek_command(timeline.end() - timeline.step());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -439,7 +448,7 @@ void MediaPlayer::step()
|
|||||||
if (!enabled_ || isPlaying())
|
if (!enabled_ || isPlaying())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( position_ == ( rate_ < 0.0 ? start_position_ : duration() ) )
|
if ( position_ == ( rate_ < 0.0 ? timeline.start() : timeline.end() ) )
|
||||||
rewind();
|
rewind();
|
||||||
|
|
||||||
// step
|
// step
|
||||||
@@ -452,7 +461,9 @@ void MediaPlayer::seek(GstClockTime pos)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// apply seek
|
// apply seek
|
||||||
GstClockTime target = CLAMP(pos, 0, duration_);
|
GstClockTime target = CLAMP(pos, 0, timeline.end());
|
||||||
|
// GstClockTime target = CLAMP(pos, timeline.start(), timeline.end());
|
||||||
|
// TODO: confirm that PTS are not possibly ZERO (use of start() is neceessary)
|
||||||
execute_seek_command(target);
|
execute_seek_command(target);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -647,14 +658,20 @@ void MediaPlayer::update()
|
|||||||
// unkock frame after reading it
|
// unkock frame after reading it
|
||||||
frame_[read_index].access.unlock();
|
frame_[read_index].access.unlock();
|
||||||
|
|
||||||
|
if (isimage_)
|
||||||
|
return;
|
||||||
|
|
||||||
// manage loop mode
|
// manage loop mode
|
||||||
if (need_loop && !isimage_) {
|
if (need_loop) {
|
||||||
execute_loop_command();
|
execute_loop_command();
|
||||||
}
|
}
|
||||||
|
|
||||||
// manage timeline
|
// manage timeline
|
||||||
// if (position_!=GST_CLOCK_TIME_NONE) {
|
// TimeInterval gap;
|
||||||
|
// if (position_ != GST_CLOCK_TIME_NONE && timeline.gapAt(position_, gap)) {
|
||||||
|
// seek( (rate_>0.f) ? gap.end : gap.begin);
|
||||||
|
|
||||||
|
// // TODO : manage loop when jumping out of timeline
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@@ -688,7 +705,7 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
|
|||||||
// 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()) < frame_duration_) {
|
else if ( ABS_DIFF(target, position()) < timeline.step()) {
|
||||||
// ignore request
|
// ignore request
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -699,6 +716,24 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
|
|||||||
if ( ABS(rate_) > 1.0 )
|
if ( ABS(rate_) > 1.0 )
|
||||||
seek_flags |= GST_SEEK_FLAG_TRICKMODE;
|
seek_flags |= GST_SEEK_FLAG_TRICKMODE;
|
||||||
|
|
||||||
|
// bool ret = false;
|
||||||
|
|
||||||
|
// if (rate_ > 0) {
|
||||||
|
|
||||||
|
// ret = gst_element_seek (pipeline_, rate_, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
|
||||||
|
// GST_SEEK_TYPE_SET, seek_pos,
|
||||||
|
// GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
|
||||||
|
// ret = gst_element_seek (pipeline_, rate_, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
|
||||||
|
// GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE,
|
||||||
|
// GST_SEEK_TYPE_SET, seek_pos);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!ret)
|
||||||
|
// Log::Warning("MediaPlayer %s Seek failed", gst_element_get_name(pipeline_));
|
||||||
|
|
||||||
// create seek event depending on direction
|
// create seek event depending on direction
|
||||||
GstEvent *seek_event = nullptr;
|
GstEvent *seek_event = nullptr;
|
||||||
if (rate_ > 0) {
|
if (rate_ > 0) {
|
||||||
@@ -712,12 +747,13 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
|
|||||||
|
|
||||||
// Send the event (ASYNC)
|
// Send the event (ASYNC)
|
||||||
if (seek_event && !gst_element_send_event(pipeline_, seek_event) )
|
if (seek_event && !gst_element_send_event(pipeline_, seek_event) )
|
||||||
Log::Warning("MediaPlayer %s Seek failed", gst_element_get_name(pipeline_));
|
Log::Warning("MediaPlayer %s Seek failed", id_.c_str());
|
||||||
else {
|
else {
|
||||||
#ifdef MEDIA_PLAYER_DEBUG
|
#ifdef MEDIA_PLAYER_DEBUG
|
||||||
Log::Info("MediaPlayer %s Seek %ld %f", gst_element_get_name(pipeline_), seek_pos, rate_);
|
Log::Info("MediaPlayer %s Seek %ld %f", id_.c_str(), seek_pos, rate_);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPlayer::setPlaySpeed(double s)
|
void MediaPlayer::setPlaySpeed(double s)
|
||||||
@@ -803,13 +839,13 @@ bool MediaPlayer::fill_frame(GstBuffer *buf, MediaPlayer::FrameStatus status)
|
|||||||
frame_[write_index_].position = buf->pts;
|
frame_[write_index_].position = buf->pts;
|
||||||
|
|
||||||
// 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 (start_position_ == GST_CLOCK_TIME_NONE)
|
if (timeline.start() == GST_CLOCK_TIME_NONE)
|
||||||
start_position_ = buf->pts;
|
timeline.setStart(buf->pts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// give a position to EOS
|
// give a position to EOS
|
||||||
else {
|
else {
|
||||||
frame_[write_index_].position = rate_ > 0.0 ? duration() : start_position_;
|
frame_[write_index_].position = rate_ > 0.0 ? timeline.end() : timeline.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// unlock access to frame
|
// unlock access to frame
|
||||||
@@ -833,7 +869,7 @@ bool MediaPlayer::fill_frame(GstBuffer *buf, MediaPlayer::FrameStatus status)
|
|||||||
void MediaPlayer::callback_end_of_stream (GstAppSink *, gpointer p)
|
void MediaPlayer::callback_end_of_stream (GstAppSink *, gpointer p)
|
||||||
{
|
{
|
||||||
MediaPlayer *m = (MediaPlayer *)p;
|
MediaPlayer *m = (MediaPlayer *)p;
|
||||||
if (m) {
|
if (m && m->ready_) {
|
||||||
m->fill_frame(NULL, MediaPlayer::EOS);
|
m->fill_frame(NULL, MediaPlayer::EOS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -849,22 +885,22 @@ GstFlowReturn MediaPlayer::callback_new_preroll (GstAppSink *sink, gpointer p)
|
|||||||
if (sample != NULL) {
|
if (sample != NULL) {
|
||||||
|
|
||||||
// get buffer from sample
|
// get buffer from sample
|
||||||
GstBuffer *buf = gst_buffer_ref ( gst_sample_get_buffer (sample) );
|
GstBuffer *buf = /*gst_buffer_ref */( gst_sample_get_buffer (sample) );
|
||||||
|
|
||||||
MediaPlayer *m = (MediaPlayer *)p;
|
MediaPlayer *m = (MediaPlayer *)p;
|
||||||
if (m) {
|
if (m && m->ready_) {
|
||||||
// fill frame from buffer
|
// fill frame from buffer
|
||||||
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
|
||||||
if (m->playSpeed() < 0.f && buf->pts == m->start_position_) {
|
if (m->playSpeed() < 0.f && buf->pts <= m->timeline.start()) {
|
||||||
m->fill_frame(NULL, MediaPlayer::EOS);
|
m->fill_frame(NULL, MediaPlayer::EOS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// free buffers
|
// free buffers
|
||||||
gst_buffer_unref (buf);
|
// gst_buffer_unref (buf);
|
||||||
gst_sample_unref (sample);
|
gst_sample_unref (sample);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -884,29 +920,29 @@ GstFlowReturn MediaPlayer::callback_new_sample (GstAppSink *sink, gpointer p)
|
|||||||
if (sample != NULL && !gst_app_sink_is_eos (sink)) {
|
if (sample != NULL && !gst_app_sink_is_eos (sink)) {
|
||||||
|
|
||||||
// get buffer from sample
|
// get buffer from sample
|
||||||
GstBuffer *buf = gst_buffer_ref ( gst_sample_get_buffer (sample) );
|
GstBuffer *buf = /*gst_buffer_ref*/ ( gst_sample_get_buffer (sample) );
|
||||||
|
|
||||||
MediaPlayer *m = (MediaPlayer *)p;
|
MediaPlayer *m = (MediaPlayer *)p;
|
||||||
if (m) {
|
if (m && m->ready_) {
|
||||||
|
|
||||||
// fill frame with buffer
|
// fill frame with buffer
|
||||||
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
|
||||||
if (m->playSpeed() < 0.f && buf->pts == m->start_position_) {
|
if (m->playSpeed() < 0.f && buf->pts <= m->timeline.start()) {
|
||||||
m->fill_frame(NULL, MediaPlayer::EOS);
|
m->fill_frame(NULL, MediaPlayer::EOS);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// free buffer & sample
|
// free buffer & sample
|
||||||
gst_buffer_unref (buf);
|
// gst_buffer_unref (buf);
|
||||||
gst_sample_unref (sample);
|
gst_sample_unref (sample);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
// else
|
||||||
ret = GST_FLOW_FLUSHING;
|
// ret = GST_FLOW_FLUSHING;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -967,7 +1003,7 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
|
|||||||
m->par_width_ = (m->width_ * parn) / pard;
|
m->par_width_ = (m->width_ * parn) / pard;
|
||||||
// if its a video, it duration, framerate, etc.
|
// if its a video, it duration, framerate, etc.
|
||||||
if ( !m->isimage_ ) {
|
if ( !m->isimage_ ) {
|
||||||
m->duration_ = gst_discoverer_info_get_duration (info);
|
m->timeline.setEnd( gst_discoverer_info_get_duration (info) );
|
||||||
m->seekable_ = gst_discoverer_info_get_seekable (info);
|
m->seekable_ = gst_discoverer_info_get_seekable (info);
|
||||||
guint frn = gst_discoverer_video_info_get_framerate_num(vinfo);
|
guint frn = gst_discoverer_video_info_get_framerate_num(vinfo);
|
||||||
guint frd = gst_discoverer_video_info_get_framerate_denom(vinfo);
|
guint frd = gst_discoverer_video_info_get_framerate_denom(vinfo);
|
||||||
@@ -976,20 +1012,22 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
|
|||||||
frd = 1;
|
frd = 1;
|
||||||
}
|
}
|
||||||
m->framerate_ = static_cast<double>(frn) / static_cast<double>(frd);
|
m->framerate_ = static_cast<double>(frn) / static_cast<double>(frd);
|
||||||
m->frame_duration_ = (GST_SECOND * static_cast<guint64>(frd)) / (static_cast<guint64>(frn));
|
m->timeline.setStep( (GST_SECOND * static_cast<guint64>(frd)) / (static_cast<guint64>(frn)) );
|
||||||
}
|
}
|
||||||
// try to fill-in the codec information
|
// try to fill-in the codec information
|
||||||
GstCaps *caps = gst_discoverer_stream_info_get_caps (tmpinf);
|
GstCaps *caps = gst_discoverer_stream_info_get_caps (tmpinf);
|
||||||
if (caps) {
|
if (caps) {
|
||||||
m->codec_name_ = std::string( gst_pb_utils_get_codec_description(caps) ) + " ";
|
gchar *codecstring = gst_pb_utils_get_codec_description(caps);
|
||||||
|
m->codec_name_ = std::string( codecstring ) + " ";
|
||||||
|
g_free(codecstring);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
}
|
}
|
||||||
const GstTagList *tags = gst_discoverer_stream_info_get_tags(tmpinf);
|
// const GstTagList *tags = gst_discoverer_stream_info_get_tags(tmpinf);
|
||||||
if ( tags ) {
|
// if ( tags ) {
|
||||||
gchar *container = NULL;
|
// gchar *container = NULL;
|
||||||
gst_tag_list_get_string (tags, GST_TAG_CONTAINER_FORMAT, &container);
|
// gst_tag_list_get_string (tags, GST_TAG_CONTAINER_FORMAT, &container);
|
||||||
if (container) m->codec_name_ += std::string(container);
|
// if (container) m->codec_name_ += std::string(container);
|
||||||
}
|
// }
|
||||||
// exit loop
|
// exit loop
|
||||||
foundvideostream = true;
|
foundvideostream = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ public:
|
|||||||
* True if enabled
|
* True if enabled
|
||||||
* */
|
* */
|
||||||
bool isEnabled() const;
|
bool isEnabled() const;
|
||||||
|
/**
|
||||||
|
* True if its an image
|
||||||
|
* */
|
||||||
|
bool isImage() const;
|
||||||
/**
|
/**
|
||||||
* Pause / Play
|
* Pause / Play
|
||||||
* Can play backward if play speed is negative
|
* Can play backward if play speed is negative
|
||||||
@@ -136,13 +140,13 @@ public:
|
|||||||
* */
|
* */
|
||||||
GstClockTime position();
|
GstClockTime position();
|
||||||
/**
|
/**
|
||||||
* Get total duration time
|
* @brief timeline contains all info on timing:
|
||||||
* */
|
* - start position : timeline.start()
|
||||||
GstClockTime duration();
|
* - end position : timeline.end()
|
||||||
/**
|
* - duration : timeline.duration()
|
||||||
* Get duration of one frame
|
* - frame duration : timeline.step()
|
||||||
* */
|
*/
|
||||||
GstClockTime frameDuration();
|
Timeline timeline;
|
||||||
/**
|
/**
|
||||||
* Get framerate of the media
|
* Get framerate of the media
|
||||||
* */
|
* */
|
||||||
@@ -195,9 +199,11 @@ private:
|
|||||||
guint par_width_; // width to match pixel aspect ratio
|
guint par_width_; // width to match pixel aspect ratio
|
||||||
guint bitrate_;
|
guint bitrate_;
|
||||||
GstClockTime position_;
|
GstClockTime position_;
|
||||||
GstClockTime start_position_;
|
|
||||||
GstClockTime duration_;
|
// GstClockTime start_position_;
|
||||||
GstClockTime frame_duration_;
|
// GstClockTime duration_;
|
||||||
|
// GstClockTime frame_duration_;
|
||||||
|
|
||||||
gdouble rate_;
|
gdouble rate_;
|
||||||
LoopMode loop_;
|
LoopMode loop_;
|
||||||
gdouble framerate_;
|
gdouble framerate_;
|
||||||
@@ -276,6 +282,7 @@ private:
|
|||||||
static void callback_end_of_stream (GstAppSink *, gpointer);
|
static void callback_end_of_stream (GstAppSink *, gpointer);
|
||||||
static GstFlowReturn callback_new_preroll (GstAppSink *, gpointer );
|
static GstFlowReturn callback_new_preroll (GstAppSink *, gpointer );
|
||||||
static GstFlowReturn callback_new_sample (GstAppSink *, gpointer);
|
static GstFlowReturn callback_new_sample (GstAppSink *, gpointer);
|
||||||
|
|
||||||
static void callback_discoverer_process (GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, MediaPlayer *m);
|
static void callback_discoverer_process (GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, MediaPlayer *m);
|
||||||
static void callback_discoverer_finished(GstDiscoverer *discoverer, MediaPlayer *m);
|
static void callback_discoverer_finished(GstDiscoverer *discoverer, MediaPlayer *m);
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ void MediaSource::init()
|
|||||||
attach(renderbuffer);
|
attach(renderbuffer);
|
||||||
|
|
||||||
// icon in mixing view
|
// icon in mixing view
|
||||||
if (mediaplayer_->duration() == GST_CLOCK_TIME_NONE) {
|
if (mediaplayer_->isImage()) {
|
||||||
overlays_[View::MIXING]->attach( new Symbol(Symbol::IMAGE, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
overlays_[View::MIXING]->attach( new Symbol(Symbol::IMAGE, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||||
overlays_[View::LAYER]->attach( new Symbol(Symbol::IMAGE, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
overlays_[View::LAYER]->attach( new Symbol(Symbol::IMAGE, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ Session::~Session()
|
|||||||
// erase this source from the list
|
// erase this source from the list
|
||||||
it = deleteSource(*it);
|
it = deleteSource(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete config_[View::RENDERING];
|
||||||
|
delete config_[View::GEOMETRY];
|
||||||
|
delete config_[View::LAYER];
|
||||||
|
delete config_[View::MIXING];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::setActive (bool on)
|
void Session::setActive (bool on)
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ SessionCreator::SessionCreator(Session *session): Visitor(), session_(session)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SessionCreator::~SessionCreator()
|
||||||
|
{
|
||||||
|
delete xmlDoc_;
|
||||||
|
}
|
||||||
|
|
||||||
bool SessionCreator::load(const std::string& filename)
|
bool SessionCreator::load(const std::string& filename)
|
||||||
{
|
{
|
||||||
XMLError eResult = xmlDoc_->LoadFile(filename.c_str());
|
XMLError eResult = xmlDoc_->LoadFile(filename.c_str());
|
||||||
@@ -179,6 +184,20 @@ void SessionCreator::visit(MediaPlayer &n)
|
|||||||
{
|
{
|
||||||
XMLElement* mediaplayerNode = xmlCurrent_->FirstChildElement("MediaPlayer");
|
XMLElement* mediaplayerNode = xmlCurrent_->FirstChildElement("MediaPlayer");
|
||||||
if (mediaplayerNode) {
|
if (mediaplayerNode) {
|
||||||
|
// timeline
|
||||||
|
XMLElement *gapselement = mediaplayerNode->FirstChildElement("Gaps");
|
||||||
|
if (gapselement) {
|
||||||
|
XMLElement* gap = gapselement->FirstChildElement("Interval");
|
||||||
|
for( ; gap ; gap = gap->NextSiblingElement())
|
||||||
|
{
|
||||||
|
GstClockTime a = GST_CLOCK_TIME_NONE;
|
||||||
|
GstClockTime b = GST_CLOCK_TIME_NONE;
|
||||||
|
gap->QueryUnsigned64Attribute("begin", &a);
|
||||||
|
gap->QueryUnsigned64Attribute("end", &b);
|
||||||
|
n.timeline.addGap( a, b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// playing properties
|
||||||
double speed = 1.0;
|
double speed = 1.0;
|
||||||
mediaplayerNode->QueryDoubleAttribute("speed", &speed);
|
mediaplayerNode->QueryDoubleAttribute("speed", &speed);
|
||||||
n.setPlaySpeed(speed);
|
n.setPlaySpeed(speed);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class SessionCreator : public Visitor {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SessionCreator(Session *session = nullptr);
|
SessionCreator(Session *session = nullptr);
|
||||||
|
~SessionCreator();
|
||||||
|
|
||||||
bool load(const std::string& filename);
|
bool load(const std::string& filename);
|
||||||
inline Session *session() const { return session_; }
|
inline Session *session() const { return session_; }
|
||||||
|
|||||||
@@ -147,7 +147,16 @@ void SessionVisitor::visit(MediaPlayer &n)
|
|||||||
newelement->SetAttribute("loop", (int) n.loop());
|
newelement->SetAttribute("loop", (int) n.loop());
|
||||||
newelement->SetAttribute("speed", n.playSpeed());
|
newelement->SetAttribute("speed", n.playSpeed());
|
||||||
|
|
||||||
// TODO Segments
|
// gaps in timeline
|
||||||
|
XMLElement *gapselement = xmlDoc_->NewElement("Gaps");
|
||||||
|
std::list< std::pair<guint64, guint64> > gaps = n.timeline.gaps();
|
||||||
|
for( auto it = gaps.begin(); it!= gaps.end(); it++) {
|
||||||
|
XMLElement *g = xmlDoc_->NewElement("Interval");
|
||||||
|
g->SetAttribute("begin", (*it).first);
|
||||||
|
g->SetAttribute("end", (*it).second);
|
||||||
|
gapselement->InsertEndChild(g);
|
||||||
|
}
|
||||||
|
newelement->InsertEndChild(gapselement);
|
||||||
|
|
||||||
xmlCurrent_->InsertEndChild(newelement);
|
xmlCurrent_->InsertEndChild(newelement);
|
||||||
}
|
}
|
||||||
|
|||||||
184
Timeline.cpp
184
Timeline.cpp
@@ -17,71 +17,181 @@ Timeline::Timeline() : array_(nullptr)
|
|||||||
Timeline::~Timeline()
|
Timeline::~Timeline()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
// free(array_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::reset()
|
void Timeline::reset()
|
||||||
{
|
{
|
||||||
start_ = GST_CLOCK_TIME_NONE;
|
// reset timing
|
||||||
end_ = GST_CLOCK_TIME_NONE;
|
timing_.begin = GST_CLOCK_TIME_NONE;
|
||||||
num_frames_ = 0;
|
timing_.end = GST_CLOCK_TIME_NONE;
|
||||||
array_size_ = 0;
|
step_ = GST_CLOCK_TIME_NONE;
|
||||||
// clear segment array
|
|
||||||
if (array_ != nullptr)
|
// // clear gaps
|
||||||
free(array_);
|
// gaps_.clear();
|
||||||
|
|
||||||
|
// // clear segment array
|
||||||
|
// if (array_ != nullptr)
|
||||||
|
// free(array_);
|
||||||
|
|
||||||
|
// // avoid crash by providing a valid pointer
|
||||||
|
// array_size_ = 1;
|
||||||
|
// array_ = (float *) malloc(sizeof(float));
|
||||||
|
// array_[0] = 1.f;
|
||||||
|
// need_update_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::init(GstClockTime start, GstClockTime end, GstClockTime frame_duration)
|
void Timeline::setStart(GstClockTime start)
|
||||||
{
|
{
|
||||||
reset();
|
timing_.begin = start;
|
||||||
|
need_update_ = true;
|
||||||
start_ = start;
|
|
||||||
end_ = end;
|
|
||||||
num_frames_ = (size_t) end_ / (size_t) frame_duration;
|
|
||||||
|
|
||||||
array_size_ = MIN( SEGMENT_ARRAY_MAX_SIZE, num_frames_);
|
|
||||||
array_ = (float *) malloc(array_size_ * sizeof(float));
|
|
||||||
for (int i = 0; i < array_size_; ++i)
|
|
||||||
array_[i] = 1.f;
|
|
||||||
|
|
||||||
Log::Info("%d frames in timeline", array_size_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timeline::addPlaySegment(GstClockTime begin, GstClockTime end)
|
void Timeline::setEnd(GstClockTime end)
|
||||||
{
|
{
|
||||||
return addPlaySegment( MediaSegment(begin, end) );
|
timing_.end = end;
|
||||||
|
need_update_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timeline::addPlaySegment(MediaSegment s)
|
void Timeline::setStep(GstClockTime dt)
|
||||||
{
|
{
|
||||||
if ( s.is_valid() )
|
step_ = dt;
|
||||||
return segments_.insert(s).second;
|
need_update_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timeline::updateGapsFromArray()
|
||||||
|
{
|
||||||
|
// if (need_update_)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// // reset gaps
|
||||||
|
// gaps_.clear();
|
||||||
|
|
||||||
|
// // loop over the array to detect gaps
|
||||||
|
// float status = 1.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 1.f to 0.f : begin of a gap
|
||||||
|
// if (status) {
|
||||||
|
// begin_gap = t;
|
||||||
|
// }
|
||||||
|
// // change from 0.f to 1.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::updateArrayFromGaps()
|
||||||
|
{
|
||||||
|
// if (step_ != GST_CLOCK_TIME_NONE && timing_.is_valid()) {
|
||||||
|
|
||||||
|
// // clear segment array
|
||||||
|
// if (array_ != nullptr)
|
||||||
|
// free(array_);
|
||||||
|
|
||||||
|
// array_size_ = MIN( SEGMENT_ARRAY_MAX_SIZE, duration() / step_);
|
||||||
|
// array_ = (float *) malloc(array_size_ * sizeof(float));
|
||||||
|
// for (int i = 0; i < array_size_; ++i)
|
||||||
|
// array_[i] = 1.f;
|
||||||
|
|
||||||
|
// Log::Info("%d frames in timeline", array_size_);
|
||||||
|
|
||||||
|
// // fill the array from gaps
|
||||||
|
// // NB: this is the less efficient algorithm possible! but we should not keep arrays anyway
|
||||||
|
// // TODO : implement an ImGui widget to plot a timeline instead of an array
|
||||||
|
// TimeInterval gap;
|
||||||
|
// for (size_t i = 0; i < array_size_; ++i) {
|
||||||
|
// GstClockTime t = (timing_.duration() * i) / array_size_;
|
||||||
|
// array_[i] = gapAt(t, gap) ? 0.f : 1.f;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// need_update_ = false;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Timeline::numGaps()
|
||||||
|
{
|
||||||
|
return gaps_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Timeline::gapAt(const GstClockTime t, TimeInterval &gap)
|
||||||
|
{
|
||||||
|
// TimeIntervalSet::const_iterator g = std::find_if(gaps_.begin(), gaps_.end(), includesTime(t));
|
||||||
|
|
||||||
|
// if ( g != gaps_.end() ) {
|
||||||
|
// gap = (*g);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timeline::removeAllPlaySegmentOverlap(MediaSegment s)
|
bool Timeline::addGap(GstClockTime begin, GstClockTime end)
|
||||||
{
|
{
|
||||||
bool ret = removePlaySegmentAt(s.begin);
|
return addGap( TimeInterval(begin, end) );
|
||||||
return removePlaySegmentAt(s.end) || ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timeline::removePlaySegmentAt(GstClockTime t)
|
bool Timeline::addGap(TimeInterval s)
|
||||||
{
|
{
|
||||||
MediaSegmentSet::const_iterator s = std::find_if(segments_.begin(), segments_.end(), containsTime(t));
|
// if ( s.is_valid() ) {
|
||||||
|
// need_update_ = true;
|
||||||
if ( s != segments_.end() ) {
|
// return gaps_.insert(s).second;
|
||||||
segments_.erase(s);
|
// }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list< std::pair<guint64, guint64> > Timeline::getPlaySegments() const
|
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);
|
||||||
|
// need_update_ = true;
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timeline::clearGaps()
|
||||||
|
{
|
||||||
|
gaps_.clear();
|
||||||
|
need_update_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list< std::pair<guint64, guint64> > Timeline::gaps() const
|
||||||
{
|
{
|
||||||
std::list< std::pair<guint64, guint64> > ret;
|
std::list< std::pair<guint64, guint64> > ret;
|
||||||
for (MediaSegmentSet::iterator it = segments_.begin(); it != segments_.end(); it++)
|
for (TimeIntervalSet::iterator it = gaps_.begin(); it != gaps_.end(); it++)
|
||||||
ret.push_back( std::make_pair( it->begin, it->end ) );
|
ret.push_back( std::make_pair( it->begin, it->end ) );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float *Timeline::array()
|
||||||
|
{
|
||||||
|
// if (need_update_)
|
||||||
|
// updateArrayFromGaps();
|
||||||
|
return array_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Timeline::arraySize()
|
||||||
|
{
|
||||||
|
// if (need_update_)
|
||||||
|
// updateArrayFromGaps();
|
||||||
|
return array_size_;
|
||||||
|
}
|
||||||
|
|||||||
89
Timeline.h
89
Timeline.h
@@ -8,18 +8,18 @@
|
|||||||
|
|
||||||
#include <gst/pbutils/pbutils.h>
|
#include <gst/pbutils/pbutils.h>
|
||||||
|
|
||||||
struct MediaSegment
|
struct TimeInterval
|
||||||
{
|
{
|
||||||
GstClockTime begin;
|
GstClockTime begin;
|
||||||
GstClockTime end;
|
GstClockTime end;
|
||||||
|
|
||||||
MediaSegment()
|
TimeInterval()
|
||||||
{
|
{
|
||||||
begin = GST_CLOCK_TIME_NONE;
|
begin = GST_CLOCK_TIME_NONE;
|
||||||
end = GST_CLOCK_TIME_NONE;
|
end = GST_CLOCK_TIME_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaSegment(GstClockTime b, GstClockTime e)
|
TimeInterval(GstClockTime b, GstClockTime e)
|
||||||
{
|
{
|
||||||
if ( b < e ) {
|
if ( b < e ) {
|
||||||
begin = b;
|
begin = b;
|
||||||
@@ -29,39 +29,55 @@ struct MediaSegment
|
|||||||
end = GST_CLOCK_TIME_NONE;
|
end = GST_CLOCK_TIME_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
inline GstClockTime duration() const
|
||||||
|
{
|
||||||
|
return is_valid() ? (end - begin) : GST_CLOCK_TIME_NONE;
|
||||||
|
}
|
||||||
inline bool is_valid() const
|
inline bool is_valid() const
|
||||||
{
|
{
|
||||||
return begin != GST_CLOCK_TIME_NONE && end != GST_CLOCK_TIME_NONE && begin < end;
|
return begin != GST_CLOCK_TIME_NONE && end != GST_CLOCK_TIME_NONE && begin < end;
|
||||||
}
|
}
|
||||||
inline bool operator < (const MediaSegment b) const
|
inline bool operator < (const TimeInterval b) const
|
||||||
{
|
{
|
||||||
return (this->is_valid() && b.is_valid() && this->end < b.begin);
|
return (this->is_valid() && b.is_valid() && this->end < b.begin);
|
||||||
}
|
}
|
||||||
inline bool operator == (const MediaSegment b) const
|
inline bool operator == (const TimeInterval b) const
|
||||||
{
|
{
|
||||||
return (this->begin == b.begin && this->end == b.end);
|
return (this->begin == b.begin && this->end == b.end);
|
||||||
}
|
}
|
||||||
inline bool operator != (const MediaSegment b) const
|
inline bool operator != (const TimeInterval b) const
|
||||||
{
|
{
|
||||||
return (this->begin != b.begin || this->end != b.end);
|
return (this->begin != b.begin || this->end != b.end);
|
||||||
}
|
}
|
||||||
|
inline TimeInterval& operator = (const TimeInterval& b)
|
||||||
|
{
|
||||||
|
if (this != &b) {
|
||||||
|
this->begin = b.begin;
|
||||||
|
this->end = b.end;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline bool includes(const GstClockTime t) const
|
||||||
|
{
|
||||||
|
return (is_valid() && t != GST_CLOCK_TIME_NONE && t > this->begin && t < this->end);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct containsTime: public std::unary_function<MediaSegment, bool>
|
struct includesTime: public std::unary_function<TimeInterval, bool>
|
||||||
{
|
{
|
||||||
inline bool operator()(const MediaSegment s) const
|
inline bool operator()(const TimeInterval s) const
|
||||||
{
|
{
|
||||||
return ( s.is_valid() && _t > s.begin && _t < s.end );
|
return s.includes(_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
containsTime(GstClockTime t) : _t(t) { }
|
includesTime(GstClockTime t) : _t(t) { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GstClockTime _t;
|
GstClockTime _t;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef std::set<MediaSegment> MediaSegmentSet;
|
typedef std::set<TimeInterval> TimeIntervalSet;
|
||||||
|
|
||||||
|
|
||||||
class Timeline
|
class Timeline
|
||||||
@@ -71,27 +87,52 @@ public:
|
|||||||
~Timeline();
|
~Timeline();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void init(GstClockTime start, GstClockTime end, GstClockTime frame_duration);
|
|
||||||
|
|
||||||
bool addPlaySegment(GstClockTime begin, GstClockTime end);
|
// global properties of the timeline
|
||||||
bool addPlaySegment(MediaSegment s);
|
// timeline is invalid untill all 3 are set
|
||||||
bool removePlaySegmentAt(GstClockTime t);
|
void setStart(GstClockTime start);
|
||||||
bool removeAllPlaySegmentOverlap(MediaSegment s);
|
void setEnd(GstClockTime end);
|
||||||
std::list< std::pair<guint64, guint64> > getPlaySegments() const;
|
void setStep(GstClockTime dt);
|
||||||
|
|
||||||
inline float *Array() { return array_; }
|
// get properties
|
||||||
inline size_t ArraySize() { return array_size_; }
|
inline GstClockTime start() const { return timing_.begin; }
|
||||||
|
inline GstClockTime end() const { return timing_.end; }
|
||||||
|
inline GstClockTime step() const { return step_; }
|
||||||
|
inline GstClockTime duration() const { return timing_.duration(); }
|
||||||
|
|
||||||
|
// Add / remove gaps in the timeline
|
||||||
|
bool addGap(TimeInterval s);
|
||||||
|
bool addGap(GstClockTime begin, GstClockTime end);
|
||||||
|
bool removeGaptAt(GstClockTime t);
|
||||||
|
void clearGaps();
|
||||||
|
|
||||||
|
// get gaps
|
||||||
|
size_t numGaps();
|
||||||
|
bool gapAt(const GstClockTime t, TimeInterval &gap);
|
||||||
|
std::list< std::pair<guint64, guint64> > gaps() const;
|
||||||
|
|
||||||
|
// direct access to the array representation of the timeline
|
||||||
|
// TODO : implement an ImGui widget to plot a timeline instead of an array
|
||||||
|
float *array();
|
||||||
|
size_t arraySize();
|
||||||
|
// synchronize data structures
|
||||||
|
void updateGapsFromArray();
|
||||||
|
void updateArrayFromGaps();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
GstClockTime start_;
|
// global information on the timeline
|
||||||
GstClockTime end_;
|
TimeInterval timing_;
|
||||||
size_t num_frames_;
|
GstClockTime step_;
|
||||||
|
|
||||||
|
// main data structure containing list of gaps in the timeline
|
||||||
|
TimeIntervalSet gaps_;
|
||||||
|
|
||||||
|
// supplementary data structure needed to display and edit the timeline
|
||||||
|
bool need_update_;
|
||||||
|
void init_array();
|
||||||
float *array_;
|
float *array_;
|
||||||
size_t array_size_;
|
size_t array_size_;
|
||||||
MediaSegmentSet segments_;
|
|
||||||
MediaSegmentSet::iterator current_segment_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -987,7 +987,7 @@ void UserInterface::RenderPreview()
|
|||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
{
|
{
|
||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
draw_list->AddRectFilled(draw_pos, ImVec2(draw_pos.x + width, draw_pos.y + ImGui::GetTextLineHeightWithSpacing()), IM_COL32(5, 5, 5, 100));
|
draw_list->AddRectFilled(draw_pos, ImVec2(draw_pos.x + width, draw_pos.y + ImGui::GetTextLineHeightWithSpacing()), IMGUI_COLOR_OVERLAY);
|
||||||
ImGui::SetCursorScreenPos(draw_pos);
|
ImGui::SetCursorScreenPos(draw_pos);
|
||||||
ImGui::Text(" %d x %d px, %d fps", output->width(), output->height(), int(1000.f / Mixer::manager().dt()) );
|
ImGui::Text(" %d x %d px, %d fps", output->width(), output->height(), int(1000.f / Mixer::manager().dt()) );
|
||||||
}
|
}
|
||||||
@@ -1066,7 +1066,7 @@ void MediaController::Render()
|
|||||||
// menu (no title bar)
|
// menu (no title bar)
|
||||||
if (ImGui::BeginMenuBar())
|
if (ImGui::BeginMenuBar())
|
||||||
{
|
{
|
||||||
if (ImGui::BeginMenu(ICON_FA_FILM))
|
if (ImGui::BeginMenu(IMGUI_TITLE_MEDIAPLAYER))
|
||||||
{
|
{
|
||||||
ImGui::MenuItem( ICON_FA_EYE " Preview", nullptr, &Settings::application.widget.media_player_view);
|
ImGui::MenuItem( ICON_FA_EYE " Preview", nullptr, &Settings::application.widget.media_player_view);
|
||||||
|
|
||||||
@@ -1127,16 +1127,18 @@ void MediaController::Render()
|
|||||||
static float timeline_zoom = 1.f;
|
static float timeline_zoom = 1.f;
|
||||||
const float width = ImGui::GetContentRegionAvail().x;
|
const float width = ImGui::GetContentRegionAvail().x;
|
||||||
const float timeline_height = 2.f * (ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y);
|
const float timeline_height = 2.f * (ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y);
|
||||||
|
const float segments_height = ImGui::GetFontSize();
|
||||||
|
const float slider_zoom_width = segments_height;
|
||||||
|
|
||||||
if (Settings::application.widget.media_player_view)
|
if (Settings::application.widget.media_player_view)
|
||||||
{
|
{
|
||||||
// set an image height to fill the vertical space, minus the height of control bar
|
// set an image height to fill the vertical space, minus the height of control bar
|
||||||
float image_height = ImGui::GetContentRegionAvail().y;
|
float image_height = ImGui::GetContentRegionAvail().y;
|
||||||
if (mp_->duration() != GST_CLOCK_TIME_NONE) {
|
if ( !mp_->isImage() ) {
|
||||||
// leave space for buttons, spacing and timeline
|
// leave space for buttons and timelines
|
||||||
image_height -= ImGui::GetFrameHeight() + timeline_height + 3.f * ImGui::GetStyle().ItemSpacing.y;
|
image_height -= ImGui::GetFrameHeight() + timeline_height + segments_height ;
|
||||||
// leave space for scrollbar
|
// leave space for scrollbar & spacing
|
||||||
image_height -= ImGui::GetStyle().ScrollbarSize;
|
image_height -= ImGui::GetStyle().ScrollbarSize + 3.f * ImGui::GetStyle().ItemSpacing.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// display media
|
// display media
|
||||||
@@ -1149,13 +1151,13 @@ void MediaController::Render()
|
|||||||
// display media information
|
// display media information
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
|
|
||||||
float tooltip_height = (follow_active_source_? 3.f:2.f)* ImGui::GetTextLineHeightWithSpacing();
|
float tooltip_height = 3.f * ImGui::GetTextLineHeightWithSpacing();
|
||||||
|
|
||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
draw_list->AddRectFilled(tooltip_pos, ImVec2(tooltip_pos.x + width, tooltip_pos.y + tooltip_height), IM_COL32(5, 5, 5, 100));
|
draw_list->AddRectFilled(ImVec2(tooltip_pos.x - 10.f, tooltip_pos.y),
|
||||||
|
ImVec2(tooltip_pos.x + width + 10.f, tooltip_pos.y + tooltip_height), IMGUI_COLOR_OVERLAY);
|
||||||
|
|
||||||
ImGui::SetCursorScreenPos(tooltip_pos);
|
ImGui::SetCursorScreenPos(tooltip_pos);
|
||||||
if (follow_active_source_)
|
|
||||||
ImGui::Text(" %s", mp_->filename().c_str());
|
ImGui::Text(" %s", mp_->filename().c_str());
|
||||||
ImGui::Text(" %s", mp_->codec().c_str());
|
ImGui::Text(" %s", mp_->codec().c_str());
|
||||||
if ( mp_->frameRate() > 0.f )
|
if ( mp_->frameRate() > 0.f )
|
||||||
@@ -1166,16 +1168,18 @@ void MediaController::Render()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// display time
|
// display time
|
||||||
|
if ( !mp_->isImage() ) {
|
||||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
|
||||||
ImGui::SetCursorPos( ImVec2(return_to_pos.x + 5, return_to_pos.y - ImGui::GetTextLineHeightWithSpacing()) );
|
ImGui::SetCursorPos( ImVec2(return_to_pos.x + 5, return_to_pos.y - ImGui::GetTextLineHeightWithSpacing()) );
|
||||||
ImGui::Text("%s", GstToolkit::time_to_string(mp_->position(), GstToolkit::TIME_STRING_FIXED).c_str());
|
ImGui::Text("%s", GstToolkit::time_to_string(mp_->position(), GstToolkit::TIME_STRING_FIXED).c_str());
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::SetCursorPos(return_to_pos);
|
ImGui::SetCursorPos(return_to_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control bar
|
// Control bar
|
||||||
if ( mp_->isEnabled() && mp_->duration() != GST_CLOCK_TIME_NONE) {
|
if ( mp_->isEnabled() && !mp_->isImage()) {
|
||||||
|
|
||||||
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
|
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
|
||||||
|
|
||||||
@@ -1195,7 +1199,7 @@ void MediaController::Render()
|
|||||||
|
|
||||||
ImGui::PushButtonRepeat(true);
|
ImGui::PushButtonRepeat(true);
|
||||||
if (ImGui::Button( mp_->playSpeed() < 0 ? ICON_FA_BACKWARD :ICON_FA_FORWARD))
|
if (ImGui::Button( mp_->playSpeed() < 0 ? ICON_FA_BACKWARD :ICON_FA_FORWARD))
|
||||||
mp_->fastForward ();
|
mp_->jump ();
|
||||||
ImGui::PopButtonRepeat();
|
ImGui::PopButtonRepeat();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1205,7 +1209,7 @@ void MediaController::Render()
|
|||||||
|
|
||||||
ImGui::PushButtonRepeat(true);
|
ImGui::PushButtonRepeat(true);
|
||||||
if (ImGui::Button( mp_->playSpeed() < 0 ? ICON_FA_STEP_BACKWARD : ICON_FA_STEP_FORWARD))
|
if (ImGui::Button( mp_->playSpeed() < 0 ? ICON_FA_STEP_BACKWARD : ICON_FA_STEP_FORWARD))
|
||||||
mp_->seekNextFrame();
|
mp_->step();
|
||||||
ImGui::PopButtonRepeat();
|
ImGui::PopButtonRepeat();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1224,39 +1228,85 @@ void MediaController::Render()
|
|||||||
// ImGui::SetNextItemWidth(width - 90.0);
|
// ImGui::SetNextItemWidth(width - 90.0);
|
||||||
if (ImGui::DragFloat( "##Speed", &speed, 0.01f, -10.f, 10.f, "Speed x %.1f", 2.f))
|
if (ImGui::DragFloat( "##Speed", &speed, 0.01f, -10.f, 10.f, "Speed x %.1f", 2.f))
|
||||||
mp_->setPlaySpeed( static_cast<double>(speed) );
|
mp_->setPlaySpeed( static_cast<double>(speed) );
|
||||||
// reset play to x1
|
|
||||||
|
// reset
|
||||||
ImGui::SameLine(0, spacing);
|
ImGui::SameLine(0, spacing);
|
||||||
if (ImGuiToolkit::ButtonIcon(19, 15)) {
|
if (ImGuiToolkit::ButtonIcon(11, 14)) {
|
||||||
|
timeline_zoom = 1.f;
|
||||||
speed = 1.f;
|
speed = 1.f;
|
||||||
mp_->setPlaySpeed( static_cast<double>(speed) );
|
mp_->setPlaySpeed( static_cast<double>(speed) );
|
||||||
mp_->setLoop( MediaPlayer::LOOP_REWIND );
|
mp_->setLoop( MediaPlayer::LOOP_REWIND );
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(3, 3));
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(3.f, 3.f));
|
||||||
|
|
||||||
|
// Prepare controllibg the current media player with timeline
|
||||||
|
// float *array = mp_->timeline.array();
|
||||||
|
// size_t array_size = mp_->timeline.arraySize();
|
||||||
|
guint64 current_t = mp_->position();
|
||||||
|
guint64 seek_t = current_t;
|
||||||
|
|
||||||
// scrolling sub-window
|
// scrolling sub-window
|
||||||
ImGui::BeginChild("##scrolling",
|
ImGui::BeginChild("##scrolling",
|
||||||
ImVec2(ImGui::GetContentRegionAvail().x - 20.0,
|
ImVec2(ImGui::GetContentRegionAvail().x - slider_zoom_width - 3.0,
|
||||||
timeline_height + ImGui::GetStyle().ScrollbarSize ),
|
timeline_height + segments_height + ImGui::GetStyle().ScrollbarSize ),
|
||||||
false, ImGuiWindowFlags_HorizontalScrollbar);
|
false, ImGuiWindowFlags_HorizontalScrollbar);
|
||||||
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(1.f, 1.f));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.f);
|
||||||
|
|
||||||
|
ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), segments_height -1);
|
||||||
|
size.x *= timeline_zoom;
|
||||||
|
|
||||||
|
// draw position when entering
|
||||||
|
// ImVec2 draw_pos = ImGui::GetCursorPos();
|
||||||
|
|
||||||
|
// // capture user input (invisible)
|
||||||
|
// uint press_index = mp_->timeline.arraySize();
|
||||||
|
// bool pressed = ImGuiToolkit::InvisibleSliderInt("##TimelinePicking", &press_index, 0, array_size-1, size);
|
||||||
|
|
||||||
|
// // behavior on action on array of segments
|
||||||
|
// static bool active = false;
|
||||||
|
// static float target_value = 0.f;
|
||||||
|
// static uint starting_index = array_size;
|
||||||
|
// if (pressed != active) {
|
||||||
|
// active = pressed;
|
||||||
|
// if (pressed) {
|
||||||
|
// starting_index = press_index;
|
||||||
|
// target_value = array[starting_index] > 0.f ? 0.f : 1.f;
|
||||||
|
// }
|
||||||
|
// else// action on released
|
||||||
|
// {
|
||||||
|
// mp_->timeline.updateGapsFromArray();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (active) {
|
||||||
|
// for (int i = MIN(starting_index, press_index); i < MAX(starting_index, press_index); ++i)
|
||||||
|
// array[i] = target_value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // back to drawing position to draw the segments data with historgram
|
||||||
|
// ImGui::SetCursorPos(draw_pos);
|
||||||
|
// ImGui::PlotHistogram("##TimelineHistogram", array, array_size-1.f, 0, NULL, 0.0f, 1.0f, size);
|
||||||
|
|
||||||
// custom timeline slider
|
// custom timeline slider
|
||||||
guint64 current_t = mp_->position();
|
|
||||||
guint64 seek_t = current_t;
|
|
||||||
slider_pressed_ = ImGuiToolkit::TimelineSlider("##timeline", &seek_t,
|
slider_pressed_ = ImGuiToolkit::TimelineSlider("##timeline", &seek_t,
|
||||||
mp_->duration(), mp_->frameDuration(), timeline_zoom);
|
mp_->timeline.end(), mp_->timeline.step(), size.x);
|
||||||
|
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
// zoom slider
|
// zoom slider
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::VSliderFloat("##zoom", ImVec2(17, timeline_height), &timeline_zoom, 1.0, 5.f, "");
|
ImGui::VSliderFloat("##TimelineZoom", ImVec2(slider_zoom_width, timeline_height + segments_height), &timeline_zoom, 1.0, 5.f, "");
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
// 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_->frameDuration() ) {
|
if ( ABS_DIFF (current_t, seek_t) > mp_->timeline.step() ) {
|
||||||
// request seek (ASYNC)
|
// request seek (ASYNC)
|
||||||
mp_->seekTo(seek_t);
|
mp_->seek(seek_t);
|
||||||
slider_pressed_ = false;
|
slider_pressed_ = false;
|
||||||
}
|
}
|
||||||
// play/stop command should be following the playing mode (buttons)
|
// play/stop command should be following the playing mode (buttons)
|
||||||
@@ -1267,7 +1317,8 @@ void MediaController::Render()
|
|||||||
// NB: The seek command performed an ASYNC state change, but
|
// NB: The seek command performed an ASYNC state change, but
|
||||||
// gst_element_get_state called in isPlaying(true) will wait
|
// gst_element_get_state called in isPlaying(true) will wait
|
||||||
// for the state change to complete : do not remove it!
|
// for the state change to complete : do not remove it!
|
||||||
if ( mp_->isPlaying(true) != media_play ) {
|
// TODO : DO NOT ask for status every frame : high performance cost
|
||||||
|
if ( mp_->isPlaying() != media_play ) {
|
||||||
mp_->play( media_play );
|
mp_->play( media_play );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1759,10 +1810,11 @@ void Navigator::RenderNewPannel()
|
|||||||
std::list<std::string> recent = Settings::application.recentImport.filenames;
|
std::list<std::string> recent = Settings::application.recentImport.filenames;
|
||||||
for (std::list<std::string>::iterator path = recent.begin(); path != recent.end(); path++ )
|
for (std::list<std::string>::iterator path = recent.begin(); path != recent.end(); path++ )
|
||||||
{
|
{
|
||||||
if ( SystemToolkit::file_exists(*path)) {
|
std::string recentpath(*path);
|
||||||
std::string label = path->substr( path->size() - MIN( 35, path->size()) );
|
if ( SystemToolkit::file_exists(recentpath)) {
|
||||||
|
std::string label = SystemToolkit::trunc_filename(recentpath, 35);
|
||||||
if (ImGui::Selectable( label.c_str() )) {
|
if (ImGui::Selectable( label.c_str() )) {
|
||||||
new_source_preview_.setSource( Mixer::manager().createSourceFile(path->c_str()), label);
|
new_source_preview_.setSource( Mixer::manager().createSourceFile(recentpath.c_str()), label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1773,7 +1825,7 @@ void Navigator::RenderNewPannel()
|
|||||||
// show preview
|
// show preview
|
||||||
new_source_preview_.Render(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, true);
|
new_source_preview_.Render(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, true);
|
||||||
// or press Validate button
|
// or press Validate button
|
||||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetTextLineHeight() / 2.f);
|
ImGui::Spacing();
|
||||||
if ( ImGui::Button(ICON_FA_CHECK " Create", ImVec2(pannel_width_ - padding_width_, 0)) ) {
|
if ( ImGui::Button(ICON_FA_CHECK " Create", ImVec2(pannel_width_ - padding_width_, 0)) ) {
|
||||||
Mixer::manager().addSource(new_source_preview_.getSource());
|
Mixer::manager().addSource(new_source_preview_.getSource());
|
||||||
selected_button[NAV_NEW] = false;
|
selected_button[NAV_NEW] = false;
|
||||||
@@ -2023,18 +2075,22 @@ void Navigator::RenderMainPannel()
|
|||||||
ImGui::ListBoxHeader("##Sessions", 5);
|
ImGui::ListBoxHeader("##Sessions", 5);
|
||||||
static std::string file_info = "";
|
static std::string file_info = "";
|
||||||
static std::list<std::string>::iterator file_selected = sessions_list.end();
|
static std::list<std::string>::iterator file_selected = sessions_list.end();
|
||||||
for(auto filename = sessions_list.begin(); filename != sessions_list.end(); filename++) {
|
for(auto it = sessions_list.begin(); it != sessions_list.end(); it++) {
|
||||||
if (ImGui::Selectable( SystemToolkit::filename(*filename).c_str(), false, ImGuiSelectableFlags_AllowDoubleClick )) {
|
std::string sessionfilename(*it);
|
||||||
if (ImGui::IsMouseDoubleClicked(0)) {
|
std::string shortname = SystemToolkit::filename(*it);
|
||||||
Mixer::manager().open( *filename );
|
if (sessionfilename.empty())
|
||||||
|
break;
|
||||||
|
if (ImGui::Selectable( shortname.c_str(), false, ImGuiSelectableFlags_AllowDoubleClick )) {
|
||||||
|
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||||
|
Mixer::manager().open( sessionfilename );
|
||||||
session_selected = true;
|
session_selected = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
file_info = SessionCreator::info(*filename);
|
file_info = SessionCreator::info(sessionfilename);
|
||||||
file_selected = filename;
|
file_selected = it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered() && file_selected != filename) {
|
if (ImGui::IsItemHovered() && file_selected != it) {
|
||||||
file_info.clear();
|
file_info.clear();
|
||||||
file_selected = sessions_list.end();
|
file_selected = sessions_list.end();
|
||||||
}
|
}
|
||||||
@@ -2105,7 +2161,7 @@ void Navigator::RenderMainPannel()
|
|||||||
else {
|
else {
|
||||||
ImGui::SetCursorPosY(height_ -h);
|
ImGui::SetCursorPosY(height_ -h);
|
||||||
}
|
}
|
||||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetTextLineHeightWithSpacing());
|
ImGui::Spacing();
|
||||||
if ( ImGui::Button( ICON_FA_CROW " vimix", ImVec2(ImGui::GetContentRegionAvail().x, 0)) )
|
if ( ImGui::Button( ICON_FA_CROW " vimix", ImVec2(ImGui::GetContentRegionAvail().x, 0)) )
|
||||||
UserInterface::manager().show_vimix_config = true;
|
UserInterface::manager().show_vimix_config = true;
|
||||||
if ( ImGui::Button(" ImGui "))
|
if ( ImGui::Button(" ImGui "))
|
||||||
@@ -2158,55 +2214,7 @@ int hover(const char *label)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hoverer(const char* label, uint *index, int min, int max, ImVec2 size)
|
#define SEGMENT_ARRAY_MAX 1000
|
||||||
{
|
|
||||||
// get window
|
|
||||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
|
||||||
if (window->SkipItems)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// get id
|
|
||||||
// ImGuiContext& g = *GImGui;
|
|
||||||
const ImGuiID id = window->GetID(label);
|
|
||||||
|
|
||||||
ImVec2 pos = window->DC.CursorPos;
|
|
||||||
ImRect bbox(pos, pos + size);
|
|
||||||
ImGui::ItemSize(size);
|
|
||||||
if (!ImGui::ItemAdd(bbox, id))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// read user input from system
|
|
||||||
bool left_mouse_press = false;
|
|
||||||
const bool hovered = ImGui::ItemHoverable(bbox, id);
|
|
||||||
bool temp_input_is_active = ImGui::TempInputIsActive(id);
|
|
||||||
if (!temp_input_is_active)
|
|
||||||
{
|
|
||||||
const bool focus_requested = ImGui::FocusableItemRegister(window, id);
|
|
||||||
left_mouse_press = hovered && ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
|
||||||
if (focus_requested || left_mouse_press)
|
|
||||||
{
|
|
||||||
ImGui::SetActiveID(id, window);
|
|
||||||
ImGui::SetFocusID(id, window);
|
|
||||||
ImGui::FocusWindow(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// time Slider behavior
|
|
||||||
ImRect grab_slider_bb;
|
|
||||||
uint _zero = min;
|
|
||||||
uint _end = max;
|
|
||||||
bool pressed = ImGui::SliderBehavior(bbox, id, ImGuiDataType_U32, index, &_zero,
|
|
||||||
&_end, "%d", 1.f, ImGuiSliderFlags_None, &grab_slider_bb);
|
|
||||||
|
|
||||||
// bbox = ImRect(pos, pos + ImVec2(size.x, size.y / 2.f));
|
|
||||||
// if (ImGui::IsMouseHoveringRect(bbox.GetTL(), bbox.GetBR()))
|
|
||||||
// *val = 1.f;
|
|
||||||
// else
|
|
||||||
// *val = 0.f;
|
|
||||||
|
|
||||||
return pressed;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ShowSandbox(bool* p_open)
|
void ShowSandbox(bool* p_open)
|
||||||
@@ -2223,35 +2231,65 @@ void ShowSandbox(bool* p_open)
|
|||||||
|
|
||||||
std::list< std::pair<guint64, guint64> > segments;
|
std::list< std::pair<guint64, guint64> > segments;
|
||||||
segments.push_back( std::make_pair<guint64, guint64>(GST_SECOND*1, GST_SECOND*2) );
|
segments.push_back( std::make_pair<guint64, guint64>(GST_SECOND*1, GST_SECOND*2) );
|
||||||
guint64 duration = GST_SECOND * 4;
|
guint64 duration = GST_SECOND * 6;
|
||||||
guint64 step = GST_MSECOND * 20;
|
guint64 step = GST_MSECOND * 20;
|
||||||
static guint64 t = 0;
|
static guint64 t = 0;
|
||||||
|
|
||||||
bool slider_pressed = ImGuiToolkit::TimelineSliderEdit("timeline", &t, duration, step, segments);
|
// bool slider_pressed = ImGuiToolkit::TimelineSlider("timeline", &t, duration, step);
|
||||||
|
|
||||||
|
static float *arr = nullptr;
|
||||||
|
static size_t array_size = 0;
|
||||||
|
// static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
||||||
|
// 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f };
|
||||||
|
|
||||||
|
MediaPlayer *mp_ = nullptr;
|
||||||
|
auto po = MediaPlayer::begin();
|
||||||
|
if (po != MediaPlayer::end())
|
||||||
|
mp_ = *po;
|
||||||
|
if (mp_) {
|
||||||
|
// duration = mp_->duration();
|
||||||
|
// step = mp_->frameDuration();
|
||||||
|
// t = mp_->position();
|
||||||
|
|
||||||
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
// arr = mp_->timelineArray();
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
// array_size = mp_->timelineArraySize();
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
// if (arr == nullptr) {
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
// array_size = MIN( SEGMENT_ARRAY_MAX, (size_t) duration / (size_t) step);
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
// arr = (float *) malloc(array_size * sizeof(float));
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
// for (int i = 0; i < array_size; ++i) {
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
// arr[i] = 1.f;
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
// }
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
// }
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
}
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
if (arr != nullptr)
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
{
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(1, 1));
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f,
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.f);
|
||||||
0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f, 0.f, 1.f, 0.4f };
|
|
||||||
|
|
||||||
ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), 20);
|
ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), 20);
|
||||||
|
|
||||||
@@ -2259,11 +2297,11 @@ void ShowSandbox(bool* p_open)
|
|||||||
ImVec2 draw_pos = ImGui::GetCursorPos();
|
ImVec2 draw_pos = ImGui::GetCursorPos();
|
||||||
// plot the histogram
|
// plot the histogram
|
||||||
uint press_index = IM_ARRAYSIZE(arr);
|
uint press_index = IM_ARRAYSIZE(arr);
|
||||||
bool pressed = hoverer("test", &press_index, 0, IM_ARRAYSIZE(arr)-1, size);
|
bool pressed = ImGuiToolkit::InvisibleSliderInt("test", &press_index, 0, array_size-1, size);
|
||||||
|
|
||||||
static bool active = false;
|
static bool active = false;
|
||||||
static float target_value = 0.f;
|
static float target_value = 0.f;
|
||||||
static uint starting_index = IM_ARRAYSIZE(arr);
|
static uint starting_index = array_size;
|
||||||
|
|
||||||
if (pressed != active) {
|
if (pressed != active) {
|
||||||
active = pressed;
|
active = pressed;
|
||||||
@@ -2276,18 +2314,15 @@ void ShowSandbox(bool* p_open)
|
|||||||
arr[i] = target_value;
|
arr[i] = target_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// back to
|
// back to
|
||||||
ImGui::SetCursorPos(draw_pos);
|
ImGui::SetCursorPos(draw_pos);
|
||||||
// ImGui::PlotLines("Lines", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, size);
|
ImGui::PlotHistogram("Histogram", arr, array_size-1, 0, NULL, 0.0f, 1.0f, size);
|
||||||
|
|
||||||
// ImVec4* colors = ImGui::GetStyle().Colors;
|
// ImGui::PopStyleColor(1);
|
||||||
// ImGui::PushStyleColor(ImGuiCol_PlotHistogram, colors[ImGuiCol_Tab]);
|
|
||||||
|
|
||||||
ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr)-1, 0, NULL, 0.0f, 1.0f, size);
|
bool slider_pressed = ImGuiToolkit::TimelineSlider("timeline", &t, duration, step, size.x);
|
||||||
|
|
||||||
// ImGui::PopStyleColor(1);
|
ImGui::PopStyleVar(2);
|
||||||
|
|
||||||
ImGui::Text("Timeline t %" GST_STIME_FORMAT "\n", GST_STIME_ARGS(t));
|
ImGui::Text("Timeline t %" GST_STIME_FORMAT "\n", GST_STIME_ARGS(t));
|
||||||
ImGui::Text("Timeline Pressed %s", slider_pressed ? "on" : "off");
|
ImGui::Text("Timeline Pressed %s", slider_pressed ? "on" : "off");
|
||||||
@@ -2295,7 +2330,9 @@ void ShowSandbox(bool* p_open)
|
|||||||
|
|
||||||
static int w = 0;
|
static int w = 0;
|
||||||
ImGui::SetNextItemWidth(size.x);
|
ImGui::SetNextItemWidth(size.x);
|
||||||
ImGui::SliderInt("##int", &w, 0, IM_ARRAYSIZE(arr)-1);
|
ImGui::SliderInt("##int", &w, 0, array_size-1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,11 +44,12 @@
|
|||||||
#define IMGUI_TITLE_MAINWINDOW ICON_FA_CIRCLE_NOTCH " vimix"
|
#define IMGUI_TITLE_MAINWINDOW ICON_FA_CIRCLE_NOTCH " vimix"
|
||||||
#define IMGUI_TITLE_MEDIAPLAYER ICON_FA_FILM " Player"
|
#define IMGUI_TITLE_MEDIAPLAYER ICON_FA_FILM " Player"
|
||||||
#define IMGUI_TITLE_TOOLBOX ICON_FA_WRENCH " Development Tools"
|
#define IMGUI_TITLE_TOOLBOX ICON_FA_WRENCH " Development Tools"
|
||||||
#define IMGUI_TITLE_SHADEREDITOR ICON_FA_CODE " Shader Editor"
|
#define IMGUI_TITLE_SHADEREDITOR ICON_FA_CODE " Code"
|
||||||
#define IMGUI_TITLE_PREVIEW ICON_FA_DESKTOP " Ouput"
|
#define IMGUI_TITLE_PREVIEW ICON_FA_DESKTOP " Ouput"
|
||||||
#define IMGUI_TITLE_DELETE ICON_FA_BROOM " Delete?"
|
#define IMGUI_TITLE_DELETE ICON_FA_BROOM " Delete?"
|
||||||
#define IMGUI_LABEL_RECENT_FILES " Recent files"
|
#define IMGUI_LABEL_RECENT_FILES " Recent files"
|
||||||
#define IMGUI_RIGHT_ALIGN -3.5f * ImGui::GetTextLineHeightWithSpacing()
|
#define IMGUI_RIGHT_ALIGN -3.5f * ImGui::GetTextLineHeightWithSpacing()
|
||||||
|
#define IMGUI_COLOR_OVERLAY IM_COL32(5, 5, 5, 150)
|
||||||
#define IMGUI_NOTIFICATION_DURATION 1.5f
|
#define IMGUI_NOTIFICATION_DURATION 1.5f
|
||||||
#ifdef APPLE
|
#ifdef APPLE
|
||||||
#define CTRL_MOD "Cmd+"
|
#define CTRL_MOD "Cmd+"
|
||||||
|
|||||||
Reference in New Issue
Block a user