change thread join strategy, fix a few leaks, fix a few bugs
[goodguy/history.git] / cinelerra-5.1 / guicast / vicon.C
1 #include "vicon.h"
2
3 #include "bctimer.h"
4 #include "bcwindow.h"
5 #include "colors.h"
6 #include "keys.h"
7 #include "mutex.h"
8 #include "condition.h"
9
10 VIcon::
11 VIcon(int vw, int vh, double rate)
12 {
13         this->vw = vw;
14         this->vh = vh;
15         this->frame_rate = rate;
16         this->cycle_start = 0;
17         this->age = 0;
18         this->seq_no = 0;
19         this->in_use = 1;
20 }
21
22 VIcon::
23 ~VIcon()
24 {
25         clear_images();
26 }
27
28 void VIcon::
29 add_image(VFrame *frm, int ww, int hh, int vcmdl)
30 {
31         VIFrame *vifrm = new VIFrame(ww, hh, vcmdl);
32         VFrame *img = *vifrm;
33         img->transfer_from(frm);
34         images.append(vifrm);
35 }
36
37 void VIcon::
38 draw_vframe(BC_WindowBase *wdw, int x, int y)
39 {
40         wdw->draw_vframe(frame(), x,y, vw,vh);
41 }
42
43 VIcon *VIconThread::low_vicon()
44 {
45         if( !t_heap.size() ) return 0;
46         VIcon *vip = t_heap[0];
47         remove_vicon(0);
48         return vip;
49 }
50
51 void VIconThread::remove_vicon(int i)
52 {
53         int sz = t_heap.size();
54         for( int k; (k=2*(i+1)) < sz; i=k ) {
55                 if( t_heap[k]->age > t_heap[k-1]->age ) --k;
56                 t_heap[i] = t_heap[k];
57         }
58         VIcon *last = t_heap[--sz];
59         t_heap.remove_number(sz);
60         double age = last->age;
61         for( int k; i>0 && age<t_heap[k=(i-1)/2]->age; i=k )
62                 t_heap[i] = t_heap[k];
63         t_heap[i] = last;
64 }
65
66
67 VIconThread::
68 VIconThread(BC_WindowBase *wdw, int vw, int vh)
69  : Thread(1, 0, 0)
70 {
71         this->wdw = wdw;
72         this->view_win = 0;  this->vicon = 0;
73         this->view_w = vw;   this->view_h = vh;
74         this->viewing = 0;
75         draw_lock = new Condition(0, "VIconThread::draw_lock", 1);
76         timer = new Timer();
77         this->refresh_rate = VICON_RATE;
78         done = 0;
79         interrupted = 1;
80 }
81
82 VIconThread::
83 ~VIconThread()
84 {
85         stop_drawing();
86         done = 1;
87         draw_lock->unlock();
88         if( Thread::running() ) {
89                 Thread::cancel();
90         }
91         Thread::join();
92         t_heap.remove_all_objects();
93         delete timer;
94         delete draw_lock;
95 }
96
97 void VIconThread::
98 start_drawing()
99 {
100         wdw->lock_window("VIconThread::start_drawing");
101         if( view_win )
102                 wdw->set_active_subwindow(view_win);
103         if( interrupted )
104                 draw_lock->unlock();
105         wdw->unlock_window();
106 }
107
108 void VIconThread::
109 stop_drawing()
110 {
111         wdw->lock_window("VIconThread::stop_drawing");
112         set_view_popup(0);
113         interrupted = 1;
114         wdw->unlock_window();
115 }
116
117 int VIconThread::keypress_event(int key)
118 {
119         if( key != ESC ) return 0;
120         set_view_popup(0);
121         return 1;
122 }
123
124 int ViewPopup::button_press_event()
125 {
126         vt->set_view_popup(0);
127         return 1;
128 }
129
130 bool VIconThread::
131 visible(VIcon *vicon, int x, int y)
132 {
133         int y0 = 0;
134         int my = y + vicon->vh;
135         if( my <= y0 ) return false;
136         int y1 = y0 + wdw->get_h();
137         if( y >= y1 ) return false;
138         int x0 = 0;
139         int mx = x + vicon->vw;
140         if( mx <= x0 ) return false;
141         int x1 = x0 + wdw->get_w();
142         if( x >= x1 ) return false;
143         return true;
144 }
145
146 int ViewPopup::keypress_event()
147 {
148         int key = get_keypress();
149         return vt->keypress_event(key);
150 }
151 ViewPopup::ViewPopup(VIconThread *vt, VFrame *frame, int x, int y, int w, int h)
152  : BC_Popup(vt->wdw, x, y, w, h, BLACK)
153 {
154         this->vt = vt;
155 }
156
157 ViewPopup::~ViewPopup()
158 {
159         vt->wdw->set_active_subwindow(0);
160 }
161
162 void ViewPopup::draw_vframe(VFrame *frame)
163 {
164         BC_WindowBase::draw_vframe(frame, 0,0, get_w(),get_h());
165 }
166
167 ViewPopup *VIconThread::new_view_window(VFrame *frame)
168 {
169         int wx = viewing->get_vx() - view_w, rx = 0;
170         int wy = viewing->get_vy() - view_h, ry = 0;
171         wdw->get_root_coordinates(wx, wy, &rx, &ry);
172         ViewPopup *vwin = new ViewPopup(this, frame, rx, ry, view_w, view_h);
173         wdw->set_active_subwindow(vwin);
174         return vwin;
175 }
176
177 void VIconThread::
178 reset_images()
179 {
180         for( int i=t_heap.size(); --i>=0; ) t_heap[i]->reset();
181         timer->update();
182         img_dirty = win_dirty = 0;
183 }
184
185 void VIconThread::add_vicon(VIcon *vip)
186 {
187         double age = vip->age;
188         int i = t_heap.size();  t_heap.append(vip);
189         for( int k; i>0 && age<t_heap[(k=(i-1)/2)]->age; i=k )
190                 t_heap[i] = t_heap[k];
191         t_heap[i] = vip;
192 }
193
194 int VIconThread::del_vicon(VIcon *&vicon)
195 {
196         int i = t_heap.size();
197         while( --i >= 0 && t_heap[i] != vicon );
198         if( i < 0 ) return 0;
199         remove_vicon(i);
200         delete vicon;  vicon = 0;
201         return 1;
202 }
203
204 void VIconThread::set_view_popup(VIcon *vicon)
205 {
206         this->vicon = vicon;
207 }
208
209 int VIconThread::
210 update_view()
211 {
212         delete view_win;  view_win = 0;
213         if( (viewing=vicon) != 0 ) {
214                 VFrame *frame = viewing->frame();
215                 view_win = new_view_window(frame);
216                 view_win->show_window();
217         }
218         wdw->set_active_subwindow(view_win);
219         return 1;
220 }
221
222
223 void VIconThread::
224 draw_images()
225 {
226         for( int i=0; i<t_heap.size(); ++i )
227                 draw(t_heap[i]);
228 }
229
230 void VIconThread::
231 flash()
232 {
233         if( !img_dirty && !win_dirty ) return;
234         if( img_dirty ) wdw->flash();
235         if( win_dirty && view_win ) view_win->flash();
236         win_dirty = img_dirty = 0;
237 }
238
239 int VIconThread::
240 draw(VIcon *vicon)
241 {
242         int x = vicon->get_vx(), y = vicon->get_vy();
243         int draw_img = visible(vicon, x, y);
244         int draw_win = view_win && viewing == vicon ? 1 : 0;
245         if( !draw_img && !draw_win ) return 0;
246         if( !vicon->frame() ) return 0;
247         if( draw_img ) {
248                 vicon->draw_vframe(wdw, x, y);
249                 img_dirty = 1;
250         }
251         if( draw_win ) {
252                 view_win->draw_vframe(vicon->frame());
253                 win_dirty = 1;
254         }
255         return 1;
256 }
257
258 void VIconThread::
259 run()
260 {
261         while(!done) {
262                 draw_lock->lock("VIconThread::run 0");
263                 if( done ) break;;
264                 wdw->lock_window("BC_WindowBase::run 1");
265                 interrupted = 0;
266                 drawing_started();
267                 reset_images();
268                 int64_t seq_no = 0, now = 0;
269                 int64_t draw_flash = 1000 / refresh_rate;
270                 while( !interrupted ) {
271                         if( viewing != vicon )
272                                 update_view();
273                         VIcon *next = low_vicon();
274                         while( next && next->age < draw_flash ) {
275                                 now = timer->get_difference();
276                                 if( now >= draw_flash ) break;
277                                 draw(next);
278                                 if( !next->seq_no ) next->cycle_start = now;
279                                 int64_t ref_no = (now - next->cycle_start) / 1000. * refresh_rate;
280                                 int count = ref_no - next->seq_no;
281                                 if( count < 1 ) count = 1;
282                                 ref_no = next->seq_no + count;
283                                 next->age =  next->cycle_start + 1000. * ref_no / refresh_rate;
284                                 if( !next->set_seq_no(ref_no) )
285                                         next->age = now + 1000.;
286                                 add_vicon(next);
287                                 next = low_vicon();
288                         }
289                         if( !next ) break;
290                         add_vicon(next);
291                         if( draw_flash < now+1 )
292                                 draw_flash = now+1;
293                         wdw->unlock_window();
294                         while( !interrupted ) {
295                                 now = timer->get_difference();
296                                 int64_t ms = draw_flash - now;
297                                 if( ms <= 0 ) break;
298                                 if( ms > 100 ) ms = 100;
299                                 Timer::delay(ms);
300                         }
301                         wdw->lock_window("BC_WindowBase::run 2");
302                         now = timer->get_difference();
303                         int64_t late = now - draw_flash;
304                         if( late < 1000 ) flash();
305                         int64_t ref_no = now / 1000. * refresh_rate;
306                         int64_t count = ref_no - seq_no;
307                         if( count < 1 ) count = 1;
308                         seq_no += count;
309                         draw_flash = seq_no * 1000. / refresh_rate;
310                 }
311                 if( viewing != vicon )
312                         update_view();
313                 drawing_stopped();
314                 interrupted = -1;
315                 wdw->unlock_window();
316         }
317 }
318
319 void VIcon::dump(const char *dir)
320 {
321         mkdir(dir,0777);
322         for( int i=0; i<images.size(); ++i ) {
323                 char fn[1024];  sprintf(fn,"%s/img%05d.png",dir,i);
324                 printf("\r%s",fn);
325                 VFrame *img = *images[i];
326                 img->write_png(fn);
327         }
328         printf("\n");
329 }
330