fix mask vframe setup, add unshared vframe constructor
[goodguy/history.git] / cinelerra-5.1 / plugins / ivtc / ivtc.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "clip.h"
23 #include "bccmodels.h"
24 #include "filexml.h"
25 #include "ivtc.h"
26 #include "ivtcwindow.h"
27 #include "language.h"
28
29 #include <stdio.h>
30 #include <string.h>
31
32
33 #if 0
34 static const char *pattern_text[] =
35 {
36         N_("A  B  BC  CD  D"),
37         N_("AB  BC  CD  DE  EF"),
38         N_("Automatic")
39 };
40 #endif
41
42 REGISTER_PLUGIN(IVTCMain)
43
44 IVTCConfig::IVTCConfig()
45 {
46         frame_offset = 0;
47         first_field = 0;
48         automatic = 1;
49         auto_threshold = 2;
50         pattern = IVTCConfig::PULLDOWN32;
51 }
52
53 IVTCMain::IVTCMain(PluginServer *server)
54  : PluginVClient(server)
55 {
56
57         engine = 0;
58         previous_min = 0x4000000000000000LL;
59         previous_strategy = 0;
60 }
61
62 IVTCMain::~IVTCMain()
63 {
64
65
66         if(engine)
67         {
68                 if(temp_frame[0]) delete temp_frame[0];
69                 if(temp_frame[1]) delete temp_frame[1];
70                 temp_frame[0] = 0;
71                 temp_frame[1] = 0;
72                 delete engine;
73         }
74 }
75
76 const char* IVTCMain::plugin_title() { return _("Inverse Telecine"); }
77 int IVTCMain::is_realtime() { return 1; }
78
79
80
81 NEW_WINDOW_MACRO(IVTCMain, IVTCWindow)
82
83
84
85 int IVTCMain::load_configuration()
86 {
87         KeyFrame *prev_keyframe;
88
89         prev_keyframe = get_prev_keyframe(get_source_position());
90 // Must also switch between interpolation between keyframes and using first keyframe
91         read_data(prev_keyframe);
92
93         return 0;
94 }
95
96 void IVTCMain::save_data(KeyFrame *keyframe)
97 {
98         FileXML output;
99
100 // cause data to be stored directly in text
101         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
102         output.tag.set_title("IVTC");
103         output.tag.set_property("FRAME_OFFSET", config.frame_offset);
104         output.tag.set_property("FIRST_FIELD", config.first_field);
105         output.tag.set_property("AUTOMATIC", config.automatic);
106         output.tag.set_property("AUTO_THRESHOLD", config.auto_threshold);
107         output.tag.set_property("PATTERN", config.pattern);
108         output.append_tag();
109         output.tag.set_title("/IVTC");
110         output.append_tag();
111         output.append_newline();
112         output.terminate_string();
113 }
114
115 void IVTCMain::read_data(KeyFrame *keyframe)
116 {
117         FileXML input;
118
119         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
120
121         int result = 0;
122         //float new_threshold;
123
124         while(!result)
125         {
126                 result = input.read_tag();
127
128                 if(!result)
129                 {
130                         if(input.tag.title_is("IVTC"))
131                         {
132                                 config.frame_offset = input.tag.get_property("FRAME_OFFSET", config.frame_offset);
133                                 config.first_field = input.tag.get_property("FIRST_FIELD", config.first_field);
134                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
135                                 //new_threshold = input.tag.get_property("AUTO_THRESHOLD", config.auto_threshold);
136                                 config.pattern = input.tag.get_property("PATTERN", config.pattern);
137                         }
138                 }
139         }
140 }
141
142
143
144 void IVTCMain::render_stop()
145 {
146         previous_min = 0x4000000000000000LL;
147 }
148
149
150
151 // Pattern A B BC CD D
152 int IVTCMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
153 {
154         load_configuration();
155
156         if(!engine)
157         {
158                 temp_frame[0] = 0;
159                 temp_frame[1] = 0;
160
161                 engine = new IVTCEngine(this, smp + 1);
162         }
163
164 // Determine position in pattern
165         int pattern_position = (PluginClient::source_position + config.frame_offset) % 5;
166
167 //printf("IVTCMain::process_realtime %d %d\n", pattern_position, config.first_field);
168         if(!temp_frame[0])
169                 temp_frame[0] = new VFrame(input_ptr->get_w(), input_ptr->get_h(),
170                         input_ptr->get_color_model(), 0);
171         if(!temp_frame[1])
172                 temp_frame[1] = new VFrame(input_ptr->get_w(), input_ptr->get_h(),
173                         input_ptr->get_color_model(), 0);
174
175         int row_size = VFrame::calculate_bytes_per_pixel(input_ptr->get_color_model()) * input_ptr->get_w();
176         this->input = input_ptr;
177         this->output = output_ptr;
178
179 // Determine pattern
180         if(config.pattern == IVTCConfig::PULLDOWN32)
181         {
182                 switch(pattern_position)
183                 {
184 // Direct copy
185                         case 0:
186                         case 4:
187                                 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
188                                         output_ptr->copy_from(input_ptr);
189                                 break;
190
191                         case 1:
192                                 temp_frame[0]->copy_from(input_ptr);
193                                 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
194                                         output_ptr->copy_from(input_ptr);
195                                 break;
196
197                         case 2:
198 // Save one field for next frame.  Reuse previous frame.
199                                 temp_frame[1]->copy_from(input_ptr);
200                                 output_ptr->copy_from(temp_frame[0]);
201                                 break;
202
203                         case 3:
204 // Combine previous field with current field.
205                                 for(int i = 0; i < input_ptr->get_h(); i++)
206                                 {
207                                         unsigned char *dst = output_ptr->get_rows()[i];
208                                         unsigned char *src = ((i + config.first_field) & 1) ?
209                                                         input_ptr->get_rows()[i] :
210                                                         temp_frame[1]->get_rows()[i];
211                                         if( src != dst )
212                                                 memcpy(dst, src, row_size);
213                                 }
214                                 break;
215                 }
216         }
217         else
218         if(config.pattern == IVTCConfig::SHIFTFIELD)
219         {
220                 temp_frame[1]->copy_from(input_ptr);
221
222 // Recycle previous bottom or top
223                 for(int i = 0; i < input_ptr->get_h(); i++)
224                 {
225                         unsigned char *dst = output_ptr->get_rows()[i];
226                         unsigned char *src = ((i + config.first_field) & 1) ?
227                                         input_ptr->get_rows()[i] :
228                                         temp_frame[0]->get_rows()[i];
229                         if( src != dst )
230                                 memcpy(dst, src, row_size);
231                 }
232
233 // Swap temp frames
234                 VFrame *temp = temp_frame[0];
235                 temp_frame[0] = temp_frame[1];
236                 temp_frame[1] = temp;
237         }
238         else
239         if(config.pattern == IVTCConfig::AUTOMATIC)
240         {
241 // Compare averaged rows with original rows and
242 // with previous rows.
243 // Take rows which are most similar to the averaged rows.
244 // Process frame.
245                 engine->process_packages();
246 // Copy current for future use
247                 temp_frame[1]->copy_from(input_ptr);
248
249 // Add results
250                 even_vs_current = 0;
251                 even_vs_prev = 0;
252                 odd_vs_current = 0;
253                 odd_vs_prev = 0;
254
255                 for(int i = 0; i < engine->get_total_clients(); i++)
256                 {
257                         IVTCUnit *unit = (IVTCUnit*)engine->get_client(i);
258                         even_vs_current += unit->even_vs_current;
259                         even_vs_prev += unit->even_vs_prev;
260                         odd_vs_current += unit->odd_vs_current;
261                         odd_vs_prev += unit->odd_vs_prev;
262                 }
263
264
265                 int64_t min;
266                 int strategy;
267
268
269 // First strategy.
270 // Even lines from previous frame are more similar to
271 // averaged even lines in current frame.
272 // Take even lines from previous frame
273                 min = even_vs_prev;
274                 strategy = 0;
275
276                 if(even_vs_current < min)
277                 {
278 // Even lines from current frame are more similar to averaged
279 // even lines in current frame than previous combinations.
280 // Take all lines from current frame
281                         min = even_vs_current;
282                         strategy = 2;
283                 }
284
285                 if(min > odd_vs_prev)
286                 {
287 // Odd lines from previous frame are more similar to averaged
288 // odd lines in current frame than previous combinations.
289 // Take odd lines from previous frame
290                         min = odd_vs_prev;
291                         strategy = 1;
292                 }
293
294                 if(min > odd_vs_current)
295                 {
296 // Odd lines from current frame are more similar to averaged
297 // odd lines in current frame than previous combinations.
298 // Take odd lines from current frame.
299                         min = odd_vs_current;
300                         strategy = 2;
301                 }
302
303 //              int confident = 1;
304 // Do something if not confident.
305 // Sometimes we never get the other field.
306 // Currently nothing is done because it doesn't fix the timing.
307 //              if(min > previous_min * 4 && previous_strategy == 2)
308 //              {
309 //                      confident = 0;
310 //                      strategy = 3;
311 //              }
312 // printf("IVTCMain::process_realtime 1: previous_min=%lld min=%lld strategy=%d confident=%d\n",
313 // previous_min,
314 // min,
315 // strategy,
316 // confident);
317
318
319
320 // printf("IVTCMain::process_realtime:\n    even_vs_current=%lld\n    even_vs_prev=%lld\n    odd_vs_current=%lld\n    odd_vs_prev=%lld\n    strategy=%d confident=%d\n",
321 // even_vs_current,
322 // even_vs_prev,
323 // odd_vs_current,
324 // odd_vs_prev,
325 // strategy,
326 // strategy == 2 && !use_direct_copy);
327
328                 switch(strategy)
329                 {
330                         case 0:
331                                 for(int i = 0; i < input_ptr->get_h(); i++)
332                                 {
333                                         unsigned char *dst = output_ptr->get_rows()[i];
334                                         unsigned char *src = (!(i & 1)) ?
335                                                         temp_frame[0]->get_rows()[i] :
336                                                         input_ptr->get_rows()[i];
337                                         if( src != dst )
338                                                 memcpy(dst, src, row_size);
339                                 }
340                                 break;
341                         case 1:
342                                 for(int i = 0; i < input_ptr->get_h(); i++)
343                                 {
344                                         unsigned char *dst = output_ptr->get_rows()[i];
345                                         unsigned char *src = (i & 1) ?
346                                                         temp_frame[0]->get_rows()[i] :
347                                                         input_ptr->get_rows()[i];
348                                         if( src != dst )
349                                                 memcpy(dst, src, row_size);
350                                 }
351                                 break;
352                         case 2:
353                                 output_ptr->copy_from(input_ptr);
354                                 break;
355                         case 3:
356 //                              output_ptr->copy_from(temp_frame[0]);
357 // Deinterlace
358                                 for(int i = 0; i < input_ptr->get_h(); i++)
359                                 {
360                                         unsigned char *dst = output_ptr->get_rows()[i];
361                                         unsigned char *src = (i & 1) ?
362                                                         input_ptr->get_rows()[i - 1] :
363                                                         input_ptr->get_rows()[i];
364                                         if( src != dst )
365                                                 memcpy(dst, src, row_size);
366                                 }
367                                 break;
368                 }
369
370                 previous_min = min;
371                 previous_strategy = strategy;
372                 VFrame *temp = temp_frame[1];
373                 temp_frame[1] = temp_frame[0];
374                 temp_frame[0] = temp;
375         }
376         return 0;
377 }
378
379
380
381 void IVTCMain::update_gui()
382 {
383         if(thread)
384         {
385                 load_configuration();
386                 ((IVTCWindow*)thread->window)->lock_window();
387                 if(config.pattern == IVTCConfig::AUTOMATIC)
388                 {
389                         ((IVTCWindow*)thread->window)->frame_offset->disable();
390                         ((IVTCWindow*)thread->window)->first_field->disable();
391                 }
392                 else
393                 {
394                         ((IVTCWindow*)thread->window)->frame_offset->enable();
395                         ((IVTCWindow*)thread->window)->first_field->enable();
396                 }
397                 ((IVTCWindow*)thread->window)->frame_offset->update((int64_t)config.frame_offset);
398                 ((IVTCWindow*)thread->window)->first_field->update(config.first_field);
399 //              ((IVTCWindow*)thread->window)->automatic->update(config.automatic);
400                 for(int i = 0; i < TOTAL_PATTERNS; i++)
401                 {
402                         ((IVTCWindow*)thread->window)->pattern[i]->update(config.pattern == i);
403                 }
404                 ((IVTCWindow*)thread->window)->unlock_window();
405         }
406 }
407
408
409
410 // labs returns different values on x86_64 causing our accumulators to explode
411 #define ABS local_abs
412
413
414 #ifdef __x86_64__
415
416 static int local_abs(int value)
417 {
418         return (value < 0 ? -value : value);
419 }
420
421 static float local_abs(float value)
422 {
423         return (value < 0 ? -value : value);
424 }
425
426 #else
427
428 static int local_abs(int value)
429 {
430         return abs(value);
431 }
432
433 static float local_abs(float value)
434 {
435         return fabsf(value);
436 }
437
438
439 #endif
440
441
442
443
444 IVTCPackage::IVTCPackage()
445  : LoadPackage()
446 {
447 }
448
449
450
451
452 IVTCUnit::IVTCUnit(IVTCEngine *server, IVTCMain *plugin)
453  : LoadClient(server)
454 {
455         this->server = server;
456         this->plugin = plugin;
457 }
458
459 #define IVTC_MACRO(type, temp_type, components, is_yuv) \
460 { \
461         type **curr_rows = (type**)plugin->input->get_rows(); \
462         type **prev_rows = (type**)plugin->temp_frame[0]->get_rows(); \
463         /* int skip = components - 1; // Components to skip for YUV */\
464         for(int i = ptr->y1; i < ptr->y2; i++) \
465         { /* Rows to average in the input frame */ \
466                 int input_row1_number = i - 1; \
467                 int input_row2_number = i + 1; \
468                 input_row1_number = MAX(0, input_row1_number); \
469                 input_row2_number = MIN(h - 1, input_row2_number); \
470                 type *input_row1 = curr_rows[input_row1_number]; \
471                 type *input_row2 = curr_rows[input_row2_number]; \
472 /* Rows to compare the averaged rows to */ \
473                 type *current_row = curr_rows[i]; \
474                 type *prev_row = prev_rows[i]; \
475                 temp_type current_difference = 0; \
476                 temp_type prev_difference = 0; \
477                 for(int j = 0; j < w; j++) \
478                 { \
479 /* This only compares luminance */ \
480 /* Get average of current rows */ \
481                         temp_type average = ((temp_type)*input_row1 + *input_row2) / 2; \
482 /* Difference between averaged current rows and original inbetween row */ \
483                         current_difference += ABS(average - *current_row); \
484 /* Difference between averaged current rows and previous inbetween row */ \
485                         prev_difference += ABS(average - *prev_row); \
486  \
487 /* Do RGB channels */ \
488                         if(!is_yuv) \
489                         { \
490                                 average = ((temp_type)input_row1[1] + input_row2[1]) / 2; \
491                                 current_difference += ABS(average - current_row[1]); \
492                                 prev_difference += ABS(average - prev_row[1]); \
493                                 average = ((temp_type)input_row1[2] + input_row2[2]) / 2; \
494                                 current_difference += ABS(average - current_row[2]); \
495                                 prev_difference += ABS(average - prev_row[2]); \
496                         } \
497  \
498 /* Add to row accumulators */ \
499                         current_row += components; \
500                         prev_row += components; \
501                         input_row1 += components; \
502                         input_row2 += components; \
503                 } \
504  \
505 /* Store row differences in even or odd variables */ \
506                 if(sizeof(type) == 4) \
507                 { \
508                         if(i % 2) \
509                         { \
510                                 odd_vs_current += (int64_t)(current_difference * 0xffff); \
511                                 odd_vs_prev += (int64_t)(prev_difference); \
512                         } \
513                         else \
514                         { \
515                                 even_vs_current += (int64_t)(current_difference); \
516                                 even_vs_prev += (int64_t)(prev_difference); \
517                         } \
518                 } \
519                 else \
520                 { \
521                         if(i % 2) \
522                         { \
523                                 odd_vs_current += (int64_t)current_difference; \
524                                 odd_vs_prev += (int64_t)prev_difference; \
525                         } \
526                         else \
527                         { \
528                                 even_vs_current += (int64_t)current_difference; \
529                                 even_vs_prev += (int64_t)prev_difference; \
530                         } \
531                 } \
532         } \
533 }
534
535 void IVTCUnit::clear_totals()
536 {
537         even_vs_current = 0;
538         even_vs_prev = 0;
539         odd_vs_current = 0;
540         odd_vs_prev = 0;
541 }
542
543 void IVTCUnit::process_package(LoadPackage *package)
544 {
545         IVTCPackage *ptr = (IVTCPackage*)package;
546         int w = plugin->input->get_w();
547         int h = plugin->input->get_h();
548
549         switch(plugin->input->get_color_model())
550         {
551                 case BC_RGB_FLOAT:
552                         IVTC_MACRO(float, float, 3, 0);
553                         break;
554                 case BC_RGB888:
555                         IVTC_MACRO(unsigned char, int, 3, 0);
556                         break;
557                 case BC_YUV888:
558                         IVTC_MACRO(unsigned char, int, 3, 1);
559                         break;
560                 case BC_RGBA_FLOAT:
561                         IVTC_MACRO(float, float, 4, 0);
562                         break;
563                 case BC_RGBA8888:
564                         IVTC_MACRO(unsigned char, int, 4, 0);
565                         break;
566                 case BC_YUVA8888:
567                         IVTC_MACRO(unsigned char, int, 4, 1);
568                         break;
569                 case BC_RGB161616:
570                         IVTC_MACRO(uint16_t, int, 3, 0);
571                         break;
572                 case BC_YUV161616:
573                         IVTC_MACRO(uint16_t, int, 3, 1);
574                         break;
575                 case BC_RGBA16161616:
576                         IVTC_MACRO(uint16_t, int, 4, 0);
577                         break;
578                 case BC_YUVA16161616:
579                         IVTC_MACRO(uint16_t, int, 4, 1);
580                         break;
581         }
582
583 }
584
585
586
587
588
589 IVTCEngine::IVTCEngine(IVTCMain *plugin, int cpus)
590  : LoadServer(cpus, cpus)
591 {
592         this->plugin = plugin;
593 }
594
595 IVTCEngine::~IVTCEngine()
596 {
597 }
598
599 void IVTCEngine::init_packages()
600 {
601         int increment = plugin->input->get_h() / get_total_packages();
602         increment /= 2;
603         increment *= 2;
604         if(!increment) increment = 2;
605         int y1 = 0;
606         for(int i = 0; i < get_total_packages(); i++)
607         {
608                 IVTCPackage *package = (IVTCPackage*)get_package(i);
609                 package->y1 = y1;
610                 y1 += increment;
611                 if(y1 > plugin->input->get_h()) y1 = plugin->input->get_h();
612                 package->y2 = y1;
613         }
614         for(int i = 0; i < get_total_clients(); i++)
615         {
616                 IVTCUnit *unit = (IVTCUnit*)get_client(i);
617                 unit->clear_totals();
618         }
619 }
620
621 LoadClient* IVTCEngine::new_client()
622 {
623         return new IVTCUnit(this, plugin);
624 }
625
626 LoadPackage* IVTCEngine::new_package()
627 {
628         return new IVTCPackage;
629 }
630
631
632
633