edl plugin names eng, fix segv for opengl brender, renderfarm rework strategy, perf...
[goodguy/history.git] / cinelerra-5.1 / plugins / motionblur / motionblur.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 <math.h>
23 #include <stdint.h>
24 #include <string.h>
25
26 #include "bcdisplayinfo.h"
27 #include "clip.h"
28 #include "bchash.h"
29 #include "filexml.h"
30 #include "keyframe.h"
31 #include "language.h"
32 #include "loadbalance.h"
33 #include "pluginvclient.h"
34 #include "vframe.h"
35
36
37 class MotionBlurMain;
38 class MotionBlurEngine;
39
40
41
42
43
44 class MotionBlurConfig
45 {
46 public:
47         MotionBlurConfig();
48
49         int equivalent(MotionBlurConfig &that);
50         void copy_from(MotionBlurConfig &that);
51         void interpolate(MotionBlurConfig &prev,
52                 MotionBlurConfig &next,
53                 long prev_frame,
54                 long next_frame,
55                 long current_frame);
56
57         int radius;
58         int steps;
59         int r;
60         int g;
61         int b;
62         int a;
63 };
64
65
66
67 class MotionBlurSize : public BC_ISlider
68 {
69 public:
70         MotionBlurSize(MotionBlurMain *plugin,
71                 int x,
72                 int y,
73                 int *output,
74                 int min,
75                 int max);
76         int handle_event();
77         MotionBlurMain *plugin;
78         int *output;
79 };
80
81
82 class MotionBlurWindow : public PluginClientWindow
83 {
84 public:
85         MotionBlurWindow(MotionBlurMain *plugin);
86         ~MotionBlurWindow();
87
88         void create_objects();
89
90
91         MotionBlurSize *steps, *radius;
92         MotionBlurMain *plugin;
93 };
94
95
96
97
98
99
100 class MotionBlurMain : public PluginVClient
101 {
102 public:
103         MotionBlurMain(PluginServer *server);
104         ~MotionBlurMain();
105
106         int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
107         int is_realtime();
108         void save_data(KeyFrame *keyframe);
109         void read_data(KeyFrame *keyframe);
110         void update_gui();
111
112         PLUGIN_CLASS_MEMBERS(MotionBlurConfig)
113
114         void delete_tables();
115         VFrame *input, *output, *temp;
116         MotionBlurEngine *engine;
117         int **scale_y_table;
118         int **scale_x_table;
119         int table_entries;
120         unsigned char *accum;
121 };
122
123 class MotionBlurPackage : public LoadPackage
124 {
125 public:
126         MotionBlurPackage();
127         int y1, y2;
128 };
129
130 class MotionBlurUnit : public LoadClient
131 {
132 public:
133         MotionBlurUnit(MotionBlurEngine *server, MotionBlurMain *plugin);
134         void process_package(LoadPackage *package);
135         MotionBlurEngine *server;
136         MotionBlurMain *plugin;
137 };
138
139 class MotionBlurEngine : public LoadServer
140 {
141 public:
142         MotionBlurEngine(MotionBlurMain *plugin,
143                 int total_clients,
144                 int total_packages);
145         void init_packages();
146         LoadClient* new_client();
147         LoadPackage* new_package();
148         MotionBlurMain *plugin;
149 };
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 REGISTER_PLUGIN(MotionBlurMain)
170
171
172
173 MotionBlurConfig::MotionBlurConfig()
174 {
175         radius = 10;
176         steps = 10;
177         r = 1;
178         g = 1;
179         b = 1;
180         a = 1;
181 }
182
183 int MotionBlurConfig::equivalent(MotionBlurConfig &that)
184 {
185         return
186                 radius == that.radius &&
187                 steps == that.steps &&
188                 r == that.r &&
189                 g == that.g &&
190                 b == that.b &&
191                 a == that.a;
192 }
193
194 void MotionBlurConfig::copy_from(MotionBlurConfig &that)
195 {
196         radius = that.radius;
197         steps = that.steps;
198         r = that.r;
199         g = that.g;
200         b = that.b;
201         a = that.a;
202 }
203
204 void MotionBlurConfig::interpolate(MotionBlurConfig &prev,
205         MotionBlurConfig &next,
206         long prev_frame,
207         long next_frame,
208         long current_frame)
209 {
210         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
211         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
212         this->radius = (int)(prev.radius * prev_scale + next.radius * next_scale + 0.5);
213         this->steps = (int)(prev.steps * prev_scale + next.steps * next_scale + 0.5);
214         r = prev.r;
215         g = prev.g;
216         b = prev.b;
217         a = prev.a;
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231
232 MotionBlurWindow::MotionBlurWindow(MotionBlurMain *plugin)
233  : PluginClientWindow(plugin,
234         260,
235         120,
236         260,
237         120,
238         0)
239 {
240         this->plugin = plugin;
241 }
242
243 MotionBlurWindow::~MotionBlurWindow()
244 {
245 }
246
247 void MotionBlurWindow::create_objects()
248 {
249         int x = 10, y = 10;
250
251         add_subwindow(new BC_Title(x, y, _("Length:")));
252         y += 20;
253         add_subwindow(radius = new MotionBlurSize(plugin, x, y, &plugin->config.radius, 0, 100));
254         y += 30;
255         add_subwindow(new BC_Title(x, y, _("Steps:")));
256         y += 20;
257         add_subwindow(steps = new MotionBlurSize(plugin, x, y, &plugin->config.steps, 1, 100));
258
259         show_window();
260         flush();
261 }
262
263
264
265
266
267 MotionBlurSize::MotionBlurSize(MotionBlurMain *plugin,
268         int x,
269         int y,
270         int *output,
271         int min,
272         int max)
273  : BC_ISlider(x, y, 0, 240, 240, min, max, *output)
274 {
275         this->plugin = plugin;
276         this->output = output;
277 }
278 int MotionBlurSize::handle_event()
279 {
280         *output = get_value();
281         plugin->send_configure_change();
282         return 1;
283 }
284
285
286
287
288
289
290
291
292
293
294 MotionBlurMain::MotionBlurMain(PluginServer *server)
295  : PluginVClient(server)
296 {
297
298         engine = 0;
299         scale_x_table = 0;
300         scale_y_table = 0;
301         table_entries = 0;
302         accum = 0;
303         temp = 0;
304 }
305
306 MotionBlurMain::~MotionBlurMain()
307 {
308
309         if(engine) delete engine;
310         delete_tables();
311         if(accum) delete [] accum;
312         if(temp) delete temp;
313 }
314
315 const char* MotionBlurMain::plugin_title() { return N_("Motion Blur"); }
316 int MotionBlurMain::is_realtime() { return 1; }
317
318
319 NEW_WINDOW_MACRO(MotionBlurMain, MotionBlurWindow)
320
321 LOAD_CONFIGURATION_MACRO(MotionBlurMain, MotionBlurConfig)
322
323 void MotionBlurMain::delete_tables()
324 {
325         if(scale_x_table)
326         {
327                 for(int i = 0; i < table_entries; i++)
328                         delete [] scale_x_table[i];
329                 delete [] scale_x_table;
330         }
331
332         if(scale_y_table)
333         {
334                 for(int i = 0; i < table_entries; i++)
335                         delete [] scale_y_table[i];
336                 delete [] scale_y_table;
337         }
338         scale_x_table = 0;
339         scale_y_table = 0;
340         table_entries = 0;
341 }
342
343 int MotionBlurMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
344 {
345         float xa,ya,za,xb,yb,zb,xd,yd,zd;
346         if (get_source_position() == 0)
347                 get_camera(&xa, &ya, &za, get_source_position());
348         else
349                 get_camera(&xa, &ya, &za, get_source_position()-1);
350         get_camera(&xb, &yb, &zb, get_source_position());
351
352         xd = xb - xa;
353         yd = yb - ya;
354         zd = zb - za;
355
356         //printf("Camera automation deltas: %.2f %.2f %.2f\n", xd, yd, zd);
357         load_configuration();
358
359 //printf("MotionBlurMain::process_realtime 1 %d\n", config.radius);
360         if(!engine) engine = new MotionBlurEngine(this,
361                 get_project_smp() + 1,
362                 get_project_smp() + 1);
363         if(!accum) accum = new unsigned char[input_ptr->get_w() *
364                 input_ptr->get_h() *
365                 BC_CModels::components(input_ptr->get_color_model()) *
366                 MAX(sizeof(int), sizeof(float))];
367
368         this->input = input_ptr;
369         this->output = output_ptr;
370
371
372         if(input_ptr->get_rows()[0] == output_ptr->get_rows()[0])
373         {
374                 if(!temp) temp = new VFrame(input_ptr->get_w(), input_ptr->get_h(),
375                         input_ptr->get_color_model(), 0);
376                 temp->copy_from(input_ptr);
377                 this->input = temp;
378         }
379
380 // Generate tables here.  The same table is used by many packages to render
381 // each horizontal stripe.  Need to cover the entire output range in  each
382 // table to avoid green borders
383         float w = input->get_w();
384         float h = input->get_h();
385         int x_offset;
386         int y_offset;
387
388         float fradius = config.radius * 0.5;
389         float zradius = (float)(zd * fradius / 4 + 1);
390         float center_x = w/2;
391         float center_y = h/2;
392
393         float min_w, min_h;
394         //float max_w, max_h;
395         float min_x1, min_y1, min_x2, min_y2;
396         float max_x1, max_y1, max_x2, max_y2;
397
398         //int steps = config.steps ? config.steps : 1;
399
400         x_offset = (int)(xd * fradius);
401         y_offset = (int)(yd * fradius);
402
403     min_w = w * zradius;
404     min_h = h * zradius;
405     //max_w = w;
406     //max_h = h;
407     min_x1 = center_x - min_w / 2;
408         min_y1 = center_y - min_h / 2;
409         min_x2 = center_x + min_w / 2;
410         min_y2 = center_y + min_h / 2;
411         max_x1 = 0;
412         max_y1 = 0;
413         max_x2 = w;
414         max_y2 = h;
415
416         delete_tables();
417         scale_x_table = new int*[config.steps];
418         scale_y_table = new int*[config.steps];
419         table_entries = config.steps;
420
421         for(int i = 0; i < config.steps; i++)
422         {
423                 float fraction = (float)(i - config.steps / 2) / config.steps;
424                 float inv_fraction = 1.0 - fraction;
425
426                 int x = (int)(fraction * x_offset);
427                 int y = (int)(fraction * y_offset);
428                 float out_x1 = min_x1 * fraction + max_x1 * inv_fraction;
429                 float out_x2 = min_x2 * fraction + max_x2 * inv_fraction;
430                 float out_y1 = min_y1 * fraction + max_y1 * inv_fraction;
431                 float out_y2 = min_y2 * fraction + max_y2 * inv_fraction;
432                 float out_w = out_x2 - out_x1;
433                 float out_h = out_y2 - out_y1;
434                 if(out_w < 0) out_w = 0;
435                 if(out_h < 0) out_h = 0;
436                 float scale_x = (float)w / out_w;
437                 float scale_y = (float)h / out_h;
438
439                 int *x_table;
440                 int *y_table;
441                 scale_y_table[i] = y_table = new int[(int)(h + 1)];
442                 scale_x_table[i] = x_table = new int[(int)(w + 1)];
443
444                 for(int j = 0; j < h; j++)
445                 {
446                         y_table[j] = (int)((j - out_y1) * scale_y) + y;
447                 }
448                 for(int j = 0; j < w; j++)
449                 {
450                         x_table[j] = (int)((j - out_x1) * scale_x) + x;
451                 }
452         }
453
454         bzero(accum,
455                 input_ptr->get_w() *
456                 input_ptr->get_h() *
457                 BC_CModels::components(input_ptr->get_color_model()) *
458                 MAX(sizeof(int), sizeof(float)));
459         engine->process_packages();
460         return 0;
461 }
462
463
464 void MotionBlurMain::update_gui()
465 {
466         if(thread)
467         {
468                 load_configuration();
469                 thread->window->lock_window();
470                 ((MotionBlurWindow*)thread->window)->radius->update(config.radius);
471                 ((MotionBlurWindow*)thread->window)->steps->update(config.steps);
472                 thread->window->unlock_window();
473         }
474 }
475
476
477
478
479
480 void MotionBlurMain::save_data(KeyFrame *keyframe)
481 {
482         FileXML output;
483
484 // cause data to be stored directly in text
485         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
486         output.tag.set_title("MOTIONBLUR");
487
488         output.tag.set_property("RADIUS", config.radius);
489         output.tag.set_property("STEPS", config.steps);
490         output.append_tag();
491         output.tag.set_title("/MOTIONBLUR");
492         output.append_tag();
493         output.append_newline();
494         output.terminate_string();
495 }
496
497 void MotionBlurMain::read_data(KeyFrame *keyframe)
498 {
499         FileXML input;
500
501         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
502
503         int result = 0;
504
505         while(!result)
506         {
507                 result = input.read_tag();
508
509                 if(!result)
510                 {
511                         if(input.tag.title_is("MOTIONBLUR"))
512                         {
513                                 config.radius = input.tag.get_property("RADIUS", config.radius);
514                                 config.steps = input.tag.get_property("STEPS", config.steps);
515                         }
516                 }
517         }
518 }
519
520
521
522
523
524
525 MotionBlurPackage::MotionBlurPackage()
526  : LoadPackage()
527 {
528 }
529
530
531
532
533 MotionBlurUnit::MotionBlurUnit(MotionBlurEngine *server,
534         MotionBlurMain *plugin)
535  : LoadClient(server)
536 {
537         this->plugin = plugin;
538         this->server = server;
539 }
540
541
542 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP, MAX, DO_YUV) \
543 { \
544         const int chroma_offset = (DO_YUV ? ((MAX + 1) / 2) : 0); \
545         for(int j = pkg->y1; j < pkg->y2; j++) \
546         { \
547                 TEMP *out_row = (TEMP*)plugin->accum + COMPONENTS * w * j; \
548                 int in_y = y_table[j]; \
549  \
550 /* Blend image */ \
551                 if(in_y >= 0 && in_y < h) \
552                 { \
553                         TYPE *in_row = (TYPE*)plugin->input->get_rows()[in_y]; \
554                         for(int k = 0; k < w; k++) \
555                         { \
556                                 int in_x = x_table[k]; \
557 /* Blend pixel */ \
558                                 if(in_x >= 0 && in_x < w) \
559                                 { \
560                                         int in_offset = in_x * COMPONENTS; \
561                                         *out_row++ += in_row[in_offset]; \
562                                         if(DO_YUV) \
563                                         { \
564                                                 *out_row++ += in_row[in_offset + 1]; \
565                                                 *out_row++ += in_row[in_offset + 2]; \
566                                         } \
567                                         else \
568                                         { \
569                                                 *out_row++ += in_row[in_offset + 1]; \
570                                                 *out_row++ += in_row[in_offset + 2]; \
571                                         } \
572                                         if(COMPONENTS == 4) \
573                                                 *out_row++ += in_row[in_offset + 3]; \
574                                 } \
575 /* Blend nothing */ \
576                                 else \
577                                 { \
578                                         out_row++; \
579                                         if(DO_YUV) \
580                                         { \
581                                                 *out_row++ += chroma_offset; \
582                                                 *out_row++ += chroma_offset; \
583                                         } \
584                                         else \
585                                         { \
586                                                 out_row += 2; \
587                                         } \
588                                         if(COMPONENTS == 4) out_row++; \
589                                 } \
590                         } \
591                 } \
592                 else \
593                 if(DO_YUV) \
594                 { \
595                         for(int k = 0; k < w; k++) \
596                         { \
597                                 out_row++; \
598                                 *out_row++ += chroma_offset; \
599                                 *out_row++ += chroma_offset; \
600                                 if(COMPONENTS == 4) out_row++; \
601                         } \
602                 } \
603         } \
604  \
605 /* Copy to output */ \
606         if(i == plugin->config.steps - 1) \
607         { \
608                 for(int j = pkg->y1; j < pkg->y2; j++) \
609                 { \
610                         TEMP *in_row = (TEMP*)plugin->accum + COMPONENTS * w * j; \
611                         TYPE *in_backup = (TYPE*)plugin->input->get_rows()[j]; \
612                         TYPE *out_row = (TYPE*)plugin->output->get_rows()[j]; \
613                         for(int k = 0; k < w; k++) \
614                         { \
615                                 *out_row++ = (*in_row++ * fraction) / 0x10000; \
616                                 in_backup++; \
617  \
618                                 if(DO_YUV) \
619                                 { \
620                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
621                                         in_backup++; \
622  \
623                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
624                                         in_backup++; \
625                                 } \
626                                 else \
627                                 { \
628                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
629                                         in_backup++; \
630                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
631                                         in_backup++; \
632                                 } \
633  \
634                                 if(COMPONENTS == 4) \
635                                 { \
636                                         *out_row++ = (*in_row++ * fraction) / 0x10000; \
637                                         in_backup++; \
638                                 } \
639                         } \
640                 } \
641         } \
642 }
643
644 void MotionBlurUnit::process_package(LoadPackage *package)
645 {
646         MotionBlurPackage *pkg = (MotionBlurPackage*)package;
647         int h = plugin->output->get_h();
648         int w = plugin->output->get_w();
649
650         int fraction = 0x10000 / plugin->config.steps;
651         for(int i = 0; i < plugin->config.steps; i++)
652         {
653                 int *x_table = plugin->scale_x_table[i];
654                 int *y_table = plugin->scale_y_table[i];
655
656                 switch(plugin->input->get_color_model())
657                 {
658                         case BC_RGB_FLOAT:
659                                 BLEND_LAYER(3, float, float, 1, 0)
660                                 break;
661                         case BC_RGB888:
662                                 BLEND_LAYER(3, uint8_t, int, 0xff, 0)
663                                 break;
664                         case BC_RGBA_FLOAT:
665                                 BLEND_LAYER(4, float, float, 1, 0)
666                                 break;
667                         case BC_RGBA8888:
668                                 BLEND_LAYER(4, uint8_t, int, 0xff, 0)
669                                 break;
670                         case BC_RGB161616:
671                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
672                                 break;
673                         case BC_RGBA16161616:
674                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
675                                 break;
676                         case BC_YUV888:
677                                 BLEND_LAYER(3, uint8_t, int, 0xff, 1)
678                                 break;
679                         case BC_YUVA8888:
680                                 BLEND_LAYER(4, uint8_t, int, 0xff, 1)
681                                 break;
682                         case BC_YUV161616:
683                                 BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
684                                 break;
685                         case BC_YUVA16161616:
686                                 BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
687                                 break;
688                 }
689         }
690 }
691
692
693
694
695
696
697 MotionBlurEngine::MotionBlurEngine(MotionBlurMain *plugin,
698         int total_clients,
699         int total_packages)
700  : LoadServer(total_clients, total_packages)
701 {
702         this->plugin = plugin;
703 }
704
705 void MotionBlurEngine::init_packages()
706 {
707         for(int i = 0; i < get_total_packages(); i++)
708         {
709                 MotionBlurPackage *package = (MotionBlurPackage*)get_package(i);
710                 package->y1 = plugin->output->get_h() * i / get_total_packages();
711                 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
712         }
713 }
714
715 LoadClient* MotionBlurEngine::new_client()
716 {
717         return new MotionBlurUnit(this, plugin);
718 }
719
720 LoadPackage* MotionBlurEngine::new_package()
721 {
722         return new MotionBlurPackage;
723 }
724
725
726
727
728