merge: leaks, nested seq segv, ffmpeg avi frames
[goodguy/history.git] / cinelerra-5.1 / cinelerra / pluginclient.C
1  
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bchash.h"
24 #include "bcsignals.h"
25 #include "clip.h"
26 #include "condition.h"
27 #include "edl.h"
28 #include "edlsession.h"
29 #include "filesystem.h"
30 #include "language.h"
31 #include "localsession.h"
32 #include "mainundo.h"
33 #include "mwindow.h"
34 #include "pluginclient.h"
35 #include "pluginserver.h"
36 #include "preferences.h"
37 #include "transportque.inc"
38
39
40 #include <ctype.h>
41 #include <errno.h>
42 #include <string.h>
43
44
45
46
47
48 PluginClientThread::PluginClientThread(PluginClient *client)
49  : Thread(1, 0, 0)
50 {
51         this->client = client;
52         window = 0;
53         init_complete = new Condition(0, "PluginClientThread::init_complete");
54 }
55
56 PluginClientThread::~PluginClientThread()
57 {
58 //printf("PluginClientThread::~PluginClientThread %p %d\n", this, __LINE__);
59         join();
60 //printf("PluginClientThread::~PluginClientThread %p %d\n", this, __LINE__);
61         delete init_complete;
62 }
63
64 void PluginClientThread::run()
65 {
66         BC_DisplayInfo info;
67         int result = 0;
68         if(client->window_x < 0) client->window_x = info.get_abs_cursor_x();
69         if(client->window_y < 0) client->window_y = info.get_abs_cursor_y();
70         window = client->new_window();
71
72         if(window)
73         {
74                 window->lock_window("PluginClientThread::run");
75                 window->create_objects();
76                 window->unlock_window();
77
78 /* Only set it here so tracking doesn't update it until everything is created. */
79                 client->thread = this;
80                 init_complete->unlock();
81
82                 result = window->run_window();
83                 window->lock_window("PluginClientThread::run");
84 //printf("PluginClientThread::run %p %d\n", this, __LINE__);
85                 window->hide_window(1);
86                 window->unlock_window();
87                 delete window;  window = 0;
88 // Can't save defaults in the destructor because it's not called immediately
89 // after closing.
90                 /* if(client->defaults) */ client->save_defaults_xml();
91 /* This is needed when the GUI is closed from itself */
92                 if(result) client->client_side_close();
93         }
94         else
95 // No window
96         {
97                 client->thread = this;
98                 init_complete->unlock();
99         }
100 }
101
102 BC_WindowBase* PluginClientThread::get_window()
103 {
104         return window;
105 }
106
107 PluginClient* PluginClientThread::get_client()
108 {
109         return client;
110 }
111
112
113
114
115
116
117 PluginClientFrame::PluginClientFrame(int data_size, 
118         int period_n, 
119         int period_d)
120 {
121         this->data_size = data_size;
122         force = 0;
123         this->period_n = period_n;
124         this->period_d = period_d;
125 }
126
127 PluginClientFrame::~PluginClientFrame()
128 {
129         
130 }
131
132
133
134
135
136 PluginClientWindow::PluginClientWindow(PluginClient *client, 
137         int w,
138         int h,
139         int min_w,
140         int min_h,
141         int allow_resize)
142  : BC_Window(client->gui_string, 
143         client->window_x /* - w / 2 */, 
144         client->window_y /* - h / 2 */, 
145         w, h, min_w, min_h, allow_resize, 0, 1)
146 {
147         this->client = client;
148 }
149
150 PluginClientWindow::PluginClientWindow(const char *title, 
151         int x, int y, int w, int h, int min_w, int min_h, int allow_resize)
152  : BC_Window(title, x, y, w, h, min_w, min_h, allow_resize, 0, 1)
153 {
154         this->client = 0;
155 }
156
157 PluginClientWindow::~PluginClientWindow()
158 {
159 }
160
161
162 int PluginClientWindow::translation_event()
163 {
164         if(client)
165         {
166                 client->window_x = get_x();
167                 client->window_y = get_y();
168         }
169
170         return 1;
171 }
172
173 int PluginClientWindow::close_event()
174 {
175 /* Set result to 1 to indicate a client side close */
176         set_done(1);
177         return 1;
178 }
179
180
181
182
183
184 PluginClient::PluginClient(PluginServer *server)
185 {
186         reset();
187         this->server = server;
188         smp = server->preferences->processors;
189         defaults = 0;
190         update_timer = new Timer;
191 // Virtual functions don't work here.
192 }
193
194 PluginClient::~PluginClient()
195 {
196 // Delete the GUI thread.  The GUI must be hidden with hide_gui first.
197         delete thread;
198
199 // Virtual functions don't work here.
200         if(defaults) delete defaults;
201         frame_buffer.remove_all_objects();
202         delete update_timer;
203 }
204
205 int PluginClient::reset()
206 {
207         window_x = -1;
208         window_y = -1;
209         interactive = 0;
210         show_initially = 0;
211         wr = rd = 0;
212         master_gui_on = 0;
213         client_gui_on = 0;
214         realtime_priority = 0;
215         gui_string[0] = 0;
216         total_in_buffers = 0;
217         total_out_buffers = 0;
218         source_position = 0;
219         source_start = 0;
220         total_len = 0;
221         direction = PLAY_FORWARD;
222         thread = 0;
223         using_defaults = 0;
224         return 0;
225 }
226
227
228 void PluginClient::hide_gui()
229 {
230         if(thread && thread->window)
231         {
232 //printf("PluginClient::delete_thread %d\n", __LINE__);
233 /* This is needed when the GUI is closed from elsewhere than itself */
234 /* Since we now use autodelete, this is all that has to be done, thread will take care of itself ... */
235 /* Thread join will wait if this was not called from the thread itself or go on if it was */
236                 thread->window->lock_window("PluginClient::hide_gui");
237                 thread->window->set_done(0);
238 //printf("PluginClient::hide_gui %d thread->window=%p\n", __LINE__, thread->window);
239                 thread->window->unlock_window();
240 //printf("PluginClient::delete_thread %d\n", __LINE__);
241         }
242 }
243
244 // For realtime plugins initialize buffers
245 int PluginClient::plugin_init_realtime(int realtime_priority, 
246         int total_in_buffers,
247         int buffer_size)
248 {
249
250 // Get parameters for all
251         master_gui_on = get_gui_status();
252
253
254
255 // get parameters depending on video or audio
256         init_realtime_parameters();
257
258         this->realtime_priority = realtime_priority;
259         this->total_in_buffers = this->total_out_buffers = total_in_buffers;
260         this->out_buffer_size = this->in_buffer_size = buffer_size;
261         return 0;
262 }
263
264 int PluginClient::plugin_start_loop(int64_t start, 
265         int64_t end, 
266         int64_t buffer_size, 
267         int total_buffers)
268 {
269 //printf("PluginClient::plugin_start_loop %d %ld %ld %ld %d\n",
270 // __LINE__, start, end, buffer_size, total_buffers);
271         this->source_start = start;
272         this->total_len = end - start;
273         this->start = start;
274         this->end = end;
275         this->in_buffer_size = this->out_buffer_size = buffer_size;
276         this->total_in_buffers = this->total_out_buffers = total_buffers;
277         start_loop();
278         return 0;
279 }
280
281 int PluginClient::plugin_process_loop()
282 {
283         return process_loop();
284 }
285
286 int PluginClient::plugin_stop_loop()
287 {
288         return stop_loop();
289 }
290
291 MainProgressBar* PluginClient::start_progress(char *string, int64_t length)
292 {
293         return server->start_progress(string, length);
294 }
295
296
297 // Non realtime parameters
298 int PluginClient::plugin_get_parameters()
299 {
300         int result = get_parameters();
301         if(defaults) save_defaults();
302         return result;
303 }
304
305 // ========================= main loop
306
307 int PluginClient::is_multichannel() { return 0; }
308 int PluginClient::is_synthesis() { return 0; }
309 int PluginClient::is_realtime() { return 0; }
310 int PluginClient::is_fileio() { return 0; }
311 int PluginClient::delete_buffer_ptrs() { return 0; }
312 const char* PluginClient::plugin_title() { return _("Untitled"); }
313
314 Theme* PluginClient::new_theme() { return 0; }
315
316 int PluginClient::load_configuration()
317 {
318         return 0;
319 }
320
321 Theme* PluginClient::get_theme()
322 {
323         return server->get_theme();
324 }
325
326 int PluginClient::show_gui()
327 {
328         load_configuration();
329         thread = new PluginClientThread(this);
330         thread->start();
331         thread->init_complete->lock("PluginClient::show_gui");
332 // Must wait before sending any hide_gui
333         if(thread->window)
334         {
335                 thread->window->init_wait();
336         }
337         else
338         {
339                 return 1;
340         }
341         return 0;
342 }
343
344 void PluginClient::raise_window()
345 {
346         if(thread && thread->window)
347         {
348                 thread->window->lock_window("PluginClient::raise_window");
349                 thread->window->raise_window();
350                 thread->window->flush();
351                 thread->window->unlock_window();
352         }
353 }
354
355 int PluginClient::set_string()
356 {
357         if(thread)
358         {
359                 thread->window->lock_window("PluginClient::set_string");
360                 thread->window->put_title(gui_string);
361                 thread->window->unlock_window();
362         }
363         return 0;
364 }
365
366
367
368
369
370 void PluginClient::begin_process_buffer()
371 {
372 // Delete all unused GUI frames
373         frame_buffer.remove_all_objects();
374 }
375
376
377 void PluginClient::end_process_buffer()
378 {
379         if(frame_buffer.size())
380         {
381                 send_render_gui();
382         }
383 }
384
385
386
387 void PluginClient::plugin_update_gui()
388 {
389         
390         update_gui();
391         
392 // Delete unused GUI frames
393         while(frame_buffer.size() > MAX_FRAME_BUFFER)
394                 frame_buffer.remove_object_number(0);
395
396 }
397
398 void PluginClient::update_gui()
399 {
400 }
401
402 int PluginClient::get_gui_update_frames()
403 {
404         if(frame_buffer.size())
405         {
406                 PluginClientFrame *frame = frame_buffer.get(0);
407                 int total_frames = update_timer->get_difference() * 
408                         frame->period_d / 
409                         frame->period_n / 
410                         1000;
411                 if(total_frames) update_timer->subtract(total_frames * 
412                         frame->period_n * 
413                         1000 / 
414                         frame->period_d);
415
416 // printf("PluginClient::get_gui_update_frames %d %ld %d %d %d\n", 
417 // __LINE__, 
418 // update_timer->get_difference(),
419 // frame->period_n * 1000 / frame->period_d,
420 // total_frames,
421 // frame_buffer.size());
422
423 // Add forced frames
424                 for(int i = 0; i < frame_buffer.size(); i++)
425                         if(frame_buffer.get(i)->force) total_frames++;
426                 total_frames = MIN(frame_buffer.size(), total_frames);
427
428
429                 return total_frames;
430         }
431         else
432         {
433                 return 0;
434         }
435 }
436
437 PluginClientFrame* PluginClient::get_gui_frame()
438 {
439         if(frame_buffer.size())
440         {
441                 PluginClientFrame *frame = frame_buffer.get(0);
442                 frame_buffer.remove_number(0);
443                 return frame;
444         }
445         else
446         {
447                 return 0;
448         }
449 }
450
451 void PluginClient::add_gui_frame(PluginClientFrame *frame)
452 {
453         frame_buffer.append(frame);
454 }
455
456 void PluginClient::send_render_gui()
457 {
458         server->send_render_gui(&frame_buffer);
459 }
460
461 void PluginClient::send_render_gui(void *data)
462 {
463         server->send_render_gui(data);
464 }
465
466 void PluginClient::send_render_gui(void *data, int size)
467 {
468         server->send_render_gui(data, size);
469 }
470
471 void PluginClient::plugin_render_gui(void *data, int size)
472 {
473         render_gui(data, size);
474 }
475
476
477 void PluginClient::plugin_render_gui(void *data)
478 {
479         render_gui(data);
480 }
481
482 void PluginClient::render_gui(void *data)
483 {
484         if(thread)
485         {
486                 thread->get_window()->lock_window("PluginClient::render_gui");
487                 
488 // Set all previous frames to draw immediately
489                 for(int i = 0; i < frame_buffer.size(); i++)
490                         frame_buffer.get(i)->force = 1;
491
492                 ArrayList<PluginClientFrame*> *src = 
493                         (ArrayList<PluginClientFrame*>*)data;
494
495 // Shift GUI data to GUI client
496                 while(src->size())
497                 {
498                         this->frame_buffer.append(src->get(0));
499                         src->remove_number(0);
500                 }
501                 
502 // Start the timer for the current buffer
503                 update_timer->update();
504                 thread->get_window()->unlock_window();
505         }
506 }
507
508 void PluginClient::render_gui(void *data, int size)
509 {
510         printf("PluginClient::render_gui %d\n", __LINE__);
511 }
512
513
514
515
516
517
518
519
520 int PluginClient::is_audio() { return 0; }
521 int PluginClient::is_video() { return 0; }
522 int PluginClient::is_theme() { return 0; }
523 int PluginClient::uses_gui() { return 1; }
524 int PluginClient::is_transition() { return 0; }
525 int PluginClient::load_defaults() 
526 {
527 //      printf("PluginClient::load_defaults undefined in %s.\n", plugin_title());
528         return 0; 
529 }
530
531 int PluginClient::save_defaults() 
532
533         save_defaults_xml();
534 //      printf("PluginClient::save_defaults undefined in %s.\n", plugin_title());
535         return 0; 
536 }
537
538 void PluginClient::load_defaults_xml() 
539 {
540         char path[BCTEXTLEN];
541         server->get_defaults_path(path);
542         FileSystem fs;
543         fs.complete_path(path);
544         using_defaults = 1;
545 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
546         
547         KeyFrame temp_keyframe;
548         FILE *fd = fopen(path, "r");
549         if(fd)
550         {
551                 char *data = temp_keyframe.get_data();
552                 int data_size = fread(data, 1, MESSAGESIZE-1, fd);
553                 if( data_size < 0 ) data_size = 0;
554                 if( data_size > 0 )
555                 {
556 // Get window extents
557                         int state = 0;
558                         for(int i = 0; i < data_size - 8; i++)
559                         {
560                                 if(data[i] == '<') break;
561                                 if(isdigit(data[i]))
562                                 {
563                                         if(state == 0)
564                                         {
565                                                 window_x = atoi(data + i);
566                                                 state++;
567                                         }
568                                         else
569                                         {
570                                                 window_y = atoi(data + i);
571                                                 break;
572                                         }
573                                         while(i < data_size && isdigit(data[i])) i++;
574                                 }
575                         }
576                         data[data_size] = 0;
577                         read_data(&temp_keyframe);
578                 }
579
580                 fclose(fd);
581         }
582         using_defaults = 0;
583 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
584 }
585
586 void PluginClient::save_defaults_xml() 
587 {
588         char path[BCTEXTLEN];
589         server->get_defaults_path(path);
590         FileSystem fs;
591         fs.complete_path(path);
592         using_defaults = 1;
593
594         KeyFrame temp_keyframe;
595
596         save_data(&temp_keyframe);
597         FILE *fd = fopen(path, "w");
598         if(fd)
599         {
600                 fprintf(fd, "%d\n%d\n", window_x, window_y);
601                 if(!fwrite(temp_keyframe.get_data(), strlen(temp_keyframe.get_data()), 1, fd))
602                 {
603                         fprintf(stderr, "PluginClient::save_defaults_xml %d \"%s\" %d bytes: %s\n",
604                                 __LINE__,
605                                 path,
606                                 (int)strlen(temp_keyframe.get_data()),
607                                 strerror(errno));
608                 }
609
610                 fclose(fd);
611         }
612         using_defaults = 0;
613 }
614
615 int PluginClient::is_defaults()
616 {
617         return using_defaults;
618 }
619
620 BC_Hash* PluginClient::get_defaults()
621 {
622         return defaults;
623 }
624 PluginClientThread* PluginClient::get_thread()
625 {
626         return thread;
627 }
628
629 BC_WindowBase* PluginClient::new_window() 
630
631         printf("PluginClient::new_window undefined in %s.\n", plugin_title());
632         return 0; 
633 }
634 int PluginClient::get_parameters() { return 0; }
635 int PluginClient::get_samplerate() { return get_project_samplerate(); }
636 double PluginClient::get_framerate() { return get_project_framerate(); }
637 int PluginClient::init_realtime_parameters() { return 0; }
638 int PluginClient::delete_nonrealtime_parameters() { return 0; }
639 int PluginClient::start_loop() { return 0; };
640 int PluginClient::process_loop() { return 0; };
641 int PluginClient::stop_loop() { return 0; };
642
643 void PluginClient::set_interactive()
644 {
645         interactive = 1;
646 }
647
648 int64_t PluginClient::get_in_buffers(int64_t recommended_size)
649 {
650         return recommended_size;
651 }
652
653 int64_t PluginClient::get_out_buffers(int64_t recommended_size)
654 {
655         return recommended_size;
656 }
657
658 int PluginClient::get_gui_status()
659 {
660         return server->get_gui_status();
661 }
662
663 int PluginClient::start_plugin()
664 {
665         printf(_("No processing defined for this plugin.\n"));
666         return 0;
667 }
668
669 // close event from client side
670 void PluginClient::client_side_close()
671 {
672 // Last command executed
673         server->client_side_close();
674 }
675
676 int PluginClient::stop_gui_client()
677 {
678         if(!client_gui_on) return 0;
679         client_gui_on = 0;
680         return 0;
681 }
682
683 int PluginClient::get_project_samplerate()
684 {
685         return server->get_project_samplerate();
686 }
687
688 double PluginClient::get_project_framerate()
689 {
690         return server->get_project_framerate();
691 }
692
693
694 void PluginClient::update_display_title()
695 {
696         server->generate_display_title(gui_string);
697         set_string();
698 }
699
700 char* PluginClient::get_gui_string()
701 {
702         return gui_string;
703 }
704
705
706 char* PluginClient::get_path()
707 {
708         return server->path;
709 }
710
711 char* PluginClient::get_plugin_dir()
712 {
713         return server->preferences->plugin_dir;
714 }
715
716 int PluginClient::set_string_client(char *string)
717 {
718         strcpy(gui_string, string);
719         set_string();
720         return 0;
721 }
722
723
724 int PluginClient::get_interpolation_type()
725 {
726         return server->get_interpolation_type();
727 }
728
729
730 float PluginClient::get_red()
731 {
732         if(server->mwindow)
733                 return server->mwindow->edl->local_session->red;
734         else
735         if(server->edl)
736                 return server->edl->local_session->red;
737         else
738                 return 0;
739 }
740
741 float PluginClient::get_green()
742 {
743         if(server->mwindow)
744                 return server->mwindow->edl->local_session->green;
745         else
746         if(server->edl)
747                 return server->edl->local_session->green;
748         else
749                 return 0;
750 }
751
752 float PluginClient::get_blue()
753 {
754         if(server->mwindow)
755                 return server->mwindow->edl->local_session->blue;
756         else
757         if(server->edl)
758                 return server->edl->local_session->blue;
759         else
760                 return 0;
761 }
762
763
764
765 int64_t PluginClient::get_source_position()
766 {
767         return source_position;
768 }
769
770 int64_t PluginClient::get_source_start()
771 {
772         return source_start;
773 }
774
775 int64_t PluginClient::get_total_len()
776 {
777         return total_len;
778 }
779
780 int PluginClient::get_direction()
781 {
782         return direction;
783 }
784
785
786 int64_t PluginClient::local_to_edl(int64_t position)
787 {
788         return position;
789 }
790
791 int64_t PluginClient::edl_to_local(int64_t position)
792 {
793         return position;
794 }
795
796 int PluginClient::get_use_opengl()
797 {
798         return server->get_use_opengl();
799 }
800
801 int PluginClient::get_total_buffers()
802 {
803         return total_in_buffers;
804 }
805
806 int PluginClient::get_buffer_size()
807 {
808         return in_buffer_size;
809 }
810
811 int PluginClient::get_project_smp()
812 {
813 //printf("PluginClient::get_project_smp %d %d\n", __LINE__, smp);
814         return smp;
815 }
816
817 const char* PluginClient::get_defaultdir()
818 {
819         return BCASTDIR;
820 }
821
822
823 int PluginClient::send_hide_gui()
824 {
825 // Stop the GUI server and delete GUI messages
826         client_gui_on = 0;
827         return 0;
828 }
829
830 int PluginClient::send_configure_change()
831 {
832         if(server->mwindow)
833                 server->mwindow->undo->update_undo_before(_("tweek"), this);
834 #ifdef USE_KEYFRAME_SPANNING
835         KeyFrame keyframe;
836         keyframe.copy_from(server->get_keyframe());
837         save_data(&keyframe);
838         server->apply_keyframe(&keyframe);
839 #else
840         KeyFrame* keyframe = server->get_keyframe();
841 // Call save routine in plugin
842         save_data(keyframe);
843 #endif
844         if(server->mwindow)
845                 server->mwindow->undo->update_undo_after(_("tweek"), LOAD_AUTOMATION);
846         server->sync_parameters();
847         return 0;
848 }
849
850
851 KeyFrame* PluginClient::get_prev_keyframe(int64_t position, int is_local)
852 {
853         if(is_local) position = local_to_edl(position);
854         return server->get_prev_keyframe(position);
855 }
856
857 KeyFrame* PluginClient::get_next_keyframe(int64_t position, int is_local)
858 {
859         if(is_local) position = local_to_edl(position);
860         return server->get_next_keyframe(position);
861 }
862
863 void PluginClient::get_camera(float *x, float *y, float *z, int64_t position)
864 {
865         server->get_camera(x, y, z, position, direction);
866 }
867
868 void PluginClient::get_projector(float *x, float *y, float *z, int64_t position)
869 {
870         server->get_projector(x, y, z, position, direction);
871 }
872
873
874 EDLSession* PluginClient::get_edlsession()
875 {
876         if(server->edl) 
877                 return server->edl->session;
878         return 0;
879 }
880
881 int PluginClient::gui_open()
882 {
883         return server->gui_open();
884 }