d976609fe305aff99585add27ab10e9c15108fb4
[goodguy/history.git] / cinelerra-5.0 / plugins / quark / quark.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 "bccmodels.h"
23 #include "filexml.h"
24 #include "language.h"
25 #include "sharpen.h"
26 #include "sharpenwindow.h"
27
28 #include <stdio.h>
29 #include <string.h>
30
31
32 PluginClient* new_plugin(PluginServer *server)
33 {
34         return new SharpenMain(server);
35 }
36
37 SharpenMain::SharpenMain(PluginServer *server)
38  : PluginVClient(server)
39 {
40         sharpness = 0;
41         thread = 0;
42 }
43
44 SharpenMain::~SharpenMain()
45 {
46         if(thread)
47         {
48 // Set result to 0 to indicate a server side close
49                 thread->window->set_done(0);
50                 thread->completion.lock();
51                 delete thread;
52         }
53
54 }
55
56 char* SharpenMain::plugin_title() { return _("Quark"); }
57 int SharpenMain::is_realtime() { return 1; }
58
59 int SharpenMain::start_realtime()
60 {
61 // Initialize
62         last_sharpness = sharpness;
63
64         total_engines = smp > 1 ? 2 : 1;
65         engine = new SharpenEngine*[total_engines];
66         for(int i = 0; i < total_engines; i++)
67         {
68                 engine[i] = new SharpenEngine(this);
69                 engine[i]->start();
70         }
71         return 0;
72 }
73
74 int SharpenMain::stop_realtime()
75 {
76         for(int i = 0; i < total_engines; i++)
77         {
78                 delete engine[i];
79         }
80         delete engine;
81         return 0;
82 }
83
84 int SharpenMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
85 {
86         int i, j, k;
87
88         load_configuration();
89
90         get_luts(pos_lut, neg_lut, input_ptr->get_color_model());
91
92         if(sharpness != 0)
93         {
94 // Arm first row
95                 row_step = (interlace || horizontal) ? 2 : 1;
96
97                 for(j = 0; j < row_step; j += total_engines)
98                 {
99                         for(k = 0; k < total_engines && k + j < row_step; k++)
100                         {
101                                 engine[k]->start_process_frame(input_ptr, input_ptr, k + j);
102                         }
103                         for(k = 0; k < total_engines && k + j < row_step; k++)
104                         {
105                                 engine[k]->wait_process_frame();
106                         }
107                 }
108         }
109         else
110         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
111         {
112                 output_ptr->copy_from(input_ptr);
113         }
114         return 0;
115 }
116
117 int SharpenMain::show_gui()
118 {
119         load_configuration();
120         thread = new SharpenThread(this);
121         thread->start();
122         return 0;
123 }
124
125 int SharpenMain::set_string()
126 {
127         if(thread) thread->window->set_title(gui_string);
128         return 0;
129 }
130
131 void SharpenMain::raise_window()
132 {
133         if(thread)
134         {
135                 thread->window->raise_window();
136                 thread->window->flush();
137         }
138 }
139
140
141 void SharpenMain::load_configuration()
142 {
143         KeyFrame *prev_keyframe, *next_keyframe;
144 //printf("BlurMain::load_configuration 1\n");
145
146         prev_keyframe = get_prev_keyframe(-1);
147         next_keyframe = get_next_keyframe(-1);
148 // Must also switch between interpolation between keyframes and using first keyframe
149 //printf("BlurMain::load_configuration %s\n", prev_keyframe->get_data());
150         read_data(prev_keyframe);
151 }
152
153
154 int SharpenMain::get_luts(int *pos_lut, int *neg_lut, int color_model)
155 {
156         int i, inv_sharpness, vmax;
157
158         vmax = cmodel_calculate_max(color_model);
159
160         inv_sharpness = (int)(100 - sharpness);
161         if(horizontal) inv_sharpness /= 2;
162         if(inv_sharpness < 1) inv_sharpness = 1;
163
164         for(i = 0; i < vmax + 1; i++)
165         {
166                 pos_lut[i] = 800 * i / inv_sharpness;
167                 neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
168         }
169
170         return 0;
171 }
172
173 void SharpenMain::save_data(KeyFrame *keyframe)
174 {
175         FileXML output;
176
177 // cause data to be stored directly in text
178         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
179         output.tag.set_title("SHARPNESS");
180         output.tag.set_property("VALUE", sharpness);
181         output.append_tag();
182
183         if(interlace)
184         {
185                 output.tag.set_title("INTERLACE");
186                 output.append_tag();
187         }
188
189         if(horizontal)
190         {
191                 output.tag.set_title("HORIZONTAL");
192                 output.append_tag();
193         }
194
195         if(luminance)
196         {
197                 output.tag.set_title("LUMINANCE");
198                 output.append_tag();
199         }
200         output.terminate_string();
201 }
202
203 void SharpenMain::read_data(KeyFrame *keyframe)
204 {
205         FileXML input;
206
207         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
208
209         int result = 0;
210         int new_interlace = 0;
211         int new_horizontal = 0;
212         int new_luminance = 0;
213
214         while(!result)
215         {
216                 result = input.read_tag();
217
218                 if(!result)
219                 {
220                         if(input.tag.title_is("SHARPNESS"))
221                         {
222                                 sharpness = input.tag.get_property("VALUE", sharpness);
223                                 last_sharpness = sharpness;
224                         }
225                         else
226                         if(input.tag.title_is("INTERLACE"))
227                         {
228                                 new_interlace = 1;
229                         }
230                         else
231                         if(input.tag.title_is("HORIZONTAL"))
232                         {
233                                 new_horizontal = 1;
234                         }
235                         else
236                         if(input.tag.title_is("LUMINANCE"))
237                         {
238                                 new_luminance = 1;
239                         }
240                 }
241         }
242
243         interlace = new_interlace;
244         horizontal = new_horizontal;
245         luminance = new_luminance;
246
247         if(sharpness > MAXSHARPNESS) 
248                 sharpness = MAXSHARPNESS;
249         else
250                 if(sharpness < 0) sharpness = 0;
251
252         if(thread) 
253         {
254                 thread->window->sharpen_slider->update((int)sharpness);
255                 thread->window->sharpen_interlace->update(interlace);
256                 thread->window->sharpen_horizontal->update(horizontal);
257                 thread->window->sharpen_luminance->update(luminance);
258         }
259 }
260
261
262
263
264 SharpenEngine::SharpenEngine(SharpenMain *plugin)
265  : Thread(1, 0, 0)
266 {
267         this->plugin = plugin;
268         last_frame = 0;
269         for(int i = 0; i < 4; i++)
270         {
271                 neg_rows[i] = new int[plugin->project_frame_w * 4];
272         }
273         input_lock.lock();
274         output_lock.lock();
275         set_synchronous(1);
276 }
277
278 SharpenEngine::~SharpenEngine()
279 {
280         last_frame = 1;
281         input_lock.unlock();
282         Thread::join();
283
284         for(int i = 0; i < 4; i++)
285         {
286                 delete [] neg_rows[i];
287         }
288 }
289
290 int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
291 {
292         this->output = output;
293         this->input = input;
294         this->field = field;
295         input_lock.unlock();
296         return 0;
297 }
298
299 int SharpenEngine::wait_process_frame()
300 {
301         output_lock.lock();
302         return 0;
303 }
304
305 #define FILTER(components, vmax, wordsize) \
306 { \
307         int *pos_lut = plugin->pos_lut; \
308  \
309 /* Skip first pixel in row */ \
310         memcpy(dst, src, components * wordsize); \
311         dst += components; \
312         src += components; \
313  \
314         w -= 2; \
315  \
316         while(w > 0) \
317         { \
318                 long pixel; \
319                 pixel = pos_lut[src[0]] -  \
320                         neg0[-components] -  \
321                         neg0[0] -  \
322                         neg0[components] -  \
323                         neg1[-components] -  \
324                         neg1[components] -  \
325                         neg2[-components] -  \
326                         neg2[0] -  \
327                         neg2[components]; \
328                 pixel = (pixel + 4) >> 3; \
329                 if(pixel < 0) dst[0] = 0; \
330                 else \
331                 if(pixel > vmax) dst[0] = vmax; \
332                 else \
333                 dst[0] = pixel; \
334  \
335                 pixel = pos_lut[src[1]] -  \
336                         neg0[-components + 1] -  \
337                         neg0[1] -  \
338                         neg0[components + 1] -  \
339                         neg1[-components + 1] -  \
340                         neg1[components + 1] -  \
341                         neg2[-components + 1] -  \
342                         neg2[1] -  \
343                         neg2[components + 1]; \
344                 pixel = (pixel + 4) >> 3; \
345                 if(pixel < 0) dst[1] = 0; \
346                 else \
347                 if(pixel > vmax) dst[1] = vmax; \
348                 else \
349                 dst[1] = pixel; \
350  \
351                 pixel = pos_lut[src[2]] -  \
352                         neg0[-components + 2] -  \
353                         neg0[2] -  \
354                         neg0[components + 2] -  \
355                         neg1[-components + 2] -  \
356                         neg1[components + 2] -  \
357                         neg2[-components + 2] -  \
358                         neg2[2] -  \
359                         neg2[components + 2]; \
360                 pixel = (pixel + 4) >> 3; \
361                 if(pixel < 0) dst[2] = 0; \
362                 else \
363                 if(pixel > vmax) dst[2] = vmax; \
364                 else \
365                 dst[2] = pixel; \
366  \
367                 if(components == 4) \
368                         dst[3] = src[3]; \
369  \
370                 src += components; \
371                 dst += components; \
372  \
373                 neg0 += components; \
374                 neg1 += components; \
375                 neg2 += components; \
376                 w--; \
377         } \
378  \
379 /* Skip last pixel in row */ \
380         memcpy(dst, src, components * wordsize); \
381 }
382
383 void SharpenEngine::filter(int components,
384         int wordsize,
385         int vmax,
386         int w, 
387         u_int16_t *src, 
388         u_int16_t *dst,
389         int *neg0, 
390         int *neg1, 
391         int *neg2)
392 {
393         FILTER(components, vmax, wordsize);
394 }
395
396 void SharpenEngine::filter(int components,
397         int wordsize,
398         int vmax,
399         int w, 
400         unsigned char *src, 
401         unsigned char *dst,
402         int *neg0, 
403         int *neg1, 
404         int *neg2)
405 {
406         FILTER(components, vmax, wordsize);
407 }
408
409
410
411
412
413
414
415 #define SHARPEN(components, wordsize, wordtype, vmax) \
416 { \
417         int count, row; \
418         unsigned char **input_rows, **output_rows; \
419  \
420         input_rows = input->get_rows(); \
421         output_rows = output->get_rows(); \
422         src_rows[0] = input_rows[field]; \
423         src_rows[1] = input_rows[field]; \
424         src_rows[2] = input_rows[field]; \
425         src_rows[3] = input_rows[field]; \
426  \
427         for(int j = 0; j < plugin->project_frame_w; j++) \
428         { \
429                 for(int k = 0; k < components; k++) \
430                         neg_rows[0][j * components + k] = plugin->neg_lut[((wordtype*)src_rows[0])[j * components + k]]; \
431         } \
432  \
433         row = 1; \
434         count = 1; \
435  \
436         for(int i = field; i < plugin->project_frame_h; i += plugin->row_step) \
437         { \
438                 if((i + plugin->row_step) < plugin->project_frame_h) \
439                 { \
440                         if(count >= 3) count--; \
441 /* Arm next row */ \
442                         src_rows[row] = input_rows[i + plugin->row_step]; \
443                         for(int k = 0; k < plugin->project_frame_w; k++) \
444                         { \
445                                 for(int j = 0; j < components; j++) \
446                                         neg_rows[row][k * components + j] = plugin->neg_lut[((wordtype*)src_rows[row])[k * components + j]]; \
447                         } \
448  \
449                         count++; \
450                         row = (row + 1) & 3; \
451                 } \
452                 else \
453                 { \
454                         count--; \
455                 } \
456  \
457                 dst_row = output_rows[i]; \
458                 if(count == 3) \
459                 { \
460 /* Do the filter */ \
461                         if(plugin->horizontal) \
462                                 filter(components, \
463                                         wordsize, \
464                                         vmax, \
465                                         plugin->project_frame_w,  \
466                                         (wordtype*)src_rows[(row + 2) & 3],  \
467                                         (wordtype*)dst_row, \
468                                         neg_rows[(row + 2) & 3] + components, \
469                                         neg_rows[(row + 2) & 3] + components, \
470                                         neg_rows[(row + 2) & 3] + components); \
471                         else \
472                                 filter(components, \
473                                         wordsize, \
474                                         vmax, \
475                                         plugin->project_frame_w,  \
476                                         (wordtype*)src_rows[(row + 2) & 3],  \
477                                         (wordtype*)dst_row, \
478                                         neg_rows[(row + 1) & 3] + components, \
479                                         neg_rows[(row + 2) & 3] + components, \
480                                         neg_rows[(row + 3) & 3] + components); \
481                 } \
482                 else  \
483                 if(count == 2) \
484                 { \
485                         if(i == 0) \
486                                 memcpy(dst_row, src_rows[0], plugin->project_frame_w * components * wordsize); \
487                         else \
488                                 memcpy(dst_row, src_rows[2], plugin->project_frame_w * components * wordsize); \
489                 } \
490         } \
491 }
492
493 void SharpenEngine::sharpen_888()
494 {
495         SHARPEN(3, 1, unsigned char, 0xff);
496 }
497
498 void SharpenEngine::sharpen_8888()
499 {
500         SHARPEN(4, 1, unsigned char, 0xff);
501 }
502
503 void SharpenEngine::sharpen_161616()
504 {
505         SHARPEN(3, 2, u_int16_t, 0xffff);
506 }
507
508 void SharpenEngine::sharpen_16161616()
509 {
510         SHARPEN(4, 2, u_int16_t, 0xffff);
511 }
512
513
514 void SharpenEngine::run()
515 {
516         while(1)
517         {
518                 input_lock.lock();
519                 if(last_frame)
520                 {
521                         output_lock.unlock();
522                         return;
523                 }
524
525
526                 switch(input->get_color_model())
527                 {
528                         case BC_RGB888:
529                         case BC_YUV888:
530                                 sharpen_888();
531                                 break;
532                         
533                         case BC_RGBA8888:
534                         case BC_YUVA8888:
535                                 sharpen_8888();
536                                 break;
537                         
538                         case BC_RGB161616:
539                         case BC_YUV161616:
540                                 sharpen_161616();
541                                 break;
542                         
543                         case BC_RGBA16161616:
544                         case BC_YUVA16161616:
545                                 sharpen_16161616();
546                                 break;
547                 }
548
549                 output_lock.unlock();
550         }
551 }
552