r286: Heroine Virutal's official release 1.2.0
[cinelerra_cv/ct.git] / hvirtual / plugins / decimate / decimate.C
blob3ce405b103a2cc9f9f2168c09937776ae06a19c0
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.h"
4 #include "filexml.h"
5 #include "guicast.h"
6 #include "keyframe.h"
7 #include "language.h"
8 #include "picon_png.h"
9 #include "pluginvclient.h"
10 #include "vframe.h"
12 #include <string.h>
13 #include <stdint.h>
16 #define TOP_FIELD_FIRST 0
17 #define BOTTOM_FIELD_FIRST 1
18 #define TOTAL_FRAMES 10
20 class Decimate;
21 class DecimateWindow;
24 class DecimateConfig
26 public:
27         DecimateConfig();
28         void copy_from(DecimateConfig *config);
29         int equivalent(DecimateConfig *config);
31         double input_rate;
32 // Averaged frames is useless.  Some of the frames are permanently
33 // destroyed in conversion from PAL to NTSC.
34         int averaged_frames;
35         int least_difference;
41 class DecimateRate : public BC_TextBox
43 public:
44         DecimateRate(Decimate *plugin, 
45                 DecimateWindow *gui, 
46                 int x, 
47                 int y);
48         int handle_event();
49         Decimate *plugin;
50         DecimateWindow *gui;
53 class DecimateRateMenu : public BC_ListBox
55 public:
56         DecimateRateMenu(Decimate *plugin, 
57                 DecimateWindow *gui, 
58                 int x, 
59                 int y);
60         int handle_event();
61         Decimate *plugin;
62         DecimateWindow *gui;
65 class DecimateDifference : public BC_CheckBox
67 public:
68         DecimateDifference(Decimate *plugin,
69                 int x, 
70                 int y);
71         int handle_event();
72         Decimate *plugin;
75 class DecimateAvgDifference : public BC_CheckBox
77 public:
78         DecimateAvgDifference(Decimate *plugin,
79                 int x, 
80                 int y);
81         int handle_event();
82         Decimate *plugin;
86 class DecimateWindow : public BC_Window
88 public:
89         DecimateWindow(Decimate *plugin, int x, int y);
90         ~DecimateWindow();
92         void create_objects();
93         int close_event();
95         ArrayList<BC_ListBoxItem*> frame_rates;
96         Decimate *plugin;
97         DecimateRate *rate;
98         DecimateRateMenu *rate_menu;
99         BC_Title *last_dropped;
100 //      DecimateDifference *difference;
101 //      DecimateAvgDifference *avg_difference;
105 PLUGIN_THREAD_HEADER(Decimate, DecimateThread, DecimateWindow)
109 class Decimate : public PluginVClient
111 public:
112         Decimate(PluginServer *server);
113         ~Decimate();
115         int process_buffer(VFrame *frame,
116                 int64_t start_position,
117                 double frame_rate);
118         int is_realtime();
119         char* plugin_title();
120         VFrame* new_picon();
121         int show_gui();
122         int load_configuration();
123         int set_string();
124         int load_defaults();
125         int save_defaults();
126         void save_data(KeyFrame *keyframe);
127         void read_data(KeyFrame *keyframe);
128         void raise_window();
129         void update_gui();
130         void render_gui(void *data);
132         int64_t calculate_difference(VFrame *frame1, VFrame *frame2);
133         void fill_lookahead(double frame_rate,
134                 int64_t start_position);
135         void decimate_frame();
136         void init_fdct();
137         void fdct(uint16_t *block);
138         int64_t calculate_fdct(VFrame *frame);
140 // fdct coefficients
141         double c[8][8];
142         int fdct_ready;
144 // each difference is the difference between the previous frame and the 
145 // subscripted frame
146         int64_t differences[TOTAL_FRAMES];
148 // read ahead number of frames
149         VFrame *frames[TOTAL_FRAMES];
150 // Number of frames in the lookahead buffer
151         int lookahead_size;
152 // Next position beyond end of lookahead buffer relative to input rate
153         int64_t lookahead_end;
154 // Framerate of lookahead buffer
155         double lookahead_rate;
156 // Last requested position
157         int64_t last_position;
159         DecimateThread *thread;
160         DecimateConfig config;
161         Defaults *defaults;
175 DecimateConfig::DecimateConfig()
177         input_rate = (double)30000 / 1001;
178         least_difference = 1;
179         averaged_frames = 0;
182 void DecimateConfig::copy_from(DecimateConfig *config)
184         this->input_rate = config->input_rate;
185         this->least_difference = config->least_difference;
186         this->averaged_frames = config->averaged_frames;
189 int DecimateConfig::equivalent(DecimateConfig *config)
191         return EQUIV(this->input_rate, config->input_rate);
202 DecimateWindow::DecimateWindow(Decimate *plugin, int x, int y)
203  : BC_Window(plugin->gui_string, 
204         x, 
205         y, 
206         210, 
207         160, 
208         200, 
209         160, 
210         0, 
211         0,
212         1)
214         this->plugin = plugin;
217 DecimateWindow::~DecimateWindow()
219         frame_rates.remove_all_objects();
222 void DecimateWindow::create_objects()
224         int x = 10, y = 10;
226         frame_rates.append(new BC_ListBoxItem("1"));
227         frame_rates.append(new BC_ListBoxItem("5"));
228         frame_rates.append(new BC_ListBoxItem("10"));
229         frame_rates.append(new BC_ListBoxItem("12"));
230         frame_rates.append(new BC_ListBoxItem("15"));
231         frame_rates.append(new BC_ListBoxItem("23.97"));
232         frame_rates.append(new BC_ListBoxItem("24"));
233         frame_rates.append(new BC_ListBoxItem("25"));
234         frame_rates.append(new BC_ListBoxItem("29.97"));
235         frame_rates.append(new BC_ListBoxItem("30"));
236         frame_rates.append(new BC_ListBoxItem("50"));
237         frame_rates.append(new BC_ListBoxItem("59.94"));
238         frame_rates.append(new BC_ListBoxItem("60"));
240         BC_Title *title;
241         add_subwindow(title = new BC_Title(x, y, "Input frames per second:"));
242         y += 30;
243         add_subwindow(rate = new DecimateRate(plugin, 
244                 this, 
245                 x, 
246                 y));
247         add_subwindow(rate_menu = new DecimateRateMenu(plugin, 
248                 this, 
249                 x + rate->get_w() + 5, 
250                 y));
251         y += 30;
252         add_subwindow(title = new BC_Title(x, y, "Last frame dropped: "));
253         add_subwindow(last_dropped = new BC_Title(x + title->get_w() + 5, y, ""));
255 //      y += 30;
256 //      add_subwindow(difference = new DecimateDifference(plugin,
257 //              x, 
258 //              y));
259 //      y += 30;
260 //      add_subwindow(avg_difference = new DecimateAvgDifference(plugin,
261 //              x, 
262 //              y));
263         show_window();
264         flush();
267 WINDOW_CLOSE_EVENT(DecimateWindow)
280 DecimateRate::DecimateRate(Decimate *plugin, 
281         DecimateWindow *gui, 
282         int x, 
283         int y)
284  : BC_TextBox(x, 
285         y, 
286         90,
287         1,
288         (float)plugin->config.input_rate)
290         this->plugin = plugin;
291         this->gui = gui;
294 int DecimateRate::handle_event()
296         plugin->config.input_rate = Units::atoframerate(get_text());
297         plugin->send_configure_change();
298         return 1;
303 // DecimateDifference::DecimateDifference(Decimate *plugin,
304 //      int x, 
305 //      int y)
306 //  : BC_CheckBox(x, y, plugin->config.least_difference, "Drop least difference")
307 // {
308 //      this->plugin = plugin;
309 // }
310 // int DecimateDifference::handle_event()
311 // {
312 //      plugin->config.least_difference = get_value();
313 //      plugin->send_configure_change();
314 //      return 1;
315 // }
316 // 
317 // 
318 // 
319 // 
320 // DecimateAvgDifference::DecimateAvgDifference(Decimate *plugin,
321 //      int x, 
322 //      int y)
323 //  : BC_CheckBox(x, y, plugin->config.averaged_frames, "Drop averaged frames")
324 // {
325 //      this->plugin = plugin;
326 // }
327 // 
328 // int DecimateAvgDifference::handle_event()
329 // {
330 //      plugin->config.averaged_frames = get_value();
331 //      plugin->send_configure_change();
332 //      return 1;
333 // }
334 // 
338 DecimateRateMenu::DecimateRateMenu(Decimate *plugin, 
339         DecimateWindow *gui, 
340         int x, 
341         int y)
342  : BC_ListBox(x,
343         y,
344         100,
345         200,
346         LISTBOX_TEXT,
347         &gui->frame_rates,
348         0,
349         0,
350         1,
351         0,
352         1)
354         this->plugin = plugin;
355         this->gui = gui;
358 int DecimateRateMenu::handle_event()
360         char *text = get_selection(0, 0)->get_text();
361         plugin->config.input_rate = atof(text);
362         gui->rate->update(text);
363         plugin->send_configure_change();
364         return 1;
377 PLUGIN_THREAD_OBJECT(Decimate, DecimateThread, DecimateWindow)
388 REGISTER_PLUGIN(Decimate)
395 Decimate::Decimate(PluginServer *server)
396  : PluginVClient(server)
398         PLUGIN_CONSTRUCTOR_MACRO
399         bzero(frames, sizeof(VFrame*) * TOTAL_FRAMES);
400         for(int i = 0; i < TOTAL_FRAMES; i++)
401                 differences[i] = -1;
402         lookahead_size = 0;
403         lookahead_end = -1;
404         last_position = -1;
405         fdct_ready = 0;
409 Decimate::~Decimate()
411         PLUGIN_DESTRUCTOR_MACRO
412         if(frames[0])
413         {
414                 for(int i = 0; i < TOTAL_FRAMES; i++)
415                 {
416                         delete frames[i];
417                 }
418         }
421 #define DIFFERENCE_MACRO(type, components) \
422 { \
423         for(int i = 0; i < h; i++) \
424         { \
425                 type *row1 = (type*)frame1->get_rows()[i]; \
426                 type *row2 = (type*)frame2->get_rows()[i]; \
427                 for(int j = 0; j < w * components; j++) \
428                 { \
429                         int64_t temp = *row1 - *row2; \
430                         result += (temp > 0 ? temp : -temp); \
431                         row1++; \
432                         row2++; \
433                 } \
434         } \
437 int64_t Decimate::calculate_difference(VFrame *frame1, VFrame *frame2)
439         int w = frame1->get_w();
440         int h = frame1->get_h();
441         int64_t result = 0;
442         switch(frame1->get_color_model())
443         {
444                 case BC_RGB888:
445                 case BC_YUV888:
446                         DIFFERENCE_MACRO(unsigned char, 3);
447                         break;
448                 case BC_RGBA8888:
449                 case BC_YUVA8888:
450                         DIFFERENCE_MACRO(unsigned char, 4);
451                         break;
452                 case BC_RGB161616:
453                 case BC_YUV161616:
454                         DIFFERENCE_MACRO(uint16_t, 3);
455                         break;
456                 case BC_RGBA16161616:
457                 case BC_YUVA16161616:
458                         DIFFERENCE_MACRO(uint16_t, 4);
459                         break;
460         }
461         return result;
464 void Decimate::init_fdct()
466   int i, j;
467   double s;
469   for (i=0; i<8; i++)
470   {
471     s = (i==0) ? sqrt(0.125) : 0.5;
473     for (j=0; j<8; j++)
474       c[i][j] = s * cos((M_PI/8.0)*i*(j+0.5));
475   }
478 void Decimate::fdct(uint16_t *block)
480         int i, j;
481         double s;
482         double tmp[64];
484         for(i = 0; i < 8; i++)
485         for(j = 0; j < 8; j++)
486         {
487                 s = 0.0;
490  *              for(k = 0; k < 8; k++)
491  *                      s += c[j][k] * block[8 * i + k];
492  */
493                 s += c[j][0] * block[8 * i + 0];
494                 s += c[j][1] * block[8 * i + 1];
495                 s += c[j][2] * block[8 * i + 2];
496                 s += c[j][3] * block[8 * i + 3];
497                 s += c[j][4] * block[8 * i + 4];
498                 s += c[j][5] * block[8 * i + 5];
499                 s += c[j][6] * block[8 * i + 6];
500                 s += c[j][7] * block[8 * i + 7];
502                 tmp[8 * i + j] = s;
503         }
505         for(j = 0; j < 8; j++)
506         for(i = 0; i < 8; i++)
507         {
508                 s = 0.0;
511  *              for(k = 0; k < 8; k++)
512  *                  s += c[i][k] * tmp[8 * k + j];
513  */
514                 s += c[i][0] * tmp[8 * 0 + j];
515                 s += c[i][1] * tmp[8 * 1 + j];
516                 s += c[i][2] * tmp[8 * 2 + j];
517                 s += c[i][3] * tmp[8 * 3 + j];
518                 s += c[i][4] * tmp[8 * 4 + j];
519                 s += c[i][5] * tmp[8 * 5 + j];
520                 s += c[i][6] * tmp[8 * 6 + j];
521                 s += c[i][7] * tmp[8 * 7 + j];
523                 block[8 * i + j] = (int)floor(s + 0.499999);
525  * reason for adding 0.499999 instead of 0.5:
526  * s is quite often x.5 (at least for i and/or j = 0 or 4)
527  * and setting the rounding threshold exactly to 0.5 leads to an
528  * extremely high arithmetic implementation dependency of the result;
529  * s being between x.5 and x.500001 (which is now incorrectly rounded
530  * downwards instead of upwards) is assumed to occur less often
531  * (if at all)
532  */
533       }
537 #define CALCULATE_DCT(type, components) \
538 { \
539         uint16_t *output = temp; \
540         for(int k = 0; k < 8; k++) \
541         { \
542                 type *input = (type*)frame->get_rows()[i + k] + j * components; \
543                 for(int l = 0; l < 8; l++) \
544                 { \
545                         *output = (*input << 8) | *input; \
546                         output++; \
547                         input += components; \
548                 } \
549         } \
550         fdct(temp); \
553 int64_t Decimate::calculate_fdct(VFrame *frame)
555         if(!fdct_ready)
556         {
557                 init_fdct();
558                 fdct_ready = 1;
559         }
561         uint16_t temp[64];
562         uint64_t result[64];
563         bzero(result, sizeof(int64_t) * 64);
564         int w = frame->get_w();
565         int h = frame->get_h();
568         for(int i = 0; i < h - 8; i += 8)
569         {
570                 for(int j = 0; j < w - 8; j += 8)
571                 {
572                         CALCULATE_DCT(unsigned char, 3)
573 // Add result to accumulation of transforms
574                         for(int k = 0; k < 64; k++)
575                         {
576                                 result[k] += temp[k];
577                         }
578                 }
579         }
581         uint64_t max_result = 0;
582         int highest = 0;
583         for(int i = 0; i < 64; i++)
584         {
585                 if(result[i] > max_result)
586                 {
587                         max_result = result[i];
588                         highest = i;
589                 }
590         }
592         return highest;
595 void Decimate::decimate_frame()
597         int64_t min_difference = 0x7fffffffffffffffLL;
598         int64_t max_difference2 = 0x0;
599         int result = -1;
601         if(!lookahead_size) return;
603         for(int i = 0; i < lookahead_size; i++)
604         {
605 // Drop least different frame from sequence
606                 if(config.least_difference && 
607                         differences[i] >= 0 &&
608                         differences[i] < min_difference)
609                 {
610                         min_difference = differences[i];
611                         result = i;
612                 }
613         }
615 // If all the frames had differences of 0, like a pure black screen, delete
616 // the first frame.
617         if(result < 0) result = 0;
619         VFrame *temp = frames[result];
620         for(int i = result; i < lookahead_size - 1; i++)
621         {
622                 frames[i] = frames[i + 1];
623                 differences[i] = differences[i + 1];
624         }
627         frames[lookahead_size - 1] = temp;
628         lookahead_size--;
629         send_render_gui(&result);
632 void Decimate::fill_lookahead(double frame_rate,
633         int64_t start_position)
635 // Lookahead rate changed
636         if(!EQUIV(config.input_rate, lookahead_rate))
637         {
638                 lookahead_size = 0;
639         }
641         lookahead_rate = config.input_rate;
643 // Start position is not contiguous with last request
644         if(last_position + 1 != start_position)
645         {
646                 lookahead_size = 0;
647         }
649         last_position = start_position;
651 // Normalize requested position to input rate
652         if(!lookahead_size)
653         {
654                 lookahead_end = (int64_t)((double)start_position * 
655                         config.input_rate / 
656                         frame_rate);
657         }
659         while(lookahead_size < TOTAL_FRAMES)
660         {
661 // Import frame into next lookahead slot
662                 read_frame(frames[lookahead_size], 
663                         0, 
664                         lookahead_end, 
665                         config.input_rate);
666 // Fill difference buffer
667                 if(lookahead_size > 0)
668                         differences[lookahead_size] = 
669                                 calculate_difference(frames[lookahead_size - 1], 
670                                         frames[lookahead_size]);
672 // Increase counters relative to input rate
673                 lookahead_size++;
674                 lookahead_end++;
676 // Decimate one if last frame in buffer and lookahead_end is behind predicted
677 // end.
678                 int64_t decimated_end = (int64_t)((double)(start_position + TOTAL_FRAMES) *
679                         config.input_rate / 
680                         frame_rate);
681                 if(lookahead_size >= TOTAL_FRAMES &&
682                         lookahead_end < decimated_end)
683                 {
684                         decimate_frame();
685                 }
686         }
690 int Decimate::process_buffer(VFrame *frame,
691         int64_t start_position,
692         double frame_rate)
695 //printf("Decimate::process_buffer 1 %lld %f\n", start_position, frame_rate);
696         load_configuration();
698         if(!frames[0])
699         {
700                 for(int i = 0; i < TOTAL_FRAMES; i++)
701                 {
702                         frames[i] = new VFrame(0,
703                                 frame->get_w(),
704                                 frame->get_h(),
705                                 frame->get_color_model(),
706                                 -1);
707                 }
708         }
711 // Fill lookahead buffer at input rate with decimation
712         fill_lookahead(frame_rate, start_position);
714 // printf("Decimate::process_buffer");
715 // for(int i = 0; i < TOTAL_FRAMES; i++)
716 // printf(" %lld", differences[i]);
717 // printf("\n");
720 // Pull first frame off lookahead
721         frame->copy_from(frames[0]);
722         VFrame *temp = frames[0];
723         for(int i = 0; i < TOTAL_FRAMES - 1; i++)
724         {
725                 frames[i] = frames[i + 1];
726                 differences[i] = differences[i + 1];
727         }
728         frames[TOTAL_FRAMES - 1] = temp;
729         lookahead_size--;
730         return 0;
735 char* Decimate::plugin_title() { return N_("Decimate"); }
736 int Decimate::is_realtime() { return 1; }
738 NEW_PICON_MACRO(Decimate) 
740 SHOW_GUI_MACRO(Decimate, DecimateThread)
742 RAISE_WINDOW_MACRO(Decimate)
744 SET_STRING_MACRO(Decimate);
746 int Decimate::load_configuration()
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);
756 int Decimate::load_defaults()
758         char directory[BCTEXTLEN];
759 // set the default directory
760         sprintf(directory, "%sdecimate.rc", BCASTDIR);
762 // load the defaults
763         defaults = new Defaults(directory);
764         defaults->load();
766         config.input_rate = defaults->get("INPUT_RATE", config.input_rate);
767 //      config.averaged_frames = defaults->get("AVERAGED_FRAMES", config.averaged_frames);
768 //      config.least_difference = defaults->get("LEAST_DIFFERENCE", config.least_difference);
769         config.input_rate = Units::fix_framerate(config.input_rate);
770         return 0;
773 int Decimate::save_defaults()
775         defaults->update("INPUT_RATE", config.input_rate);
776 //      defaults->update("AVERAGED_FRAMES", config.averaged_frames);
777 //      defaults->update("LEAST_DIFFERENCE", config.least_difference);
778         defaults->save();
779         return 0;
782 void Decimate::save_data(KeyFrame *keyframe)
784         FileXML output;
786 // cause data to be stored directly in text
787         output.set_shared_string(keyframe->data, MESSAGESIZE);
788         output.tag.set_title("DECIMATE");
789         output.tag.set_property("INPUT_RATE", config.input_rate);
790 //      output.tag.set_property("AVERAGED_FRAMES", config.averaged_frames);
791 //      output.tag.set_property("LEAST_DIFFERENCE", config.least_difference);
792         output.append_tag();
793         output.terminate_string();
796 void Decimate::read_data(KeyFrame *keyframe)
798         FileXML input;
800         input.set_shared_string(keyframe->data, strlen(keyframe->data));
802         int result = 0;
804         while(!input.read_tag())
805         {
806                 if(input.tag.title_is("DECIMATE"))
807                 {
808                         config.input_rate = input.tag.get_property("INPUT_RATE", config.input_rate);
809 //                      config.averaged_frames = input.tag.get_property("AVERAGED_FRAMES", config.averaged_frames);
810 //                      config.least_difference = input.tag.get_property("LEAST_DIFFERENCE", config.least_difference);
811                         config.input_rate = Units::fix_framerate(config.input_rate);
812                 }
813         }
816 void Decimate::update_gui()
818         if(thread)
819         {
820                 if(load_configuration())
821                 {
822                         thread->window->lock_window("Decimate::update_gui");
823                         thread->window->rate->update((float)config.input_rate);
824 //              thread->window->difference->update(config.least_difference);
825 //              thread->window->avg_difference->update(config.averaged_frames);
826                         thread->window->unlock_window();
827                 }
828         }
831 void Decimate::render_gui(void *data)
833         if(thread)
834         {
835                 thread->window->lock_window("Decimate::render_gui");
837                 int dropped = *(int*)data;
838                 char string[BCTEXTLEN];
840                 sprintf(string, "%d", dropped);
841                 thread->window->last_dropped->update(string);
843                 thread->window->unlock_window();
844         }