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