edl plugin names eng, fix segv for opengl brender, renderfarm rework strategy, perf...
[goodguy/history.git] / cinelerra-5.1 / plugins / deinterlace / deinterlace.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 "clip.h"
23 #include "bchash.h"
24 #include "deinterlace.h"
25 #include "deinterwindow.h"
26 #include "filexml.h"
27 #include "keyframe.h"
28 #include "language.h"
29 #include "vframe.h"
30
31 #include <stdint.h>
32 #include <string.h>
33
34
35 REGISTER_PLUGIN(DeInterlaceMain)
36
37 DeInterlaceConfig::DeInterlaceConfig()
38 {
39         mode = DEINTERLACE_EVEN;
40 //      adaptive = 0;
41 //      threshold = 40;
42 }
43
44 int DeInterlaceConfig::equivalent(DeInterlaceConfig &that)
45 {
46         return mode == that.mode;
47 //              &&
48 //              adaptive == that.adaptive &&
49 //              threshold == that.threshold;
50 }
51
52 void DeInterlaceConfig::copy_from(DeInterlaceConfig &that)
53 {
54         mode = that.mode;
55 //      adaptive = that.adaptive;
56 //      threshold = that.threshold;
57 }
58
59 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev,
60         DeInterlaceConfig &next,
61         int64_t prev_frame,
62         int64_t next_frame,
63         int64_t current_frame)
64 {
65         copy_from(prev);
66 }
67
68
69
70
71 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
72  : PluginVClient(server)
73 {
74
75 //      temp = 0;
76 }
77
78 DeInterlaceMain::~DeInterlaceMain()
79 {
80
81 //      if(temp) delete temp;
82 }
83
84 const char* DeInterlaceMain::plugin_title() { return N_("Deinterlace"); }
85 int DeInterlaceMain::is_realtime() { return 1; }
86
87
88
89 #define DEINTERLACE_EVEN_MACRO(type, components, dominance) \
90 { \
91         int w = input->get_w(); \
92         int h = input->get_h(); \
93  \
94         for(int i = 0; i < h - 1; i += 2) \
95         { \
96                 type *input_row = (type*)input->get_rows()[dominance ? i + 1 : i]; \
97                 type *output_row1 = (type*)output->get_rows()[i]; \
98                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
99                 memcpy(output_row1, input_row, w * components * sizeof(type)); \
100                 memcpy(output_row2, input_row, w * components * sizeof(type)); \
101         } \
102 }
103
104 #define DEINTERLACE_AVG_EVEN_MACRO(type, temp_type, components, dominance) \
105 { \
106         int w = input->get_w(); \
107         int h = input->get_h(); \
108         changed_rows = 0; \
109  \
110         type **in_rows = (type**)input->get_rows(); \
111         type **out_rows = (type**)temp->get_rows(); \
112         int max_h = h - 1; \
113 /*      temp_type abs_diff = 0, total = 0; */ \
114  \
115         for(int i = 0; i < max_h; i += 2) \
116         { \
117                 int in_number1 = dominance ? i - 1 : i + 0; \
118                 int in_number2 = dominance ? i + 1 : i + 2; \
119                 int out_number1 = dominance ? i - 1 : i; \
120                 int out_number2 = dominance ? i : i + 1; \
121                 in_number1 = MAX(in_number1, 0); \
122                 in_number2 = MIN(in_number2, max_h); \
123                 out_number1 = MAX(out_number1, 0); \
124                 out_number2 = MIN(out_number2, max_h); \
125  \
126                 type *input_row1 = in_rows[in_number1]; \
127                 type *input_row2 = in_rows[in_number2]; \
128 /*              type *input_row3 = in_rows[out_number2]; */\
129                 type *temp_row1 = out_rows[out_number1]; \
130                 type *temp_row2 = out_rows[out_number2]; \
131 /*              temp_type sum = 0; */\
132                 temp_type accum_r, accum_b, accum_g, accum_a; \
133  \
134                 memcpy(temp_row1, input_row1, w * components * sizeof(type)); \
135                 for(int j = 0; j < w; j++) \
136                 { \
137                         accum_r = (*input_row1++) + (*input_row2++); \
138                         accum_g = (*input_row1++) + (*input_row2++); \
139                         accum_b = (*input_row1++) + (*input_row2++); \
140                         if(components == 4) \
141                                 accum_a = (*input_row1++) + (*input_row2++); \
142                         accum_r /= 2; \
143                         accum_g /= 2; \
144                         accum_b /= 2; \
145                         accum_a /= 2; \
146  \
147 /*                      total += *input_row3; */\
148 /*                      sum = ((temp_type)*input_row3++) - accum_r; */\
149 /*                      abs_diff += (sum < 0 ? -sum : sum); */\
150                         *temp_row2++ = accum_r; \
151  \
152 /*                      total += *input_row3; */\
153 /*                      sum = ((temp_type)*input_row3++) - accum_g; */\
154 /*                      abs_diff += (sum < 0 ? -sum : sum); */\
155                         *temp_row2++ = accum_g; \
156  \
157 /*                      total += *input_row3; */\
158 /*                      sum = ((temp_type)*input_row3++) - accum_b; */\
159 /*                      abs_diff += (sum < 0 ? -sum : sum); */\
160                         *temp_row2++ = accum_b; \
161  \
162                         if(components == 4) \
163                         { \
164 /*                              total += *input_row3; */\
165 /*                              sum = ((temp_type)*input_row3++) - accum_a; */\
166 /*                              abs_diff += (sum < 0 ? -sum : sum); */\
167                                 *temp_row2++ = accum_a; \
168                         } \
169                 } \
170         } \
171  \
172 /*      temp_type threshold = (temp_type)total * config.threshold / THRESHOLD_SCALAR; */\
173 /* printf("total=%lld threshold=%lld abs_diff=%lld\n", total, threshold, abs_diff); */ \
174 /*      if(abs_diff > threshold || !config.adaptive) */\
175 /*      { */\
176 /*              output->copy_from(temp); */ \
177 /*              changed_rows = 240; */ \
178 /*      } */\
179 /*      else */\
180 /*      { */\
181 /*              output->copy_from(input); */\
182 /*              changed_rows = 0; */\
183 /*      } */\
184  \
185 }
186
187 #define DEINTERLACE_AVG_MACRO(type, temp_type, components) \
188 { \
189         int w = input->get_w(); \
190         int h = input->get_h(); \
191  \
192         for(int i = 0; i < h - 1; i += 2) \
193         { \
194                 type *input_row1 = (type*)input->get_rows()[i]; \
195                 type *input_row2 = (type*)input->get_rows()[i + 1]; \
196                 type *output_row1 = (type*)output->get_rows()[i]; \
197                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
198                 type result; \
199  \
200                 for(int j = 0; j < w * components; j++) \
201                 { \
202                         result = ((temp_type)input_row1[j] + input_row2[j]) / 2; \
203                         output_row1[j] = result; \
204                         output_row2[j] = result; \
205                 } \
206         } \
207 }
208
209 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
210 { \
211         int w = input->get_w(); \
212         int h = input->get_h(); \
213  \
214         for(int i = dominance; i < h - 1; i += 2) \
215         { \
216                 type *input_row1 = (type*)input->get_rows()[i]; \
217                 type *input_row2 = (type*)input->get_rows()[i + 1]; \
218                 type *output_row1 = (type*)output->get_rows()[i]; \
219                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
220                 type temp1, temp2; \
221  \
222                 for(int j = 0; j < w * components; j++) \
223                 { \
224                         temp1 = input_row1[j]; \
225                         temp2 = input_row2[j]; \
226                         output_row1[j] = temp2; \
227                         output_row2[j] = temp1; \
228                 } \
229         } \
230 }
231
232
233 void DeInterlaceMain::deinterlace_even(VFrame *input, VFrame *output, int dominance)
234 {
235         switch(input->get_color_model())
236         {
237                 case BC_RGB888:
238                 case BC_YUV888:
239                         DEINTERLACE_EVEN_MACRO(unsigned char, 3, dominance);
240                         break;
241                 case BC_RGB_FLOAT:
242                         DEINTERLACE_EVEN_MACRO(float, 3, dominance);
243                         break;
244                 case BC_RGBA8888:
245                 case BC_YUVA8888:
246                         DEINTERLACE_EVEN_MACRO(unsigned char, 4, dominance);
247                         break;
248                 case BC_RGBA_FLOAT:
249                         DEINTERLACE_EVEN_MACRO(float, 4, dominance);
250                         break;
251                 case BC_RGB161616:
252                 case BC_YUV161616:
253                         DEINTERLACE_EVEN_MACRO(uint16_t, 3, dominance);
254                         break;
255                 case BC_RGBA16161616:
256                 case BC_YUVA16161616:
257                         DEINTERLACE_EVEN_MACRO(uint16_t, 4, dominance);
258                         break;
259         }
260 }
261
262 void DeInterlaceMain::deinterlace_avg_even(VFrame *input, VFrame *output, int dominance)
263 {
264         switch(input->get_color_model())
265         {
266                 case BC_RGB888:
267                 case BC_YUV888:
268                         DEINTERLACE_AVG_EVEN_MACRO(unsigned char, int64_t, 3, dominance);
269                         break;
270                 case BC_RGB_FLOAT:
271                         DEINTERLACE_AVG_EVEN_MACRO(float, double, 3, dominance);
272                         break;
273                 case BC_RGBA8888:
274                 case BC_YUVA8888:
275                         DEINTERLACE_AVG_EVEN_MACRO(unsigned char, int64_t, 4, dominance);
276                         break;
277                 case BC_RGBA_FLOAT:
278                         DEINTERLACE_AVG_EVEN_MACRO(float, double, 4, dominance);
279                         break;
280                 case BC_RGB161616:
281                 case BC_YUV161616:
282                         DEINTERLACE_AVG_EVEN_MACRO(uint16_t, int64_t, 3, dominance);
283                         break;
284                 case BC_RGBA16161616:
285                 case BC_YUVA16161616:
286                         DEINTERLACE_AVG_EVEN_MACRO(uint16_t, int64_t, 4, dominance);
287                         break;
288         }
289 }
290
291 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
292 {
293         switch(input->get_color_model())
294         {
295                 case BC_RGB888:
296                 case BC_YUV888:
297                         DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 3);
298                         break;
299                 case BC_RGB_FLOAT:
300                         DEINTERLACE_AVG_MACRO(float, double, 3);
301                         break;
302                 case BC_RGBA8888:
303                 case BC_YUVA8888:
304                         DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 4);
305                         break;
306                 case BC_RGBA_FLOAT:
307                         DEINTERLACE_AVG_MACRO(float, double, 4);
308                         break;
309                 case BC_RGB161616:
310                 case BC_YUV161616:
311                         DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 3);
312                         break;
313                 case BC_RGBA16161616:
314                 case BC_YUVA16161616:
315                         DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 4);
316                         break;
317         }
318 }
319
320 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
321 {
322         switch(input->get_color_model())
323         {
324                 case BC_RGB888:
325                 case BC_YUV888:
326                         DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
327                         break;
328                 case BC_RGB_FLOAT:
329                         DEINTERLACE_SWAP_MACRO(float, 3, dominance);
330                         break;
331                 case BC_RGBA8888:
332                 case BC_YUVA8888:
333                         DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
334                         break;
335                 case BC_RGBA_FLOAT:
336                         DEINTERLACE_SWAP_MACRO(float, 4, dominance);
337                         break;
338                 case BC_RGB161616:
339                 case BC_YUV161616:
340                         DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
341                         break;
342                 case BC_RGBA16161616:
343                 case BC_YUVA16161616:
344                         DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
345                         break;
346         }
347 }
348
349
350 int DeInterlaceMain::process_buffer(VFrame *frame,
351         int64_t start_position,
352         double frame_rate)
353 {
354         changed_rows = frame->get_h();
355         load_configuration();
356
357
358         read_frame(frame,
359                 0,
360                 start_position,
361                 frame_rate,
362                 get_use_opengl());
363         if(get_use_opengl()) return run_opengl();
364
365 // Temp was used for adaptive deinterlacing where it took deinterlacing
366 // an entire frame to decide if the deinterlaced output should be used.
367         temp = frame;
368
369 //      if(!temp)
370 //              temp = new VFrame(frame->get_w(), frame->get_h(),
371 //                      frame->get_color_model(), 0);
372
373         switch(config.mode)
374         {
375                 case DEINTERLACE_NONE:
376 //                      output->copy_from(input);
377                         break;
378                 case DEINTERLACE_EVEN:
379                         deinterlace_even(frame, frame, 0);
380                         break;
381                 case DEINTERLACE_ODD:
382                         deinterlace_even(frame, frame, 1);
383                         break;
384                 case DEINTERLACE_AVG:
385                         deinterlace_avg(frame, frame);
386                         break;
387                 case DEINTERLACE_AVG_EVEN:
388                         deinterlace_avg_even(frame, frame, 0);
389                         break;
390                 case DEINTERLACE_AVG_ODD:
391                         deinterlace_avg_even(frame, frame, 1);
392                         break;
393                 case DEINTERLACE_SWAP_ODD:
394                         deinterlace_swap(frame, frame, 1);
395                         break;
396                 case DEINTERLACE_SWAP_EVEN:
397                         deinterlace_swap(frame, frame, 0);
398                         break;
399         }
400         send_render_gui(&changed_rows);
401         return 0;
402 }
403
404 int DeInterlaceMain::handle_opengl()
405 {
406 #ifdef HAVE_GL
407         static const char *head_frag =
408                 "uniform sampler2D tex;\n"
409                 "uniform float double_line_h;\n"
410                 "uniform float line_h;\n"
411                 "uniform float y_offset;\n"
412                 "void main()\n"
413                 "{\n"
414                 "       vec2 coord = gl_TexCoord[0].st;\n";
415
416         static const char *line_double_frag =
417                 "       float line1 = floor((coord.y - y_offset) / double_line_h) * double_line_h + y_offset;\n"
418                 "       gl_FragColor =  texture2D(tex, vec2(coord.x, line1));\n";
419
420         static const char *line_avg_frag =
421                 "       float line1 = floor((coord.y - 0.0) / double_line_h) * double_line_h + 0.0;\n"
422                 "       float line2 = line1 + line_h;\n"
423                 "       gl_FragColor = (texture2D(tex, vec2(coord.x, line1)) + \n"
424                 "               texture2D(tex, vec2(coord.x, line2))) / 2.0;\n";
425
426         static const char *field_avg_frag =
427                 "       float line1 = floor((coord.y - y_offset) / double_line_h) * double_line_h + y_offset;\n"
428                 "       float line2 = line1 + double_line_h;\n"
429                 "       float frac = (line2 - coord.y) / double_line_h;\n"
430                 "       gl_FragColor = mix(texture2D(tex, vec2(coord.x, line2)),\n"
431                 "               texture2D(tex, vec2(coord.x, line1)),frac);\n";
432
433         static const char *line_swap_frag =
434                 "       float line1 = floor((coord.y - y_offset) / double_line_h) * double_line_h + y_offset;\n"
435 // This is the input line for line2, not the denominator of the fraction
436                 "       float line2 = line1 + line_h;\n"
437                 "       float frac = (coord.y - line1) / double_line_h;\n"
438                 "       gl_FragColor = mix(texture2D(tex, vec2(coord.x, line2)),\n"
439                 "               texture2D(tex, vec2(coord.x, line1)), frac);\n";
440
441         static const char *tail_frag =
442                 "}\n";
443
444         get_output()->to_texture();
445         get_output()->enable_opengl();
446         get_output()->init_screen();
447
448         if( config.mode != DEINTERLACE_NONE ) {
449                 const char *shader_stack[16];
450                 memset(shader_stack,0, sizeof(shader_stack));
451                 int current_shader = 0;
452
453                 shader_stack[current_shader++] = head_frag;
454
455                 float double_line_h = 2.0 / get_output()->get_texture_h();
456                 float line_h = 1.0 / get_output()->get_texture_h();
457                 float y_offset = 0.0;
458                 const char *shader_frag = 0;
459
460                 switch(config.mode) {
461                 case DEINTERLACE_EVEN:
462                         shader_frag = line_double_frag;
463                         break;
464                 case DEINTERLACE_ODD:
465                         shader_frag = line_double_frag;
466                         y_offset += 1.0;
467                         break;
468
469                 case DEINTERLACE_AVG:
470                         shader_frag = line_avg_frag;
471                         break;
472
473                 case DEINTERLACE_AVG_EVEN:
474                         shader_frag = field_avg_frag;
475                         break;
476
477                 case DEINTERLACE_AVG_ODD:
478                         shader_frag = field_avg_frag;
479                         y_offset += 1.0;
480                         break;
481
482                 case DEINTERLACE_SWAP_EVEN:
483                         shader_frag = line_swap_frag;
484                         break;
485
486                 case DEINTERLACE_SWAP_ODD:
487                         shader_frag = line_swap_frag;
488                         y_offset += 1.0;
489                         break;
490                 }
491                 if( shader_frag )
492                         shader_stack[current_shader++] = shader_frag;
493
494                 shader_stack[current_shader++] = tail_frag;
495                 shader_stack[current_shader] = 0;
496                 unsigned int shader = VFrame::make_shader(shader_stack);
497                 if( shader > 0 ) {
498                         y_offset /= get_output()->get_texture_h();
499                         glUseProgram(shader);
500                         glUniform1i(glGetUniformLocation(shader, "tex"), 0);
501                         glUniform1f(glGetUniformLocation(shader, "line_h"), line_h);
502                         glUniform1f(glGetUniformLocation(shader, "double_line_h"), double_line_h);
503                         glUniform1f(glGetUniformLocation(shader, "y_offset"), y_offset);
504                 }
505         }
506
507         get_output()->bind_texture(0);
508         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
509         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
510         get_output()->draw_texture();
511
512         glUseProgram(0);
513         get_output()->set_opengl_state(VFrame::SCREEN);
514         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
515         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
516
517 #endif
518         return 0;
519 }
520
521 void DeInterlaceMain::render_gui(void *data)
522 {
523         if(thread)
524         {
525                 ((DeInterlaceWindow*)thread->window)->lock_window();
526                 char string[BCTEXTLEN];
527                 ((DeInterlaceWindow*)thread->window)->get_status_string(string, *(int*)data);
528 //              ((DeInterlaceWindow*)thread->window)->status->update(string);
529                 ((DeInterlaceWindow*)thread->window)->flush();
530                 ((DeInterlaceWindow*)thread->window)->unlock_window();
531         }
532 }
533
534 NEW_WINDOW_MACRO(DeInterlaceMain, DeInterlaceWindow)
535 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
536
537
538
539 void DeInterlaceMain::save_data(KeyFrame *keyframe)
540 {
541         FileXML output;
542         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
543         output.tag.set_title("DEINTERLACE");
544         output.tag.set_property("MODE", config.mode);
545 //      output.tag.set_property("ADAPTIVE", config.adaptive);
546 //      output.tag.set_property("THRESHOLD", config.threshold);
547         output.append_tag();
548         output.tag.set_title("/DEINTERLACE");
549         output.append_tag();
550         output.append_newline();
551         output.terminate_string();
552 }
553
554 void DeInterlaceMain::read_data(KeyFrame *keyframe)
555 {
556         FileXML input;
557         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
558
559         while(!input.read_tag())
560         {
561                 if(input.tag.title_is("DEINTERLACE"))
562                 {
563                         config.mode = input.tag.get_property("MODE", config.mode);
564 //                      config.adaptive = input.tag.get_property("ADAPTIVE", config.adaptive);
565 //                      config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
566                 }
567         }
568
569 }
570
571 void DeInterlaceMain::update_gui()
572 {
573         if(thread)
574         {
575                 load_configuration();
576                 ((DeInterlaceWindow*)thread->window)->lock_window();
577                 ((DeInterlaceWindow*)thread->window)->set_mode(config.mode, 1);
578 //              ((DeInterlaceWindow*)thread->window)->adaptive->update(config.adaptive);
579 //              ((DeInterlaceWindow*)thread->window)->threshold->update(config.threshold);
580                 ((DeInterlaceWindow*)thread->window)->unlock_window();
581         }
582 }
583