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-cv.h"
25 #include "deinterwindow-cv.h"
43 REGISTER_PLUGIN(DeInterlaceMain)
48 DeInterlaceConfig::DeInterlaceConfig()
50 mode = DEINTERLACE_AVG;
56 int DeInterlaceConfig::equivalent(DeInterlaceConfig &that)
58 return mode == that.mode &&
59 dominance == that.dominance &&
60 adaptive == that.adaptive &&
61 threshold == that.threshold;
64 void DeInterlaceConfig::copy_from(DeInterlaceConfig &that)
67 dominance = that.dominance;
68 adaptive = that.adaptive;
69 threshold = that.threshold;
72 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev,
73 DeInterlaceConfig &next,
76 int64_t current_frame)
84 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
85 : PluginVClient(server)
91 DeInterlaceMain::~DeInterlaceMain()
93 // if(temp) delete temp;
94 if(temp_prevframe) delete temp_prevframe;
97 const char* DeInterlaceMain::plugin_title() { return N_("Deinterlace-CV"); }
98 int DeInterlaceMain::is_realtime() { return 1; }
102 #define DEINTERLACE_TOP_MACRO(type, components, dominance) \
104 int w = input->get_w(); \
105 int h = input->get_h(); \
107 for(int i = 0; i < h - 1; i += 2) \
109 type *input_row = (type*)input->get_rows()[dominance ? i + 1 : i]; \
110 type *output_row1 = (type*)output->get_rows()[i]; \
111 type *output_row2 = (type*)output->get_rows()[i + 1]; \
112 memcpy(output_row1, input_row, w * components * sizeof(type)); \
113 memcpy(output_row2, input_row, w * components * sizeof(type)); \
117 #define DEINTERLACE_AVG_TOP_MACRO(type, temp_type, components, dominance) \
119 int w = input->get_w(); \
120 int h = input->get_h(); \
123 type **in_rows = (type**)input->get_rows(); \
124 type **out_rows = (type**)temp->get_rows(); \
126 temp_type abs_diff = 0, total = 0; \
128 for(int i = 0; i < max_h; i += 2) \
130 int in_number1 = dominance ? i - 1 : i + 0; \
131 int in_number2 = dominance ? i + 1 : i + 2; \
132 int out_number1 = dominance ? i - 1 : i; \
133 int out_number2 = dominance ? i : i + 1; \
134 in_number1 = MAX(in_number1, 0); \
135 in_number2 = MIN(in_number2, max_h); \
136 out_number1 = MAX(out_number1, 0); \
137 out_number2 = MIN(out_number2, max_h); \
139 type *input_row1 = in_rows[in_number1]; \
140 type *input_row2 = in_rows[in_number2]; \
141 type *input_row3 = in_rows[out_number2]; \
142 type *temp_row1 = out_rows[out_number1]; \
143 type *temp_row2 = out_rows[out_number2]; \
145 temp_type accum_r, accum_b, accum_g, accum_a; \
147 memcpy(temp_row1, input_row1, w * components * sizeof(type)); \
148 for(int j = 0; j < w; j++) \
150 accum_r = (*input_row1++) + (*input_row2++); \
151 accum_g = (*input_row1++) + (*input_row2++); \
152 accum_b = (*input_row1++) + (*input_row2++); \
153 if(components == 4) \
154 accum_a = (*input_row1++) + (*input_row2++); \
160 total += *input_row3; \
161 sum = ((temp_type)*input_row3++) - accum_r; \
162 abs_diff += (sum < 0 ? -sum : sum); \
163 *temp_row2++ = accum_r; \
165 total += *input_row3; \
166 sum = ((temp_type)*input_row3++) - accum_g; \
167 abs_diff += (sum < 0 ? -sum : sum); \
168 *temp_row2++ = accum_g; \
170 total += *input_row3; \
171 sum = ((temp_type)*input_row3++) - accum_b; \
172 abs_diff += (sum < 0 ? -sum : sum); \
173 *temp_row2++ = accum_b; \
175 if(components == 4) \
177 total += *input_row3; \
178 sum = ((temp_type)*input_row3++) - accum_a; \
179 abs_diff += (sum < 0 ? -sum : sum); \
180 *temp_row2++ = accum_a; \
185 temp_type threshold = (temp_type)total * config.threshold / THRESHOLD_SCALAR; \
186 /* printf("total=%lld threshold=%lld abs_diff=%lld\n", total, threshold, abs_diff); */ \
187 if(abs_diff > threshold || !config.adaptive) \
189 output->copy_from(temp); \
190 changed_rows = 240; \
194 output->copy_from(input); \
200 #define DEINTERLACE_AVG_MACRO(type, temp_type, components) \
202 int w = input->get_w(); \
203 int h = input->get_h(); \
205 for(int i = 0; i < h - 1; i += 2) \
207 type *input_row1 = (type*)input->get_rows()[i]; \
208 type *input_row2 = (type*)input->get_rows()[i + 1]; \
209 type *output_row1 = (type*)output->get_rows()[i]; \
210 type *output_row2 = (type*)output->get_rows()[i + 1]; \
213 for(int j = 0; j < w * components; j++) \
215 result = ((temp_type)input_row1[j] + input_row2[j]) / 2; \
216 output_row1[j] = result; \
217 output_row2[j] = result; \
222 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
224 int w = input->get_w(); \
225 int h = input->get_h(); \
227 for(int i = dominance; i < h - 1; i += 2) \
229 type *input_row1 = (type*)input->get_rows()[i]; \
230 type *input_row2 = (type*)input->get_rows()[i + 1]; \
231 type *output_row1 = (type*)output->get_rows()[i]; \
232 type *output_row2 = (type*)output->get_rows()[i + 1]; \
235 for(int j = 0; j < w * components; j++) \
237 temp1 = input_row1[j]; \
238 temp2 = input_row2[j]; \
239 output_row1[j] = temp2; \
240 output_row2[j] = temp1; \
246 #define DEINTERLACE_TEMPORALSWAP_MACRO(type, components, dominance) \
248 int w = input->get_w(); \
249 int h = input->get_h(); \
251 for(int i = 0; i < h - 1; i += 2) \
255 type *output_row1 = (type*)output->get_rows()[i]; \
256 type *output_row2 = (type*)output->get_rows()[i + 1]; \
260 input_row1 = (type*)input->get_rows()[i]; \
261 input_row2 = (type*)prevframe->get_rows()[i+1]; \
264 input_row1 = (type*)prevframe->get_rows()[i]; \
265 input_row2 = (type*)input->get_rows()[i+1]; \
268 for(int j = 0; j < w * components; j++) \
270 temp1 = input_row1[j]; \
271 temp2 = input_row2[j]; \
272 output_row1[j] = temp1; \
273 output_row2[j] = temp2; \
279 /* Bob & Weave deinterlacer:
282 if it's similar to the previous frame
284 else average with line above and below
286 Similar is defined as in abs(difference)/(sum) < threshold
288 // cplr warns, #define FABS(a) (((a)<0)?(0-(a)):(a))
289 static inline int FABS(int8_t v) { return v<0 ? -v : v; }
290 static inline int FABS(uint8_t v) { return v; }
291 static inline int FABS(int16_t v) { return v<0 ? -v : v; }
292 static inline int FABS(uint16_t v) { return v; }
293 static inline int FABS(int32_t v) { return v<0 ? -v : v; }
294 static inline int64_t FABS(uint32_t v) { return v; }
295 static inline int64_t FABS(int64_t v) { return v<0 ? -v : v; }
296 static inline int64_t FABS(uint64_t v) { return v; }
297 static inline float FABS(float v) { return v<0 ? -v : v; }
298 static inline double FABS(double v) { return v<0 ? -v : v; }
299 #define FMAX(a,b) (((a)>(b))?(a):(b))
300 #define FMIN(a,b) (((a)<(b))?(a):(b))
302 #define SQ(a) ((a)*(a))
303 // threshold < 100 -> a-b/a+b <
306 #define DEINTERLACE_BOBWEAVE_MACRO(type, temp_type, components, dominance, threshold, noise_threshold) \
308 /* Ooooohh, I like fudge factors */ \
309 double exp_threshold=exp(((double)threshold - 50 )/2);\
310 int w = input->get_w(); \
311 int h = input->get_h(); \
312 type *row_above=(type*)input->get_rows()[0]; \
313 for(int i = dominance ?0:1; i < h - 1; i += 2) \
318 type *output_row1 = (type*)output->get_rows()[i]; \
319 type *output_row2 = (type*)output->get_rows()[i + 1]; \
320 temp_type pixel, below, old, above; \
322 input_row = (type*)input->get_rows()[i]; \
323 input_row2 = (type*)input->get_rows()[i+1]; \
324 old_row = (type*)prevframe->get_rows()[i]; \
326 for(int j = 0; j < w * components; j++) \
328 pixel = input_row[j]; \
329 below = input_row2[j]; \
331 above = row_above[j]; \
333 if ( ( FABS(pixel-old) <= noise_threshold ) \
334 || ((pixel+old != 0) && (((FABS((double) pixel-old))/((double) pixel+old)) >= exp_threshold )) \
335 || ((above+below != 0) && (((FABS((double) pixel-old))/((double) above+below)) >= exp_threshold )) \
337 pixel=(above+below)/2 ;\
339 output_row1[j] = pixel; \
340 output_row2[j] = below; \
342 row_above=input_row2; \
347 void DeInterlaceMain::deinterlace_top(VFrame *input, VFrame *output, int dominance)
349 switch(input->get_color_model())
353 DEINTERLACE_TOP_MACRO(unsigned char, 3, dominance);
356 DEINTERLACE_TOP_MACRO(float, 3, dominance);
360 DEINTERLACE_TOP_MACRO(unsigned char, 4, dominance);
363 DEINTERLACE_TOP_MACRO(float, 4, dominance);
367 DEINTERLACE_TOP_MACRO(uint16_t, 3, dominance);
369 case BC_RGBA16161616:
370 case BC_YUVA16161616:
371 DEINTERLACE_TOP_MACRO(uint16_t, 4, dominance);
376 void DeInterlaceMain::deinterlace_avg_top(VFrame *input, VFrame *output, int dominance)
378 switch(input->get_color_model())
382 DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 3, dominance);
385 DEINTERLACE_AVG_TOP_MACRO(float, double, 3, dominance);
389 DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 4, dominance);
392 DEINTERLACE_AVG_TOP_MACRO(float, double, 4, dominance);
396 DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 3, dominance);
398 case BC_RGBA16161616:
399 case BC_YUVA16161616:
400 DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 4, dominance);
405 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
407 switch(input->get_color_model())
411 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 3);
414 DEINTERLACE_AVG_MACRO(float, double, 3);
418 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 4);
421 DEINTERLACE_AVG_MACRO(float, double, 4);
425 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 3);
427 case BC_RGBA16161616:
428 case BC_YUVA16161616:
429 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 4);
434 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
436 switch(input->get_color_model())
440 DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
443 DEINTERLACE_SWAP_MACRO(float, 3, dominance);
447 DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
450 DEINTERLACE_SWAP_MACRO(float, 4, dominance);
454 DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
456 case BC_RGBA16161616:
457 case BC_YUVA16161616:
458 DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
463 void DeInterlaceMain::deinterlace_temporalswap(VFrame *input, VFrame *prevframe, VFrame *output, int dominance)
465 switch(input->get_color_model())
469 DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 3, dominance);
472 DEINTERLACE_TEMPORALSWAP_MACRO(float, 3, dominance);
476 DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 4, dominance);
479 DEINTERLACE_TEMPORALSWAP_MACRO(float, 4, dominance);
483 DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 3, dominance);
485 case BC_RGBA16161616:
486 case BC_YUVA16161616:
487 DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 4, dominance);
492 void DeInterlaceMain::deinterlace_bobweave(VFrame *input, VFrame *prevframe, VFrame *output, int dominance)
494 int threshold=config.threshold;
495 int noise_threshold=0;
497 switch(input->get_color_model())
501 DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 3, dominance, threshold, noise_threshold);
504 DEINTERLACE_BOBWEAVE_MACRO(float, double, 3, dominance, threshold, noise_threshold);
508 DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 4, dominance, threshold, noise_threshold);
511 DEINTERLACE_BOBWEAVE_MACRO(float, double, 4, dominance, threshold, noise_threshold);
515 DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 3, dominance, threshold, noise_threshold);
517 case BC_RGBA16161616:
518 case BC_YUVA16161616:
519 DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 4, dominance, threshold, noise_threshold);
525 int DeInterlaceMain::process_buffer(VFrame *frame,
526 int64_t start_position,
529 changed_rows = frame->get_h();
530 load_configuration();
533 read_frame(frame, 0, start_position, frame_rate, 0);
535 // Temp was used for adaptive deinterlacing where it took deinterlacing
536 // an entire frame to decide if the deinterlaced output should be used.
540 // temp = new VFrame(frame->get_w(), frame->get_h(),
541 // frame->get_color_model(), 0);
543 temp_prevframe = new VFrame(frame->get_w(), frame->get_h(),
544 frame->get_color_model(), 0);
548 case DEINTERLACE_NONE:
549 // output->copy_from(input);
551 case DEINTERLACE_KEEP:
552 deinterlace_top(frame, frame, config.dominance);
554 case DEINTERLACE_AVG:
555 deinterlace_avg(frame, frame);
557 case DEINTERLACE_AVG_1F:
558 deinterlace_avg_top(frame, frame, config.dominance);
560 case DEINTERLACE_SWAP:
561 deinterlace_swap(frame, frame, config.dominance);
563 case DEINTERLACE_BOBWEAVE:
564 if (get_source_position()==0)
565 read_frame(temp_prevframe,0, get_source_position(), get_framerate(), 0);
567 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate(), 0);
568 deinterlace_bobweave(frame, temp_prevframe, frame, config.dominance);
570 case DEINTERLACE_TEMPORALSWAP:
571 if (get_source_position()==0)
572 read_frame(temp_prevframe,0, get_source_position(), get_framerate(), 0);
574 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate(), 0);
575 deinterlace_temporalswap(frame, temp_prevframe, frame, config.dominance);
578 send_render_gui(&changed_rows);
583 void DeInterlaceMain::render_gui(void *data)
587 thread->window->lock_window();
588 char string[BCTEXTLEN];
589 DeInterlaceWindow *window = (DeInterlaceWindow *)thread->window;
590 window->get_status_string(string, *(int*)data);
591 window->status->update(string);
593 window->unlock_window();
597 NEW_WINDOW_MACRO(DeInterlaceMain, DeInterlaceWindow)
598 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
602 void DeInterlaceMain::save_data(KeyFrame *keyframe)
605 output.set_shared_output(keyframe->xbuf);
606 output.tag.set_title("DEINTERLACE");
607 output.tag.set_property("MODE", config.mode);
608 output.tag.set_property("DOMINANCE", config.dominance);
609 output.tag.set_property("ADAPTIVE", config.adaptive);
610 output.tag.set_property("THRESHOLD", config.threshold);
612 output.tag.set_title("/DEINTERLACE");
614 output.terminate_string();
617 void DeInterlaceMain::read_data(KeyFrame *keyframe)
620 input.set_shared_input(keyframe->xbuf);
622 while(!input.read_tag())
624 if(input.tag.title_is("DEINTERLACE"))
626 config.mode = input.tag.get_property("MODE", config.mode);
627 config.dominance = input.tag.get_property("DOMINANCE", config.dominance);
628 config.adaptive = input.tag.get_property("ADAPTIVE", config.adaptive);
629 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
635 void DeInterlaceMain::update_gui()
639 load_configuration();
640 DeInterlaceWindow *window = (DeInterlaceWindow *)thread->window;
641 window->lock_window();
642 window->set_mode(config.mode, 1);
643 if (window->dominance_top)
644 window->dominance_top->update(config.dominance?0:BC_Toggle::TOGGLE_CHECKED);
645 if (window->dominance_bottom)
646 window->dominance_bottom->update(config.dominance?BC_Toggle::TOGGLE_CHECKED:0);
647 if (window->adaptive)
648 window->adaptive->update(config.adaptive);
649 if (window->threshold)
650 window->threshold->update(config.threshold);
651 window->unlock_window();