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