r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / sharpen / sharpen.C
blob049cbf6875afb8cdb04386ccbf2e310d3af81deb
1 #include "clip.h"
2 #include "colormodels.h"
3 #include "filexml.h"
4 #include "picon_png.h"
5 #include "sharpen.h"
6 #include "sharpenwindow.h"
8 #include <stdio.h>
9 #include <string.h>
11 #include <libintl.h>
12 #define _(String) gettext(String)
13 #define gettext_noop(String) String
14 #define N_(String) gettext_noop (String)
16 REGISTER_PLUGIN(SharpenMain)
24 SharpenConfig::SharpenConfig()
26         horizontal = 0;
27         interlace = 0;
28         sharpness = 50;
29         luminance = 0;
32 void SharpenConfig::copy_from(SharpenConfig &that)
34         horizontal = that.horizontal;
35         interlace = that.interlace;
36         sharpness = that.sharpness;
37         luminance = that.luminance;
40 int SharpenConfig::equivalent(SharpenConfig &that)
42         return horizontal == that.horizontal &&
43                 interlace == that.interlace &&
44                 EQUIV(sharpness, that.sharpness) &&
45                 luminance == that.luminance;
48 void SharpenConfig::interpolate(SharpenConfig &prev, 
49         SharpenConfig &next, 
50         long prev_frame, 
51         long next_frame, 
52         long current_frame)
54         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
55         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
56         this->sharpness = prev.sharpness * prev_scale + next.sharpness * next_scale;
57         this->interlace = prev.interlace;
58         this->horizontal = prev.horizontal;
59         this->luminance = prev.luminance;
72 SharpenMain::SharpenMain(PluginServer *server)
73  : PluginVClient(server)
75         thread = 0;
76         engine = 0;
77         load_defaults();
80 SharpenMain::~SharpenMain()
82         if(thread)
83         {
84 // Set result to 0 to indicate a server side close
85                 thread->window->set_done(0);
86                 thread->completion.lock();
87                 delete thread;
88         }
90         save_defaults();
91         delete defaults;
93         if(engine)
94         {
95                 for(int i = 0; i < total_engines; i++)
96                 {
97                         delete engine[i];
98                 }
99                 delete engine;
100         }
103 SHOW_GUI_MACRO(SharpenMain, SharpenThread)
105 SET_STRING_MACRO(SharpenMain)
107 RAISE_WINDOW_MACRO(SharpenMain)
109 NEW_PICON_MACRO(SharpenMain)
111 LOAD_CONFIGURATION_MACRO(SharpenMain, SharpenConfig)
113 char* SharpenMain::plugin_title() { return _("Sharpen"); }
114 int SharpenMain::is_realtime() { return 1; }
118 int SharpenMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
120         int i, j, k;
121         output = output_ptr;
122         input = input_ptr;
124         load_configuration();
125         if(!engine)
126         {
128                 total_engines = smp > 1 ? 2 : 1;
129                 engine = new SharpenEngine*[total_engines];
130                 for(int i = 0; i < total_engines; i++)
131                 {
132                         engine[i] = new SharpenEngine(this);
133                         engine[i]->start();
134                 }
135         }
137         get_luts(pos_lut, neg_lut, input_ptr->get_color_model());
139         if(config.sharpness != 0)
140         {
141 // Arm first row
142                 row_step = (config.interlace || config.horizontal) ? 2 : 1;
144                 for(j = 0; j < row_step; j += total_engines)
145                 {
146                         for(k = 0; k < total_engines && k + j < row_step; k++)
147                         {
148                                 engine[k]->start_process_frame(input_ptr, input_ptr, k + j);
149                         }
150                         for(k = 0; k < total_engines && k + j < row_step; k++)
151                         {
152                                 engine[k]->wait_process_frame();
153                         }
154                 }
155         }
156         else
157         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
158         {
159                 output_ptr->copy_from(input_ptr);
160         }
161         return 0;
164 void SharpenMain::update_gui()
166         if(thread)
167         {
168                 load_configuration();
169                 thread->window->lock_window();
170                 thread->window->sharpen_slider->update((int)config.sharpness);
171                 thread->window->sharpen_interlace->update(config.interlace);
172                 thread->window->sharpen_horizontal->update(config.horizontal);
173                 thread->window->sharpen_luminance->update(config.luminance);
174                 thread->window->unlock_window();
175         }
178 int SharpenMain::load_defaults()
180         char directory[1024], string[1024];
181 // set the default directory
182         sprintf(directory, "%ssharpen.rc", BCASTDIR);
184 // load the defaults
185         defaults = new Defaults(directory);
186         defaults->load();
188         config.sharpness = defaults->get("SHARPNESS", config.sharpness);
189         config.interlace = defaults->get("INTERLACE", config.interlace);
190         config.horizontal = defaults->get("HORIZONTAL", config.horizontal);
191         config.luminance = defaults->get("LUMINANCE", config.luminance);
192 //printf("SharpenMain::load_defaults 1 %f %d %d %d\n", sharpness, interlace, horizontal, luminance);
193         return 0;
196 int SharpenMain::save_defaults()
198 //printf("SharpenMain::save_defaults 1 %f %d %d %d\n", sharpness, interlace, horizontal, luminance);
199         defaults->update("SHARPNESS", config.sharpness);
200         defaults->update("INTERLACE", config.interlace);
201         defaults->update("HORIZONTAL", config.horizontal);
202         defaults->update("LUMINANCE", config.luminance);
203         defaults->save();
204         return 0;
210 int SharpenMain::get_luts(int *pos_lut, int *neg_lut, int color_model)
212         int i, inv_sharpness, vmax;
214         vmax = cmodel_calculate_max(color_model);
216         inv_sharpness = (int)(100 - config.sharpness);
217         if(config.horizontal) inv_sharpness /= 2;
218         if(inv_sharpness < 1) inv_sharpness = 1;
220         for(i = 0; i < vmax + 1; i++)
221         {
222                 pos_lut[i] = 800 * i / inv_sharpness;
223                 neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
224         }
226         return 0;
229 void SharpenMain::save_data(KeyFrame *keyframe)
231         FileXML output;
233 // cause data to be stored directly in text
234         output.set_shared_string(keyframe->data, MESSAGESIZE);
235         output.tag.set_title("SHARPNESS");
236         output.tag.set_property("VALUE", config.sharpness);
237         output.append_tag();
239         if(config.interlace)
240         {
241                 output.tag.set_title("INTERLACE");
242                 output.append_tag();
243         }
245         if(config.horizontal)
246         {
247                 output.tag.set_title("HORIZONTAL");
248                 output.append_tag();
249         }
251         if(config.luminance)
252         {
253                 output.tag.set_title("LUMINANCE");
254                 output.append_tag();
255         }
256         output.terminate_string();
259 void SharpenMain::read_data(KeyFrame *keyframe)
261         FileXML input;
263         input.set_shared_string(keyframe->data, strlen(keyframe->data));
265         int result = 0;
266         int new_interlace = 0;
267         int new_horizontal = 0;
268         int new_luminance = 0;
270         while(!result)
271         {
272                 result = input.read_tag();
274                 if(!result)
275                 {
276                         if(input.tag.title_is("SHARPNESS"))
277                         {
278                                 config.sharpness = input.tag.get_property("VALUE", config.sharpness);
279 //printf("SharpenMain::read_data %f\n", sharpness);
280                         }
281                         else
282                         if(input.tag.title_is("INTERLACE"))
283                         {
284                                 new_interlace = 1;
285                         }
286                         else
287                         if(input.tag.title_is("HORIZONTAL"))
288                         {
289                                 new_horizontal = 1;
290                         }
291                         else
292                         if(input.tag.title_is("LUMINANCE"))
293                         {
294                                 new_luminance = 1;
295                         }
296                 }
297         }
299         config.interlace = new_interlace;
300         config.horizontal = new_horizontal;
301         config.luminance = new_luminance;
303         if(config.sharpness > MAXSHARPNESS) 
304                 config.sharpness = MAXSHARPNESS;
305         else
306                 if(config.sharpness < 0) config.sharpness = 0;
312 SharpenEngine::SharpenEngine(SharpenMain *plugin)
313  : Thread()
315         this->plugin = plugin;
316         last_frame = 0;
317         for(int i = 0; i < 4; i++)
318         {
319                 neg_rows[i] = new int[plugin->input->get_w() * 4];
320         }
321         input_lock.lock();
322         output_lock.lock();
323         set_synchronous(1);
326 SharpenEngine::~SharpenEngine()
328         last_frame = 1;
329         input_lock.unlock();
330         Thread::join();
332         for(int i = 0; i < 4; i++)
333         {
334                 delete [] neg_rows[i];
335         }
338 int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
340         this->output = output;
341         this->input = input;
342         this->field = field;
343         input_lock.unlock();
344         return 0;
347 int SharpenEngine::wait_process_frame()
349         output_lock.lock();
350         return 0;
353 #define FILTER(components, vmax, wordsize) \
354 { \
355         int *pos_lut = plugin->pos_lut; \
357 /* Skip first pixel in row */ \
358         memcpy(dst, src, components * wordsize); \
359         dst += components; \
360         src += components; \
362         w -= 2; \
364         while(w > 0) \
365         { \
366                 long pixel; \
367                 pixel = (long)pos_lut[src[0]] -  \
368                         (long)neg0[-components] -  \
369                         (long)neg0[0] -  \
370                         (long)neg0[components] -  \
371                         (long)neg1[-components] -  \
372                         (long)neg1[components] -  \
373                         (long)neg2[-components] -  \
374                         (long)neg2[0] -  \
375                         (long)neg2[components]; \
376                 pixel = (pixel + 4) >> 3; \
377                 if(pixel < 0) dst[0] = 0; \
378                 else \
379                 if(pixel > vmax) dst[0] = vmax; \
380                 else \
381                 dst[0] = pixel; \
383                 pixel = (long)pos_lut[src[1]] -  \
384                         (long)neg0[-components + 1] -  \
385                         (long)neg0[1] -  \
386                         (long)neg0[components + 1] -  \
387                         (long)neg1[-components + 1] -  \
388                         (long)neg1[components + 1] -  \
389                         (long)neg2[-components + 1] -  \
390                         (long)neg2[1] -  \
391                         (long)neg2[components + 1]; \
392                 pixel = (pixel + 4) >> 3; \
393                 if(pixel < 0) dst[1] = 0; \
394                 else \
395                 if(pixel > vmax) dst[1] = vmax; \
396                 else \
397                 dst[1] = pixel; \
399                 pixel = (long)pos_lut[src[2]] -  \
400                         (long)neg0[-components + 2] -  \
401                         (long)neg0[2] -  \
402                         (long)neg0[components + 2] -  \
403                         (long)neg1[-components + 2] -  \
404                         (long)neg1[components + 2] -  \
405                         (long)neg2[-components + 2] -  \
406                         (long)neg2[2] -  \
407                         (long)neg2[components + 2]; \
408                 pixel = (pixel + 4) >> 3; \
409                 if(pixel < 0) dst[2] = 0; \
410                 else \
411                 if(pixel > vmax) dst[2] = vmax; \
412                 else \
413                 dst[2] = pixel; \
415                 if(components == 4) \
416                         dst[3] = src[3]; \
418                 src += components; \
419                 dst += components; \
421                 neg0 += components; \
422                 neg1 += components; \
423                 neg2 += components; \
424                 w--; \
425         } \
427 /* Skip last pixel in row */ \
428         memcpy(dst, src, components * wordsize); \
431 void SharpenEngine::filter(int components,
432         int wordsize,
433         int vmax,
434         int w, 
435         u_int16_t *src, 
436         u_int16_t *dst,
437         int *neg0, 
438         int *neg1, 
439         int *neg2)
441         FILTER(components, vmax, wordsize);
444 void SharpenEngine::filter(int components,
445         int wordsize,
446         int vmax,
447         int w, 
448         unsigned char *src, 
449         unsigned char *dst,
450         int *neg0, 
451         int *neg1, 
452         int *neg2)
454         FILTER(components, vmax, wordsize);
463 #define SHARPEN(components, wordsize, wordtype, vmax) \
464 { \
465         int count, row; \
466         unsigned char **input_rows, **output_rows; \
467         int w = plugin->input->get_w(); \
468         int h = plugin->input->get_h(); \
470         input_rows = input->get_rows(); \
471         output_rows = output->get_rows(); \
472         src_rows[0] = input_rows[field]; \
473         src_rows[1] = input_rows[field]; \
474         src_rows[2] = input_rows[field]; \
475         src_rows[3] = input_rows[field]; \
477         for(int j = 0; j < w; j++) \
478         { \
479                 for(int k = 0; k < components; k++) \
480                         neg_rows[0][j * components + k] = plugin->neg_lut[((wordtype*)src_rows[0])[j * components + k]]; \
481         } \
483         row = 1; \
484         count = 1; \
486         for(int i = field; i < h; i += plugin->row_step) \
487         { \
488                 if((i + plugin->row_step) < h) \
489                 { \
490                         if(count >= 3) count--; \
491 /* Arm next row */ \
492                         src_rows[row] = input_rows[i + plugin->row_step]; \
493                         for(int k = 0; k < w; k++) \
494                         { \
495                                 for(int j = 0; j < components; j++) \
496                                         neg_rows[row][k * components + j] = plugin->neg_lut[((wordtype*)src_rows[row])[k * components + j]]; \
497                         } \
499                         count++; \
500                         row = (row + 1) & 3; \
501                 } \
502                 else \
503                 { \
504                         count--; \
505                 } \
507                 dst_row = output_rows[i]; \
508                 if(count == 3) \
509                 { \
510 /* Do the filter */ \
511                         if(plugin->config.horizontal) \
512                                 filter(components, \
513                                         wordsize, \
514                                         vmax, \
515                                         w,  \
516                                         (wordtype*)src_rows[(row + 2) & 3],  \
517                                         (wordtype*)dst_row, \
518                                         neg_rows[(row + 2) & 3] + components, \
519                                         neg_rows[(row + 2) & 3] + components, \
520                                         neg_rows[(row + 2) & 3] + components); \
521                         else \
522                                 filter(components, \
523                                         wordsize, \
524                                         vmax, \
525                                         w,  \
526                                         (wordtype*)src_rows[(row + 2) & 3],  \
527                                         (wordtype*)dst_row, \
528                                         neg_rows[(row + 1) & 3] + components, \
529                                         neg_rows[(row + 2) & 3] + components, \
530                                         neg_rows[(row + 3) & 3] + components); \
531                 } \
532                 else  \
533                 if(count == 2) \
534                 { \
535                         if(i == 0) \
536                                 memcpy(dst_row, src_rows[0], w * components * wordsize); \
537                         else \
538                                 memcpy(dst_row, src_rows[2], w * components * wordsize); \
539                 } \
540         } \
543 void SharpenEngine::sharpen_888()
545         SHARPEN(3, 1, unsigned char, 0xff);
548 void SharpenEngine::sharpen_8888()
550         SHARPEN(4, 1, unsigned char, 0xff);
553 void SharpenEngine::sharpen_161616()
555         SHARPEN(3, 2, u_int16_t, 0xffff);
558 void SharpenEngine::sharpen_16161616()
560         SHARPEN(4, 2, u_int16_t, 0xffff);
564 void SharpenEngine::run()
566         while(1)
567         {
568                 input_lock.lock();
569                 if(last_frame)
570                 {
571                         output_lock.unlock();
572                         return;
573                 }
576                 switch(input->get_color_model())
577                 {
578                         case BC_RGB888:
579                         case BC_YUV888:
580                                 sharpen_888();
581                                 break;
582                         
583                         case BC_RGBA8888:
584                         case BC_YUVA8888:
585                                 sharpen_8888();
586                                 break;
587                         
588                         case BC_RGB161616:
589                         case BC_YUV161616:
590                                 sharpen_161616();
591                                 break;
592                         
593                         case BC_RGBA16161616:
594                         case BC_YUVA16161616:
595                                 sharpen_16161616();
596                                 break;
597                 }
599                 output_lock.unlock();
600         }