fix mask vframe setup, add unshared vframe constructor
[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(frame->get_w(), frame->get_h(),
382 //                      frame->get_color_model(), 0);
383
384         switch(config.mode)
385         {
386                 case DEINTERLACE_NONE:
387 //                      output->copy_from(input);
388                         break;
389                 case DEINTERLACE_EVEN:
390                         deinterlace_even(frame, frame, 0);
391                         break;
392                 case DEINTERLACE_ODD:
393                         deinterlace_even(frame, frame, 1);
394                         break;
395                 case DEINTERLACE_AVG:
396                         deinterlace_avg(frame, frame);
397                         break;
398                 case DEINTERLACE_AVG_EVEN:
399                         deinterlace_avg_even(frame, frame, 0);
400                         break;
401                 case DEINTERLACE_AVG_ODD:
402                         deinterlace_avg_even(frame, frame, 1);
403                         break;
404                 case DEINTERLACE_SWAP_ODD:
405                         deinterlace_swap(frame, frame, 1);
406                         break;
407                 case DEINTERLACE_SWAP_EVEN:
408                         deinterlace_swap(frame, frame, 0);
409                         break;
410         }
411         send_render_gui(&changed_rows);
412         return 0;
413 }
414
415 int DeInterlaceMain::handle_opengl()
416 {
417 #ifdef HAVE_GL
418         static const char *head_frag =
419                 "uniform sampler2D tex;\n"
420                 "uniform float double_line_h;\n"
421                 "uniform float line_h;\n"
422                 "uniform float y_offset;\n"
423                 "void main()\n"
424                 "{\n"
425                 "       vec2 coord = gl_TexCoord[0].st;\n";
426
427         static const char *line_double_frag =
428                 "       float line1 = floor((coord.y - y_offset) / double_line_h) * double_line_h + y_offset;\n"
429                 "       gl_FragColor =  texture2D(tex, vec2(coord.x, line1));\n";
430
431         static const char *line_avg_frag =
432                 "       float line1 = floor((coord.y - 0.0) / double_line_h) * double_line_h + 0.0;\n"
433                 "       float line2 = line1 + line_h;\n"
434                 "       gl_FragColor = (texture2D(tex, vec2(coord.x, line1)) + \n"
435                 "               texture2D(tex, vec2(coord.x, line2))) / 2.0;\n";
436
437         static const char *field_avg_frag =
438                 "       float line1 = floor((coord.y - y_offset) / double_line_h) * double_line_h + y_offset;\n"
439                 "       float line2 = line1 + double_line_h;\n"
440                 "       float frac = (line2 - coord.y) / double_line_h;\n"
441                 "       gl_FragColor = mix(texture2D(tex, vec2(coord.x, line2)),\n"
442                 "               texture2D(tex, vec2(coord.x, line1)),frac);\n";
443
444         static const char *line_swap_frag =
445                 "       float line1 = floor((coord.y - y_offset) / double_line_h) * double_line_h + y_offset;\n"
446 // This is the input line for line2, not the denominator of the fraction
447                 "       float line2 = line1 + line_h;\n"
448                 "       float frac = (coord.y - line1) / double_line_h;\n"
449                 "       gl_FragColor = mix(texture2D(tex, vec2(coord.x, line2)),\n"
450                 "               texture2D(tex, vec2(coord.x, line1)), frac);\n";
451
452         static const char *tail_frag =
453                 "}\n";
454
455         get_output()->to_texture();
456         get_output()->enable_opengl();
457         get_output()->init_screen();
458
459         const char *shader_stack[] = { 0, 0, 0 };
460         shader_stack[0] = head_frag;
461
462         float double_line_h = 2.0 / get_output()->get_texture_h();
463         float line_h = 1.0 / get_output()->get_texture_h();
464         float y_offset = 0.0;
465         switch(config.mode)
466         {
467                 case DEINTERLACE_EVEN:
468                         shader_stack[1] = line_double_frag;
469                         break;
470                 case DEINTERLACE_ODD:
471                         shader_stack[1] = line_double_frag;
472                         y_offset += 1.0;
473                         break;
474
475                 case DEINTERLACE_AVG:
476                         shader_stack[1] = line_avg_frag;
477                         break;
478
479                 case DEINTERLACE_AVG_EVEN:
480                         shader_stack[1] = field_avg_frag;
481                         break;
482
483                 case DEINTERLACE_AVG_ODD:
484                         shader_stack[1] = field_avg_frag;
485                         y_offset += 1.0;
486                         break;
487
488                 case DEINTERLACE_SWAP_EVEN:
489                         shader_stack[1] = line_swap_frag;
490                         break;
491
492                 case DEINTERLACE_SWAP_ODD:
493                         shader_stack[1] = line_swap_frag;
494                         y_offset += 1.0;
495                         break;
496         }
497
498         y_offset /= get_output()->get_texture_h();
499
500         shader_stack[2] = tail_frag;
501
502         if(config.mode != DEINTERLACE_NONE)
503         {
504                 unsigned int frag = VFrame::make_shader(0,
505                         shader_stack[0],
506                         shader_stack[1],
507                         shader_stack[2],
508                         0);
509                 if(frag)
510                 {
511                         glUseProgram(frag);
512                         glUniform1i(glGetUniformLocation(frag, "tex"), 0);
513                         glUniform1f(glGetUniformLocation(frag, "line_h"), line_h);
514                         glUniform1f(glGetUniformLocation(frag, "double_line_h"), double_line_h);
515                         glUniform1f(glGetUniformLocation(frag, "y_offset"), y_offset);
516                 }
517         }
518
519         get_output()->bind_texture(0);
520         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
521         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
522         get_output()->draw_texture();
523
524         glUseProgram(0);
525         get_output()->set_opengl_state(VFrame::SCREEN);
526         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
527         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
528
529 #endif
530         return 0;
531 }
532
533 void DeInterlaceMain::render_gui(void *data)
534 {
535         if(thread)
536         {
537                 ((DeInterlaceWindow*)thread->window)->lock_window();
538                 char string[BCTEXTLEN];
539                 ((DeInterlaceWindow*)thread->window)->get_status_string(string, *(int*)data);
540 //              ((DeInterlaceWindow*)thread->window)->status->update(string);
541                 ((DeInterlaceWindow*)thread->window)->flush();
542                 ((DeInterlaceWindow*)thread->window)->unlock_window();
543         }
544 }
545
546 NEW_WINDOW_MACRO(DeInterlaceMain, DeInterlaceWindow)
547 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
548
549
550
551 void DeInterlaceMain::save_data(KeyFrame *keyframe)
552 {
553         FileXML output;
554         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
555         output.tag.set_title("DEINTERLACE");
556         output.tag.set_property("MODE", config.mode);
557 //      output.tag.set_property("ADAPTIVE", config.adaptive);
558 //      output.tag.set_property("THRESHOLD", config.threshold);
559         output.append_tag();
560         output.tag.set_title("/DEINTERLACE");
561         output.append_tag();
562         output.append_newline();
563         output.terminate_string();
564 }
565
566 void DeInterlaceMain::read_data(KeyFrame *keyframe)
567 {
568         FileXML input;
569         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
570
571         while(!input.read_tag())
572         {
573                 if(input.tag.title_is("DEINTERLACE"))
574                 {
575                         config.mode = input.tag.get_property("MODE", config.mode);
576 //                      config.adaptive = input.tag.get_property("ADAPTIVE", config.adaptive);
577 //                      config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
578                 }
579         }
580
581 }
582
583 void DeInterlaceMain::update_gui()
584 {
585         if(thread)
586         {
587                 load_configuration();
588                 ((DeInterlaceWindow*)thread->window)->lock_window();
589                 ((DeInterlaceWindow*)thread->window)->set_mode(config.mode, 1);
590 //              ((DeInterlaceWindow*)thread->window)->adaptive->update(config.adaptive);
591 //              ((DeInterlaceWindow*)thread->window)->threshold->update(config.threshold);
592                 ((DeInterlaceWindow*)thread->window)->unlock_window();
593         }
594 }
595