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