4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
24 #include "bcsignals.h"
25 #include "attachmentpoint.h"
27 #include "condition.h"
31 #include "edlsession.h"
33 #include "filesystem.h"
35 #include "indexable.h"
37 #include "localsession.h"
41 #include "pluginclient.h"
42 #include "pluginserver.h"
43 #include "preferences.h"
44 #include "renderengine.h"
46 #include "transportque.h"
56 PluginClientFrame::PluginClientFrame()
61 PluginClientFrame::~PluginClientFrame()
66 PluginClientThread::PluginClientThread(PluginClient *client)
69 this->client = client;
71 init_complete = new Condition(0, "PluginClientThread::init_complete");
74 PluginClientThread::~PluginClientThread()
81 void PluginClientThread::run()
85 if(client->window_x < 0) client->window_x = info.get_abs_cursor_x();
86 if(client->window_y < 0) client->window_y = info.get_abs_cursor_y();
88 window = (PluginClientWindow*)client->new_window();
91 window->lock_window("PluginClientThread::run");
92 window->create_objects();
93 VFrame *picon = client->server->get_picon();
94 if( picon ) window->set_icon(picon);
95 window->unlock_window();
97 /* Only set it here so tracking doesn't update it until everything is created. */
98 client->thread = this;
99 init_complete->unlock();
101 result = window->run_window();
102 window->lock_window("PluginClientThread::run");
103 //printf("PluginClientThread::run %p %d\n", this, __LINE__);
104 window->hide_window(1);
105 window->unlock_window();
106 window->done_event(result);
107 // Can't save defaults in the destructor because it's not called immediately
109 /* if(client->defaults) */ client->save_defaults_xml();
110 /* This is needed when the GUI is closed from itself */
111 if(result) client->client_side_close();
116 client->thread = this;
117 init_complete->unlock();
121 BC_WindowBase* PluginClientThread::get_window()
126 PluginClient* PluginClientThread::get_client()
132 PluginClientWindow::PluginClientWindow(PluginClient *client,
133 int w, int h, int min_w, int min_h, int allow_resize)
134 : BC_Window(client->gui_string,
135 client->window_x /* - w / 2 */, client->window_y /* - h / 2 */,
136 w, h, min_w, min_h, allow_resize, 0, 1)
138 this->client = client;
141 PluginClientWindow::PluginClientWindow(const char *title,
142 int x, int y, int w, int h, int min_w, int min_h, int allow_resize)
143 : BC_Window(title, x, y, w, h, min_w, min_h, allow_resize, 0, 1)
148 PluginClientWindow::~PluginClientWindow()
153 int PluginClientWindow::translation_event()
157 client->window_x = get_x();
158 client->window_y = get_y();
164 int PluginClientWindow::close_event()
166 /* Set result to 1 to indicate a client side close */
171 void PluginClientWindow::param_updated()
173 printf("PluginClientWindow::param_updated %d undefined\n", __LINE__);
177 PluginParam::PluginParam(PluginClient *plugin, PluginClientWindow *gui,
178 int x1, int x2, int x3, int y, int text_w,
179 int *output_i, float *output_f, int *output_q,
180 const char *title, float min, float max)
182 this->output_i = output_i;
183 this->output_f = output_f;
184 this->output_q = output_q;
185 this->title = cstrdup(title);
186 this->plugin = plugin;
191 this->text_w = text_w;
201 PluginParam::~PluginParam()
211 void PluginParam::initialize()
215 (BC_Pot::calculate_h() -
216 BC_Title::calculate_h(gui, _(title), MEDIUMFONT)) / 2;
217 gui->add_tool(title_ = new BC_Title(x1, y2, _(title)));
221 gui->add_tool(fpot = new PluginFPot(this, x2, y));
226 gui->add_tool(ipot = new PluginIPot(this, x2, y));
231 gui->add_tool(qpot = new PluginQPot(this, x2, y));
235 (BC_Pot::calculate_h() -
236 BC_TextBox::calculate_h(gui, MEDIUMFONT, 1, 1)) / 2;
239 gui->add_tool(text = new PluginText(this, x3, y3, *output_i));
243 gui->add_tool(text = new PluginText(this, x3, y3, *output_f));
247 gui->add_tool(text = new PluginText(this, x3, y3, *output_q));
250 set_precision(precision);
253 void PluginParam::update(int skip_text, int skip_pot)
259 text->update((int64_t)*output_i);
263 text->update((int64_t)*output_q);
267 text->update((float)*output_f);
275 ipot->update((int64_t)*output_i);
279 qpot->update((int64_t)*output_q);
283 fpot->update((float)*output_f);
288 void PluginParam::set_precision(int digits)
290 this->precision = digits;
295 text->set_precision(digits);
298 fpot->set_precision(1.0f / pow(10, digits));
303 PluginFPot::PluginFPot(PluginParam *param, int x, int y)
314 int PluginFPot::handle_event()
316 *param->output_f = get_value();
318 param->plugin->send_configure_change();
319 param->gui->param_updated();
323 PluginIPot::PluginIPot(PluginParam *param, int x, int y)
334 int PluginIPot::handle_event()
336 *param->output_i = get_value();
338 param->plugin->send_configure_change();
339 param->gui->param_updated();
344 PluginQPot::PluginQPot(PluginParam *param, int x, int y)
353 int PluginQPot::handle_event()
355 *param->output_q = get_value();
357 param->plugin->send_configure_change();
358 param->gui->param_updated();
362 PluginText::PluginText(PluginParam *param, int x, int y, int value)
374 PluginText::PluginText(PluginParam *param, int x, int y, float value)
387 int PluginText::handle_event()
391 *param->output_i = atoi(get_text());
396 *param->output_f = atof(get_text());
401 *param->output_q = atoi(get_text());
404 param->plugin->send_configure_change();
405 param->gui->param_updated();
410 PluginClient::PluginClient(PluginServer *server)
413 this->server = server;
414 smp = server->preferences->project_smp;
416 update_timer = new Timer;
417 // Virtual functions don't work here.
420 PluginClient::~PluginClient()
428 // Virtual functions don't work here.
429 if(defaults) delete defaults;
433 int PluginClient::reset()
442 realtime_priority = 0;
444 total_in_buffers = 0;
445 total_out_buffers = 0;
449 direction = PLAY_FORWARD;
456 void PluginClient::hide_gui()
458 if(thread && thread->window)
460 //printf("PluginClient::delete_thread %d\n", __LINE__);
461 /* This is needed when the GUI is closed from elsewhere than itself */
462 /* Since we now use autodelete, this is all that has to be done, thread will take care of itself ... */
463 /* Thread join will wait if this was not called from the thread itself or go on if it was */
464 thread->window->lock_window("PluginClient::hide_gui");
465 thread->window->set_done(0);
466 //printf("PluginClient::hide_gui %d thread->window=%p\n", __LINE__, thread->window);
467 thread->window->unlock_window();
471 // For realtime plugins initialize buffers
472 int PluginClient::plugin_init_realtime(int realtime_priority,
473 int total_in_buffers,
477 // Get parameters for all
478 master_gui_on = get_gui_status();
482 // get parameters depending on video or audio
483 init_realtime_parameters();
485 this->realtime_priority = realtime_priority;
486 this->total_in_buffers = this->total_out_buffers = total_in_buffers;
487 this->out_buffer_size = this->in_buffer_size = buffer_size;
491 int PluginClient::plugin_start_loop(int64_t start,
496 //printf("PluginClient::plugin_start_loop %d %ld %ld %ld %d\n",
497 // __LINE__, start, end, buffer_size, total_buffers);
498 this->source_start = start;
499 this->total_len = end - start;
502 this->in_buffer_size = this->out_buffer_size = buffer_size;
503 this->total_in_buffers = this->total_out_buffers = total_buffers;
508 int PluginClient::plugin_process_loop()
510 return process_loop();
513 int PluginClient::plugin_stop_loop()
518 MainProgressBar* PluginClient::start_progress(char *string, int64_t length)
520 return server->start_progress(string, length);
524 // Non realtime parameters
525 int PluginClient::plugin_get_parameters()
527 int result = get_parameters();
528 if(defaults) save_defaults();
532 // ========================= main loop
534 int PluginClient::is_multichannel() { return 0; }
535 int PluginClient::is_synthesis() { return 0; }
536 int PluginClient::is_realtime() { return 0; }
537 int PluginClient::is_fileio() { return 0; }
538 const char* PluginClient::plugin_title() { return _("Untitled"); }
540 Theme* PluginClient::new_theme() { return 0; }
542 int PluginClient::load_configuration()
547 Theme* PluginClient::get_theme()
549 return server->get_theme();
552 int PluginClient::show_gui()
554 load_configuration();
555 thread = new PluginClientThread(this);
557 thread->init_complete->lock("PluginClient::show_gui");
558 // Must wait before sending any hide_gui
559 if( !thread->window ) return 1;
560 thread->window->init_wait();
564 void PluginClient::raise_window()
566 if(thread && thread->window)
568 thread->window->lock_window("PluginClient::raise_window");
569 thread->window->raise_window();
570 thread->window->flush();
571 thread->window->unlock_window();
575 int PluginClient::set_string()
579 thread->window->lock_window("PluginClient::set_string");
580 thread->window->put_title(gui_string);
581 thread->window->unlock_window();
590 PluginClientFrames::PluginClientFrames()
594 PluginClientFrames::~PluginClientFrames()
598 int PluginClientFrames::fwd_cmpr(PluginClientFrame *a, PluginClientFrame *b)
600 double d = a->position - b->position;
601 return d < 0 ? -1 : !d ? 0 : 1;
604 int PluginClientFrames::rev_cmpr(PluginClientFrame *a, PluginClientFrame *b)
606 double d = b->position - a->position;
607 return d < 0 ? -1 : !d ? 0 : 1;
610 void PluginClientFrames::reset()
616 void PluginClientFrames::add_gui_frame(PluginClientFrame *frame)
622 void PluginClientFrames::concatenate(PluginClientFrames *frames)
625 count += frames->count;
629 void PluginClientFrames::sort_position(int dir)
632 if( dir == PLAY_REVERSE )
638 // pop frames until buffer passes position=pos in direction=dir
639 // dir==0, pop frame; pos<0, pop all frames
640 // delete past frames, return last popped frame
641 PluginClientFrame* PluginClientFrames::get_gui_frame(double pos, int dir)
644 while( first != last ) {
645 if( pos >= 0 && dir*(first->next->position - pos) > 0 ) break;
646 delete first; --count;
649 PluginClientFrame *frame = first;
650 if( frame ) { remove_pointer(frame); --count; }
654 PluginClientFrame* PluginClient::get_gui_frame(double pos, int dir)
656 return client_frames.get_gui_frame(pos, dir);
658 PluginClientFrame* PluginClient::next_gui_frame()
660 return client_frames.first;
664 void PluginClient::plugin_update_gui()
669 void PluginClient::update_gui()
673 int PluginClient::pending_gui_frame()
675 PluginClientFrame *frame = client_frames.first;
676 if( !frame ) return 0;
677 double tracking_position = get_tracking_position();
678 int direction = get_tracking_direction();
679 int ret = !(direction == PLAY_REVERSE ?
680 frame->position < tracking_position :
681 frame->position > tracking_position);
685 int PluginClient::pending_gui_frames()
687 PluginClientFrame *frame = client_frames.first;
688 if( !frame ) return 0;
689 double tracking_position = get_tracking_position();
690 int direction = get_tracking_direction();
692 while( frame && !(direction == PLAY_REVERSE ?
693 frame->position < tracking_position :
694 frame->position > tracking_position) ) {
695 ++count; frame=frame->next;
700 void PluginClient::add_gui_frame(PluginClientFrame *frame)
702 client_frames.add_gui_frame(frame);
704 int PluginClient::get_gui_frames()
706 return client_frames.total();
709 double PluginClient::get_tracking_position()
711 return server->mwindow->get_tracking_position();
714 int PluginClient::get_tracking_direction()
716 return server->mwindow->get_tracking_direction();
719 void PluginClient::send_render_gui()
721 server->send_render_gui(&client_frames);
724 void PluginClient::send_render_gui(void *data)
726 server->send_render_gui(data);
729 void PluginClient::send_render_gui(void *data, int size)
731 server->send_render_gui(data, size);
735 void PluginClient::plugin_reset_gui_frames()
737 if( !thread ) return;
738 BC_WindowBase *window = thread->get_window();
739 if( !window ) return;
740 window->lock_window("PluginClient::plugin_reset_gui_frames");
741 client_frames.reset();
742 window->unlock_window();
745 void PluginClient::plugin_render_gui_frames(PluginClientFrames *frames)
747 if( !thread ) return;
748 BC_WindowBase *window = thread->get_window();
749 if( !window ) return;
750 window->lock_window("PluginClient::render_gui");
751 while( client_frames.count > MAX_FRAME_BUFFER )
752 delete get_gui_frame(0, 0);
753 // append client frames to gui client_frames, consumes frames
754 client_frames.concatenate(frames);
755 client_frames.sort_position(get_tracking_direction());
756 update_timer->update();
757 window->unlock_window();
760 void PluginClient::plugin_render_gui(void *data)
765 void PluginClient::plugin_render_gui(void *data, int size)
767 render_gui(data, size);
770 void PluginClient::render_gui(void *data)
772 printf("PluginClient::render_gui %d\n", __LINE__);
775 void PluginClient::render_gui(void *data, int size)
777 printf("PluginClient::render_gui %d\n", __LINE__);
780 void PluginClient::reset_gui_frames()
782 server->reset_gui_frames();
785 int PluginClient::is_audio() { return 0; }
786 int PluginClient::is_video() { return 0; }
787 int PluginClient::is_theme() { return 0; }
788 int PluginClient::uses_gui() { return 1; }
789 int PluginClient::is_transition() { return 0; }
790 int PluginClient::load_defaults()
792 // printf("PluginClient::load_defaults undefined in %s.\n", plugin_title());
796 int PluginClient::save_defaults()
799 // printf("PluginClient::save_defaults undefined in %s.\n", plugin_title());
803 void PluginClient::load_defaults_xml()
805 char path[BCTEXTLEN];
806 server->get_defaults_path(path);
808 fs.complete_path(path);
810 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
815 int fd = open(path, O_RDONLY);
816 if( fd >= 0 && !fstat(fd, &st) ) {
817 int64_t sz = st.st_size;
818 data = new char[sz+1];
819 len = read(fd, data, sz);
822 if( data && len >= 0 ) {
824 // Get window extents
826 for( int state=0; i<len && state>=0; ++i ) {
827 if( !data[i] || data[i] == '<' ) break;
828 if( !isdigit(data[i]) ) continue;
830 window_x = atoi(data+i);
834 window_y = atoi(data+i);
837 while( i<len && isdigit(data[i]) ) ++i;
839 KeyFrame keyframe(data+i, len-i);
840 read_data(&keyframe);
845 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
848 void PluginClient::save_defaults_xml()
850 char path[BCTEXTLEN];
851 server->get_defaults_path(path);
853 fs.complete_path(path);
856 KeyFrame temp_keyframe;
857 save_data(&temp_keyframe);
859 const char *data = temp_keyframe.get_data();
860 int len = strlen(data);
861 FILE *fp = fopen(path, "w");
864 fprintf(fp, "%d\n%d\n", window_x, window_y);
865 if( len > 0 && !fwrite(data, len, 1, fp) ) {
866 fprintf(stderr, "PluginClient::save_defaults_xml %d \"%s\" %d bytes: %s\n",
867 __LINE__, path, len, strerror(errno));
875 int PluginClient::is_defaults()
877 return using_defaults;
880 BC_Hash* PluginClient::get_defaults()
884 PluginClientThread* PluginClient::get_thread()
889 BC_WindowBase* PluginClient::new_window()
891 printf("PluginClient::new_window undefined in %s.\n", plugin_title());
894 int PluginClient::get_parameters() { return 0; }
895 int PluginClient::get_samplerate() { return get_project_samplerate(); }
896 double PluginClient::get_framerate() { return get_project_framerate(); }
897 int PluginClient::init_realtime_parameters() { return 0; }
898 int PluginClient::delete_nonrealtime_parameters() { return 0; }
899 int PluginClient::start_loop() { return 0; };
900 int PluginClient::process_loop() { return 0; };
901 int PluginClient::stop_loop() { return 0; };
903 void PluginClient::set_interactive()
908 int64_t PluginClient::get_in_buffers(int64_t recommended_size)
910 return recommended_size;
913 int64_t PluginClient::get_out_buffers(int64_t recommended_size)
915 return recommended_size;
918 int PluginClient::get_gui_status()
920 return server->get_gui_status();
923 // close event from client side
924 void PluginClient::client_side_close()
926 // Last command executed
927 server->client_side_close();
930 int PluginClient::stop_gui_client()
932 if(!client_gui_on) return 0;
937 int PluginClient::get_project_samplerate()
939 return server->get_project_samplerate();
942 double PluginClient::get_project_framerate()
944 return server->get_project_framerate();
947 const char *PluginClient::get_source_path()
949 if( server->plugin ) return 0;
950 int64_t source_position = server->plugin->startproject;
951 Edit *edit = server->plugin->track->edits->editof(source_position,PLAY_FORWARD,0);
952 Indexable *indexable = edit ? edit->get_source() : 0;
953 return indexable ? indexable->path : 0;
957 void PluginClient::update_display_title()
959 server->generate_display_title(gui_string);
963 char* PluginClient::get_gui_string()
969 char* PluginClient::get_path()
974 char* PluginClient::get_plugin_dir()
976 return server->preferences->plugin_dir;
979 int PluginClient::set_string_client(char *string)
981 strcpy(gui_string, string);
987 int PluginClient::get_interpolation_type()
989 return server->get_interpolation_type();
993 float PluginClient::get_red()
995 EDL *edl = get_edl();
996 return edl->local_session->use_max ?
997 edl->local_session->red_max :
998 edl->local_session->red;
1001 float PluginClient::get_green()
1003 EDL *edl = get_edl();
1004 return edl->local_session->use_max ?
1005 edl->local_session->green_max :
1006 edl->local_session->green;
1009 float PluginClient::get_blue()
1011 EDL *edl = get_edl();
1012 return edl->local_session->use_max ?
1013 edl->local_session->blue_max :
1014 edl->local_session->blue;
1018 int64_t PluginClient::get_source_position()
1020 return source_position;
1023 int64_t PluginClient::get_source_start()
1025 return source_start;
1028 int64_t PluginClient::get_total_len()
1033 int PluginClient::get_direction()
1038 int64_t PluginClient::local_to_edl(int64_t position)
1043 int64_t PluginClient::edl_to_local(int64_t position)
1048 int PluginClient::get_use_opengl()
1050 return server->get_use_opengl();
1053 int PluginClient::get_total_buffers()
1055 return total_in_buffers;
1058 int PluginClient::get_buffer_size()
1060 return in_buffer_size;
1063 int PluginClient::get_project_smp()
1065 //printf("PluginClient::get_project_smp %d %d\n", __LINE__, smp);
1069 const char* PluginClient::get_defaultdir()
1071 return File::get_plugin_path();
1075 int PluginClient::send_hide_gui()
1077 // Stop the GUI server and delete GUI messages
1082 int PluginClient::send_configure_change()
1085 server->mwindow->undo->update_undo_before(_("tweek"), this);
1086 #ifdef USE_KEYFRAME_SPANNING
1088 save_data(&keyframe);
1089 server->apply_keyframe(&keyframe);
1091 KeyFrame* keyframe = server->get_keyframe();
1092 // Call save routine in plugin
1093 save_data(keyframe);
1096 server->mwindow->undo->update_undo_after(_("tweek"), LOAD_AUTOMATION);
1097 server->sync_parameters();
1102 KeyFrame* PluginClient::get_prev_keyframe(int64_t position, int is_local)
1104 if(is_local) position = local_to_edl(position);
1105 return server->get_prev_keyframe(position);
1108 KeyFrame* PluginClient::get_next_keyframe(int64_t position, int is_local)
1110 if(is_local) position = local_to_edl(position);
1111 return server->get_next_keyframe(position);
1114 void PluginClient::get_camera(float *x, float *y, float *z, int64_t position)
1116 server->get_camera(x, y, z, position, direction);
1119 void PluginClient::get_projector(float *x, float *y, float *z, int64_t position)
1121 server->get_projector(x, y, z, position, direction);
1125 void PluginClient::output_to_track(float ox, float oy, float &tx, float &ty)
1127 float projector_x, projector_y, projector_z;
1128 int64_t position = get_source_position();
1129 get_projector(&projector_x, &projector_y, &projector_z, position);
1130 EDL *edl = get_edl();
1131 projector_x += edl->session->output_w / 2;
1132 projector_y += edl->session->output_h / 2;
1133 Track *track = server->plugin ? server->plugin->track : 0;
1134 int track_w = track ? track->track_w : edl->session->output_w;
1135 int track_h = track ? track->track_h : edl->session->output_h;
1136 tx = (ox - projector_x) / projector_z + track_w / 2;
1137 ty = (oy - projector_y) / projector_z + track_h / 2;
1140 void PluginClient::track_to_output(float tx, float ty, float &ox, float &oy)
1142 float projector_x, projector_y, projector_z;
1143 int64_t position = get_source_position();
1144 get_projector(&projector_x, &projector_y, &projector_z, position);
1145 EDL *edl = get_edl();
1146 projector_x += edl->session->output_w / 2;
1147 projector_y += edl->session->output_h / 2;
1148 Track *track = server->plugin ? server->plugin->track : 0;
1149 int track_w = track ? track->track_w : edl->session->output_w;
1150 int track_h = track ? track->track_h : edl->session->output_h;
1151 ox = (tx - track_w / 2) * projector_z + projector_x;
1152 oy = (ty - track_h / 2) * projector_z + projector_y;
1156 EDL *PluginClient::get_edl()
1158 return server->mwindow ? server->mwindow->edl : server->edl;
1161 int PluginClient::gui_open()
1163 return server->gui_open();