4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
24 #include "deinterlace.h"
25 #include "deinterwindow.h"
43 REGISTER_PLUGIN(DeInterlaceMain)
48 DeInterlaceConfig::DeInterlaceConfig()
50 mode = DEINTERLACE_EVEN;
55 int DeInterlaceConfig::equivalent(DeInterlaceConfig &that)
57 return mode == that.mode;
59 // adaptive == that.adaptive &&
60 // threshold == that.threshold;
63 void DeInterlaceConfig::copy_from(DeInterlaceConfig &that)
66 // adaptive = that.adaptive;
67 // threshold = that.threshold;
70 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev,
71 DeInterlaceConfig &next,
74 int64_t current_frame)
82 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
83 : PluginVClient(server)
89 DeInterlaceMain::~DeInterlaceMain()
92 // if(temp) delete temp;
95 const char* DeInterlaceMain::plugin_title() { return _("Deinterlace"); }
96 int DeInterlaceMain::is_realtime() { return 1; }
100 #define DEINTERLACE_EVEN_MACRO(type, components, dominance) \
102 int w = input->get_w(); \
103 int h = input->get_h(); \
105 for(int i = 0; i < h - 1; i += 2) \
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)); \
115 #define DEINTERLACE_AVG_EVEN_MACRO(type, temp_type, components, dominance) \
117 int w = input->get_w(); \
118 int h = input->get_h(); \
121 type **in_rows = (type**)input->get_rows(); \
122 type **out_rows = (type**)temp->get_rows(); \
124 /* temp_type abs_diff = 0, total = 0; */ \
126 for(int i = 0; i < max_h; i += 2) \
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); \
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; \
145 memcpy(temp_row1, input_row1, w * components * sizeof(type)); \
146 for(int j = 0; j < w; j++) \
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++); \
158 /* total += *input_row3; */\
159 /* sum = ((temp_type)*input_row3++) - accum_r; */\
160 /* abs_diff += (sum < 0 ? -sum : sum); */\
161 *temp_row2++ = accum_r; \
163 /* total += *input_row3; */\
164 /* sum = ((temp_type)*input_row3++) - accum_g; */\
165 /* abs_diff += (sum < 0 ? -sum : sum); */\
166 *temp_row2++ = accum_g; \
168 /* total += *input_row3; */\
169 /* sum = ((temp_type)*input_row3++) - accum_b; */\
170 /* abs_diff += (sum < 0 ? -sum : sum); */\
171 *temp_row2++ = accum_b; \
173 if(components == 4) \
175 /* total += *input_row3; */\
176 /* sum = ((temp_type)*input_row3++) - accum_a; */\
177 /* abs_diff += (sum < 0 ? -sum : sum); */\
178 *temp_row2++ = accum_a; \
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) */\
187 /* output->copy_from(temp); */ \
188 /* changed_rows = 240; */ \
192 /* output->copy_from(input); */\
193 /* changed_rows = 0; */\
198 #define DEINTERLACE_AVG_MACRO(type, temp_type, components) \
200 int w = input->get_w(); \
201 int h = input->get_h(); \
203 for(int i = 0; i < h - 1; i += 2) \
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]; \
211 for(int j = 0; j < w * components; j++) \
213 result = ((temp_type)input_row1[j] + input_row2[j]) / 2; \
214 output_row1[j] = result; \
215 output_row2[j] = result; \
220 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
222 int w = input->get_w(); \
223 int h = input->get_h(); \
225 for(int i = dominance; i < h - 1; i += 2) \
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]; \
233 for(int j = 0; j < w * components; j++) \
235 temp1 = input_row1[j]; \
236 temp2 = input_row2[j]; \
237 output_row1[j] = temp2; \
238 output_row2[j] = temp1; \
244 void DeInterlaceMain::deinterlace_even(VFrame *input, VFrame *output, int dominance)
246 switch(input->get_color_model())
250 DEINTERLACE_EVEN_MACRO(unsigned char, 3, dominance);
253 DEINTERLACE_EVEN_MACRO(float, 3, dominance);
257 DEINTERLACE_EVEN_MACRO(unsigned char, 4, dominance);
260 DEINTERLACE_EVEN_MACRO(float, 4, dominance);
264 DEINTERLACE_EVEN_MACRO(uint16_t, 3, dominance);
266 case BC_RGBA16161616:
267 case BC_YUVA16161616:
268 DEINTERLACE_EVEN_MACRO(uint16_t, 4, dominance);
273 void DeInterlaceMain::deinterlace_avg_even(VFrame *input, VFrame *output, int dominance)
275 switch(input->get_color_model())
279 DEINTERLACE_AVG_EVEN_MACRO(unsigned char, int64_t, 3, dominance);
282 DEINTERLACE_AVG_EVEN_MACRO(float, double, 3, dominance);
286 DEINTERLACE_AVG_EVEN_MACRO(unsigned char, int64_t, 4, dominance);
289 DEINTERLACE_AVG_EVEN_MACRO(float, double, 4, dominance);
293 DEINTERLACE_AVG_EVEN_MACRO(uint16_t, int64_t, 3, dominance);
295 case BC_RGBA16161616:
296 case BC_YUVA16161616:
297 DEINTERLACE_AVG_EVEN_MACRO(uint16_t, int64_t, 4, dominance);
302 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
304 switch(input->get_color_model())
308 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 3);
311 DEINTERLACE_AVG_MACRO(float, double, 3);
315 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 4);
318 DEINTERLACE_AVG_MACRO(float, double, 4);
322 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 3);
324 case BC_RGBA16161616:
325 case BC_YUVA16161616:
326 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 4);
331 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
333 switch(input->get_color_model())
337 DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
340 DEINTERLACE_SWAP_MACRO(float, 3, dominance);
344 DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
347 DEINTERLACE_SWAP_MACRO(float, 4, dominance);
351 DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
353 case BC_RGBA16161616:
354 case BC_YUVA16161616:
355 DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
361 int DeInterlaceMain::process_buffer(VFrame *frame,
362 int64_t start_position,
365 changed_rows = frame->get_h();
366 load_configuration();
374 if(get_use_opengl()) return run_opengl();
376 // Temp was used for adaptive deinterlacing where it took deinterlacing
377 // an entire frame to decide if the deinterlaced output should be used.
381 // temp = new VFrame(0,
384 // frame->get_color_model());
388 case DEINTERLACE_NONE:
389 // output->copy_from(input);
391 case DEINTERLACE_EVEN:
392 deinterlace_even(frame, frame, 0);
394 case DEINTERLACE_ODD:
395 deinterlace_even(frame, frame, 1);
397 case DEINTERLACE_AVG:
398 deinterlace_avg(frame, frame);
400 case DEINTERLACE_AVG_EVEN:
401 deinterlace_avg_even(frame, frame, 0);
403 case DEINTERLACE_AVG_ODD:
404 deinterlace_avg_even(frame, frame, 1);
406 case DEINTERLACE_SWAP_ODD:
407 deinterlace_swap(frame, frame, 1);
409 case DEINTERLACE_SWAP_EVEN:
410 deinterlace_swap(frame, frame, 0);
413 send_render_gui(&changed_rows);
417 int DeInterlaceMain::handle_opengl()
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"
427 " vec2 coord = gl_TexCoord[0].st;\n";
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";
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";
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";
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";
454 static const char *tail_frag =
457 get_output()->to_texture();
458 get_output()->enable_opengl();
459 get_output()->init_screen();
461 const char *shader_stack[] = { 0, 0, 0 };
462 shader_stack[0] = head_frag;
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;
469 case DEINTERLACE_EVEN:
470 shader_stack[1] = line_double_frag;
472 case DEINTERLACE_ODD:
473 shader_stack[1] = line_double_frag;
477 case DEINTERLACE_AVG:
478 shader_stack[1] = line_avg_frag;
481 case DEINTERLACE_AVG_EVEN:
482 shader_stack[1] = field_avg_frag;
485 case DEINTERLACE_AVG_ODD:
486 shader_stack[1] = field_avg_frag;
490 case DEINTERLACE_SWAP_EVEN:
491 shader_stack[1] = line_swap_frag;
494 case DEINTERLACE_SWAP_ODD:
495 shader_stack[1] = line_swap_frag;
500 y_offset /= get_output()->get_texture_h();
502 shader_stack[2] = tail_frag;
504 if(config.mode != DEINTERLACE_NONE)
506 unsigned int frag = VFrame::make_shader(0,
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);
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();
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);
535 void DeInterlaceMain::render_gui(void *data)
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();
548 NEW_WINDOW_MACRO(DeInterlaceMain, DeInterlaceWindow)
549 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
553 void DeInterlaceMain::save_data(KeyFrame *keyframe)
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);
562 output.tag.set_title("/DEINTERLACE");
564 output.append_newline();
565 output.terminate_string();
568 void DeInterlaceMain::read_data(KeyFrame *keyframe)
571 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
573 while(!input.read_tag())
575 if(input.tag.title_is("DEINTERLACE"))
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);
585 void DeInterlaceMain::update_gui()
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();