Skip to content

Commit 6d0b153

Browse files
author
David Millan Escriva
committed
Video time line tracker and progressbar
1 parent 792086d commit 6d0b153

File tree

8 files changed

+488
-5
lines changed

8 files changed

+488
-5
lines changed

CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ TARGET_LINK_LIBRARIES(example_2dplot ${OpenCV_LIBS} opencvgui ${EXTRA_LIBS} ${GL
155155
ADD_EXECUTABLE(basic_sample src/basic_sample.cpp )
156156
TARGET_LINK_LIBRARIES(basic_sample ${OpenCV_LIBS} opencvgui ${EXTRA_LIBS} ${GLEW_LIBRARIES} ${EXTRA_LIBS_EXE})
157157

158+
find_package(OpenMP)
159+
add_executable(example_videotimeline src/example_videotimeline.cpp)
160+
target_link_libraries(example_videotimeline OpenMP::OpenMP_CXX ${OpenCV_LIBS} opencvgui ${EXTRA_LIBS} ${GLEW_LIBRARIES} ${EXTRA_LIBS_EXE})
161+
162+
158163
ADD_EXECUTABLE(font2c src/font2c.cpp )
159164

160165
# INSTALLATION

include/OpenCVGUI/OGUIArea.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class OGUIArea {
1717
virtual void draw(int x, int y, int width, int height);
1818
virtual void draw3d(int x, int y, int width, int height);
1919
virtual void updateScrollStatus(double xoffset,double yoffset);
20-
void drawTitle();
20+
void drawTitle(bool always_show=false);
2121
bool isMouseIn();
2222
int x, y, width, height;
2323
int r,g,b;

include/OpenCVGUI/OGUIVideoTimeline.h

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#ifndef OpenCVGUI_OGUIVideoTimeline_h
2+
#define OpenCVGUI_OGUIVideoTimeline_h
3+
4+
#include <opencv2/core/core.hpp>
5+
#include <opencv2/videoio.hpp>
6+
#include "OGUIArea.h"
7+
#include "nanovg.h"
8+
9+
using namespace cv;
10+
using namespace std;
11+
12+
namespace OpenCVGUI {
13+
14+
class TimeMarker {
15+
public:
16+
int start; // in ms
17+
int end;
18+
string title;
19+
NVGcolor color;
20+
TimeMarker(string title, int start, int end, NVGcolor color): title(title), start(start), end(end), color(color) {};
21+
void draw(void* vvg, int x, int y, int mouse_x, int mouse_y);
22+
};
23+
24+
class Track {
25+
public:
26+
Track(string title, VideoCapture* videocap);
27+
Mat thumbnail;
28+
VideoCapture* videocap;
29+
double duration;
30+
string title;
31+
void draw(void* vvg, int x, int y, int width, int height, int mouse_x, int mouse_y);
32+
void add_marker(string title, int start, int end, NVGcolor color);
33+
private:
34+
vector<TimeMarker> markers;
35+
int nvg_thumbnail_id;
36+
const unsigned char* thumb_data;
37+
};
38+
39+
class OGUIVideoTimeline: public OGUIArea {
40+
public:
41+
void draw(int x, int y, int width, int height);
42+
OGUIVideoTimeline(OGUIWindow* window, std::string title);
43+
void updateScrollStatus(double xoffset,double yoffset);
44+
void addTrack(Track *track);
45+
int get_time_pos();
46+
void set_time_pos(int pos_ms);
47+
bool is_playing();
48+
private:
49+
bool _playing;
50+
int time_pos; // time position in px
51+
int time_pos_msec;
52+
vector<Track*> tracks;
53+
string format_secs(int secs);
54+
55+
};
56+
57+
58+
}
59+
#endif // OpenCVGUI_OGUIVideoTimeline_h

include/OpenCVGUI/OGUIWindow.h

+6
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ class OGUIWindow {
104104
// font scale, default value 1.0
105105
float font_scale=1.0;
106106

107+
void show_progress(string title, float percentage);
108+
void hide_progress();
109+
107110
private:
108111

109112
/**
@@ -118,6 +121,9 @@ class OGUIWindow {
118121
PerfGraph fps;
119122
double prevt = 0;
120123
bool _show_graph= false;
124+
bool _show_progress= false;
125+
float _progress = 0;
126+
string _progress_title;
121127

122128
std::function<void(void* context)> _external2dDraw;
123129

src/OpenCVGUI/OGUIArea.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ void OGUIArea::draw(int x, int y, int width, int height)
4242

4343
}
4444

45-
void OGUIArea::drawTitle()
45+
void OGUIArea::drawTitle(bool always_show)
4646
{
4747
NVGcontext* vg= (NVGcontext*)(window->vg);
48-
if(isMouseIn() && _show_title_bar) {
48+
if((isMouseIn() && _show_title_bar) || always_show ) {
4949
nvgBeginPath(vg);
5050
nvgRect(vg, x, y, width, 22);
5151
nvgFillColor(vg, nvgRGBA(0, 0, 0, 100));

src/OpenCVGUI/OGUIVideoTimeline.cpp

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#include "OGUIVideoTimeline.h"
2+
#include "OGUIWindow.h"
3+
#include "OGUIUtils.h"
4+
#include "nanovg.h"
5+
#include <sstream>
6+
#include <iostream>
7+
#include <iomanip>
8+
#include <GLFW/glfw3.h>
9+
10+
namespace OpenCVGUI {
11+
12+
OGUIVideoTimeline::OGUIVideoTimeline(OGUIWindow* window, std::string title): OGUIArea(window)
13+
{
14+
this->title= title;
15+
time_pos = 0;
16+
time_pos_msec = 0;
17+
_playing= false;
18+
}
19+
20+
string OGUIVideoTimeline::format_secs(int sec) {
21+
int min = sec / 60;
22+
int hours = min / 60;
23+
24+
std::stringstream ss;
25+
ss << std::setfill('0') << std::setw(2) << hours;
26+
ss << ":";
27+
ss << std::setfill('0') << std::setw(2) << min%60;
28+
ss << ":";
29+
ss << std::setfill('0') << std::setw(2) << sec%60;
30+
return ss.str();
31+
}
32+
33+
bool OGUIVideoTimeline::is_playing()
34+
{
35+
return _playing;
36+
}
37+
38+
void OGUIVideoTimeline::draw(int x, int y, int width, int height)
39+
{
40+
this->x=x;
41+
this->y=y;
42+
this->width= width;
43+
this->height= height;
44+
NVGcontext* vg= (NVGcontext*)(window->vg);
45+
nvgScissor(vg, x, y, width, height);
46+
OGUIArea::draw(x,y,width,height);
47+
48+
drawTitle(true);
49+
50+
int offset_time=150;
51+
52+
53+
// Draw tracks
54+
for(int i=0; i<tracks.size(); i++){
55+
Track* track= tracks[i];
56+
track->draw(vg, x, y+43+i*40, width, 40, this->window->mouse_x, this->window->mouse_y);
57+
}
58+
59+
if(isMouseIn() && this->window->mouse_state == GLFW_PRESS){
60+
// check if is in the header track part
61+
if(this->window->mouse_x > x+offset_time && this->window->mouse_y > y+22 && this->window->mouse_y < y+height)
62+
time_pos = this->window->mouse_x - x - offset_time;
63+
time_pos_msec = time_pos*100;
64+
}
65+
66+
// Draw header time
67+
nvgBeginPath(vg);
68+
nvgRect(vg, x+offset_time, y + 22, width-offset_time, 20);
69+
nvgFillColor(vg, nvgRGBA(0, 0, 0, 50));
70+
nvgFill(vg);
71+
72+
// Draw time dragger
73+
nvgBeginPath(vg);
74+
nvgRect(vg, x + offset_time + time_pos, y+22, 1, height);
75+
nvgFillColor(vg, nvgRGBA(255,255,255, 255));
76+
nvgFill(vg);
77+
78+
nvgBeginPath(vg);
79+
nvgMoveTo(vg, x + offset_time - 5 + time_pos, y + 22);
80+
nvgLineTo(vg, x + offset_time + time_pos, y + 22 + 5);
81+
nvgLineTo(vg, x + offset_time + 5 + time_pos, y + 22);
82+
nvgFillColor(vg, nvgRGBA(255,255,255, 255));
83+
nvgFill(vg);
84+
85+
86+
// Draw ticks
87+
for(int i=offset_time; i<width; i=i+25){
88+
int t= (i-offset_time)%100;
89+
nvgBeginPath(vg);
90+
if(t==0)
91+
nvgRect(vg, x + i, y+28, 1, 14);
92+
else
93+
nvgRect(vg, x + i, y+37, 1, 5);
94+
nvgFillColor(vg, nvgRGBA(255,255,255, 125));
95+
nvgFill(vg);
96+
}
97+
// Draw time texts
98+
for(int i=offset_time; i<width; i=i+100){
99+
int start_time = i-offset_time;
100+
int sec=start_time/10;
101+
drawLabel(vg, format_secs(sec).c_str(), x + i + 2, y+32, "sans", 12.0f, 255,255,255,125 );
102+
}
103+
104+
// draw right header tracks
105+
nvgBeginPath(vg);
106+
nvgRect(vg, x, y + 22, offset_time - 1, 20);
107+
nvgFillColor(vg, nvgRGBA(0, 0, 0, 50));
108+
nvgFill(vg);
109+
110+
if(drawBasicButton(vg, this->window, "\uF04b", x+2, y + 22 , 20, 20, this->window->mouse_x, this->window->mouse_y, "icons", 16)){
111+
_playing= true;
112+
}
113+
114+
if(drawBasicButton(vg, this->window, "\uF04c", x+24, y + 22 , 20, 20, this->window->mouse_x, this->window->mouse_y, "icons", 16)){
115+
_playing= false;
116+
}
117+
118+
// draw actual time
119+
int act_secs = time_pos_msec/1000;
120+
string actuall_time_str = format_secs(act_secs);
121+
drawLabel(vg, actuall_time_str.c_str(), x + 52, y+32, "sans", 16.0f, 255,255,255,255 );
122+
123+
// draw right header tracks
124+
nvgBeginPath(vg);
125+
nvgRect(vg, x, y + 43, offset_time - 1, height - 21);
126+
nvgFillColor(vg, nvgRGBA(0, 0, 0, 50));
127+
nvgFill(vg);
128+
129+
130+
}
131+
132+
void OGUIVideoTimeline::updateScrollStatus(double xoffset,double yoffset)
133+
{
134+
if(isMouseIn()){
135+
136+
}
137+
}
138+
139+
void OGUIVideoTimeline::addTrack(Track *track)
140+
{
141+
tracks.push_back(track);
142+
}
143+
144+
int OGUIVideoTimeline::get_time_pos()
145+
{
146+
return time_pos_msec;
147+
}
148+
149+
void OGUIVideoTimeline::set_time_pos(int pos_ms)
150+
{
151+
time_pos_msec = pos_ms;
152+
time_pos = pos_ms/100;
153+
}
154+
155+
156+
Track::Track(string title, VideoCapture* videocap)
157+
{
158+
this->title = title;
159+
this->videocap = videocap;
160+
double fps = this->videocap->get(CAP_PROP_FPS);
161+
double frame_count = this->videocap->get(CAP_PROP_FRAME_COUNT);
162+
duration = frame_count/fps;
163+
this->videocap->set(CAP_PROP_POS_MSEC, 0);
164+
this->videocap->read(this->thumbnail);
165+
// this->thumbnail = thumbnail;
166+
cvtColor(thumbnail, thumbnail, COLOR_BGR2RGBA);
167+
nvg_thumbnail_id=-1;
168+
}
169+
170+
void Track::draw(void* vvg, int x, int y, int width, int height, int mouse_x, int mouse_y)
171+
{
172+
NVGcontext* vg= (NVGcontext*)(vvg);
173+
const int offset_time=150;
174+
nvgBeginPath(vg);
175+
nvgRect(vg, x + offset_time, y, width-offset_time, 38);
176+
nvgFillColor(vg, nvgRGBA(0, 0, 0, 20));
177+
nvgFill(vg);
178+
179+
nvgBeginPath(vg);
180+
nvgRect(vg, x, y + 39, width, 1);
181+
nvgFillColor(vg, nvgRGBA(255,255,255, 20));
182+
nvgFill(vg);
183+
184+
// Draw box of duration time size
185+
nvgBeginPath(vg);
186+
nvgRect(vg, x + offset_time, y, duration*10, 38);
187+
nvgFillColor(vg, nvgRGBA(255, 0, 0, 20));
188+
nvgFill(vg);
189+
190+
// Draw thumbnail
191+
int w=thumbnail.cols*40/thumbnail.rows;
192+
int h=40;
193+
if (nvg_thumbnail_id==-1){
194+
thumb_data= thumbnail.data;
195+
nvg_thumbnail_id= nvgCreateImageRGBA(vg, thumbnail.cols, thumbnail.rows, NVG_IMAGE_NEAREST, thumb_data);
196+
// nvgUpdateImage(vg, nvg_thumbnail_id, thumbnail.data);
197+
}
198+
199+
200+
NVGpaint imgPaint = nvgImagePattern(vg, x+offset_time, y, w, h, 0, nvg_thumbnail_id, 1);
201+
nvgBeginPath(vg);
202+
nvgRect(vg, x+offset_time, y, w, h);
203+
nvgFillPaint(vg, imgPaint);
204+
nvgFill(vg);
205+
206+
drawLabel(vg, title.c_str(), x + 10, y+20, "sans", 16.0f, 255,255,255,255 );
207+
208+
for(auto m:markers){
209+
m.draw(vg, x+offset_time, y, mouse_x, mouse_y);
210+
}
211+
212+
}
213+
214+
void Track::add_marker(string title, int start, int end, NVGcolor color)
215+
{
216+
markers.push_back(TimeMarker(title, start, end, color));
217+
}
218+
219+
void TimeMarker::draw(void* vvg, int x, int y, int mouse_x, int mouse_y)
220+
{
221+
NVGcontext* vg= (NVGcontext*)(vvg);
222+
nvgBeginPath(vg);
223+
int w= (end-start)/100;
224+
int s = x + start/100;
225+
nvgRect(vg, s, y, w, 5);
226+
nvgFillColor(vg, color);
227+
nvgFill(vg);
228+
229+
if(mouse_x > s && mouse_x< s+w && mouse_y > y && mouse_y < y+5)
230+
{
231+
nvgBeginPath(vg);
232+
nvgRect(vg, mouse_x+12, mouse_y+12, title.length()*8, 20);
233+
nvgFillColor(vg, nvgRGBA(0, 0, 0, 200));
234+
nvgFill(vg);
235+
236+
drawLabel(vg, title.c_str(), mouse_x+16, mouse_y+22, "sans", 16.0f, 255,255,255,255 );
237+
}
238+
}
239+
240+
}

0 commit comments

Comments
 (0)