r870: Merge 2.1:
[cinelerra_cv.git] / plugins / deinterlace / deinterlace.C
blobdcc51409acbe10131c2e3dc9e370e42e2f8c4342
1 #include "clip.h"
2 #include "bchash.h"
3 #include "deinterlace.h"
4 #include "deinterwindow.h"
5 #include "filexml.h"
6 #include "keyframe.h"
7 #include "language.h"
8 #include "picon_png.h"
9 #include "vframe.h"
19 #include <stdint.h>
20 #include <string.h>
21 #include <math.h>
23 REGISTER_PLUGIN(DeInterlaceMain)
28 DeInterlaceConfig::DeInterlaceConfig()
30         mode = DEINTERLACE_AVG;
31         dominance = 0;
32         adaptive = 1;
33         threshold = 40;
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)
46         mode = that.mode;
47         dominance = that.dominance;
48         adaptive = that.adaptive;
49         threshold = that.threshold;
52 void DeInterlaceConfig::interpolate(DeInterlaceConfig &prev, 
53         DeInterlaceConfig &next, 
54         int64_t prev_frame, 
55         int64_t next_frame, 
56         int64_t current_frame)
58         copy_from(prev);
64 DeInterlaceMain::DeInterlaceMain(PluginServer *server)
65  : PluginVClient(server)
67         PLUGIN_CONSTRUCTOR_MACRO
68         temp = 0;
69         temp_prevframe=0;
72 DeInterlaceMain::~DeInterlaceMain()
74         PLUGIN_DESTRUCTOR_MACRO
75         if(temp) delete temp;
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) \
85 { \
86         int w = input->get_w(); \
87         int h = input->get_h(); \
88  \
89         for(int i = 0; i < h - 1; i += 2) \
90         { \
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)); \
96         } \
99 #define DEINTERLACE_AVG_TOP_MACRO(type, temp_type, components, dominance) \
100 { \
101         int w = input->get_w(); \
102         int h = input->get_h(); \
103         changed_rows = 0; \
105         type **in_rows = (type**)input->get_rows(); \
106         type **out_rows = (type**)temp->get_rows(); \
107         int max_h = h - 1; \
108         temp_type abs_diff = 0, total = 0; \
110         for(int i = 0; i < max_h; i += 2) \
111         { \
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]; \
126                 temp_type sum = 0; \
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++) \
131                 { \
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++); \
137                         accum_r /= 2; \
138                         accum_g /= 2; \
139                         accum_b /= 2; \
140                         accum_a /= 2; \
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) \
158                         { \
159                                 total += *input_row3; \
160                                 sum = ((temp_type)*input_row3++) - accum_a; \
161                                 abs_diff += (sum < 0 ? -sum : sum); \
162                                 *temp_row2++ = accum_a; \
163                         } \
164                 } \
165         } \
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) \
170         { \
171                 output->copy_from(temp); \
172                 changed_rows = 240; \
173         } \
174         else \
175         { \
176                 output->copy_from(input); \
177                 changed_rows = 0; \
178         } \
182 #define DEINTERLACE_AVG_MACRO(type, temp_type, components) \
183 { \
184         int w = input->get_w(); \
185         int h = input->get_h(); \
187         for(int i = 0; i < h - 1; i += 2) \
188         { \
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]; \
193                 type result; \
195                 for(int j = 0; j < w * components; j++) \
196                 { \
197                         result = ((temp_type)input_row1[j] + input_row2[j]) / 2; \
198                         output_row1[j] = result; \
199                         output_row2[j] = result; \
200                 } \
201         } \
204 #define DEINTERLACE_SWAP_MACRO(type, components, dominance) \
205 { \
206         int w = input->get_w(); \
207         int h = input->get_h(); \
209         for(int i = dominance; i < h - 1; i += 2) \
210         { \
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]; \
215                 type temp1, temp2; \
217                 for(int j = 0; j < w * components; j++) \
218                 { \
219                         temp1 = input_row1[j]; \
220                         temp2 = input_row2[j]; \
221                         output_row1[j] = temp2; \
222                         output_row2[j] = temp1; \
223                 } \
224         } \
228 #define DEINTERLACE_TEMPORALSWAP_MACRO(type, components, dominance) \
229 { \
230         int w = input->get_w(); \
231         int h = input->get_h(); \
233         for(int i = 0; i < h - 1; i += 2) \
234         { \
235                 type *input_row1;\
236                 type *input_row2; \
237                 type *output_row1 = (type*)output->get_rows()[i]; \
238                 type *output_row2 = (type*)output->get_rows()[i + 1]; \
239                 type temp1, temp2; \
240                 \
241                 if (dominance) { \
242                         input_row1 = (type*)input->get_rows()[i]; \
243                         input_row2 = (type*)prevframe->get_rows()[i+1]; \
244                 } \
245                 else  {\
246                         input_row1 = (type*)prevframe->get_rows()[i]; \
247                         input_row2 = (type*)input->get_rows()[i+1]; \
248                 } \
250                 for(int j = 0; j < w * components; j++) \
251                 { \
252                         temp1 = input_row1[j]; \
253                         temp2 = input_row2[j]; \
254                         output_row1[j] = temp1; \
255                         output_row2[j] = temp2; \
256                 } \
257         } \
261 /* Bob & Weave deinterlacer:
263 For each pixel, 
264         if it's similar to the previous frame 
265         then keep it
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) \
279 { \
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) \
286         { \
287                 type *input_row;\
288                 type *input_row2; \
289                 type *old_row; \
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; \
293                 \
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++) \
299                 { \
300                         pixel = input_row[j]; \
301                         below = input_row2[j]; \
302                         old = old_row[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 )) \
308                         ) {\
309                                 pixel=(above+below)/2 ;\
310                         }\
311                         output_row1[j] = pixel; \
312                         output_row2[j] = below; \
313                 } \
314                 row_above=input_row2; \
315         } \
319 void DeInterlaceMain::deinterlace_top(VFrame *input, VFrame *output, int dominance)
321         switch(input->get_color_model())
322         {
323                 case BC_RGB888:
324                 case BC_YUV888:
325                         DEINTERLACE_TOP_MACRO(unsigned char, 3, dominance);
326                         break;
327                 case BC_RGB_FLOAT:
328                         DEINTERLACE_TOP_MACRO(float, 3, dominance);
329                         break;
330                 case BC_RGBA8888:
331                 case BC_YUVA8888:
332                         DEINTERLACE_TOP_MACRO(unsigned char, 4, dominance);
333                         break;
334                 case BC_RGBA_FLOAT:
335                         DEINTERLACE_TOP_MACRO(float, 4, dominance);
336                         break;
337                 case BC_RGB161616:
338                 case BC_YUV161616:
339                         DEINTERLACE_TOP_MACRO(uint16_t, 3, dominance);
340                         break;
341                 case BC_RGBA16161616:
342                 case BC_YUVA16161616:
343                         DEINTERLACE_TOP_MACRO(uint16_t, 4, dominance);
344                         break;
345         }
348 void DeInterlaceMain::deinterlace_avg_top(VFrame *input, VFrame *output, int dominance)
350         switch(input->get_color_model())
351         {
352                 case BC_RGB888:
353                 case BC_YUV888:
354                         DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 3, dominance);
355                         break;
356                 case BC_RGB_FLOAT:
357                         DEINTERLACE_AVG_TOP_MACRO(float, double, 3, dominance);
358                         break;
359                 case BC_RGBA8888:
360                 case BC_YUVA8888:
361                         DEINTERLACE_AVG_TOP_MACRO(unsigned char, int64_t, 4, dominance);
362                         break;
363                 case BC_RGBA_FLOAT:
364                         DEINTERLACE_AVG_TOP_MACRO(float, double, 4, dominance);
365                         break;
366                 case BC_RGB161616:
367                 case BC_YUV161616:
368                         DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 3, dominance);
369                         break;
370                 case BC_RGBA16161616:
371                 case BC_YUVA16161616:
372                         DEINTERLACE_AVG_TOP_MACRO(uint16_t, int64_t, 4, dominance);
373                         break;
374         }
377 void DeInterlaceMain::deinterlace_avg(VFrame *input, VFrame *output)
379         switch(input->get_color_model())
380         {
381                 case BC_RGB888:
382                 case BC_YUV888:
383                         DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 3);
384                         break;
385                 case BC_RGB_FLOAT:
386                         DEINTERLACE_AVG_MACRO(float, double, 3);
387                         break;
388                 case BC_RGBA8888:
389                 case BC_YUVA8888:
390                         DEINTERLACE_AVG_MACRO(unsigned char, uint64_t, 4);
391                         break;
392                 case BC_RGBA_FLOAT:
393                         DEINTERLACE_AVG_MACRO(float, double, 4);
394                         break;
395                 case BC_RGB161616:
396                 case BC_YUV161616:
397                         DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 3);
398                         break;
399                 case BC_RGBA16161616:
400                 case BC_YUVA16161616:
401                         DEINTERLACE_AVG_MACRO(uint16_t, uint64_t, 4);
402                         break;
403         }
406 void DeInterlaceMain::deinterlace_swap(VFrame *input, VFrame *output, int dominance)
408         switch(input->get_color_model())
409         {
410                 case BC_RGB888:
411                 case BC_YUV888:
412                         DEINTERLACE_SWAP_MACRO(unsigned char, 3, dominance);
413                         break;
414                 case BC_RGB_FLOAT:
415                         DEINTERLACE_SWAP_MACRO(float, 3, dominance);
416                         break;
417                 case BC_RGBA8888:
418                 case BC_YUVA8888:
419                         DEINTERLACE_SWAP_MACRO(unsigned char, 4, dominance);
420                         break;
421                 case BC_RGBA_FLOAT:
422                         DEINTERLACE_SWAP_MACRO(float, 4, dominance);
423                         break;
424                 case BC_RGB161616:
425                 case BC_YUV161616:
426                         DEINTERLACE_SWAP_MACRO(uint16_t, 3, dominance);
427                         break;
428                 case BC_RGBA16161616:
429                 case BC_YUVA16161616:
430                         DEINTERLACE_SWAP_MACRO(uint16_t, 4, dominance);
431                         break;
432         }
435 void DeInterlaceMain::deinterlace_temporalswap(VFrame *input, VFrame *prevframe, VFrame *output, int dominance)
437         switch(input->get_color_model())
438         {
439                 case BC_RGB888:
440                 case BC_YUV888:
441                         DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 3, dominance);
442                         break;
443                 case BC_RGB_FLOAT:
444                         DEINTERLACE_TEMPORALSWAP_MACRO(float, 3, dominance);
445                         break;
446                 case BC_RGBA8888:
447                 case BC_YUVA8888:
448                         DEINTERLACE_TEMPORALSWAP_MACRO(unsigned char, 4, dominance);
449                         break;
450                 case BC_RGBA_FLOAT:
451                         DEINTERLACE_TEMPORALSWAP_MACRO(float, 4, dominance);
452                         break;
453                 case BC_RGB161616:
454                 case BC_YUV161616:
455                         DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 3, dominance);
456                         break;
457                 case BC_RGBA16161616:
458                 case BC_YUVA16161616:
459                         DEINTERLACE_TEMPORALSWAP_MACRO(uint16_t, 4, dominance);
460                         break;
461         }
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())
470         {
471                 case BC_RGB888:
472                 case BC_YUV888:
473                         DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 3, dominance, threshold, noise_threshold);
474                         break;
475                 case BC_RGB_FLOAT:
476                         DEINTERLACE_BOBWEAVE_MACRO(float, double, 3, dominance, threshold, noise_threshold);
477                         break;
478                 case BC_RGBA8888:
479                 case BC_YUVA8888:
480                         DEINTERLACE_BOBWEAVE_MACRO(unsigned char, uint64_t, 4, dominance, threshold, noise_threshold);
481                         break;
482                 case BC_RGBA_FLOAT:
483                         DEINTERLACE_BOBWEAVE_MACRO(float, double, 4, dominance, threshold, noise_threshold);
484                         break;
485                 case BC_RGB161616:
486                 case BC_YUV161616:
487                         DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 3, dominance, threshold, noise_threshold);
488                         break;
489                 case BC_RGBA16161616:
490                 case BC_YUVA16161616:
491                         DEINTERLACE_BOBWEAVE_MACRO(uint16_t, uint64_t, 4, dominance, threshold, noise_threshold);
492                         break;
493         }
497 int DeInterlaceMain::process_buffer(VFrame *frame,
498         int64_t start_position,
499         double frame_rate)
501         changed_rows = frame->get_h();
502         load_configuration();
505         read_frame(frame, 
506                 0, 
507                 start_position, 
508                 frame_rate);
510 // Temp was used for adaptive deinterlacing where it took deinterlacing
511 // an entire frame to decide if the deinterlaced output should be used.
512         temp = frame;
514 //      if(!temp)
515 //              temp = new VFrame(0,
516 //                      frame->get_w(),
517 //                      frame->get_h(),
518 //                      frame->get_color_model());
519         if(!temp_prevframe)
520                 temp_prevframe = new VFrame(0,
521                         frame->get_w(),
522                         frame->get_h(),
523                         frame->get_color_model());
525         switch(config.mode)
526         {
527                 case DEINTERLACE_NONE:
528 //                      output->copy_from(input);
529                         break;
530                 case DEINTERLACE_KEEP:
531                         deinterlace_top(frame, frame, config.dominance);
532                         break;
533                 case DEINTERLACE_AVG:
534                         deinterlace_avg(frame, frame);
535                         break;
536                 case DEINTERLACE_AVG_1F:
537                         deinterlace_avg_top(frame, frame, config.dominance);
538                         break;
539                 case DEINTERLACE_SWAP:
540                         deinterlace_swap(frame, frame, config.dominance);
541                         break;
542                 case DEINTERLACE_BOBWEAVE:
543                         if (get_source_position()==0)
544                                 read_frame(temp_prevframe,0, get_source_position(), get_framerate());
545                         else 
546                                 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate());
547                         deinterlace_bobweave(frame, temp_prevframe, frame, config.dominance);
548                         break;
549                 case DEINTERLACE_TEMPORALSWAP:
550                         if (get_source_position()==0)
551                                 read_frame(temp_prevframe,0, get_source_position(), get_framerate());
552                         else 
553                                 read_frame(temp_prevframe,0, get_source_position()-1, get_framerate());
554                         deinterlace_temporalswap(frame, temp_prevframe, frame, config.dominance);
555                         break; 
556         }
557         send_render_gui(&changed_rows);
558         return 0;
562 void DeInterlaceMain::render_gui(void *data)
564         if(thread)
565         {
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();
572         }
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);
586         
587         defaults = new BC_Hash(directory);
588         defaults->load();
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);
593         return 0;
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);
603         defaults->save();
604         return 0;
607 void DeInterlaceMain::save_data(KeyFrame *keyframe)
609         FileXML output;
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);
616         output.append_tag();
617         output.terminate_string();
620 void DeInterlaceMain::read_data(KeyFrame *keyframe)
622         FileXML input;
623         input.set_shared_string(keyframe->data, strlen(keyframe->data));
625         while(!input.read_tag())
626         {
627                 if(input.tag.title_is("DEINTERLACE"))
628                 {
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);
633                 }
634         }
638 void DeInterlaceMain::update_gui()
640         if(thread) 
641         {
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();
654         }