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(frame->get_w(), frame->get_h(),
382 // frame->get_color_model(), 0);
386 case DEINTERLACE_NONE:
387 // output->copy_from(input);
389 case DEINTERLACE_EVEN:
390 deinterlace_even(frame, frame, 0);
392 case DEINTERLACE_ODD:
393 deinterlace_even(frame, frame, 1);
395 case DEINTERLACE_AVG:
396 deinterlace_avg(frame, frame);
398 case DEINTERLACE_AVG_EVEN:
399 deinterlace_avg_even(frame, frame, 0);
401 case DEINTERLACE_AVG_ODD:
402 deinterlace_avg_even(frame, frame, 1);
404 case DEINTERLACE_SWAP_ODD:
405 deinterlace_swap(frame, frame, 1);
407 case DEINTERLACE_SWAP_EVEN:
408 deinterlace_swap(frame, frame, 0);
411 send_render_gui(&changed_rows);
415 int DeInterlaceMain::handle_opengl()
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"
425 " vec2 coord = gl_TexCoord[0].st;\n";
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";
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";
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";
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";
452 static const char *tail_frag =
455 get_output()->to_texture();
456 get_output()->enable_opengl();
457 get_output()->init_screen();
459 const char *shader_stack[] = { 0, 0, 0 };
460 shader_stack[0] = head_frag;
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;
467 case DEINTERLACE_EVEN:
468 shader_stack[1] = line_double_frag;
470 case DEINTERLACE_ODD:
471 shader_stack[1] = line_double_frag;
475 case DEINTERLACE_AVG:
476 shader_stack[1] = line_avg_frag;
479 case DEINTERLACE_AVG_EVEN:
480 shader_stack[1] = field_avg_frag;
483 case DEINTERLACE_AVG_ODD:
484 shader_stack[1] = field_avg_frag;
488 case DEINTERLACE_SWAP_EVEN:
489 shader_stack[1] = line_swap_frag;
492 case DEINTERLACE_SWAP_ODD:
493 shader_stack[1] = line_swap_frag;
498 y_offset /= get_output()->get_texture_h();
500 shader_stack[2] = tail_frag;
502 if(config.mode != DEINTERLACE_NONE)
504 unsigned int frag = VFrame::make_shader(0,
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);
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();
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);
533 void DeInterlaceMain::render_gui(void *data)
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();
546 NEW_WINDOW_MACRO(DeInterlaceMain, DeInterlaceWindow)
547 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
551 void DeInterlaceMain::save_data(KeyFrame *keyframe)
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);
560 output.tag.set_title("/DEINTERLACE");
562 output.append_newline();
563 output.terminate_string();
566 void DeInterlaceMain::read_data(KeyFrame *keyframe)
569 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
571 while(!input.read_tag())
573 if(input.tag.title_is("DEINTERLACE"))
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);
583 void DeInterlaceMain::update_gui()
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();