r1008: pt_BR translation update
[cinelerra_cv/mob.git] / plugins / sharpen / sharpen.C
blob199c66b1c5b29cb5bba023ab16bd065fdc038c08
1 #include "clip.h"
2 #include "colormodels.h"
3 #include "condition.h"
4 #include "filexml.h"
5 #include "language.h"
6 #include "picon_png.h"
7 #include "sharpen.h"
8 #include "sharpenwindow.h"
10 #include <stdio.h>
11 #include <string.h>
13 REGISTER_PLUGIN(SharpenMain)
21 SharpenConfig::SharpenConfig()
23         horizontal = 0;
24         interlace = 0;
25         sharpness = 50;
26         luminance = 0;
29 void SharpenConfig::copy_from(SharpenConfig &that)
31         horizontal = that.horizontal;
32         interlace = that.interlace;
33         sharpness = that.sharpness;
34         luminance = that.luminance;
37 int SharpenConfig::equivalent(SharpenConfig &that)
39         return horizontal == that.horizontal &&
40                 interlace == that.interlace &&
41                 EQUIV(sharpness, that.sharpness) &&
42                 luminance == that.luminance;
45 void SharpenConfig::interpolate(SharpenConfig &prev, 
46         SharpenConfig &next, 
47         long prev_frame, 
48         long next_frame, 
49         long current_frame)
51         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
52         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
53         this->sharpness = prev.sharpness * prev_scale + next.sharpness * next_scale;
54         this->interlace = prev.interlace;
55         this->horizontal = prev.horizontal;
56         this->luminance = prev.luminance;
69 SharpenMain::SharpenMain(PluginServer *server)
70  : PluginVClient(server)
72         PLUGIN_CONSTRUCTOR_MACRO
73         engine = 0;
76 SharpenMain::~SharpenMain()
78         PLUGIN_DESTRUCTOR_MACRO
80         if(engine)
81         {
82                 for(int i = 0; i < total_engines; i++)
83                 {
84                         delete engine[i];
85                 }
86                 delete engine;
87         }
90 SHOW_GUI_MACRO(SharpenMain, SharpenThread)
92 SET_STRING_MACRO(SharpenMain)
94 RAISE_WINDOW_MACRO(SharpenMain)
96 NEW_PICON_MACRO(SharpenMain)
98 LOAD_CONFIGURATION_MACRO(SharpenMain, SharpenConfig)
100 char* SharpenMain::plugin_title() { return N_("Sharpen"); }
101 int SharpenMain::is_realtime() { return 1; }
105 int SharpenMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
107         int i, j, k;
108         output = output_ptr;
109         input = input_ptr;
111         load_configuration();
112         if(!engine)
113         {
115                 total_engines = PluginClient::smp > 1 ? 2 : 1;
116                 engine = new SharpenEngine*[total_engines];
117                 for(int i = 0; i < total_engines; i++)
118                 {
119                         engine[i] = new SharpenEngine(this);
120                         engine[i]->start();
121                 }
122         }
124         get_luts(pos_lut, neg_lut, input_ptr->get_color_model());
126         if(config.sharpness != 0)
127         {
128 // Arm first row
129                 row_step = (config.interlace /* || config.horizontal */) ? 2 : 1;
131                 for(j = 0; j < row_step; j += total_engines)
132                 {
133                         for(k = 0; k < total_engines && k + j < row_step; k++)
134                         {
135                                 engine[k]->start_process_frame(input_ptr, input_ptr, k + j);
136                         }
137                         for(k = 0; k < total_engines && k + j < row_step; k++)
138                         {
139                                 engine[k]->wait_process_frame();
140                         }
141                 }
142         }
143         else
144         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
145         {
146                 output_ptr->copy_from(input_ptr);
147         }
148         return 0;
151 void SharpenMain::update_gui()
153         if(thread)
154         {
155                 load_configuration();
156                 thread->window->lock_window();
157                 thread->window->sharpen_slider->update((int)config.sharpness);
158                 thread->window->sharpen_interlace->update(config.interlace);
159                 thread->window->sharpen_horizontal->update(config.horizontal);
160                 thread->window->sharpen_luminance->update(config.luminance);
161                 thread->window->unlock_window();
162         }
165 int SharpenMain::load_defaults()
167         char directory[1024], string[1024];
168 // set the default directory
169         sprintf(directory, "%ssharpen.rc", BCASTDIR);
171 // load the defaults
172         defaults = new BC_Hash(directory);
173         defaults->load();
175         config.sharpness = defaults->get("SHARPNESS", config.sharpness);
176         config.interlace = defaults->get("INTERLACE", config.interlace);
177         config.horizontal = defaults->get("HORIZONTAL", config.horizontal);
178         config.luminance = defaults->get("LUMINANCE", config.luminance);
179 //printf("SharpenMain::load_defaults 1 %f %d %d %d\n", sharpness, interlace, horizontal, luminance);
180         return 0;
183 int SharpenMain::save_defaults()
185 //printf("SharpenMain::save_defaults 1 %f %d %d %d\n", sharpness, interlace, horizontal, luminance);
186         defaults->update("SHARPNESS", config.sharpness);
187         defaults->update("INTERLACE", config.interlace);
188         defaults->update("HORIZONTAL", config.horizontal);
189         defaults->update("LUMINANCE", config.luminance);
190         defaults->save();
191         return 0;
197 int SharpenMain::get_luts(int *pos_lut, int *neg_lut, int color_model)
199         int i, inv_sharpness, vmax;
201         vmax = cmodel_calculate_max(color_model);
203         inv_sharpness = (int)(100 - config.sharpness);
204         if(config.horizontal) inv_sharpness /= 2;
205         if(inv_sharpness < 1) inv_sharpness = 1;
207         for(i = 0; i < vmax + 1; i++)
208         {
209                 pos_lut[i] = 800 * i / inv_sharpness;
210                 neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
211         }
213         return 0;
216 void SharpenMain::save_data(KeyFrame *keyframe)
218         FileXML output;
220 // cause data to be stored directly in text
221         output.set_shared_string(keyframe->data, MESSAGESIZE);
222         output.tag.set_title("SHARPNESS");
223         output.tag.set_property("VALUE", config.sharpness);
224         output.append_tag();
226         if(config.interlace)
227         {
228                 output.tag.set_title("INTERLACE");
229                 output.append_tag();
230         }
232         if(config.horizontal)
233         {
234                 output.tag.set_title("HORIZONTAL");
235                 output.append_tag();
236         }
238         if(config.luminance)
239         {
240                 output.tag.set_title("LUMINANCE");
241                 output.append_tag();
242         }
243         output.terminate_string();
246 void SharpenMain::read_data(KeyFrame *keyframe)
248         FileXML input;
250         input.set_shared_string(keyframe->data, strlen(keyframe->data));
252         int result = 0;
253         int new_interlace = 0;
254         int new_horizontal = 0;
255         int new_luminance = 0;
257         while(!result)
258         {
259                 result = input.read_tag();
261                 if(!result)
262                 {
263                         if(input.tag.title_is("SHARPNESS"))
264                         {
265                                 config.sharpness = input.tag.get_property("VALUE", config.sharpness);
266 //printf("SharpenMain::read_data %f\n", sharpness);
267                         }
268                         else
269                         if(input.tag.title_is("INTERLACE"))
270                         {
271                                 new_interlace = 1;
272                         }
273                         else
274                         if(input.tag.title_is("HORIZONTAL"))
275                         {
276                                 new_horizontal = 1;
277                         }
278                         else
279                         if(input.tag.title_is("LUMINANCE"))
280                         {
281                                 new_luminance = 1;
282                         }
283                 }
284         }
286         config.interlace = new_interlace;
287         config.horizontal = new_horizontal;
288         config.luminance = new_luminance;
290         if(config.sharpness > MAXSHARPNESS) 
291                 config.sharpness = MAXSHARPNESS;
292         else
293                 if(config.sharpness < 0) config.sharpness = 0;
299 SharpenEngine::SharpenEngine(SharpenMain *plugin)
300  : Thread(1, 0, 0)
302         this->plugin = plugin;
303         input_lock = new Condition(0,"SharpenEngine::input_lock");
304         output_lock = new Condition(0, "SharpenEngine::output_lock");
305         last_frame = 0;
306         for(int i = 0; i < 4; i++)
307         {
308                 neg_rows[i] = new unsigned char[plugin->input->get_w() * 
309                         4 * 
310                         MAX(sizeof(float), sizeof(int))];
311         }
314 SharpenEngine::~SharpenEngine()
316         last_frame = 1;
317         input_lock->unlock();
318         Thread::join();
320         for(int i = 0; i < 4; i++)
321         {
322                 delete [] neg_rows[i];
323         }
324         delete input_lock;
325         delete output_lock;
328 int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
330         this->output = output;
331         this->input = input;
332         this->field = field;
334 // Get coefficient for floating point
335         sharpness_coef = 100 - plugin->config.sharpness;
336         if(plugin->config.horizontal) sharpness_coef /= 2;
337         if(sharpness_coef < 1) sharpness_coef = 1;
338         sharpness_coef = 800.0 / sharpness_coef;
339         
340         input_lock->unlock();
341         return 0;
344 int SharpenEngine::wait_process_frame()
346         output_lock->lock("SharpenEngine::wait_process_frame");
347         return 0;
350 float SharpenEngine::calculate_pos(float value)
352         return sharpness_coef * value;
355 float SharpenEngine::calculate_neg(float value)
357         return (calculate_pos(value) - (value * 8)) / 8;
360 #define FILTER(components, vmax) \
361 { \
362         int *pos_lut = plugin->pos_lut; \
363         const int wordsize = sizeof(*src); \
365 /* Skip first pixel in row */ \
366         memcpy(dst, src, components * wordsize); \
367         dst += components; \
368         src += components; \
370         w -= 2; \
372         while(w > 0) \
373         { \
374                 long pixel; \
375                 pixel = (long)pos_lut[src[0]] -  \
376                         (long)neg0[-components] -  \
377                         (long)neg0[0] -  \
378                         (long)neg0[components] -  \
379                         (long)neg1[-components] -  \
380                         (long)neg1[components] -  \
381                         (long)neg2[-components] -  \
382                         (long)neg2[0] -  \
383                         (long)neg2[components]; \
384                 pixel = (pixel + 4) >> 3; \
385                 if(pixel < 0) dst[0] = 0; \
386                 else \
387                 if(pixel > vmax) dst[0] = vmax; \
388                 else \
389                 dst[0] = pixel; \
391                 pixel = (long)pos_lut[src[1]] -  \
392                         (long)neg0[-components + 1] -  \
393                         (long)neg0[1] -  \
394                         (long)neg0[components + 1] -  \
395                         (long)neg1[-components + 1] -  \
396                         (long)neg1[components + 1] -  \
397                         (long)neg2[-components + 1] -  \
398                         (long)neg2[1] -  \
399                         (long)neg2[components + 1]; \
400                 pixel = (pixel + 4) >> 3; \
401                 if(pixel < 0) dst[1] = 0; \
402                 else \
403                 if(pixel > vmax) dst[1] = vmax; \
404                 else \
405                 dst[1] = pixel; \
407                 pixel = (long)pos_lut[src[2]] -  \
408                         (long)neg0[-components + 2] -  \
409                         (long)neg0[2] -  \
410                         (long)neg0[components + 2] -  \
411                         (long)neg1[-components + 2] -  \
412                         (long)neg1[components + 2] -  \
413                         (long)neg2[-components + 2] -  \
414                         (long)neg2[2] -  \
415                         (long)neg2[components + 2]; \
416                 pixel = (pixel + 4) >> 3; \
417                 if(pixel < 0) dst[2] = 0; \
418                 else \
419                 if(pixel > vmax) dst[2] = vmax; \
420                 else \
421                 dst[2] = pixel; \
423                 src += components; \
424                 dst += components; \
426                 neg0 += components; \
427                 neg1 += components; \
428                 neg2 += components; \
429                 w--; \
430         } \
432 /* Skip last pixel in row */ \
433         memcpy(dst, src, components * wordsize); \
436 void SharpenEngine::filter(int components,
437         int vmax,
438         int w, 
439         u_int16_t *src, 
440         u_int16_t *dst,
441         int *neg0, 
442         int *neg1, 
443         int *neg2)
445         FILTER(components, vmax);
448 void SharpenEngine::filter(int components,
449         int vmax,
450         int w, 
451         unsigned char *src, 
452         unsigned char *dst,
453         int *neg0, 
454         int *neg1, 
455         int *neg2)
457         FILTER(components, vmax);
460 void SharpenEngine::filter(int components,
461         int vmax,
462         int w, 
463         float *src, 
464         float *dst,
465         float *neg0, 
466         float *neg1, 
467         float *neg2)
469         const int wordsize = sizeof(float);
470 // First pixel in row
471         memcpy(dst, src, components * wordsize);
472         dst += components;
473         src += components;
475         w -= 2;
476         while(w > 0)
477         {
478                 float pixel;
479                 pixel = calculate_pos(src[0]) -
480                         neg0[-components] -
481                         neg0[0] - 
482                         neg0[components] -
483                         neg1[-components] -
484                         neg1[components] -
485                         neg2[-components] -
486                         neg2[0] -
487                         neg2[components];
488                 pixel /= 8;
489                 dst[0] = pixel;
491                 pixel = calculate_pos(src[1]) -
492                         neg0[-components + 1] -
493                         neg0[1] - 
494                         neg0[components + 1] -
495                         neg1[-components + 1] -
496                         neg1[components + 1] -
497                         neg2[-components + 1] -
498                         neg2[1] -
499                         neg2[components + 1];
500                 pixel /= 8;
501                 dst[1] = pixel;
503                 pixel = calculate_pos(src[2]) -
504                         neg0[-components + 2] -
505                         neg0[2] - 
506                         neg0[components + 2] -
507                         neg1[-components + 2] -
508                         neg1[components + 2] -
509                         neg2[-components + 2] -
510                         neg2[2] -
511                         neg2[components + 2];
512                 pixel /= 8;
513                 dst[2] = pixel;
515                 src += components;
516                 dst += components;
517                 neg0 += components;
518                 neg1 += components;
519                 neg2 += components;
520                 w--;
521         }
523 /* Last pixel */
524         memcpy(dst, src, components * wordsize);
533 #define SHARPEN(components, type, temp_type, vmax) \
534 { \
535         int count, row; \
536         int wordsize = sizeof(type); \
537         unsigned char **input_rows, **output_rows; \
538         int w = plugin->input->get_w(); \
539         int h = plugin->input->get_h(); \
541         input_rows = input->get_rows(); \
542         output_rows = output->get_rows(); \
543         src_rows[0] = input_rows[field]; \
544         src_rows[1] = input_rows[field]; \
545         src_rows[2] = input_rows[field]; \
546         src_rows[3] = input_rows[field]; \
548         for(int j = 0; j < w; j++) \
549         { \
550                 temp_type *neg = (temp_type*)neg_rows[0]; \
551                 type *src = (type*)src_rows[0]; \
552                 for(int k = 0; k < components; k++) \
553                 { \
554                         if(wordsize == 4) \
555                         { \
556                                 neg[j * components + k] = \
557                                         (temp_type)calculate_neg(src[j * components + k]); \
558                         } \
559                         else \
560                         { \
561                                 neg[j * components + k] = \
562                                         (temp_type)plugin->neg_lut[(int)src[j * components + k]]; \
563                         } \
564                 } \
565         } \
567         row = 1; \
568         count = 1; \
570         for(int i = field; i < h; i += plugin->row_step) \
571         { \
572                 if((i + plugin->row_step) < h) \
573                 { \
574                         if(count >= 3) count--; \
575 /* Arm next row */ \
576                         src_rows[row] = input_rows[i + plugin->row_step]; \
577 /* Calculate neg rows */ \
578                         type *src = (type*)src_rows[row]; \
579                         temp_type *neg = (temp_type*)neg_rows[row]; \
580                         for(int k = 0; k < w; k++) \
581                         { \
582                                 for(int j = 0; j < components; j++) \
583                                 { \
584                                         if(wordsize == 4) \
585                                         { \
586                                                 neg[k * components + j] = \
587                                                         (temp_type)calculate_neg(src[k * components + j]); \
588                                         } \
589                                         else \
590                                         { \
591                                                 neg[k * components + j] = \
592                                                         plugin->neg_lut[(int)src[k * components + j]]; \
593                                         } \
594                                 } \
595                         } \
597                         count++; \
598                         row = (row + 1) & 3; \
599                 } \
600                 else \
601                 { \
602                         count--; \
603                 } \
605                 dst_row = output_rows[i]; \
606                 if(count == 3) \
607                 { \
608 /* Do the filter */ \
609                         if(plugin->config.horizontal) \
610                                 filter(components, \
611                                         vmax, \
612                                         w,  \
613                                         (type*)src_rows[(row + 2) & 3],  \
614                                         (type*)dst_row, \
615                                         (temp_type*)neg_rows[(row + 2) & 3] + components, \
616                                         (temp_type*)neg_rows[(row + 2) & 3] + components, \
617                                         (temp_type*)neg_rows[(row + 2) & 3] + components); \
618                         else \
619                                 filter(components, \
620                                         vmax, \
621                                         w,  \
622                                         (type*)src_rows[(row + 2) & 3],  \
623                                         (type*)dst_row, \
624                                         (temp_type*)neg_rows[(row + 1) & 3] + components, \
625                                         (temp_type*)neg_rows[(row + 2) & 3] + components, \
626                                         (temp_type*)neg_rows[(row + 3) & 3] + components); \
627                 } \
628                 else  \
629                 if(count == 2) \
630                 { \
631                         if(i == 0) \
632                                 memcpy(dst_row, src_rows[0], w * components * wordsize); \
633                         else \
634                                 memcpy(dst_row, src_rows[2], w * components * wordsize); \
635                 } \
636         } \
641 void SharpenEngine::run()
643         while(1)
644         {
645                 input_lock->lock("SharpenEngine::run");
646                 if(last_frame)
647                 {
648                         output_lock->unlock();
649                         return;
650                 }
653                 switch(input->get_color_model())
654                 {
655                         case BC_RGB_FLOAT:
656                                 SHARPEN(3, float, float, 1);
657                                 break;
659                         case BC_RGB888:
660                         case BC_YUV888:
661                                 SHARPEN(3, unsigned char, int, 0xff);
662                                 break;
663                         
664                         case BC_RGBA_FLOAT:
665                                 SHARPEN(4, float, float, 1);
666                                 break;
668                         case BC_RGBA8888:
669                         case BC_YUVA8888:
670                                 SHARPEN(4, unsigned char, int, 0xff);
671                                 break;
672                         
673                         case BC_RGB161616:
674                         case BC_YUV161616:
675                                 SHARPEN(3, u_int16_t, int, 0xffff);
676                                 break;
677                         
678                         case BC_RGBA16161616:
679                         case BC_YUVA16161616:
680                                 SHARPEN(4, u_int16_t, int, 0xffff);
681                                 break;
682                 }
684                 output_lock->unlock();
685         }