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"
35 REGISTER_PLUGIN(DeInterlaceMain)
37 DeInterlaceConfig::DeInterlaceConfig()
39 mode = DEINTERLACE_EVEN;
44 int DeInterlaceConfig::equivalent(DeInterlaceConfig &that)
46 return mode == that.mode;
48 // adaptive == that.adaptive &&
49 // threshold == that.threshold;
52 void DeInterlaceConfig::copy_from(DeInterlaceConfig &that)
55 // adaptive = that.adaptive;
56 // threshold = that.threshold;
59 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev,
60 DeInterlaceConfig &next,
63 int64_t current_frame)
71 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
72 : PluginVClient(server)
78 DeInterlaceMain::~DeInterlaceMain()
81 // if(temp) delete temp;
84 const char* DeInterlaceMain::plugin_title() { return N_("Deinterlace"); }
85 int DeInterlaceMain::is_realtime() { return 1; }
89 #define DEINTERLACE_EVEN_MACRO(type, components, dominance) \
91 int w = input->get_w(); \
92 int h = input->get_h(); \
94 for(int i = 0; i < h - 1; i += 2) \
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)); \
104 #define DEINTERLACE_AVG_EVEN_MACRO(type, temp_type, components, dominance) \
106 int w = input->get_w(); \
107 int h = input->get_h(); \
110 type **in_rows = (type**)input->get_rows(); \
111 type **out_rows = (type**)temp->get_rows(); \
113 /* temp_type abs_diff = 0, total = 0; */ \
115 for(int i = 0; i < max_h; i += 2) \
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); \
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; \
134 memcpy(temp_row1, input_row1, w * components * sizeof(type)); \
135 for(int j = 0; j < w; j++) \
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++); \
147 /* total += *input_row3; */\
148 /* sum = ((temp_type)*input_row3++) - accum_r; */\
149 /* abs_diff += (sum < 0 ? -sum : sum); */\
150 *temp_row2++ = accum_r; \
152 /* total += *input_row3; */\
153 /* sum = ((temp_type)*input_row3++) - accum_g; */\
154 /* abs_diff += (sum < 0 ? -sum : sum); */\
155 *temp_row2++ = accum_g; \
157 /* total += *input_row3; */\
158 /* sum = ((temp_type)*input_row3++) - accum_b; */\
159 /* abs_diff += (sum < 0 ? -sum : sum); */\
160 *temp_row2++ = accum_b; \
162 if(components == 4) \
164 /* total += *input_row3; */\
165 /* sum = ((temp_type)*input_row3++) - accum_a; */\
166 /* abs_diff += (sum < 0 ? -sum : sum); */\
167 *temp_row2++ = accum_a; \
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) */\
176 /* output->copy_from(temp); */ \
177 /* changed_rows = 240; */ \
181 /* output->copy_from(input); */\
182 /* changed_rows = 0; */\
187 #define DEINTERLACE_AVG_MACRO(type, temp_type, components) \
189 int w = input->get_w(); \
190 int h = input->get_h(); \
192 for(int i = 0; i < h - 1; i += 2) \
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]; \
200 for(int j = 0; j < w * components; j++) \
202 result = ((temp_type)input_row1[j] + input_row2[j]) / 2; \
203 output_row1[j] = result; \
204 output_row2[j] = result; \
209 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
211 int w = input->get_w(); \
212 int h = input->get_h(); \
214 for(int i = dominance; i < h - 1; i += 2) \
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]; \
222 for(int j = 0; j < w * components; j++) \
224 temp1 = input_row1[j]; \
225 temp2 = input_row2[j]; \
226 output_row1[j] = temp2; \
227 output_row2[j] = temp1; \
233 void DeInterlaceMain::deinterlace_even(VFrame *input, VFrame *output, int dominance)
235 switch(input->get_color_model())
239 DEINTERLACE_EVEN_MACRO(unsigned char, 3, dominance);
242 DEINTERLACE_EVEN_MACRO(float, 3, dominance);
246 DEINTERLACE_EVEN_MACRO(unsigned char, 4, dominance);
249 DEINTERLACE_EVEN_MACRO(float, 4, dominance);
253 DEINTERLACE_EVEN_MACRO(uint16_t, 3, dominance);
255 case BC_RGBA16161616:
256 case BC_YUVA16161616:
257 DEINTERLACE_EVEN_MACRO(uint16_t, 4, dominance);
262 void DeInterlaceMain::deinterlace_avg_even(VFrame *input, VFrame *output, int dominance)
264 switch(input->get_color_model())
268 DEINTERLACE_AVG_EVEN_MACRO(unsigned char, int64_t, 3, dominance);
271 DEINTERLACE_AVG_EVEN_MACRO(float, double, 3, dominance);
275 DEINTERLACE_AVG_EVEN_MACRO(unsigned char, int64_t, 4, dominance);
278 DEINTERLACE_AVG_EVEN_MACRO(float, double, 4, dominance);
282 DEINTERLACE_AVG_EVEN_MACRO(uint16_t, int64_t, 3, dominance);
284 case BC_RGBA16161616:
285 case BC_YUVA16161616:
286 DEINTERLACE_AVG_EVEN_MACRO(uint16_t, int64_t, 4, dominance);
291 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
293 switch(input->get_color_model())
297 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 3);
300 DEINTERLACE_AVG_MACRO(float, double, 3);
304 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 4);
307 DEINTERLACE_AVG_MACRO(float, double, 4);
311 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 3);
313 case BC_RGBA16161616:
314 case BC_YUVA16161616:
315 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 4);
320 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
322 switch(input->get_color_model())
326 DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
329 DEINTERLACE_SWAP_MACRO(float, 3, dominance);
333 DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
336 DEINTERLACE_SWAP_MACRO(float, 4, dominance);
340 DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
342 case BC_RGBA16161616:
343 case BC_YUVA16161616:
344 DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
350 int DeInterlaceMain::process_buffer(VFrame *frame,
351 int64_t start_position,
354 changed_rows = frame->get_h();
355 load_configuration();
363 if(get_use_opengl()) return run_opengl();
365 // Temp was used for adaptive deinterlacing where it took deinterlacing
366 // an entire frame to decide if the deinterlaced output should be used.
370 // temp = new VFrame(frame->get_w(), frame->get_h(),
371 // frame->get_color_model(), 0);
375 case DEINTERLACE_NONE:
376 // output->copy_from(input);
378 case DEINTERLACE_EVEN:
379 deinterlace_even(frame, frame, 0);
381 case DEINTERLACE_ODD:
382 deinterlace_even(frame, frame, 1);
384 case DEINTERLACE_AVG:
385 deinterlace_avg(frame, frame);
387 case DEINTERLACE_AVG_EVEN:
388 deinterlace_avg_even(frame, frame, 0);
390 case DEINTERLACE_AVG_ODD:
391 deinterlace_avg_even(frame, frame, 1);
393 case DEINTERLACE_SWAP_ODD:
394 deinterlace_swap(frame, frame, 1);
396 case DEINTERLACE_SWAP_EVEN:
397 deinterlace_swap(frame, frame, 0);
400 send_render_gui(&changed_rows);
404 int DeInterlaceMain::handle_opengl()
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"
414 " vec2 coord = gl_TexCoord[0].st;\n";
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";
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";
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";
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";
441 static const char *tail_frag =
444 get_output()->to_texture();
445 get_output()->enable_opengl();
446 get_output()->init_screen();
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;
453 shader_stack[current_shader++] = head_frag;
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;
460 switch(config.mode) {
461 case DEINTERLACE_EVEN:
462 shader_frag = line_double_frag;
464 case DEINTERLACE_ODD:
465 shader_frag = line_double_frag;
469 case DEINTERLACE_AVG:
470 shader_frag = line_avg_frag;
473 case DEINTERLACE_AVG_EVEN:
474 shader_frag = field_avg_frag;
477 case DEINTERLACE_AVG_ODD:
478 shader_frag = field_avg_frag;
482 case DEINTERLACE_SWAP_EVEN:
483 shader_frag = line_swap_frag;
486 case DEINTERLACE_SWAP_ODD:
487 shader_frag = line_swap_frag;
492 shader_stack[current_shader++] = shader_frag;
494 shader_stack[current_shader++] = tail_frag;
495 shader_stack[current_shader] = 0;
496 unsigned int shader = VFrame::make_shader(shader_stack);
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);
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();
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);
521 void DeInterlaceMain::render_gui(void *data)
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();
534 NEW_WINDOW_MACRO(DeInterlaceMain, DeInterlaceWindow)
535 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
539 void DeInterlaceMain::save_data(KeyFrame *keyframe)
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);
548 output.tag.set_title("/DEINTERLACE");
550 output.append_newline();
551 output.terminate_string();
554 void DeInterlaceMain::read_data(KeyFrame *keyframe)
557 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
559 while(!input.read_tag())
561 if(input.tag.title_is("DEINTERLACE"))
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);
571 void DeInterlaceMain::update_gui()
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();