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