dynamic keyframes, textbox rework, andrea ffmpeg.opts, perpetual chkpt undo, lv2...
[goodguy/history.git] / cinelerra-5.1 / plugins / reroute / reroute.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2007 Hermann Vosseler
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 "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "keyframe.h"
28 #include "language.h"
29 #include "overlayframe.h"
30 #include "pluginvclient.h"
31 #include "vframe.h"
32
33 #include <string.h>
34 #include <stdint.h>
35
36
37 class Reroute;
38 class RerouteWindow;
39
40
41 class RerouteConfig
42 {
43 public:
44         RerouteConfig();
45
46
47
48         static const char* operation_to_text(int operation);
49         int operation;
50         enum
51         {
52                 REPLACE,
53                 REPLACE_COMPONENTS,
54                 REPLACE_ALPHA
55         };
56
57         static const char* output_to_text(int output_track);
58         int output_track;
59         enum
60         {
61                 TOP,
62                 BOTTOM
63         };
64 };
65
66
67
68
69
70
71 class RerouteOperation : public BC_PopupMenu
72 {
73 public:
74         RerouteOperation(Reroute *plugin,
75                 int x,
76                 int y);
77         void create_objects();
78         int handle_event();
79         Reroute *plugin;
80 };
81
82 class RerouteOutput : public BC_PopupMenu
83 {
84 public:
85         RerouteOutput(Reroute *plugin,
86                 int x,
87                 int y);
88         void create_objects();
89         int handle_event();
90         Reroute *plugin;
91 };
92
93
94 class RerouteWindow : public PluginClientWindow
95 {
96 public:
97         RerouteWindow(Reroute *plugin);
98         ~RerouteWindow();
99
100         void create_objects();
101
102         Reroute *plugin;
103         RerouteOperation *operation;
104         RerouteOutput *output;
105 };
106
107
108
109
110
111 class Reroute : public PluginVClient
112 {
113 public:
114         Reroute(PluginServer *server);
115         ~Reroute();
116
117
118         PLUGIN_CLASS_MEMBERS(RerouteConfig);
119
120         int process_buffer(VFrame **frame, int64_t start_position, double frame_rate);
121         int is_realtime();
122         int is_multichannel();
123         void save_data(KeyFrame *keyframe);
124         void read_data(KeyFrame *keyframe);
125         void update_gui();
126
127         int output_track;
128         int input_track;
129 };
130
131
132
133
134
135
136
137
138
139
140
141
142 RerouteConfig::RerouteConfig()
143 {
144         operation = RerouteConfig::REPLACE;
145         output_track = RerouteConfig::TOP;
146 }
147
148
149 const char* RerouteConfig::operation_to_text(int operation)
150 {
151         switch(operation)
152         {
153                 case RerouteConfig::REPLACE:                    return _("replace Target");
154                 case RerouteConfig::REPLACE_COMPONENTS: return _("Components only");
155                 case RerouteConfig::REPLACE_ALPHA:      return _("Alpha replace");
156         }
157         return "";
158 }
159
160 const char* RerouteConfig::output_to_text(int output_track)
161 {
162         switch(output_track)
163         {
164                 case RerouteConfig::TOP:    return _("Top");
165                 case RerouteConfig::BOTTOM: return _("Bottom");
166         }
167         return "";
168 }
169
170
171
172
173
174
175
176
177
178 RerouteWindow::RerouteWindow(Reroute *plugin)
179  : PluginClientWindow(plugin, 300, 160, 0, 0, 1)
180 {
181         this->plugin = plugin;
182 }
183
184 RerouteWindow::~RerouteWindow()
185 {
186 }
187
188 void RerouteWindow::create_objects()
189 {
190         int x = 10, y = 10;
191
192         BC_Title *title;
193         add_subwindow(title = new BC_Title(x, y, _("Target track:")));
194
195         int col2 = title->get_w() + 5;
196         add_subwindow(output = new RerouteOutput(plugin,
197                 x + col2,
198                 y));
199         output->create_objects();
200
201         y += 30;
202         add_subwindow(title = new BC_Title(x, y, _("Operation:")));
203         add_subwindow(operation = new RerouteOperation(plugin,
204                 x + col2,
205                 y));
206         operation->create_objects();
207
208         show_window();
209         flush();
210 }
211
212
213
214
215
216
217
218
219 RerouteOperation::RerouteOperation(Reroute *plugin,
220         int x,
221         int y)
222  : BC_PopupMenu(x,
223         y,
224         150,
225         RerouteConfig::operation_to_text(plugin->config.operation),
226         1)
227 {
228         this->plugin = plugin;
229 }
230
231 void RerouteOperation::create_objects()
232 {
233         add_item(new BC_MenuItem(
234                 RerouteConfig::operation_to_text(
235                         RerouteConfig::REPLACE)));
236         add_item(new BC_MenuItem(
237                 RerouteConfig::operation_to_text(
238                         RerouteConfig::REPLACE_COMPONENTS)));
239         add_item(new BC_MenuItem(
240                 RerouteConfig::operation_to_text(
241                         RerouteConfig::REPLACE_ALPHA)));
242 }
243
244 int RerouteOperation::handle_event()
245 {
246         char *text = get_text();
247
248         if(!strcmp(text,
249                 RerouteConfig::operation_to_text(
250                         RerouteConfig::REPLACE)))
251                 plugin->config.operation = RerouteConfig::REPLACE;
252         else
253         if(!strcmp(text,
254                 RerouteConfig::operation_to_text(
255                         RerouteConfig::REPLACE_COMPONENTS)))
256                 plugin->config.operation = RerouteConfig::REPLACE_COMPONENTS;
257         else
258         if(!strcmp(text,
259                 RerouteConfig::operation_to_text(
260                         RerouteConfig::REPLACE_ALPHA)))
261                 plugin->config.operation = RerouteConfig::REPLACE_ALPHA;
262
263         plugin->send_configure_change();
264         return 1;
265 }
266
267
268 RerouteOutput::RerouteOutput(Reroute *plugin,
269         int x,
270         int y)
271  : BC_PopupMenu(x,
272         y,
273         100,
274         RerouteConfig::output_to_text(plugin->config.output_track),
275         1)
276 {
277         this->plugin = plugin;
278 }
279
280 void RerouteOutput::create_objects()
281 {
282         add_item(new BC_MenuItem(
283                 RerouteConfig::output_to_text(
284                         RerouteConfig::TOP)));
285         add_item(new BC_MenuItem(
286                 RerouteConfig::output_to_text(
287                         RerouteConfig::BOTTOM)));
288 }
289
290 int RerouteOutput::handle_event()
291 {
292         char *text = get_text();
293
294         if(!strcmp(text,
295                 RerouteConfig::output_to_text(
296                         RerouteConfig::TOP)))
297                 plugin->config.output_track = RerouteConfig::TOP;
298         else
299         if(!strcmp(text,
300                 RerouteConfig::output_to_text(
301                         RerouteConfig::BOTTOM)))
302                 plugin->config.output_track = RerouteConfig::BOTTOM;
303
304         plugin->send_configure_change();
305         return 1;
306 }
307
308
309
310
311
312 /***** Register Plugin ***********************************/
313
314
315 REGISTER_PLUGIN(Reroute)
316
317
318
319
320
321
322
323 Reroute::Reroute(PluginServer *server)
324  : PluginVClient(server)
325 {
326 }
327
328
329 Reroute::~Reroute()
330 {
331 }
332
333
334
335 /*
336  *  Main operation
337  *
338  *****************************************/
339 template<class TYPE, int COMPONENTS>
340 struct px_type
341 {
342         static inline
343         void transfer(VFrame*, VFrame*, bool, bool) ;
344 };
345
346 template<class TYPE, int COMPONENTS>
347 void px_type<TYPE,COMPONENTS>::transfer(VFrame *source, VFrame *target, bool do_components, bool do_alpha)
348 //partially overwrite target data buffer
349 {
350         int w = target->get_w();
351         int h = source->get_h();
352         do_alpha = do_alpha && (COMPONENTS > 3);  // only possible if we have alpha
353
354         for(int i = 0; i < h; i++)
355         {
356                 TYPE *inpx  = (TYPE*)source->get_rows()[i];
357                 TYPE *outpx = (TYPE*)target->get_rows()[i];
358
359                 for(int j = 0; j < w; j++)
360                 {
361                         if(do_components)
362                         {
363                                 outpx[0] = inpx[0];
364                                 outpx[1] = inpx[1];
365                                 outpx[2] = inpx[2];
366                         }
367                         if(do_alpha)
368                                 outpx[3] = inpx[3];
369
370                         inpx += COMPONENTS;
371                         outpx += COMPONENTS;
372                 }
373         }
374 }
375
376
377
378 int Reroute::process_buffer(VFrame **frame,
379         int64_t start_position,
380         double frame_rate)
381 {
382         load_configuration();
383
384         bool do_components = true, do_alpha = true;
385         switch(config.operation)
386         {
387                 case RerouteConfig::REPLACE:            break;
388                 case RerouteConfig::REPLACE_ALPHA:      do_components = false; break;
389                 case RerouteConfig::REPLACE_COMPONENTS: do_alpha = false; break;
390         }
391
392         if(config.output_track == RerouteConfig::TOP)
393         {
394                 input_track  = get_total_buffers() - 1;
395                 output_track = 0;
396         }
397         else
398         {
399                 input_track  = 0;
400                 output_track = get_total_buffers() - 1;
401         }
402
403
404         // output buffers for source and target track
405         VFrame *source = frame[input_track];
406         VFrame *target = frame[output_track];
407
408         // input track always passed through unaltered
409         read_frame(source,
410                 input_track,
411                 start_position,
412                 frame_rate,
413                 false );  // no OpenGL support
414
415          // no real operation necessary
416         //  unless applied to multiple tracks....
417         if(get_total_buffers() <= 1)
418                 return 0;
419
420         if(config.operation == RerouteConfig::REPLACE)
421         {
422                 target->copy_from(source);
423                 return 0;
424         }
425
426
427         // prepare data for output track
428         // (to be overidden partially)
429         read_frame(target,
430                 output_track,
431                 start_position,
432                 frame_rate,
433                 0);
434
435         switch(source->get_color_model())
436         {
437                 case BC_RGB_FLOAT:
438                         px_type<float,3>::transfer(source,target, do_components,do_alpha);
439                         break;
440                 case BC_RGBA_FLOAT:
441                         px_type<float,4>::transfer(source,target, do_components,do_alpha);
442                         break;
443                 case BC_RGB888:
444                 case BC_YUV888:
445                         px_type<unsigned char,3>::transfer(source,target, do_components,do_alpha);
446                         break;
447                 case BC_RGBA8888:
448                 case BC_YUVA8888:
449                         px_type<unsigned char,4>::transfer(source,target, do_components,do_alpha);
450                         break;
451                 case BC_RGB161616:
452                 case BC_YUV161616:
453                         px_type<uint16_t,3>::transfer(source,target, do_components,do_alpha);
454                         break;
455                 case BC_RGBA16161616:
456                 case BC_YUVA16161616:
457                         px_type<uint16_t,4>::transfer(source,target, do_components,do_alpha);
458                         break;
459         }
460
461         return 0;
462 }
463
464
465
466
467
468
469
470
471 const char* Reroute::plugin_title() { return N_("Reroute"); }
472 int Reroute::is_realtime()              { return 1; }
473 int Reroute::is_multichannel()  { return 1; }
474
475
476
477
478
479 NEW_WINDOW_MACRO(Reroute,RerouteWindow)
480
481 int Reroute::load_configuration()
482 {
483         KeyFrame *prev_keyframe;
484         prev_keyframe = get_prev_keyframe(get_source_position());
485         read_data(prev_keyframe);
486         return 0;
487 }
488
489
490 void Reroute::save_data(KeyFrame *keyframe)
491 {
492         FileXML output;
493
494 // write configuration data as XML text
495         output.set_shared_output(keyframe->xbuf);
496         output.tag.set_title("REROUTE");
497         output.tag.set_property("OPERATION", config.operation);
498         output.tag.set_property("OUTPUT_TRACK", config.output_track);
499         output.append_tag();
500         output.tag.set_title("/REROUTE");
501         output.append_tag();
502         output.terminate_string();
503 }
504
505 void Reroute::read_data(KeyFrame *keyframe)
506 {
507         FileXML input;
508         input.set_shared_input(keyframe->xbuf);
509
510         while(!input.read_tag())
511         {
512                 if(input.tag.title_is("REROUTE"))
513                 {
514                         config.operation = input.tag.get_property("OPERATION", config.operation);
515                         config.output_track = input.tag.get_property("OUTPUT_TRACK", config.output_track);
516                 }
517         }
518 }
519
520 void Reroute::update_gui()
521 {
522         if(thread)
523         {
524                 RerouteWindow *window = (RerouteWindow *)thread->window;
525                 window->lock_window("Reroute::update_gui");
526                 window->operation->set_text(RerouteConfig::operation_to_text(config.operation));
527                 window->output->set_text(RerouteConfig::output_to_text(config.output_track));
528                 window->unlock_window();
529         }
530 }