Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / interpolate / interpolate.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 "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bccmodels.h"
25 #include "filexml.h"
26 #include "aggregated.h"
27 #include "language.h"
28 #include "interpolate.h"
29
30 #include <stdio.h>
31 #include <string.h>
32
33
34 REGISTER_PLUGIN(InterpolatePixelsMain)
35
36
37
38
39
40
41 InterpolatePixelsOffset::InterpolatePixelsOffset(InterpolatePixelsWindow *window,
42         int x,
43         int y,
44         int *output)
45  : BC_ISlider(x, y, 0, xS(50), yS(50), 0, 1, *output, 0)
46 {
47         this->window = window;
48         this->output = output;
49 }
50
51 InterpolatePixelsOffset::~InterpolatePixelsOffset()
52 {
53 }
54
55 int InterpolatePixelsOffset::handle_event()
56 {
57         *output = get_value();
58         window->client->send_configure_change();
59         return 1;
60 }
61
62
63
64
65
66
67 InterpolatePixelsWindow::InterpolatePixelsWindow(InterpolatePixelsMain *client)
68  : PluginClientWindow(client,
69         xS(200), yS(70), xS(200), yS(70), 0)
70 {
71         this->client = client;
72 }
73
74 InterpolatePixelsWindow::~InterpolatePixelsWindow()
75 {
76 }
77
78 void InterpolatePixelsWindow::create_objects()
79 {
80         int xs5 = xS(5), xs10 = xS(10);
81         int ys5 = yS(5), ys10 = yS(10);
82         int x = xs10, y = ys10;
83
84         BC_Title *title;
85         add_tool(title = new BC_Title(x, y, _("X Offset:")));
86         add_tool(x_offset = new InterpolatePixelsOffset(this,
87                 x + title->get_w() + xs5,
88                 y,
89                 &client->config.x));
90         y += MAX(x_offset->get_h(), title->get_h()) + ys5;
91         add_tool(title = new BC_Title(x, y, _("Y Offset:")));
92         add_tool(y_offset = new InterpolatePixelsOffset(this,
93                 x + title->get_w() + xs5,
94                 y,
95                 &client->config.y));
96         y += MAX(y_offset->get_h(), title->get_h()) + ys5;
97
98         show_window();
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 InterpolatePixelsConfig::InterpolatePixelsConfig()
116 {
117         x = 0;
118         y = 0;
119 }
120
121 int InterpolatePixelsConfig::equivalent(InterpolatePixelsConfig &that)
122 {
123         return x == that.x && y == that.y;
124 }
125
126 void InterpolatePixelsConfig::copy_from(InterpolatePixelsConfig &that)
127 {
128         x = that.x;
129         y = that.y;
130 }
131
132 void InterpolatePixelsConfig::interpolate(InterpolatePixelsConfig &prev,
133     InterpolatePixelsConfig &next,
134     int64_t prev_position,
135     int64_t next_position,
136     int64_t current_position)
137 {
138     this->x = prev.x;
139     this->y = prev.y;
140 }
141
142
143
144
145
146
147 InterpolatePixelsMain::InterpolatePixelsMain(PluginServer *server)
148  : PluginVClient(server)
149 {
150         out_temp = out_frame = 0;
151         engine = 0;
152 }
153
154 InterpolatePixelsMain::~InterpolatePixelsMain()
155 {
156         delete out_temp;
157         delete engine;
158 }
159
160 const char* InterpolatePixelsMain::plugin_title() { return N_("Interpolate Bayer"); }
161 int InterpolatePixelsMain::is_realtime() { return 1; }
162
163
164 NEW_WINDOW_MACRO(InterpolatePixelsMain, InterpolatePixelsWindow)
165
166
167 void InterpolatePixelsMain::update_gui()
168 {
169         if(thread)
170         {
171                 int changed = load_configuration();
172                 if(changed)
173                 {
174                         thread->window->lock_window("InterpolatePixelsMain::update_gui");
175                         ((InterpolatePixelsWindow*)thread->window)->x_offset->update(config.x);
176                         ((InterpolatePixelsWindow*)thread->window)->y_offset->update(config.y);
177                         thread->window->unlock_window();
178                 }
179         }
180 }
181
182
183 LOAD_CONFIGURATION_MACRO(InterpolatePixelsMain, InterpolatePixelsConfig)
184
185
186 void InterpolatePixelsMain::save_data(KeyFrame *keyframe)
187 {
188         FileXML output;
189
190 // cause data to be stored directly in text
191         output.set_shared_output(keyframe->xbuf);
192         output.tag.set_title("INTERPOLATEPIXELS");
193         output.tag.set_property("X", config.x);
194         output.tag.set_property("Y", config.y);
195         output.append_tag();
196         output.tag.set_title("/INTERPOLATEPIXELS");
197         output.append_tag();
198         output.append_newline();
199         output.terminate_string();
200 }
201
202 void InterpolatePixelsMain::read_data(KeyFrame *keyframe)
203 {
204         FileXML input;
205
206         input.set_shared_input(keyframe->xbuf);
207
208         int result = 0;
209
210         while(!result)
211         {
212                 result = input.read_tag();
213
214                 if(!result)
215                 {
216                         if(input.tag.title_is("INTERPOLATEPIXELS"))
217                         {
218                                 config.x = input.tag.get_property("X", config.x);
219                                 config.y = input.tag.get_property("Y", config.y);
220                         }
221                 }
222         }
223 }
224
225 int InterpolatePixelsMain::process_buffer(VFrame *frame,
226         int64_t start_position,
227         double frame_rate)
228 {
229         load_configuration();
230
231 // Set aggregation parameters
232         frame->get_params()->update("INTERPOLATEPIXELS_X", config.x);
233         frame->get_params()->update("INTERPOLATEPIXELS_Y", config.y);
234
235         read_frame(frame,
236                 0,
237                 start_position,
238                 frame_rate,
239                 get_use_opengl());
240 //frame->dump_params();
241
242         if(get_use_opengl())
243         {
244 // Aggregate with gamma
245                 if(next_effect_is(_("Gamma")) ||
246                         next_effect_is(_("Histogram")) ||
247                         next_effect_is(_("Color Balance")))
248                         return 0;
249
250
251                 return run_opengl();
252         }
253
254         int color_model = frame->get_color_model();
255         int active_model = BC_CModels::has_alpha(color_model) ?
256                 BC_RGBA_FLOAT : BC_RGB_FLOAT;
257         new_temp(frame->get_w(), frame->get_h(), active_model);
258         get_temp()->transfer_from(frame);
259
260         out_frame = get_output();
261         color_model = out_frame->get_color_model();
262         active_model = BC_CModels::has_alpha(color_model) ?
263                 BC_RGBA_FLOAT : BC_RGB_FLOAT;
264         if( active_model != color_model ) {
265                 int w = out_frame->get_w(), h = out_frame->get_h();
266                 if( out_temp && ( out_temp->get_color_model() != active_model ||
267                              out_temp->get_w() != w || out_temp->get_w() != h ) ) {
268                         delete out_temp;  out_temp = 0;
269                 }
270                 if( !out_temp )
271                         out_temp = new VFrame(w, h, active_model, 0);
272                 out_frame = out_temp;
273         }
274
275         if(!engine)
276                 engine = new InterpolatePixelsEngine(this);
277         engine->process_packages();
278
279         if( out_frame != get_output() ) {
280                 if( BC_CModels::has_alpha(out_frame->get_color_model()) ) {
281                         unsigned char **out_rows = out_frame->get_rows();
282                         int w = out_frame->get_w(), h = out_frame->get_h();
283                         if( BC_CModels::has_alpha(get_temp()->get_color_model()) ) {
284                                 unsigned char **in_rows = get_temp()->get_rows();
285                                 for( int y=0; y<h; ++y ) {
286                                         float *inp = (float *)in_rows[y];
287                                         float *outp = (float *)out_rows[y];
288                                         for( int x=0; x<w; ++x,inp+=4,outp+=4 ) outp[3] = inp[3];
289                                 }
290                         }
291                         else {
292                                 for( int y=0; y<h; ++y ) {
293                                         float *outp = (float *)out_rows[y];
294                                         for( int x=0; x<w; ++x,outp+=4 ) outp[3] = 1;
295                                 }
296                         }
297                 }
298                 get_output()->transfer_from(out_frame);
299         }
300
301         return 0;
302 }
303
304 // The pattern is
305 //   G B
306 //   R G
307 // And is offset to recreate the 4 possibilities.
308 // The color values are interpolated in the most basic way.
309 // No adaptive algorithm is used.
310
311 int InterpolatePixelsMain::handle_opengl()
312 {
313 //printf("InterpolatePixelsMain::handle_opengl\n");
314 #ifdef HAVE_GL
315
316
317         get_output()->to_texture();
318         get_output()->enable_opengl();
319
320         const char *shader_stack[16];
321         memset(shader_stack,0, sizeof(shader_stack));
322         int current_shader = 0;
323
324         INTERPOLATE_COMPILE(shader_stack, current_shader);
325
326         shader_stack[current_shader] = 0;
327         unsigned int shader = VFrame::make_shader(shader_stack);
328         if( shader > 0 ) {
329                 glUseProgram(shader);
330                 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
331                 INTERPOLATE_UNIFORMS(shader);
332         }
333
334         get_output()->init_screen();
335         get_output()->bind_texture(0);
336         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
337         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
338
339
340         get_output()->draw_texture();
341         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
342         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
343         glUseProgram(0);
344         get_output()->set_opengl_state(VFrame::SCREEN);
345
346 #endif
347         return 0;
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361
362 InterpolatePixelsPackage::InterpolatePixelsPackage()
363  : LoadPackage()
364 {
365
366 }
367
368
369
370
371
372
373 InterpolatePixelsUnit::InterpolatePixelsUnit(InterpolatePixelsEngine *server, InterpolatePixelsMain *plugin)
374  : LoadClient(server)
375 {
376         this->plugin = plugin;
377         this->server = server;
378 }
379
380 void InterpolatePixelsUnit::process_package(LoadPackage *package)
381 {
382         InterpolatePixelsPackage *pkg = (InterpolatePixelsPackage*)package;
383         int h = plugin->get_temp()->get_h();
384         int w = plugin->get_temp()->get_w();
385         int pattern_offset_x = plugin->config.x;
386         int pattern_offset_y = plugin->config.y;
387         int y1 = pkg->y1;
388         int y2 = pkg->y2;
389         int components = BC_CModels::components(plugin->out_frame->get_color_model());
390         float color_matrix[9];
391         memcpy(color_matrix, server->color_matrix, sizeof(color_matrix));
392
393 // printf("InterpolatePixelsUnit::process_package %d color_matrix=", __LINE__);
394 // for(int i = 0; i < 9; i++)
395 // {
396 //      printf("%f ", color_matrix[i]);
397 // }
398 // printf("\n");
399
400         y1 = MAX(y1, 1);
401         y2 = MIN(y2, h - 1);
402
403 // Only supports float because it's useless in any other colormodel.
404         for(int i = y1; i < y2; i++)
405         {
406                 int pattern_coord_y = (i - pattern_offset_y) % 2;
407                 float *prev_row = (float*)plugin->get_temp()->get_rows()[i - 1];
408                 float *current_row = (float*)plugin->get_temp()->get_rows()[i];
409                 float *next_row = (float*)plugin->get_temp()->get_rows()[i + 1];
410                 float *out_row = (float*)plugin->out_frame->get_rows()[i];
411
412                 prev_row += components;
413                 current_row += components;
414                 next_row += components;
415                 out_row += components;
416                 float r;
417                 float g;
418                 float b;
419 #undef RED
420 #define RED 0
421 #undef GREEN
422 #define GREEN 1
423 #undef BLUE
424 #define BLUE 2
425                 if(pattern_coord_y == 0)
426                 {
427                         for(int j = 1; j < w - 1; j++)
428                         {
429                                 int pattern_coord_x = (j - pattern_offset_x) % 2;
430 // Top left pixel
431                                 if(pattern_coord_x == 0)
432                                 {
433                                         r = (prev_row[RED] + next_row[RED]) / 2;
434                                         g = current_row[GREEN];
435                                         b = (current_row[-components + BLUE] + current_row[components + BLUE]) / 2;
436                                 }
437                                 else
438 // Top right pixel
439                                 {
440                                         r = (prev_row[-components + RED] +
441                                                 prev_row[components + RED] +
442                                                 next_row[-components + RED] +
443                                                 next_row[components + RED]) / 4;
444                                         g = (current_row[-components + GREEN] +
445                                                 prev_row[GREEN] +
446                                                 current_row[components + GREEN] +
447                                                 next_row[GREEN]) / 4;
448                                         b = current_row[BLUE];
449                                 }
450
451 //                              out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
452 //                              out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
453 //                              out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
454
455                                 out_row[0] = r;
456                                 out_row[1] = g;
457                                 out_row[2] = b;
458
459                                 prev_row += components;
460                                 current_row += components;
461                                 next_row += components;
462                                 out_row += components;
463                         }
464                 }
465                 else
466                 {
467                         for(int j = 1; j < w - 1; j++)
468                         {
469                                 int pattern_coord_x = (j - pattern_offset_x) % 2;
470 // Bottom left pixel
471                                 if(pattern_coord_x == 0)
472                                 {
473                                         r = current_row[RED];
474                                         g = (current_row[-components + GREEN] +
475                                                 prev_row[GREEN] +
476                                                 current_row[components + GREEN] +
477                                                 next_row[GREEN]) / 4;
478                                         b = (prev_row[-components + BLUE] +
479                                                 prev_row[components + BLUE] +
480                                                 next_row[-components + BLUE] +
481                                                 next_row[components + BLUE]) / 4;
482                                 }
483                                 else
484 // Bottom right pixel
485                                 {
486                                         r = (current_row[-components + RED] + current_row[components + RED]) / 2;
487                                         g = current_row[GREEN];
488                                         b = (prev_row[BLUE] + next_row[BLUE]) / 2;
489                                 }
490
491 //                              out_row[0] = r * color_matrix[0] + g * color_matrix[1] + b * color_matrix[2];
492 //                              out_row[1] = r * color_matrix[3] + g * color_matrix[4] + b * color_matrix[5];
493 //                              out_row[2] = r * color_matrix[6] + g * color_matrix[7] + b * color_matrix[8];
494
495                                 out_row[0] = r;
496                                 out_row[1] = g;
497                                 out_row[2] = b;
498
499                                 prev_row += components;
500                                 current_row += components;
501                                 next_row += components;
502                                 out_row += components;
503                         }
504                 }
505         }
506 }
507
508
509
510
511 InterpolatePixelsEngine::InterpolatePixelsEngine(InterpolatePixelsMain *plugin)
512  : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1)
513 {
514         this->plugin = plugin;
515 }
516
517 void InterpolatePixelsEngine::init_packages()
518 {
519         for( int i=0; i<9; ++i ) color_matrix[i] = 0;
520         for( int i=0; i<3; ++i ) color_matrix[i*3 + i] = 1;
521         char string[BCTEXTLEN];
522         string[0] = 0;
523         plugin->get_output()->get_params()->get("DCRAW_MATRIX", string);
524
525 // printf("InterpolatePixelsEngine::init_packages %d\n", __LINE__);
526 // plugin->get_output()->dump_params();
527
528         sscanf(string,
529                 "%f %f %f %f %f %f %f %f %f",
530                 &color_matrix[0],
531                 &color_matrix[1],
532                 &color_matrix[2],
533                 &color_matrix[3],
534                 &color_matrix[4],
535                 &color_matrix[5],
536                 &color_matrix[6],
537                 &color_matrix[7],
538                 &color_matrix[8]);
539         for(int i = 0; i < get_total_packages(); i++)
540         {
541                 InterpolatePixelsPackage *package = (InterpolatePixelsPackage*)get_package(i);
542                 package->y1 = plugin->get_temp()->get_h() * i / get_total_packages();
543                 package->y2 = plugin->get_temp()->get_h() * (i + 1) / get_total_packages();
544         }
545 }
546
547
548 LoadClient* InterpolatePixelsEngine::new_client()
549 {
550         return new InterpolatePixelsUnit(this, plugin);
551 }
552
553
554 LoadPackage* InterpolatePixelsEngine::new_package()
555 {
556         return new InterpolatePixelsPackage;
557 }
558
559