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"
47 #include "transportque.h"
57 PluginClientFrame::PluginClientFrame()
62 PluginClientFrame::~PluginClientFrame()
67 PluginClientThread::PluginClientThread(PluginClient *client)
70 this->client = client;
72 init_complete = new Condition(0, "PluginClientThread::init_complete");
75 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 client->save_defaults_xml(); // needs window lock
106 window->unlock_window();
107 window->done_event(result);
108 /* This is needed when the GUI is closed from itself */
109 if(result) client->client_side_close();
114 client->thread = this;
115 init_complete->unlock();
119 BC_WindowBase* PluginClientThread::get_window()
124 PluginClient* PluginClientThread::get_client()
130 PluginClientWindow::PluginClientWindow(PluginClient *client,
131 int w, int h, int min_w, int min_h, int allow_resize)
132 : BC_Window(client->gui_string,
133 client->window_x /* - w / 2 */, client->window_y /* - h / 2 */,
134 w, h, min_w, min_h, allow_resize, 0, 1)
136 char title[BCTEXTLEN];
138 this->client = client;
140 // *** CONTEXT_HELP ***
142 strcpy(title, client->plugin_title());
143 if(! strcmp(title, "Overlay")) {
144 // "Overlay" plugin title is ambiguous
145 if(client->is_audio()) strcat(title, " \\(Audio\\)");
146 if(client->is_video()) strcat(title, " \\(Video\\)");
148 if(client->server->is_ffmpeg()) {
149 // FFmpeg plugins can be audio or video
150 if(client->is_audio())
151 strcpy(title, "FFmpeg Audio Plugins");
152 if(client->is_video())
153 strcpy(title, "FFmpeg Video Plugins");
155 context_help_set_keyword(title);
159 PluginClientWindow::PluginClientWindow(const char *title,
160 int x, int y, int w, int h, int min_w, int min_h, int allow_resize)
161 : BC_Window(title, x, y, w, h, min_w, min_h, allow_resize, 0, 1)
164 // *** CONTEXT_HELP ***
165 context_help_set_keyword(title);
168 PluginClientWindow::~PluginClientWindow()
173 int PluginClientWindow::translation_event()
177 client->window_x = get_x();
178 client->window_y = get_y();
184 int PluginClientWindow::close_event()
186 /* Set result to 1 to indicate a client side close */
191 void PluginClientWindow::param_updated()
193 printf("PluginClientWindow::param_updated %d undefined\n", __LINE__);
197 PluginParam::PluginParam(PluginClient *plugin, PluginClientWindow *gui,
198 int x1, int x2, int x3, int y, int text_w,
199 int *output_i, float *output_f, int *output_q,
200 const char *title, float min, float max)
202 this->output_i = output_i;
203 this->output_f = output_f;
204 this->output_q = output_q;
205 this->title = cstrdup(title);
206 this->plugin = plugin;
211 this->text_w = text_w;
221 PluginParam::~PluginParam()
231 void PluginParam::initialize()
235 (BC_Pot::calculate_h() -
236 BC_Title::calculate_h(gui, _(title), MEDIUMFONT)) / 2;
237 gui->add_tool(title_ = new BC_Title(x1, y2, _(title)));
241 gui->add_tool(fpot = new PluginFPot(this, x2, y));
246 gui->add_tool(ipot = new PluginIPot(this, x2, y));
251 gui->add_tool(qpot = new PluginQPot(this, x2, y));
255 (BC_Pot::calculate_h() -
256 BC_TextBox::calculate_h(gui, MEDIUMFONT, 1, 1)) / 2;
259 gui->add_tool(text = new PluginText(this, x3, y3, *output_i));
263 gui->add_tool(text = new PluginText(this, x3, y3, *output_f));
267 gui->add_tool(text = new PluginText(this, x3, y3, *output_q));
270 set_precision(precision);
273 void PluginParam::update(int skip_text, int skip_pot)
279 text->update((int64_t)*output_i);
283 text->update((int64_t)*output_q);
287 text->update((float)*output_f);
295 ipot->update((int64_t)*output_i);
299 qpot->update((int64_t)*output_q);
303 fpot->update((float)*output_f);
308 void PluginParam::set_precision(int digits)
310 this->precision = digits;
315 text->set_precision(digits);
318 fpot->set_precision(1.0f / pow(10, digits));
323 PluginFPot::PluginFPot(PluginParam *param, int x, int y)
334 int PluginFPot::handle_event()
336 *param->output_f = get_value();
338 param->plugin->send_configure_change();
339 param->gui->param_updated();
343 PluginIPot::PluginIPot(PluginParam *param, int x, int y)
354 int PluginIPot::handle_event()
356 *param->output_i = get_value();
358 param->plugin->send_configure_change();
359 param->gui->param_updated();
364 PluginQPot::PluginQPot(PluginParam *param, int x, int y)
373 int PluginQPot::handle_event()
375 *param->output_q = get_value();
377 param->plugin->send_configure_change();
378 param->gui->param_updated();
382 PluginText::PluginText(PluginParam *param, int x, int y, int value)
394 PluginText::PluginText(PluginParam *param, int x, int y, float value)
407 int PluginText::handle_event()
411 *param->output_i = atoi(get_text());
416 *param->output_f = atof(get_text());
421 *param->output_q = atoi(get_text());
424 param->plugin->send_configure_change();
425 param->gui->param_updated();
430 PluginClient::PluginClient(PluginServer *server)
433 this->server = server;
434 smp = server->preferences->project_smp;
436 update_timer = new Timer;
437 // Virtual functions don't work here.
440 PluginClient::~PluginClient()
448 // Virtual functions don't work here.
449 if(defaults) delete defaults;
453 int PluginClient::reset()
462 realtime_priority = 0;
464 total_in_buffers = 0;
465 total_out_buffers = 0;
469 direction = PLAY_FORWARD;
476 void PluginClient::hide_gui()
478 if(thread && thread->window)
480 thread->window->lock_window("PluginClient::hide_gui");
481 thread->window->set_done(0);
482 thread->window->unlock_window();
486 // For realtime plugins initialize buffers
487 int PluginClient::plugin_init_realtime(int realtime_priority,
488 int total_in_buffers,
492 // Get parameters for all
493 master_gui_on = get_gui_status();
497 // get parameters depending on video or audio
498 init_realtime_parameters();
500 this->realtime_priority = realtime_priority;
501 this->total_in_buffers = this->total_out_buffers = total_in_buffers;
502 this->out_buffer_size = this->in_buffer_size = buffer_size;
506 int PluginClient::plugin_start_loop(int64_t start,
511 //printf("PluginClient::plugin_start_loop %d %ld %ld %ld %d\n",
512 // __LINE__, start, end, buffer_size, total_buffers);
513 this->source_start = start;
514 this->total_len = end - start;
517 this->in_buffer_size = this->out_buffer_size = buffer_size;
518 this->total_in_buffers = this->total_out_buffers = total_buffers;
523 int PluginClient::plugin_process_loop()
525 return process_loop();
528 int PluginClient::plugin_stop_loop()
533 MainProgressBar* PluginClient::start_progress(char *string, int64_t length)
535 return server->start_progress(string, length);
539 // Non realtime parameters
540 int PluginClient::plugin_get_parameters()
542 int result = get_parameters();
543 if(defaults) save_defaults();
547 // ========================= main loop
549 int PluginClient::is_multichannel() { return 0; }
550 int PluginClient::is_synthesis() { return 0; }
551 int PluginClient::is_realtime() { return 0; }
552 int PluginClient::is_fileio() { return 0; }
553 const char* PluginClient::plugin_title() { return _("Untitled"); }
555 Theme* PluginClient::new_theme() { return 0; }
557 int PluginClient::load_configuration()
562 Theme* PluginClient::get_theme()
564 return server->get_theme();
567 int PluginClient::show_gui()
569 load_configuration();
570 thread = new PluginClientThread(this);
572 thread->init_complete->lock("PluginClient::show_gui");
573 // Must wait before sending any hide_gui
574 if( !thread->window ) return 1;
575 thread->window->init_wait();
579 void PluginClient::raise_window()
581 if(thread && thread->window)
583 thread->window->lock_window("PluginClient::raise_window");
584 thread->window->raise_window();
585 thread->window->flush();
586 thread->window->unlock_window();
590 int PluginClient::set_string()
594 thread->window->lock_window("PluginClient::set_string");
595 thread->window->put_title(gui_string);
596 thread->window->unlock_window();
605 PluginClientFrames::PluginClientFrames()
609 PluginClientFrames::~PluginClientFrames()
613 int PluginClientFrames::fwd_cmpr(PluginClientFrame *a, PluginClientFrame *b)
615 double d = a->position - b->position;
616 return d < 0 ? -1 : !d ? 0 : 1;
619 int PluginClientFrames::rev_cmpr(PluginClientFrame *a, PluginClientFrame *b)
621 double d = b->position - a->position;
622 return d < 0 ? -1 : !d ? 0 : 1;
625 void PluginClientFrames::reset()
631 void PluginClientFrames::add_gui_frame(PluginClientFrame *frame)
637 void PluginClientFrames::concatenate(PluginClientFrames *frames)
640 count += frames->count;
644 void PluginClientFrames::sort_position(int dir)
647 if( dir == PLAY_REVERSE )
653 // pop frames until buffer passes position=pos in direction=dir
654 // dir==0, pop frame; pos<0, pop all frames
655 // delete past frames, return last popped frame
656 PluginClientFrame* PluginClientFrames::get_gui_frame(double pos, int dir)
659 while( first != last ) {
660 if( pos >= 0 && dir*(first->next->position - pos) > 0 ) break;
661 delete first; --count;
664 PluginClientFrame *frame = first;
665 if( frame ) { remove_pointer(frame); --count; }
669 PluginClientFrame* PluginClient::get_gui_frame(double pos, int dir)
671 return client_frames.get_gui_frame(pos, dir);
673 PluginClientFrame* PluginClient::next_gui_frame()
675 return client_frames.first;
679 void PluginClient::plugin_update_gui()
684 void PluginClient::update_gui()
688 int PluginClient::pending_gui_frame()
690 PluginClientFrame *frame = client_frames.first;
691 if( !frame ) return 0;
692 double tracking_position = get_tracking_position();
693 int direction = get_tracking_direction();
694 int ret = !(direction == PLAY_REVERSE ?
695 frame->position < tracking_position :
696 frame->position > tracking_position);
700 int PluginClient::pending_gui_frames()
702 PluginClientFrame *frame = client_frames.first;
703 if( !frame ) return 0;
704 double tracking_position = get_tracking_position();
705 int direction = get_tracking_direction();
707 while( frame && !(direction == PLAY_REVERSE ?
708 frame->position < tracking_position :
709 frame->position > tracking_position) ) {
710 ++count; frame=frame->next;
715 void PluginClient::add_gui_frame(PluginClientFrame *frame)
717 client_frames.add_gui_frame(frame);
719 int PluginClient::get_gui_frames()
721 return client_frames.total();
724 double PluginClient::get_tracking_position()
726 return server->mwindow->get_tracking_position();
729 int PluginClient::get_tracking_direction()
731 return server->mwindow->get_tracking_direction();
734 void PluginClient::send_render_gui()
736 server->send_render_gui(&client_frames);
739 void PluginClient::send_render_gui(void *data)
741 server->send_render_gui(data);
744 void PluginClient::send_render_gui(void *data, int size)
746 server->send_render_gui(data, size);
750 void PluginClient::plugin_reset_gui_frames()
752 if( !thread ) return;
753 BC_WindowBase *window = thread->get_window();
754 if( !window ) return;
755 window->lock_window("PluginClient::plugin_reset_gui_frames");
756 client_frames.reset();
757 window->unlock_window();
760 void PluginClient::plugin_render_gui_frames(PluginClientFrames *frames)
762 if( !thread ) return;
763 BC_WindowBase *window = thread->get_window();
764 if( !window ) return;
765 window->lock_window("PluginClient::render_gui");
766 while( client_frames.count > MAX_FRAME_BUFFER )
767 delete get_gui_frame(0, 0);
768 // append client frames to gui client_frames, consumes frames
769 client_frames.concatenate(frames);
770 client_frames.sort_position(get_tracking_direction());
771 update_timer->update();
772 window->unlock_window();
775 void PluginClient::plugin_render_gui(void *data)
780 void PluginClient::plugin_render_gui(void *data, int size)
782 render_gui(data, size);
785 void PluginClient::render_gui(void *data)
787 printf("PluginClient::render_gui %d\n", __LINE__);
790 void PluginClient::render_gui(void *data, int size)
792 printf("PluginClient::render_gui %d\n", __LINE__);
795 void PluginClient::reset_gui_frames()
797 server->reset_gui_frames();
800 int PluginClient::is_audio() { return 0; }
801 int PluginClient::is_video() { return 0; }
802 int PluginClient::is_theme() { return 0; }
803 int PluginClient::uses_gui() { return 1; }
804 int PluginClient::is_transition() { return 0; }
805 int PluginClient::load_defaults()
807 // printf("PluginClient::load_defaults undefined in %s.\n", plugin_title());
811 int PluginClient::save_defaults()
814 // printf("PluginClient::save_defaults undefined in %s.\n", plugin_title());
818 void PluginClient::load_defaults_xml()
820 char path[BCTEXTLEN];
821 server->get_defaults_path(path);
823 fs.complete_path(path);
825 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
830 int fd = open(path, O_RDONLY);
831 if( fd >= 0 && !fstat(fd, &st) ) {
832 int64_t sz = st.st_size;
833 data = new char[sz+1];
834 len = read(fd, data, sz);
837 if( data && len >= 0 ) {
839 // Get window extents
841 for( int state=0; i<len && state>=0; ++i ) {
842 if( !data[i] || data[i] == '<' ) break;
843 if( !isdigit(data[i]) ) continue;
845 window_x = atoi(data+i);
849 window_y = atoi(data+i);
852 while( i<len && isdigit(data[i]) ) ++i;
854 KeyFrame keyframe(data+i, len-i);
855 read_data(&keyframe);
860 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
863 void PluginClient::save_defaults_xml()
865 char path[BCTEXTLEN];
866 server->get_defaults_path(path);
868 fs.complete_path(path);
871 KeyFrame temp_keyframe;
872 save_data(&temp_keyframe);
874 const char *data = temp_keyframe.get_data();
875 int len = strlen(data);
876 FILE *fp = fopen(path, "w");
879 fprintf(fp, "%d\n%d\n", window_x, window_y);
880 if( len > 0 && !fwrite(data, len, 1, fp) ) {
881 fprintf(stderr, "PluginClient::save_defaults_xml %d \"%s\" %d bytes: %s\n",
882 __LINE__, path, len, strerror(errno));
890 int PluginClient::is_defaults()
892 return using_defaults;
895 BC_Hash* PluginClient::get_defaults()
899 PluginClientThread* PluginClient::get_thread()
904 BC_WindowBase* PluginClient::new_window()
906 printf("PluginClient::new_window undefined in %s.\n", plugin_title());
909 int PluginClient::get_parameters() { return 0; }
910 int PluginClient::get_samplerate() { return get_project_samplerate(); }
911 double PluginClient::get_framerate() { return get_project_framerate(); }
912 int PluginClient::init_realtime_parameters() { return 0; }
913 int PluginClient::delete_nonrealtime_parameters() { return 0; }
914 int PluginClient::start_loop() { return 0; };
915 int PluginClient::process_loop() { return 0; };
916 int PluginClient::stop_loop() { return 0; };
918 void PluginClient::set_interactive()
923 int64_t PluginClient::get_in_buffers(int64_t recommended_size)
925 return recommended_size;
928 int64_t PluginClient::get_out_buffers(int64_t recommended_size)
930 return recommended_size;
933 int PluginClient::get_gui_status()
935 return server->get_gui_status();
938 // close event from client side
939 void PluginClient::client_side_close()
941 // Last command executed
942 server->client_side_close();
945 int PluginClient::stop_gui_client()
947 if(!client_gui_on) return 0;
952 int PluginClient::get_project_samplerate()
954 return server->get_project_samplerate();
957 double PluginClient::get_project_framerate()
959 return server->get_project_framerate();
962 const char *PluginClient::get_source_path()
964 Plugin *plugin = server->edl->tracks->plugin_exists(server->plugin_id);
965 int64_t source_position = plugin->startproject;
966 Edit *edit = plugin->track->edits->editof(source_position,PLAY_FORWARD,0);
967 Indexable *indexable = edit ? edit->get_source() : 0;
968 return indexable ? indexable->path : 0;
972 void PluginClient::update_display_title()
974 server->generate_display_title(gui_string);
978 char* PluginClient::get_gui_string()
984 char* PluginClient::get_path()
989 char* PluginClient::get_plugin_dir()
991 return server->preferences->plugin_dir;
994 int PluginClient::set_string_client(char *string)
996 strcpy(gui_string, string);
1002 int PluginClient::get_interpolation_type()
1004 return server->get_interpolation_type();
1008 float PluginClient::get_red()
1010 EDL *edl = get_edl();
1011 return edl->local_session->use_max ?
1012 edl->local_session->red_max :
1013 edl->local_session->red;
1016 float PluginClient::get_green()
1018 EDL *edl = get_edl();
1019 return edl->local_session->use_max ?
1020 edl->local_session->green_max :
1021 edl->local_session->green;
1024 float PluginClient::get_blue()
1026 EDL *edl = get_edl();
1027 return edl->local_session->use_max ?
1028 edl->local_session->blue_max :
1029 edl->local_session->blue;
1033 int64_t PluginClient::get_source_position()
1035 return source_position;
1038 int64_t PluginClient::get_source_start()
1040 return source_start;
1043 int64_t PluginClient::get_total_len()
1048 int PluginClient::get_direction()
1053 int64_t PluginClient::local_to_edl(int64_t position)
1058 int64_t PluginClient::edl_to_local(int64_t position)
1063 int PluginClient::get_use_opengl()
1065 return server->get_use_opengl();
1068 int PluginClient::to_ram(VFrame *vframe)
1070 return server->to_ram(vframe);
1073 int PluginClient::get_total_buffers()
1075 return total_in_buffers;
1078 int PluginClient::get_buffer_size()
1080 return in_buffer_size;
1083 int PluginClient::get_project_smp()
1085 //printf("PluginClient::get_project_smp %d %d\n", __LINE__, smp);
1089 const char* PluginClient::get_defaultdir()
1091 return File::get_plugin_path();
1095 int PluginClient::send_hide_gui()
1097 // Stop the GUI server and delete GUI messages
1102 int PluginClient::send_configure_change()
1105 server->mwindow->undo->update_undo_before(_("tweek"), this);
1106 #ifdef USE_KEYFRAME_SPANNING
1107 EDL *edl = server->edl;
1108 Plugin *plugin = edl->tracks->plugin_exists(server->plugin_id);
1109 KeyFrames *keyframes = plugin ? plugin->keyframes : 0;
1110 KeyFrame keyframe(edl, keyframes);
1111 save_data(&keyframe);
1112 server->apply_keyframe(plugin, &keyframe);
1114 KeyFrame* keyframe = server->get_keyframe();
1115 // Call save routine in plugin
1116 save_data(keyframe);
1119 server->mwindow->undo->update_undo_after(_("tweek"), LOAD_AUTOMATION);
1120 server->sync_parameters();
1124 // virtual default spanning keyframe update. If a range is selected,
1125 // then changed parameters are copied to (prev + selected) keyframes.
1126 // redefine per client for custom keyframe updates, see tracer, sketcher, crikey
1127 void PluginClient::span_keyframes(KeyFrame *src, int64_t start, int64_t end)
1129 src->span_keyframes(start, end);
1133 KeyFrame* PluginClient::get_prev_keyframe(int64_t position, int is_local)
1135 if(is_local) position = local_to_edl(position);
1136 return server->get_prev_keyframe(position);
1139 KeyFrame* PluginClient::get_next_keyframe(int64_t position, int is_local)
1141 if(is_local) position = local_to_edl(position);
1142 return server->get_next_keyframe(position);
1145 void PluginClient::get_camera(float *x, float *y, float *z, int64_t position)
1147 server->get_camera(x, y, z, position, direction);
1150 void PluginClient::get_projector(float *x, float *y, float *z, int64_t position)
1152 server->get_projector(x, y, z, position, direction);
1156 void PluginClient::output_to_track(float ox, float oy, float &tx, float &ty)
1158 float projector_x, projector_y, projector_z;
1159 int64_t position = get_source_position();
1160 get_projector(&projector_x, &projector_y, &projector_z, position);
1161 EDL *edl = get_edl();
1162 projector_x += edl->session->output_w / 2;
1163 projector_y += edl->session->output_h / 2;
1164 Plugin *plugin = edl->tracks->plugin_exists(server->plugin_id);
1165 Track *track = plugin ? plugin->track : 0;
1166 int track_w = track ? track->track_w : edl->session->output_w;
1167 int track_h = track ? track->track_h : edl->session->output_h;
1168 tx = (ox - projector_x) / projector_z + track_w / 2;
1169 ty = (oy - projector_y) / projector_z + track_h / 2;
1172 void PluginClient::track_to_output(float tx, float ty, float &ox, float &oy)
1174 float projector_x, projector_y, projector_z;
1175 int64_t position = get_source_position();
1176 get_projector(&projector_x, &projector_y, &projector_z, position);
1177 EDL *edl = get_edl();
1178 projector_x += edl->session->output_w / 2;
1179 projector_y += edl->session->output_h / 2;
1180 Plugin *plugin = edl->tracks->plugin_exists(server->plugin_id);
1181 Track *track = plugin ? plugin->track : 0;
1182 int track_w = track ? track->track_w : edl->session->output_w;
1183 int track_h = track ? track->track_h : edl->session->output_h;
1184 ox = (tx - track_w / 2) * projector_z + projector_x;
1185 oy = (ty - track_h / 2) * projector_z + projector_y;
1189 EDL *PluginClient::get_edl()
1191 return server->mwindow ? server->mwindow->edl : server->edl;
1194 int PluginClient::gui_open()
1196 return server->gui_open();