r945: Revert merge of editing modes
[cinelerra_cv/mob.git] / plugins / holo / holo.C
blobf00e8944dd2c1332fee1345b1d605ae63f3d9ec5
1 #include "clip.h"
2 #include "colormodels.h"
3 #include "effecttv.h"
4 #include "filexml.h"
5 #include "holo.h"
6 #include "holowindow.h"
7 #include "language.h"
8 #include "picon_png.h"
9 #include "plugincolors.h"
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <string.h>
16 REGISTER_PLUGIN(HoloMain)
27 HoloConfig::HoloConfig()
29         threshold = 40;
30         recycle = 1.0;
37 HoloMain::HoloMain(PluginServer *server)
38  : PluginVClient(server)
40         effecttv = 0;
41         bgimage = 0;
42         do_reconfigure = 1;
43         yuv = new YUV;
44         PLUGIN_CONSTRUCTOR_MACRO
47 HoloMain::~HoloMain()
49         PLUGIN_DESTRUCTOR_MACRO
52         if(effecttv)
53         {
54                 delete holo_server;
55                 delete effecttv;
56         }
58         if(bgimage)
59                 delete bgimage;
60         delete yuv;
63 char* HoloMain::plugin_title() { return N_("HolographicTV"); }
64 int HoloMain::is_realtime() { return 1; }
66 VFrame* HoloMain::new_picon()
68         return new VFrame(picon_png);
71 int HoloMain::load_defaults()
73         return 0;
76 int HoloMain::save_defaults()
78         return 0;
81 void HoloMain::load_configuration()
86 void HoloMain::save_data(KeyFrame *keyframe)
90 void HoloMain::read_data(KeyFrame *keyframe)
94 void HoloMain::reconfigure()
96         do_reconfigure = 0;
98         effecttv->image_set_threshold_y(config.threshold);
102 #define ADD_FRAMES(type, components) \
103 { \
104         type **input_rows = (type**)input->get_rows(); \
105         type **output_rows = (type**)output->get_rows(); \
106         int w = input->get_w(); \
107         int h = input->get_h(); \
109         for(int i = 0; i < h; i++) \
110         { \
111                 type *output_row = (type*)output_rows[i]; \
112                 type *input_row = (type*)input_rows[i]; \
114                 for(int j = 0; j < w; j++) \
115                 { \
116                         for(int k = 0; k < 3; k++) \
117                         { \
118                                 if(sizeof(type) == 4) \
119                                 { \
120                                         int in_temp = (int)(*input_row * 0xffff); \
121                                         int out_temp = (int)(*output_row * 0xffff); \
122                                         int temp = (in_temp & out_temp) + \
123                                                 ((in_temp ^ out_temp) >> 1); \
124                                         *output_row = (type)temp / 0xffff; \
125                                 } \
126                                 else \
127                                 { \
128                                         *output_row = ((uint16_t)*input_row & (uint16_t)*output_row) + \
129                                                 (((uint16_t)*input_row ^ (uint16_t)*output_row) >> 1); \
130                                 } \
131                                 output_row++; \
132                                 input_row++; \
133                         } \
135                         if(components == 4) \
136                         { \
137                                 output_row++; \
138                                 input_row++; \
139                         } \
140                 } \
141         } \
145 // Add input to output and store result in output
146 void HoloMain::add_frames(VFrame *output, VFrame *input)
148         switch(output->get_color_model())
149         {
150                 case BC_RGB888:
151                 case BC_YUV888:
152                         ADD_FRAMES(uint8_t, 3);
153                         break;
154                 case BC_RGB_FLOAT:
155                         ADD_FRAMES(float, 3);
156                         break;
157                 case BC_RGBA_FLOAT:
158                         ADD_FRAMES(float, 4);
159                         break;
160                 case BC_RGBA8888:
161                 case BC_YUVA8888:
162                         ADD_FRAMES(uint8_t, 4);
163                         break;
164                 case BC_RGB161616:
165                 case BC_YUV161616:
166                         ADD_FRAMES(uint16_t, 3);
167                         break;
168                 case BC_RGBA16161616:
169                 case BC_YUVA16161616:
170                         ADD_FRAMES(uint16_t, 4);
171                         break;
172         }
175 void HoloMain::set_background()
178  * grab 4 frames and composite them to get a quality background image
179  */
181  * For Cinelerra, we make every frame a holograph and expect the user to
182  * provide a matte.
183  **/
184 total = 0;
186         switch(total)
187         {
188                 case 0:
189 /* step 1: grab frame-1 to buffer-1 */
190 //                      tmp = new VFrame(0, 
191 //                              input_ptr->get_w(), 
192 //                              input_ptr->get_h(),
193 //                              project_color_model);
194                         bgimage->copy_from(input_ptr);
195                         break;
197                 case 1:
198 /* step 2: add frame-2 to buffer-1 */
199                         add_frames(bgimage, input_ptr);
200                         break;
202                 case 2:
203 /* step 3: grab frame-3 to buffer-2 */
204                         tmp->copy_from(input_ptr);
205                         break;
207                 case 3:
208 /* step 4: add frame-4 to buffer-2 */
209                         add_frames(tmp, input_ptr);
213 /* step 5: add buffer-3 to buffer-1 */
214                         add_frames(bgimage, tmp);
216                         effecttv->image_bgset_y(bgimage);
219                         delete tmp;
220                         break;
221         }
225 int HoloMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
227         this->input_ptr = input_ptr;
228         this->output_ptr = output_ptr;
233         load_configuration();
237         if(do_reconfigure)
238         {
239                 if(!effecttv)
240                 {
241                         effecttv = new EffectTV(input_ptr->get_w(), input_ptr->get_h());
242                         bgimage = new VFrame(0, 
243                                 input_ptr->get_w(), 
244                                 input_ptr->get_h(), 
245                                 input_ptr->get_color_model());
247                         for(int i = 0; i < 256; i++)
248                         {
249                                 noisepattern[i] = (i * i * i / 40000)* i / 256;
250                         }
252                         holo_server = new HoloServer(this, 1, 1);
253                 }
255                 reconfigure();
256         }
258         set_background();
259         
260         holo_server->process_packages();
261         
262         total++;
263         if(total >= config.recycle * project_frame_rate)
264                 total = 0;
266         return 0;
269 int HoloMain::show_gui()
271         load_configuration();
272         thread = new HoloThread(this);
273         thread->start();
274         return 0;
277 int HoloMain::set_string()
279         if(thread) thread->window->set_title(gui_string);
280         return 0;
283 void HoloMain::raise_window()
285         if(thread)
286         {
287                 thread->window->raise_window();
288                 thread->window->flush();
289         }
295 HoloServer::HoloServer(HoloMain *plugin, int total_clients, int total_packages)
296  : LoadServer(total_clients, total_packages)
298         this->plugin = plugin;
302 LoadClient* HoloServer::new_client() 
304         return new HoloClient(this);
310 LoadPackage* HoloServer::new_package() 
312         return new HoloPackage; 
317 void HoloServer::init_packages()
319         for(int i = 0; i < get_total_packages(); i++)
320         {
321                 HoloPackage *package = (HoloPackage*)get_package(i);
322                 package->row1 = plugin->input_ptr->get_h() * i / get_total_packages();
323                 package->row2 = plugin->input_ptr->get_h() * (i + 1) / get_total_packages();
324         }
334 HoloClient::HoloClient(HoloServer *server)
335  : LoadClient(server)
337         this->plugin = server->plugin;
338         phase = 0;
342 void HoloClient::process_package(LoadPackage *package)
344         int x, y;
345         int sx, sy;
346         HoloPackage *local_package = (HoloPackage*)package;
347         unsigned char **input_rows = plugin->input_ptr->get_rows() + local_package->row1;
348         unsigned char **output_rows = plugin->output_ptr->get_rows() + local_package->row1;
349         int width = plugin->input_ptr->get_w();
350         int height = local_package->row2 - local_package->row1;
351         unsigned char *diff;
352         uint32_t s, t;
353         int r, g, b;
355         diff = plugin->effecttv->image_diff_filter(plugin->effecttv->image_bgsubtract_y(input_rows, 
356                 plugin->input_ptr->get_color_model()));
358         diff += width;
359         output_rows++;
360         input_rows++;
363 // Convert discrete channels to a single 24 bit number
364 #define STORE_PIXEL(type, components, dest, src, is_yuv) \
365 if(sizeof(type) == 4) \
366 { \
367         int r = (int)(src[0] * 0xff); \
368         int g = (int)(src[1] * 0xff); \
369         int b = (int)(src[2] * 0xff); \
370         CLAMP(r, 0, 0xff); \
371         CLAMP(g, 0, 0xff); \
372         CLAMP(b, 0, 0xff); \
373         dest = (r << 16) | (g << 8) | b; \
374 } \
375 else \
376 if(sizeof(type) == 2) \
377 { \
378         if(is_yuv) \
379         { \
380                 int r = (int)src[0] >> 8; \
381                 int g = (int)src[1] >> 8; \
382                 int b = (int)src[2] >> 8; \
383                 plugin->yuv->yuv_to_rgb_8(r, g, b); \
384                 dest = (r << 16) | (g << 8) | b; \
385         } \
386         else \
387         { \
388                 dest = (((uint32_t)src[0] << 8) & 0xff0000) | \
389                         ((uint32_t)src[1] & 0xff00) | \
390                         ((uint32_t)src[2]) >> 8; \
391         } \
392 } \
393 else \
394 { \
395         if(is_yuv) \
396         { \
397                 int r = (int)src[0]; \
398                 int g = (int)src[1]; \
399                 int b = (int)src[2]; \
400                 plugin->yuv->yuv_to_rgb_8(r, g, b); \
401                 dest = (r << 16) | (g << 8) | b; \
402         } \
403         else \
404         { \
405                 dest = ((uint32_t)src[0] << 16) | \
406                         ((uint32_t)src[1] << 8) | \
407                         (uint32_t)src[2]; \
408         } \
414 #define HOLO_CORE(type, components, is_yuv) \
415         for(y = 1; y < height - 1; y++) \
416         { \
417                 type *src = (type*)input_rows[y]; \
418                 type *bg = (type*)plugin->bgimage->get_rows()[y]; \
419                 type *dest = (type*)output_rows[y]; \
423                 if(((y + phase) & 0x7f) < 0x58)  \
424                 { \
425                         for(x = 0 ; x < width; x++)  \
426                         { \
427                                 if(*diff) \
428                                 { \
429                                         STORE_PIXEL(type, components, s, src, is_yuv); \
431                                         t = (s & 0xff) +  \
432                                                 ((s & 0xff00) >> 7) +  \
433                                                 ((s & 0xff0000) >> 16); \
434                                         t += plugin->noisepattern[EffectTV::fastrand() >> 24]; \
436                                         r = ((s & 0xff0000) >> 17) + t; \
437                                         g = ((s & 0xff00) >> 8) + t; \
438                                         b = (s & 0xff) + t; \
440                                         r = (r >> 1) - 100; \
441                                         g = (g >> 1) - 100; \
442                                         b = b >> 2; \
444                                         if(r < 20) r = 20; \
445                                         if(g < 20) g = 20; \
447                                         STORE_PIXEL(type, components, s, bg, is_yuv); \
449                                         r += (s & 0xff0000) >> 17; \
450                                         g += (s & 0xff00) >> 9; \
451                                         b += ((s & 0xff) >> 1) + 40; \
453                                         if(r > 255) r = 255; \
454                                         if(g > 255) g = 255; \
455                                         if(b > 255) b = 255; \
457                                         if(is_yuv) plugin->yuv->rgb_to_yuv_8(r, g, b); \
458                                         if(sizeof(type) == 4) \
459                                         { \
460                                                 dest[0] = (type)r / 0xff; \
461                                                 dest[1] = (type)g / 0xff; \
462                                                 dest[2] = (type)b / 0xff; \
463                                         } \
464                                         else \
465                                         if(sizeof(type) == 2) \
466                                         { \
467                                                 dest[0] = (r << 8) | r; \
468                                                 dest[1] = (g << 8) | g; \
469                                                 dest[2] = (b << 8) | b; \
470                                         } \
471                                         else \
472                                         { \
473                                                 dest[0] = r; \
474                                                 dest[1] = g; \
475                                                 dest[2] = b; \
476                                         } \
477                                 }  \
478                                 else  \
479                                 { \
480                                         dest[0] = bg[0]; \
481                                         dest[1] = bg[1]; \
482                                         dest[2] = bg[2]; \
483                                 } \
485                                 diff++; \
486                                 src += components; \
487                                 dest += components; \
488                                 bg += components; \
489                         } \
490                 }  \
491                 else  \
492                 { \
493                         for(x = 0; x < width; x++) \
494                         { \
495                                 if(*diff) \
496                                 { \
497                                         STORE_PIXEL(type, components, s, src, is_yuv); \
500                                         t = (s & 0xff) + ((s & 0xff00) >> 6) + ((s & 0xff0000) >> 16); \
501                                         t += plugin->noisepattern[EffectTV::fastrand() >> 24]; \
503                                         r = ((s & 0xff0000) >> 16) + t; \
504                                         g = ((s & 0xff00) >> 8) + t; \
505                                         b = (s & 0xff) + t; \
507                                         r = (r >> 1) - 100; \
508                                         g = (g >> 1) - 100; \
509                                         b = b >> 2; \
511                                         if(r < 0) r = 0; \
512                                         if(g < 0) g = 0; \
514                                         STORE_PIXEL(type, components, s, bg, is_yuv); \
516                                         r += ((s & 0xff0000) >> 17) + 10; \
517                                         g += ((s & 0xff00) >> 9) + 10; \
518                                         b += ((s & 0xff) >> 1) + 40; \
520                                         if(r > 255) r = 255; \
521                                         if(g > 255) g = 255; \
522                                         if(b > 255) b = 255; \
524                                         if(is_yuv) plugin->yuv->rgb_to_yuv_8(r, g, b); \
525                                         if(sizeof(type) == 4) \
526                                         { \
527                                                 dest[0] = (type)r / 0xff; \
528                                                 dest[1] = (type)g / 0xff; \
529                                                 dest[2] = (type)b / 0xff; \
530                                         } \
531                                         else \
532                                         if(sizeof(type) == 2) \
533                                         { \
534                                                 dest[0] = (r << 8) | r; \
535                                                 dest[1] = (g << 8) | g; \
536                                                 dest[2] = (b << 8) | b; \
537                                         } \
538                                         else \
539                                         { \
540                                                 dest[0] = r; \
541                                                 dest[1] = g; \
542                                                 dest[2] = b; \
543                                         } \
544                                 }  \
545                                 else  \
546                                 { \
547                                         dest[0] = bg[0]; \
548                                         dest[1] = bg[1]; \
549                                         dest[2] = bg[2]; \
550                                 } \
552                                 diff++; \
553                                 src += components; \
554                                 dest += components; \
555                                 bg += components; \
556                         } \
557                 } \
558         }
563         switch(plugin->input_ptr->get_color_model())
564         {
565                 case BC_RGB888:
566                         HOLO_CORE(uint8_t, 3, 0);
567                         break;
568                 case BC_RGB_FLOAT:
569                         HOLO_CORE(float, 3, 0);
570                         break;
571                 case BC_YUV888:
572                         HOLO_CORE(uint8_t, 3, 1);
573                         break;
574                 case BC_RGBA_FLOAT:
575                         HOLO_CORE(float, 4, 0);
576                         break;
577                 case BC_RGBA8888:
578                         HOLO_CORE(uint8_t, 4, 0);
579                         break;
580                 case BC_YUVA8888:
581                         HOLO_CORE(uint8_t, 4, 1);
582                         break;
583                 case BC_RGB161616:
584                         HOLO_CORE(uint16_t, 3, 0);
585                         break;
586                 case BC_YUV161616:
587                         HOLO_CORE(uint16_t, 3, 1);
588                         break;
589                 case BC_RGBA16161616:
590                         HOLO_CORE(uint16_t, 4, 0);
591                         break;
592                 case BC_YUVA16161616:
593                         HOLO_CORE(uint16_t, 4, 1);
594                         break;
595         }
599         phase -= 37;
604 HoloPackage::HoloPackage()