4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "deinterlace-cv.h"
26 #include "deinterwindow-cv.h"
44 REGISTER_PLUGIN(DeInterlaceMain)
49 DeInterlaceConfig::DeInterlaceConfig()
51 mode = DEINTERLACE_AVG;
57 int DeInterlaceConfig::equivalent(DeInterlaceConfig &that)
59 return mode == that.mode &&
60 dominance == that.dominance &&
61 adaptive == that.adaptive &&
62 threshold == that.threshold;
65 void DeInterlaceConfig::copy_from(DeInterlaceConfig &that)
68 dominance = that.dominance;
69 adaptive = that.adaptive;
70 threshold = that.threshold;
73 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev,
74 DeInterlaceConfig &next,
77 int64_t current_frame)
85 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
86 : PluginVClient(server)
92 DeInterlaceMain::~DeInterlaceMain()
94 // if(temp) delete temp;
95 if(temp_prevframe) delete temp_prevframe;
98 const char* DeInterlaceMain::plugin_title() { return N_("Deinterlace-CV"); }
99 int DeInterlaceMain::is_realtime() { return 1; }
103 #define DEINTERLACE_TOP_MACRO(type, components, dominance) \
105 int w = input->get_w(); \
106 int h = input->get_h(); \
108 for(int i = 0; i < h - 1; i += 2) \
110 type *input_row = (type*)input->get_rows()[dominance ? i + 1 : i]; \
111 type *output_row1 = (type*)output->get_rows()[i]; \
112 type *output_row2 = (type*)output->get_rows()[i + 1]; \
113 memcpy(output_row1, input_row, w * components * sizeof(type)); \
114 memcpy(output_row2, input_row, w * components * sizeof(type)); \
118 #define DEINTERLACE_AVG_TOP_MACRO(type, temp_type, components, dominance) \
120 int w = input->get_w(); \
121 int h = input->get_h(); \
124 type **in_rows = (type**)input->get_rows(); \
125 type **out_rows = (type**)temp->get_rows(); \
127 temp_type abs_diff = 0, total = 0; \
129 for(int i = 0; i < max_h; i += 2) \
131 int in_number1 = dominance ? i - 1 : i + 0; \
132 int in_number2 = dominance ? i + 1 : i + 2; \
133 int out_number1 = dominance ? i - 1 : i; \
134 int out_number2 = dominance ? i : i + 1; \
135 in_number1 = MAX(in_number1, 0); \
136 in_number2 = MIN(in_number2, max_h); \
137 out_number1 = MAX(out_number1, 0); \
138 out_number2 = MIN(out_number2, max_h); \
140 type *input_row1 = in_rows[in_number1]; \
141 type *input_row2 = in_rows[in_number2]; \
142 type *input_row3 = in_rows[out_number2]; \
143 type *temp_row1 = out_rows[out_number1]; \
144 type *temp_row2 = out_rows[out_number2]; \
146 temp_type accum_r, accum_b, accum_g, accum_a; \
148 memcpy(temp_row1, input_row1, w * components * sizeof(type)); \
149 for(int j = 0; j < w; j++) \
151 accum_r = (*input_row1++) + (*input_row2++); \
152 accum_g = (*input_row1++) + (*input_row2++); \
153 accum_b = (*input_row1++) + (*input_row2++); \
154 if(components == 4) \
155 accum_a = (*input_row1++) + (*input_row2++); \
161 total += *input_row3; \
162 sum = ((temp_type)*input_row3++) - accum_r; \
163 abs_diff += (sum < 0 ? -sum : sum); \
164 *temp_row2++ = accum_r; \
166 total += *input_row3; \
167 sum = ((temp_type)*input_row3++) - accum_g; \
168 abs_diff += (sum < 0 ? -sum : sum); \
169 *temp_row2++ = accum_g; \
171 total += *input_row3; \
172 sum = ((temp_type)*input_row3++) - accum_b; \
173 abs_diff += (sum < 0 ? -sum : sum); \
174 *temp_row2++ = accum_b; \
176 if(components == 4) \
178 total += *input_row3; \
179 sum = ((temp_type)*input_row3++) - accum_a; \
180 abs_diff += (sum < 0 ? -sum : sum); \
181 *temp_row2++ = accum_a; \
186 temp_type threshold = (temp_type)total * config.threshold / THRESHOLD_SCALAR; \
187 /* printf("total=%lld threshold=%lld abs_diff=%lld\n", total, threshold, abs_diff); */ \
188 if(abs_diff > threshold || !config.adaptive) \
190 output->copy_from(temp); \
191 changed_rows = 240; \
195 output->copy_from(input); \
201 #define DEINTERLACE_AVG_MACRO(type, temp_type, components) \
203 int w = input->get_w(); \
204 int h = input->get_h(); \
206 for(int i = 0; i < h - 1; i += 2) \
208 type *input_row1 = (type*)input->get_rows()[i]; \
209 type *input_row2 = (type*)input->get_rows()[i + 1]; \
210 type *output_row1 = (type*)output->get_rows()[i]; \
211 type *output_row2 = (type*)output->get_rows()[i + 1]; \
214 for(int j = 0; j < w * components; j++) \
216 result = ((temp_type)input_row1[j] + input_row2[j]) / 2; \
217 output_row1[j] = result; \
218 output_row2[j] = result; \
223 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
225 int w = input->get_w(); \
226 int h = input->get_h(); \
228 for(int i = dominance; i < h - 1; i += 2) \
230 type *input_row1 = (type*)input->get_rows()[i]; \
231 type *input_row2 = (type*)input->get_rows()[i + 1]; \
232 type *output_row1 = (type*)output->get_rows()[i]; \
233 type *output_row2 = (type*)output->get_rows()[i + 1]; \
236 for(int j = 0; j < w * components; j++) \
238 temp1 = input_row1[j]; \
239 temp2 = input_row2[j]; \
240 output_row1[j] = temp2; \
241 output_row2[j] = temp1; \
247 #define DEINTERLACE_TEMPORALSWAP_MACRO(type, components, dominance) \
249 int w = input->get_w(); \
250 int h = input->get_h(); \
252 for(int i = 0; i < h - 1; i += 2) \
256 type *output_row1 = (type*)output->get_rows()[i]; \
257 type *output_row2 = (type*)output->get_rows()[i + 1]; \
261 input_row1 = (type*)input->get_rows()[i]; \
262 input_row2 = (type*)prevframe->get_rows()[i+1]; \
265 input_row1 = (type*)prevframe->get_rows()[i]; \
266 input_row2 = (type*)input->get_rows()[i+1]; \
269 for(int j = 0; j < w * components; j++) \
271 temp1 = input_row1[j]; \
272 temp2 = input_row2[j]; \
273 output_row1[j] = temp1; \
274 output_row2[j] = temp2; \
280 /* Bob & Weave deinterlacer:
283 if it's similar to the previous frame
285 else average with line above and below
287 Similar is defined as in abs(difference)/(sum) < threshold
289 // cplr warns, #define FABS(a) (((a)<0)?(0-(a)):(a))
290 static inline int FABS(int8_t v) { return v<0 ? -v : v; }
291 static inline int FABS(uint8_t v) { return v; }
292 static inline int FABS(int16_t v) { return v<0 ? -v : v; }
293 static inline int FABS(uint16_t v) { return v; }
294 static inline int FABS(int32_t v) { return v<0 ? -v : v; }
295 static inline int64_t FABS(uint32_t v) { return v; }
296 static inline int64_t FABS(int64_t v) { return v<0 ? -v : v; }
297 static inline int64_t FABS(uint64_t v) { return v; }
298 static inline float FABS(float v) { return v<0 ? -v : v; }
299 static inline double FABS(double v) { return v<0 ? -v : v; }
300 #define FMAX(a,b) (((a)>(b))?(a):(b))
301 #define FMIN(a,b) (((a)<(b))?(a):(b))
303 #define SQ(a) ((a)*(a))
304 // threshold < 100 -> a-b/a+b <
307 #define DEINTERLACE_BOBWEAVE_MACRO(type, temp_type, components, dominance, threshold, noise_threshold) \
309 /* Ooooohh, I like fudge factors */ \
310 double exp_threshold=exp(((double)threshold - 50 )/2);\
311 int w = input->get_w(); \
312 int h = input->get_h(); \
313 type *row_above=(type*)input->get_rows()[0]; \
314 for(int i = dominance ?0:1; i < h - 1; i += 2) \
319 type *output_row1 = (type*)output->get_rows()[i]; \
320 type *output_row2 = (type*)output->get_rows()[i + 1]; \
321 temp_type pixel, below, old, above; \
323 input_row = (type*)input->get_rows()[i]; \
324 input_row2 = (type*)input->get_rows()[i+1]; \
325 old_row = (type*)prevframe->get_rows()[i]; \
327 for(int j = 0; j < w * components; j++) \
329 pixel = input_row[j]; \
330 below = input_row2[j]; \
332 above = row_above[j]; \
334 if ( ( FABS(pixel-old) <= noise_threshold ) \
335 || ((pixel+old != 0) && (((FABS((double) pixel-old))/((double) pixel+old)) >= exp_threshold )) \
336 || ((above+below != 0) && (((FABS((double) pixel-old))/((double) above+below)) >= exp_threshold )) \
338 pixel=(above+below)/2 ;\
340 output_row1[j] = pixel; \
341 output_row2[j] = below; \
343 row_above=input_row2; \
348 void DeInterlaceMain::deinterlace_top(VFrame *input, VFrame *output, int dominance)
350 switch(input->get_color_model())
354 DEINTERLACE_TOP_MACRO(unsigned char, 3, dominance);
357 DEINTERLACE_TOP_MACRO(float, 3, dominance);
361 DEINTERLACE_TOP_MACRO(unsigned char, 4, dominance);
364 DEINTERLACE_TOP_MACRO(float, 4, dominance);
368 DEINTERLACE_TOP_MACRO(uint16_t, 3, dominance);
370 case BC_RGBA16161616:
371 case BC_YUVA16161616:
372 DEINTERLACE_TOP_MACRO(uint16_t, 4, dominance);
377 void DeInterlaceMain::deinterlace_avg_top(VFrame *input, VFrame *output, int dominance)
379 switch(input->get_color_model())
383 DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 3, dominance);
386 DEINTERLACE_AVG_TOP_MACRO(float, double, 3, dominance);
390 DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 4, dominance);
393 DEINTERLACE_AVG_TOP_MACRO(float, double, 4, dominance);
397 DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 3, dominance);
399 case BC_RGBA16161616:
400 case BC_YUVA16161616:
401 DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 4, dominance);
406 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
408 switch(input->get_color_model())
412 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 3);
415 DEINTERLACE_AVG_MACRO(float, double, 3);
419 DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 4);
422 DEINTERLACE_AVG_MACRO(float, double, 4);
426 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 3);
428 case BC_RGBA16161616:
429 case BC_YUVA16161616:
430 DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 4);
435 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
437 switch(input->get_color_model())
441 DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
444 DEINTERLACE_SWAP_MACRO(float, 3, dominance);
448 DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
451 DEINTERLACE_SWAP_MACRO(float, 4, dominance);
455 DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
457 case BC_RGBA16161616:
458 case BC_YUVA16161616:
459 DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
464 void DeInterlaceMain::deinterlace_temporalswap(VFrame *input, VFrame *prevframe, VFrame *output, int dominance)
466 switch(input->get_color_model())
470 DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 3, dominance);
473 DEINTERLACE_TEMPORALSWAP_MACRO(float, 3, dominance);
477 DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 4, dominance);
480 DEINTERLACE_TEMPORALSWAP_MACRO(float, 4, dominance);
484 DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 3, dominance);
486 case BC_RGBA16161616:
487 case BC_YUVA16161616:
488 DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 4, dominance);
493 void DeInterlaceMain::deinterlace_bobweave(VFrame *input, VFrame *prevframe, VFrame *output, int dominance)
495 int threshold=config.threshold;
496 int noise_threshold=0;
498 switch(input->get_color_model())
502 DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 3, dominance, threshold, noise_threshold);
505 DEINTERLACE_BOBWEAVE_MACRO(float, double, 3, dominance, threshold, noise_threshold);
509 DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 4, dominance, threshold, noise_threshold);
512 DEINTERLACE_BOBWEAVE_MACRO(float, double, 4, dominance, threshold, noise_threshold);
516 DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 3, dominance, threshold, noise_threshold);
518 case BC_RGBA16161616:
519 case BC_YUVA16161616:
520 DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 4, dominance, threshold, noise_threshold);
526 int DeInterlaceMain::process_buffer(VFrame *frame,
527 int64_t start_position,
530 changed_rows = frame->get_h();
531 load_configuration();
534 read_frame(frame, 0, start_position, frame_rate, 0);
536 // Temp was used for adaptive deinterlacing where it took deinterlacing
537 // an entire frame to decide if the deinterlaced output should be used.
541 // temp = new VFrame(frame->get_w(), frame->get_h(),
542 // frame->get_color_model(), 0);
544 temp_prevframe = new VFrame(frame->get_w(), frame->get_h(),
545 frame->get_color_model(), 0);
549 case DEINTERLACE_NONE:
550 // output->copy_from(input);
552 case DEINTERLACE_KEEP:
553 deinterlace_top(frame, frame, config.dominance);
555 case DEINTERLACE_AVG:
556 deinterlace_avg(frame, frame);
558 case DEINTERLACE_AVG_1F:
559 deinterlace_avg_top(frame, frame, config.dominance);
561 case DEINTERLACE_SWAP:
562 deinterlace_swap(frame, frame, config.dominance);
564 case DEINTERLACE_BOBWEAVE:
565 if (get_source_position()==0)
566 read_frame(temp_prevframe,0, get_source_position(), get_framerate(), 0);
568 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate(), 0);
569 deinterlace_bobweave(frame, temp_prevframe, frame, config.dominance);
571 case DEINTERLACE_TEMPORALSWAP:
572 if (get_source_position()==0)
573 read_frame(temp_prevframe,0, get_source_position(), get_framerate(), 0);
575 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate(), 0);
576 deinterlace_temporalswap(frame, temp_prevframe, frame, config.dominance);
579 send_render_gui(&changed_rows);
584 void DeInterlaceMain::render_gui(void *data)
588 thread->window->lock_window();
589 char string[BCTEXTLEN];
590 DeInterlaceWindow *window = (DeInterlaceWindow *)thread->window;
591 window->get_status_string(string, *(int*)data);
592 window->status->update(string);
594 window->unlock_window();
598 NEW_WINDOW_MACRO(DeInterlaceMain, DeInterlaceWindow)
599 LOAD_CONFIGURATION_MACRO(DeInterlaceMain, DeInterlaceConfig)
603 void DeInterlaceMain::save_data(KeyFrame *keyframe)
606 output.set_shared_output(keyframe->xbuf);
607 output.tag.set_title("DEINTERLACE");
608 output.tag.set_property("MODE", config.mode);
609 output.tag.set_property("DOMINANCE", config.dominance);
610 output.tag.set_property("ADAPTIVE", config.adaptive);
611 output.tag.set_property("THRESHOLD", config.threshold);
613 output.tag.set_title("/DEINTERLACE");
615 output.terminate_string();
618 void DeInterlaceMain::read_data(KeyFrame *keyframe)
621 input.set_shared_input(keyframe->xbuf);
623 while(!input.read_tag())
625 if(input.tag.title_is("DEINTERLACE"))
627 config.mode = input.tag.get_property("MODE", config.mode);
628 config.dominance = input.tag.get_property("DOMINANCE", config.dominance);
629 config.adaptive = input.tag.get_property("ADAPTIVE", config.adaptive);
630 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
636 void DeInterlaceMain::update_gui()
640 load_configuration();
641 DeInterlaceWindow *window = (DeInterlaceWindow *)thread->window;
642 window->lock_window();
643 window->set_mode(config.mode, 1);
644 if (window->dominance_top)
645 window->dominance_top->update(config.dominance?0:BC_Toggle::TOGGLE_CHECKED);
646 if (window->dominance_bottom)
647 window->dominance_bottom->update(config.dominance?BC_Toggle::TOGGLE_CHECKED:0);
648 if (window->adaptive)
649 window->adaptive->update(config.adaptive);
650 if (window->threshold)
651 window->threshold->update(config.threshold);
652 window->unlock_window();