3 #include "deinterlace.h"
4 #include "deinterwindow.h"
23 REGISTER_PLUGIN(DeInterlaceMain)
28 DeInterlaceConfig::DeInterlaceConfig()
30 mode = DEINTERLACE_AVG;
36 int DeInterlaceConfig::equivalent(DeInterlaceConfig &that)
38 return mode == that.mode &&
39 dominance == that.dominance &&
40 adaptive == that.adaptive &&
41 threshold == that.threshold;
44 void DeInterlaceConfig::copy_from(DeInterlaceConfig &that)
47 dominance = that.dominance;
48 adaptive = that.adaptive;
49 threshold = that.threshold;
52 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev,
53 DeInterlaceConfig &next,
56 int64_t current_frame)
64 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
65 : PluginVClient(server)
67 PLUGIN_CONSTRUCTOR_MACRO
72 DeInterlaceMain::~DeInterlaceMain()
74 PLUGIN_DESTRUCTOR_MACRO
76 if(temp_prevframe) delete temp_prevframe;
79 char* DeInterlaceMain::plugin_title() { return N_("Deinterlace"); }
80 int DeInterlaceMain::is_realtime() { return 1; }
84 #define DEINTERLACE_TOP_MACRO(type, components, dominance) \
86 int w = input->get_w(); \
87 int h = input->get_h(); \
89 for(int i = 0; i < h - 1; i += 2) \
91 type *input_row = (type*)input->get_rows()[dominance ? i + 1 : i]; \
92 type *output_row1 = (type*)output->get_rows()[i]; \
93 type *output_row2 = (type*)output->get_rows()[i + 1]; \
94 memcpy(output_row1, input_row, w * components * sizeof(type)); \
95 memcpy(output_row2, input_row, w * components * sizeof(type)); \
99 #define DEINTERLACE_AVG_TOP_MACRO(type, temp_type, components, dominance) \
101 int w = input->get_w(); \
102 int h = input->get_h(); \
105 type **in_rows = (type**)input->get_rows(); \
106 type **out_rows = (type**)temp->get_rows(); \
108 temp_type abs_diff = 0, total = 0; \
110 for(int i = 0; i < max_h; i += 2) \
112 int in_number1 = dominance ? i - 1 : i + 0; \
113 int in_number2 = dominance ? i + 1 : i + 2; \
114 int out_number1 = dominance ? i - 1 : i; \
115 int out_number2 = dominance ? i : i + 1; \
116 in_number1 = MAX(in_number1, 0); \
117 in_number2 = MIN(in_number2, max_h); \
118 out_number1 = MAX(out_number1, 0); \
119 out_number2 = MIN(out_number2, max_h); \
121 type *input_row1 = in_rows[in_number1]; \
122 type *input_row2 = in_rows[in_number2]; \
123 type *input_row3 = in_rows[out_number2]; \
124 type *temp_row1 = out_rows[out_number1]; \
125 type *temp_row2 = out_rows[out_number2]; \
127 temp_type accum_r, accum_b, accum_g, accum_a; \
129 memcpy(temp_row1, input_row1, w * components * sizeof(type)); \
130 for(int j = 0; j < w; j++) \
132 accum_r = (*input_row1++) + (*input_row2++); \
133 accum_g = (*input_row1++) + (*input_row2++); \
134 accum_b = (*input_row1++) + (*input_row2++); \
135 if(components == 4) \
136 accum_a = (*input_row1++) + (*input_row2++); \
142 total += *input_row3; \
143 sum = ((temp_type)*input_row3++) - accum_r; \
144 abs_diff += (sum < 0 ? -sum : sum); \
145 *temp_row2++ = accum_r; \
147 total += *input_row3; \
148 sum = ((temp_type)*input_row3++) - accum_g; \
149 abs_diff += (sum < 0 ? -sum : sum); \
150 *temp_row2++ = accum_g; \
152 total += *input_row3; \
153 sum = ((temp_type)*input_row3++) - accum_b; \
154 abs_diff += (sum < 0 ? -sum : sum); \
155 *temp_row2++ = accum_b; \
157 if(components == 4) \
159 total += *input_row3; \
160 sum = ((temp_type)*input_row3++) - accum_a; \
161 abs_diff += (sum < 0 ? -sum : sum); \
162 *temp_row2++ = accum_a; \
167 temp_type threshold = (temp_type)total * config.threshold / THRESHOLD_SCALAR; \
168 /* printf("total=%lld threshold=%lld abs_diff=%lld\n", total, threshold, abs_diff); */ \
169 if(abs_diff > threshold || !config.adaptive) \
171 output->copy_from(temp); \
172 changed_rows = 240; \
176 output->copy_from(input); \
182 #define DEINTERLACE_AVG_MACRO(type, temp_type, components) \
184 int w = input->get_w(); \
185 int h = input->get_h(); \
187 for(int i = 0; i < h - 1; i += 2) \
189 type *input_row1 = (type*)input->get_rows()[i]; \
190 type *input_row2 = (type*)input->get_rows()[i + 1]; \
191 type *output_row1 = (type*)output->get_rows()[i]; \
192 type *output_row2 = (type*)output->get_rows()[i + 1]; \
195 for(int j = 0; j < w * components; j++) \
197 result = ((temp_type)input_row1[j] + input_row2[j]) / 2; \
198 output_row1[j] = result; \
199 output_row2[j] = result; \
204 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
206 int w = input->get_w(); \
207 int h = input->get_h(); \
209 for(int i = dominance; i < h - 1; i += 2) \
211 type *input_row1 = (type*)input->get_rows()[i]; \
212 type *input_row2 = (type*)input->get_rows()[i + 1]; \
213 type *output_row1 = (type*)output->get_rows()[i]; \
214 type *output_row2 = (type*)output->get_rows()[i + 1]; \
217 for(int j = 0; j < w * components; j++) \
219 temp1 = input_row1[j]; \
220 temp2 = input_row2[j]; \
221 output_row1[j] = temp2; \
222 output_row2[j] = temp1; \
228 #define DEINTERLACE_TEMPORALSWAP_MACRO(type, components, dominance) \
230 int w = input->get_w(); \
231 int h = input->get_h(); \
233 for(int i = 0; i < h - 1; i += 2) \
237 type *output_row1 = (type*)output->get_rows()[i]; \
238 type *output_row2 = (type*)output->get_rows()[i + 1]; \
242 input_row1 = (type*)input->get_rows()[i]; \
243 input_row2 = (type*)prevframe->get_rows()[i+1]; \
246 input_row1 = (type*)prevframe->get_rows()[i]; \
247 input_row2 = (type*)input->get_rows()[i+1]; \
250 for(int j = 0; j < w * components; j++) \
252 temp1 = input_row1[j]; \
253 temp2 = input_row2[j]; \
254 output_row1[j] = temp1; \
255 output_row2[j] = temp2; \
261 /* Bob & Weave deinterlacer:
264 if it's similar to the previous frame
266 else average with line above and below
268 Similar is defined as in abs(difference)/(sum) < threshold
270 #define FABS(a) (((a)<0)?(0-(a)):(a))
271 #define FMAX(a,b) (((a)>(b))?(a):(b))
272 #define FMIN(a,b) (((a)<(b))?(a):(b))
274 #define SQ(a) ((a)*(a))
275 // threshold < 100 -> a-b/a+b <
278 #define DEINTERLACE_BOBWEAVE_MACRO(type, temp_type, components, dominance, threshold, noise_threshold) \
280 /* Ooooohh, I like fudge factors */ \
281 double exp_threshold=exp(((double)threshold - 50 )/2);\
282 int w = input->get_w(); \
283 int h = input->get_h(); \
284 type *row_above=(type*)input->get_rows()[0]; \
285 for(int i = dominance ?0:1; i < h - 1; i += 2) \
290 type *output_row1 = (type*)output->get_rows()[i]; \
291 type *output_row2 = (type*)output->get_rows()[i + 1]; \
292 temp_type pixel, below, old, above; \
294 input_row = (type*)input->get_rows()[i]; \
295 input_row2 = (type*)input->get_rows()[i+1]; \
296 old_row = (type*)prevframe->get_rows()[i]; \
298 for(int j = 0; j < w * components; j++) \
300 pixel = input_row[j]; \
301 below = input_row2[j]; \
303 above = row_above[j]; \
305 if ( ( FABS(pixel-old) <= noise_threshold ) \
306 || ((pixel+old != 0) && (((FABS((double) pixel-old))/((double) pixel+old)) >= exp_threshold )) \
307 || ((above+below != 0) && (((FABS((double) pixel-old))/((double) above+below)) >= exp_threshold )) \
309 pixel=(above+below)/2 ;\
311 output_row1[j] = pixel; \
312 output_row2[j] = below; \
314 row_above=input_row2; \
319 void DeInterlaceMain::deinterlace_top(VFrame *input, VFrame *output, int dominance)
321 switch(input->get_color_model())
325 DEINTERLACE_TOP_MACRO(unsigned char, 3, dominance);
328 DEINTERLACE_TOP_MACRO(float, 3, dominance);
332 DEINTERLACE_TOP_MACRO(unsigned char, 4, dominance);
335 DEINTERLACE_TOP_MACRO(float, 4, dominance);
339 DEINTERLACE_TOP_MACRO(uint16_t, 3, dominance);
341 case BC_RGBA16161616:
342 case BC_YUVA16161616:
343 DEINTERLACE_TOP_MACRO(uint16_t, 4, dominance);
348 void DeInterlaceMain::deinterlace_avg_top(VFrame *input, VFrame *output, int dominance)
350 switch(input->get_color_model())
354 DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 3, dominance);
357 DEINTERLACE_AVG_TOP_MACRO(float, double, 3, dominance);
361 DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 4, dominance);
364 DEINTERLACE_AVG_TOP_MACRO(float, double, 4, dominance);
368 DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 3, dominance);
370 case BC_RGBA16161616:
371 case BC_YUVA16161616:
372 DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 4, dominance);
377 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
379 switch(input->get_color_model())
383 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 3);
386 DEINTERLACE_AVG_MACRO(float, double, 3);
390 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 4);
393 DEINTERLACE_AVG_MACRO(float, double, 4);
397 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 3);
399 case BC_RGBA16161616:
400 case BC_YUVA16161616:
401 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 4);
406 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
408 switch(input->get_color_model())
412 DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
415 DEINTERLACE_SWAP_MACRO(float, 3, dominance);
419 DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
422 DEINTERLACE_SWAP_MACRO(float, 4, dominance);
426 DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
428 case BC_RGBA16161616:
429 case BC_YUVA16161616:
430 DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
435 void DeInterlaceMain::deinterlace_temporalswap(VFrame *input, VFrame *prevframe, VFrame *output, int dominance)
437 switch(input->get_color_model())
441 DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 3, dominance);
444 DEINTERLACE_TEMPORALSWAP_MACRO(float, 3, dominance);
448 DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 4, dominance);
451 DEINTERLACE_TEMPORALSWAP_MACRO(float, 4, dominance);
455 DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 3, dominance);
457 case BC_RGBA16161616:
458 case BC_YUVA16161616:
459 DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 4, dominance);
464 void DeInterlaceMain::deinterlace_bobweave(VFrame *input, VFrame *prevframe, VFrame *output, int dominance)
466 int threshold=config.threshold;
467 int noise_threshold=0;
469 switch(input->get_color_model())
473 DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 3, dominance, threshold, noise_threshold);
476 DEINTERLACE_BOBWEAVE_MACRO(float, double, 3, dominance, threshold, noise_threshold);
480 DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 4, dominance, threshold, noise_threshold);
483 DEINTERLACE_BOBWEAVE_MACRO(float, double, 4, dominance, threshold, noise_threshold);
487 DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 3, dominance, threshold, noise_threshold);
489 case BC_RGBA16161616:
490 case BC_YUVA16161616:
491 DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 4, dominance, threshold, noise_threshold);
497 int DeInterlaceMain::process_buffer(VFrame *frame,
498 int64_t start_position,
501 changed_rows = frame->get_h();
502 load_configuration();
510 // Temp was used for adaptive deinterlacing where it took deinterlacing
511 // an entire frame to decide if the deinterlaced output should be used.
515 // temp = new VFrame(0,
518 // frame->get_color_model());
520 temp_prevframe = new VFrame(0,
523 frame->get_color_model());
527 case DEINTERLACE_NONE:
528 // output->copy_from(input);
530 case DEINTERLACE_KEEP:
531 deinterlace_top(frame, frame, config.dominance);
533 case DEINTERLACE_AVG:
534 deinterlace_avg(frame, frame);
536 case DEINTERLACE_AVG_1F:
537 deinterlace_avg_top(frame, frame, config.dominance);
539 case DEINTERLACE_SWAP:
540 deinterlace_swap(frame, frame, config.dominance);
542 case DEINTERLACE_BOBWEAVE:
543 if (get_source_position()==0)
544 read_frame(temp_prevframe,0, get_source_position(), get_framerate());
546 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate());
547 deinterlace_bobweave(frame, temp_prevframe, frame, config.dominance);
549 case DEINTERLACE_TEMPORALSWAP:
550 if (get_source_position()==0)
551 read_frame(temp_prevframe,0, get_source_position(), get_framerate());
553 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate());
554 deinterlace_temporalswap(frame, temp_prevframe, frame, config.dominance);
557 send_render_gui(&changed_rows);
562 void DeInterlaceMain::render_gui(void *data)
566 thread->window->lock_window();
567 char string[BCTEXTLEN];
568 thread->window->get_status_string(string, *(int*)data);
569 thread->window->status->update(string);
570 thread->window->flush();
571 thread->window->unlock_window();
575 SHOW_GUI_MACRO(DeInterlaceMain, DeInterlaceThread)
576 RAISE_WINDOW_MACRO(DeInterlaceMain)
577 SET_STRING_MACRO(DeInterlaceMain)
578 NEW_PICON_MACRO(DeInterlaceMain)
579 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
582 int DeInterlaceMain::load_defaults()
584 char directory[BCTEXTLEN], string[BCTEXTLEN];
585 sprintf(directory, "%sdeinterlace.rc", BCASTDIR);
587 defaults = new BC_Hash(directory);
589 config.mode = defaults->get("MODE", config.mode);
590 config.dominance = defaults->get("DOMINANCE", config.dominance);
591 config.adaptive = defaults->get("ADAPTIVE", config.adaptive);
592 config.threshold = defaults->get("THRESHOLD", config.threshold);
597 int DeInterlaceMain::save_defaults()
599 defaults->update("MODE", config.mode);
600 defaults->update("DOMINANCE", config.dominance);
601 defaults->update("ADAPTIVE", config.adaptive);
602 defaults->update("THRESHOLD", config.threshold);
607 void DeInterlaceMain::save_data(KeyFrame *keyframe)
610 output.set_shared_string(keyframe->data, MESSAGESIZE);
611 output.tag.set_title("DEINTERLACE");
612 output.tag.set_property("MODE", config.mode);
613 output.tag.set_property("DOMINANCE", config.dominance);
614 output.tag.set_property("ADAPTIVE", config.adaptive);
615 output.tag.set_property("THRESHOLD", config.threshold);
617 output.terminate_string();
620 void DeInterlaceMain::read_data(KeyFrame *keyframe)
623 input.set_shared_string(keyframe->data, strlen(keyframe->data));
625 while(!input.read_tag())
627 if(input.tag.title_is("DEINTERLACE"))
629 config.mode = input.tag.get_property("MODE", config.mode);
630 config.dominance = input.tag.get_property("DOMINANCE", config.dominance);
631 config.adaptive = input.tag.get_property("ADAPTIVE", config.adaptive);
632 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
638 void DeInterlaceMain::update_gui()
642 load_configuration();
643 thread->window->lock_window();
644 thread->window->set_mode(config.mode, 1);
645 if (thread->window->dominance_top)
646 thread->window->dominance_top->update(config.dominance?0:BC_Toggle::TOGGLE_CHECKED);
647 if (thread->window->dominance_bottom)
648 thread->window->dominance_bottom->update(config.dominance?BC_Toggle::TOGGLE_CHECKED:0);
649 if (thread->window->adaptive)
650 thread->window->adaptive->update(config.adaptive);
651 if (thread->window->threshold)
652 thread->window->threshold->update(config.threshold);
653 thread->window->unlock_window();