add BC_SCALE env var for hi def monitors, cleanup theme data
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / decimate / decimate.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 "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "keyframe.h"
28 #include "language.h"
29 #include "pluginvclient.h"
30 #include "vframe.h"
31
32 #include <string.h>
33 #include <stdint.h>
34
35
36 #define TOP_FIELD_FIRST 0
37 #define BOTTOM_FIELD_FIRST 1
38 #define TOTAL_FRAMES 10
39
40 class Decimate;
41 class DecimateWindow;
42
43
44 class DecimateConfig
45 {
46 public:
47         DecimateConfig();
48         void copy_from(DecimateConfig *config);
49         int equivalent(DecimateConfig *config);
50
51         double input_rate;
52 // Averaged frames is useless.  Some of the frames are permanently
53 // destroyed in conversion from PAL to NTSC.
54         int averaged_frames;
55         int least_difference;
56 };
57
58
59
60
61 class DecimateRate : public BC_TextBox
62 {
63 public:
64         DecimateRate(Decimate *plugin,
65                 DecimateWindow *gui,
66                 int x,
67                 int y);
68         int handle_event();
69         Decimate *plugin;
70         DecimateWindow *gui;
71 };
72
73 class DecimateRateMenu : public BC_ListBox
74 {
75 public:
76         DecimateRateMenu(Decimate *plugin,
77                 DecimateWindow *gui,
78                 int x,
79                 int y);
80         int handle_event();
81         Decimate *plugin;
82         DecimateWindow *gui;
83 };
84
85 class DecimateDifference : public BC_CheckBox
86 {
87 public:
88         DecimateDifference(Decimate *plugin,
89                 int x,
90                 int y);
91         int handle_event();
92         Decimate *plugin;
93 };
94
95 class DecimateAvgDifference : public BC_CheckBox
96 {
97 public:
98         DecimateAvgDifference(Decimate *plugin,
99                 int x,
100                 int y);
101         int handle_event();
102         Decimate *plugin;
103 };
104
105
106 class DecimateWindow : public PluginClientWindow
107 {
108 public:
109         DecimateWindow(Decimate *plugin);
110         ~DecimateWindow();
111
112         void create_objects();
113
114         ArrayList<BC_ListBoxItem*> frame_rates;
115         Decimate *plugin;
116         DecimateRate *rate;
117         DecimateRateMenu *rate_menu;
118         BC_Title *last_dropped;
119 //      DecimateDifference *difference;
120 //      DecimateAvgDifference *avg_difference;
121 };
122
123
124
125
126
127 class Decimate : public PluginVClient
128 {
129 public:
130         Decimate(PluginServer *server);
131         ~Decimate();
132
133         PLUGIN_CLASS_MEMBERS(DecimateConfig)
134
135         int process_buffer(VFrame *frame,
136                 int64_t start_position,
137                 double frame_rate);
138         int is_realtime();
139         void save_data(KeyFrame *keyframe);
140         void read_data(KeyFrame *keyframe);
141         void update_gui();
142         void render_gui(void *data);
143
144         int64_t calculate_difference(VFrame *frame1, VFrame *frame2);
145         void fill_lookahead(double frame_rate,
146                 int64_t start_position);
147         void decimate_frame();
148         void init_fdct();
149         void fdct(uint16_t *block);
150         int64_t calculate_fdct(VFrame *frame);
151
152 // fdct coefficients
153         double c[8][8];
154         int fdct_ready;
155
156 // each difference is the difference between the previous frame and the
157 // subscripted frame
158         int64_t differences[TOTAL_FRAMES];
159
160 // read ahead number of frames
161         VFrame *frames[TOTAL_FRAMES];
162 // Number of frames in the lookahead buffer
163         int lookahead_size;
164 // Next position beyond end of lookahead buffer relative to input rate
165         int64_t lookahead_end;
166 // Framerate of lookahead buffer
167         double lookahead_rate;
168 // Last requested position
169         int64_t last_position;
170
171 };
172
173
174
175
176
177
178
179
180
181
182
183
184 DecimateConfig::DecimateConfig()
185 {
186         input_rate = (double)30000 / 1001;
187         least_difference = 1;
188         averaged_frames = 0;
189 }
190
191 void DecimateConfig::copy_from(DecimateConfig *config)
192 {
193         this->input_rate = config->input_rate;
194         this->least_difference = config->least_difference;
195         this->averaged_frames = config->averaged_frames;
196 }
197
198 int DecimateConfig::equivalent(DecimateConfig *config)
199 {
200         return EQUIV(this->input_rate, config->input_rate);
201 }
202
203
204
205
206
207
208
209
210
211 DecimateWindow::DecimateWindow(Decimate *plugin)
212  : PluginClientWindow(plugin,
213         xS(210),
214         yS(160),
215         xS(200),
216         yS(160),
217         0)
218 {
219         this->plugin = plugin;
220 }
221
222 DecimateWindow::~DecimateWindow()
223 {
224         frame_rates.remove_all_objects();
225 }
226
227 void DecimateWindow::create_objects()
228 {
229         int ys30 = yS(30);
230         int x = xS(10), y = yS(10);
231
232         frame_rates.append(new BC_ListBoxItem("1"));
233         frame_rates.append(new BC_ListBoxItem("5"));
234         frame_rates.append(new BC_ListBoxItem("10"));
235         frame_rates.append(new BC_ListBoxItem("12"));
236         frame_rates.append(new BC_ListBoxItem("15"));
237         frame_rates.append(new BC_ListBoxItem("23.97"));
238         frame_rates.append(new BC_ListBoxItem("24"));
239         frame_rates.append(new BC_ListBoxItem("25"));
240         frame_rates.append(new BC_ListBoxItem("29.97"));
241         frame_rates.append(new BC_ListBoxItem("30"));
242         frame_rates.append(new BC_ListBoxItem("50"));
243         frame_rates.append(new BC_ListBoxItem("59.94"));
244         frame_rates.append(new BC_ListBoxItem("60"));
245
246         BC_Title *title;
247         add_subwindow(title = new BC_Title(x, y, _("Input frames per second:")));
248         y += ys30;
249         add_subwindow(rate = new DecimateRate(plugin,
250                 this,
251                 x,
252                 y));
253         add_subwindow(rate_menu = new DecimateRateMenu(plugin,
254                 this,
255                 x + rate->get_w() + xS(5),
256                 y));
257         y += ys30;
258         add_subwindow(title = new BC_Title(x, y, _("Last frame dropped: ")));
259         add_subwindow(last_dropped = new BC_Title(x + title->get_w() + 5, y, ""));
260
261 //      y += ys30;
262 //      add_subwindow(difference = new DecimateDifference(plugin,
263 //              x,
264 //              y));
265 //      y += ys30;
266 //      add_subwindow(avg_difference = new DecimateAvgDifference(plugin,
267 //              x,
268 //              y));
269         show_window();
270         flush();
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284
285 DecimateRate::DecimateRate(Decimate *plugin,
286         DecimateWindow *gui,
287         int x,
288         int y)
289  : BC_TextBox(x, y, xS(90), 1,
290         (float)plugin->config.input_rate)
291 {
292         this->plugin = plugin;
293         this->gui = gui;
294 }
295
296 int DecimateRate::handle_event()
297 {
298         plugin->config.input_rate = Units::atoframerate(get_text());
299         plugin->send_configure_change();
300         return 1;
301 }
302
303
304
305 // DecimateDifference::DecimateDifference(Decimate *plugin,
306 //      int x,
307 //      int y)
308 //  : BC_CheckBox(x, y, plugin->config.least_difference, "Drop least difference")
309 // {
310 //      this->plugin = plugin;
311 // }
312 // int DecimateDifference::handle_event()
313 // {
314 //      plugin->config.least_difference = get_value();
315 //      plugin->send_configure_change();
316 //      return 1;
317 // }
318 //
319 //
320 //
321 //
322 // DecimateAvgDifference::DecimateAvgDifference(Decimate *plugin,
323 //      int x,
324 //      int y)
325 //  : BC_CheckBox(x, y, plugin->config.averaged_frames, "Drop averaged frames")
326 // {
327 //      this->plugin = plugin;
328 // }
329 //
330 // int DecimateAvgDifference::handle_event()
331 // {
332 //      plugin->config.averaged_frames = get_value();
333 //      plugin->send_configure_change();
334 //      return 1;
335 // }
336 //
337
338
339
340 DecimateRateMenu::DecimateRateMenu(Decimate *plugin,
341         DecimateWindow *gui,
342         int x,
343         int y)
344  : BC_ListBox(x,
345         y,
346         xS(100),
347         yS(200),
348         LISTBOX_TEXT,
349         &gui->frame_rates,
350         0,
351         0,
352         1,
353         0,
354         1)
355 {
356         this->plugin = plugin;
357         this->gui = gui;
358 }
359
360 int DecimateRateMenu::handle_event()
361 {
362         char *text = get_selection(0, 0)->get_text();
363         plugin->config.input_rate = atof(text);
364         gui->rate->update(text);
365         plugin->send_configure_change();
366         return 1;
367 }
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389 REGISTER_PLUGIN(Decimate)
390
391
392
393
394
395
396 Decimate::Decimate(PluginServer *server)
397  : PluginVClient(server)
398 {
399
400         bzero(frames, sizeof(VFrame*) * TOTAL_FRAMES);
401         for(int i = 0; i < TOTAL_FRAMES; i++)
402                 differences[i] = -1;
403         lookahead_size = 0;
404         lookahead_end = -1;
405         last_position = -1;
406         fdct_ready = 0;
407 }
408
409
410 Decimate::~Decimate()
411 {
412
413         if(frames[0])
414         {
415                 for(int i = 0; i < TOTAL_FRAMES; i++)
416                 {
417                         delete frames[i];
418                 }
419         }
420 }
421
422 #define DIFFERENCE_MACRO(type, temp_type, components) \
423 { \
424         temp_type result2 = 0; \
425         for(int i = 0; i < h; i++) \
426         { \
427                 type *row1 = (type*)frame1->get_rows()[i]; \
428                 type *row2 = (type*)frame2->get_rows()[i]; \
429                 for(int j = 0; j < w * components; j++) \
430                 { \
431                         temp_type temp = *row1 - *row2; \
432                         result2 += (temp > 0 ? temp : -temp); \
433                         row1++; \
434                         row2++; \
435                 } \
436         } \
437         result = (int64_t)result2; \
438 }
439
440 int64_t Decimate::calculate_difference(VFrame *frame1, VFrame *frame2)
441 {
442         int w = frame1->get_w();
443         int h = frame1->get_h();
444         int64_t result = 0;
445         switch(frame1->get_color_model())
446         {
447                 case BC_RGB888:
448                 case BC_YUV888:
449                         DIFFERENCE_MACRO(unsigned char, int64_t, 3);
450                         break;
451                 case BC_RGB_FLOAT:
452                         DIFFERENCE_MACRO(float, double, 3);
453                         break;
454                 case BC_RGBA8888:
455                 case BC_YUVA8888:
456                         DIFFERENCE_MACRO(unsigned char, int64_t, 4);
457                         break;
458                 case BC_RGBA_FLOAT:
459                         DIFFERENCE_MACRO(float, double, 4);
460                         break;
461                 case BC_RGB161616:
462                 case BC_YUV161616:
463                         DIFFERENCE_MACRO(uint16_t, int64_t, 3);
464                         break;
465                 case BC_RGBA16161616:
466                 case BC_YUVA16161616:
467                         DIFFERENCE_MACRO(uint16_t, int64_t, 4);
468                         break;
469         }
470         return result;
471 }
472
473 void Decimate::init_fdct()
474 {
475   int i, j;
476   double s;
477
478   for (i=0; i<8; i++)
479   {
480     s = (i==0) ? sqrt(0.125) : 0.5;
481
482     for (j=0; j<8; j++)
483       c[i][j] = s * cos((M_PI/8.0)*i*(j+0.5));
484   }
485 }
486
487 void Decimate::fdct(uint16_t *block)
488 {
489         int i, j;
490         double s;
491         double tmp[64];
492
493         for(i = 0; i < 8; i++)
494         for(j = 0; j < 8; j++)
495         {
496                 s = 0.0;
497
498 /*
499  *              for(k = 0; k < 8; k++)
500  *                      s += c[j][k] * block[8 * i + k];
501  */
502                 s += c[j][0] * block[8 * i + 0];
503                 s += c[j][1] * block[8 * i + 1];
504                 s += c[j][2] * block[8 * i + 2];
505                 s += c[j][3] * block[8 * i + 3];
506                 s += c[j][4] * block[8 * i + 4];
507                 s += c[j][5] * block[8 * i + 5];
508                 s += c[j][6] * block[8 * i + 6];
509                 s += c[j][7] * block[8 * i + 7];
510
511                 tmp[8 * i + j] = s;
512         }
513
514         for(j = 0; j < 8; j++)
515         for(i = 0; i < 8; i++)
516         {
517                 s = 0.0;
518
519 /*
520  *              for(k = 0; k < 8; k++)
521  *                  s += c[i][k] * tmp[8 * k + j];
522  */
523                 s += c[i][0] * tmp[8 * 0 + j];
524                 s += c[i][1] * tmp[8 * 1 + j];
525                 s += c[i][2] * tmp[8 * 2 + j];
526                 s += c[i][3] * tmp[8 * 3 + j];
527                 s += c[i][4] * tmp[8 * 4 + j];
528                 s += c[i][5] * tmp[8 * 5 + j];
529                 s += c[i][6] * tmp[8 * 6 + j];
530                 s += c[i][7] * tmp[8 * 7 + j];
531
532                 block[8 * i + j] = (int)floor(s + 0.499999);
533 /*
534  * reason for adding 0.499999 instead of 0.5:
535  * s is quite often x.5 (at least for i and/or j = 0 or 4)
536  * and setting the rounding threshold exactly to 0.5 leads to an
537  * extremely high arithmetic implementation dependency of the result;
538  * s being between x.5 and x.500001 (which is now incorrectly rounded
539  * downwards instead of upwards) is assumed to occur less often
540  * (if at all)
541  */
542       }
543 }
544
545
546 #define CALCULATE_DCT(type, components) \
547 { \
548         uint16_t *output = temp; \
549         for(int k = 0; k < 8; k++) \
550         { \
551                 type *input = (type*)frame->get_rows()[i + k] + j * components; \
552                 for(int l = 0; l < 8; l++) \
553                 { \
554                         *output = (*input << 8) | *input; \
555                         output++; \
556                         input += components; \
557                 } \
558         } \
559         fdct(temp); \
560 }
561
562 int64_t Decimate::calculate_fdct(VFrame *frame)
563 {
564         if(!fdct_ready)
565         {
566                 init_fdct();
567                 fdct_ready = 1;
568         }
569
570         uint16_t temp[64];
571         uint64_t result[64];
572         bzero(result, sizeof(int64_t) * 64);
573         int w = frame->get_w();
574         int h = frame->get_h();
575
576
577         for(int i = 0; i < h - 8; i += 8)
578         {
579                 for(int j = 0; j < w - 8; j += 8)
580                 {
581                         CALCULATE_DCT(unsigned char, 3)
582 // Add result to accumulation of transforms
583                         for(int k = 0; k < 64; k++)
584                         {
585                                 result[k] += temp[k];
586                         }
587                 }
588         }
589
590         uint64_t max_result = 0;
591         int highest = 0;
592         for(int i = 0; i < 64; i++)
593         {
594                 if(result[i] > max_result)
595                 {
596                         max_result = result[i];
597                         highest = i;
598                 }
599         }
600
601         return highest;
602 }
603
604 void Decimate::decimate_frame()
605 {
606         int64_t min_difference = 0x7fffffffffffffffLL;
607         int result = -1;
608
609         if(!lookahead_size) return;
610
611         for(int i = 0; i < lookahead_size; i++)
612         {
613 // Drop least different frame from sequence
614                 if(config.least_difference &&
615                         differences[i] >= 0 &&
616                         differences[i] < min_difference)
617                 {
618                         min_difference = differences[i];
619                         result = i;
620                 }
621         }
622
623 // If all the frames had differences of 0, like a pure black screen, delete
624 // the first frame.
625         if(result < 0) result = 0;
626
627         VFrame *temp = frames[result];
628         for(int i = result; i < lookahead_size - 1; i++)
629         {
630                 frames[i] = frames[i + 1];
631                 differences[i] = differences[i + 1];
632         }
633
634
635         frames[lookahead_size - 1] = temp;
636         lookahead_size--;
637         send_render_gui(&result);
638 }
639
640 void Decimate::fill_lookahead(double frame_rate,
641         int64_t start_position)
642 {
643 // Lookahead rate changed
644         if(!EQUIV(config.input_rate, lookahead_rate))
645         {
646                 lookahead_size = 0;
647         }
648
649         lookahead_rate = config.input_rate;
650
651 // Start position is not contiguous with last request
652         if(last_position + 1 != start_position)
653         {
654                 lookahead_size = 0;
655         }
656
657         last_position = start_position;
658
659 // Normalize requested position to input rate
660         if(!lookahead_size)
661         {
662                 lookahead_end = (int64_t)((double)start_position *
663                         config.input_rate /
664                         frame_rate);
665         }
666
667         while(lookahead_size < TOTAL_FRAMES)
668         {
669 // Import frame into next lookahead slot
670                 read_frame(frames[lookahead_size],
671                         0,
672                         lookahead_end,
673                         config.input_rate,
674                         0);
675 // Fill difference buffer
676                 if(lookahead_size > 0)
677                         differences[lookahead_size] =
678                                 calculate_difference(frames[lookahead_size - 1],
679                                         frames[lookahead_size]);
680
681 // Increase counters relative to input rate
682                 lookahead_size++;
683                 lookahead_end++;
684
685 // Decimate one if last frame in buffer and lookahead_end is behind predicted
686 // end.
687                 int64_t decimated_end = (int64_t)((double)(start_position + TOTAL_FRAMES) *
688                         config.input_rate /
689                         frame_rate);
690                 if(lookahead_size >= TOTAL_FRAMES &&
691                         lookahead_end < decimated_end)
692                 {
693                         decimate_frame();
694                 }
695         }
696 }
697
698
699 int Decimate::process_buffer(VFrame *frame,
700         int64_t start_position,
701         double frame_rate)
702 {
703
704 //printf("Decimate::process_buffer 1 %lld %f\n", start_position, frame_rate);
705         load_configuration();
706
707         if(!frames[0])
708         {
709                 for(int i = 0; i < TOTAL_FRAMES; i++) {
710                         frames[i] = new VFrame(frame->get_w(), frame->get_h(),
711                                         frame->get_color_model(), 0);
712                 }
713         }
714
715
716 // Fill lookahead buffer at input rate with decimation
717         fill_lookahead(frame_rate, start_position);
718
719 // printf("Decimate::process_buffer");
720 // for(int i = 0; i < TOTAL_FRAMES; i++)
721 // printf(" %lld", differences[i]);
722 // printf("\n");
723
724
725 // Pull first frame off lookahead
726         frame->copy_from(frames[0]);
727         VFrame *temp = frames[0];
728         for(int i = 0; i < TOTAL_FRAMES - 1; i++)
729         {
730                 frames[i] = frames[i + 1];
731                 differences[i] = differences[i + 1];
732         }
733         frames[TOTAL_FRAMES - 1] = temp;
734         lookahead_size--;
735         return 0;
736 }
737
738
739
740 const char* Decimate::plugin_title() { return N_("Decimate"); }
741 int Decimate::is_realtime() { return 1; }
742
743 NEW_WINDOW_MACRO(Decimate, DecimateWindow)
744
745
746 int Decimate::load_configuration()
747 {
748         KeyFrame *prev_keyframe;
749         DecimateConfig old_config;
750         old_config.copy_from(&config);
751         prev_keyframe = get_prev_keyframe(get_source_position());
752         read_data(prev_keyframe);
753         return !old_config.equivalent(&config);
754 }
755
756
757 void Decimate::save_data(KeyFrame *keyframe)
758 {
759         FileXML output;
760
761 // cause data to be stored directly in text
762         output.set_shared_output(keyframe->xbuf);
763         output.tag.set_title("DECIMATE");
764         output.tag.set_property("INPUT_RATE", config.input_rate);
765 //      output.tag.set_property("AVERAGED_FRAMES", config.averaged_frames);
766 //      output.tag.set_property("LEAST_DIFFERENCE", config.least_difference);
767         output.append_tag();
768         output.tag.set_title("/DECIMATE");
769         output.append_tag();
770         output.append_newline();
771         output.terminate_string();
772 }
773
774 void Decimate::read_data(KeyFrame *keyframe)
775 {
776         FileXML input;
777
778         input.set_shared_input(keyframe->xbuf);
779
780         while(!input.read_tag())
781         {
782                 if(input.tag.title_is("DECIMATE"))
783                 {
784                         config.input_rate = input.tag.get_property("INPUT_RATE", config.input_rate);
785 //                      config.averaged_frames = input.tag.get_property("AVERAGED_FRAMES", config.averaged_frames);
786 //                      config.least_difference = input.tag.get_property("LEAST_DIFFERENCE", config.least_difference);
787                         config.input_rate = Units::fix_framerate(config.input_rate);
788                 }
789         }
790 }
791
792 void Decimate::update_gui()
793 {
794         if(thread)
795         {
796                 if(load_configuration())
797                 {
798                         ((DecimateWindow*)thread->window)->lock_window("Decimate::update_gui");
799                         ((DecimateWindow*)thread->window)->rate->update((float)config.input_rate);
800 //              ((DecimateWindow*)thread->window)->difference->update(config.least_difference);
801 //              ((DecimateWindow*)thread->window)->avg_difference->update(config.averaged_frames);
802                         ((DecimateWindow*)thread->window)->unlock_window();
803                 }
804         }
805 }
806
807 void Decimate::render_gui(void *data)
808 {
809         if(thread)
810         {
811                 ((DecimateWindow*)thread->window)->lock_window("Decimate::render_gui");
812
813                 int dropped = *(int*)data;
814                 char string[BCTEXTLEN];
815
816                 sprintf(string, "%d", dropped);
817                 ((DecimateWindow*)thread->window)->last_dropped->update(string);
818
819                 ((DecimateWindow*)thread->window)->unlock_window();
820         }
821 }
822
823
824