r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / plugins / decimate / decimate.C
blob447132fed2e3663ee154682cef24b154dd7f4728
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, temp_type, components) \
422 { \
423         temp_type result2 = 0; \
424         for(int i = 0; i < h; i++) \
425         { \
426                 type *row1 = (type*)frame1->get_rows()[i]; \
427                 type *row2 = (type*)frame2->get_rows()[i]; \
428                 for(int j = 0; j < w * components; j++) \
429                 { \
430                         temp_type temp = *row1 - *row2; \
431                         result2 += (temp > 0 ? temp : -temp); \
432                         row1++; \
433                         row2++; \
434                 } \
435         } \
436         result = (int64_t)result2; \
439 int64_t Decimate::calculate_difference(VFrame *frame1, VFrame *frame2)
441         int w = frame1->get_w();
442         int h = frame1->get_h();
443         int64_t result = 0;
444         switch(frame1->get_color_model())
445         {
446                 case BC_RGB888:
447                 case BC_YUV888:
448                         DIFFERENCE_MACRO(unsigned char, int64_t, 3);
449                         break;
450                 case BC_RGB_FLOAT:
451                         DIFFERENCE_MACRO(float, double, 3);
452                         break;
453                 case BC_RGBA8888:
454                 case BC_YUVA8888:
455                         DIFFERENCE_MACRO(unsigned char, int64_t, 4);
456                         break;
457                 case BC_RGBA_FLOAT:
458                         DIFFERENCE_MACRO(float, double, 4);
459                         break;
460                 case BC_RGB161616:
461                 case BC_YUV161616:
462                         DIFFERENCE_MACRO(uint16_t, int64_t, 3);
463                         break;
464                 case BC_RGBA16161616:
465                 case BC_YUVA16161616:
466                         DIFFERENCE_MACRO(uint16_t, int64_t, 4);
467                         break;
468         }
469         return result;
472 void Decimate::init_fdct()
474   int i, j;
475   double s;
477   for (i=0; i<8; i++)
478   {
479     s = (i==0) ? sqrt(0.125) : 0.5;
481     for (j=0; j<8; j++)
482       c[i][j] = s * cos((M_PI/8.0)*i*(j+0.5));
483   }
486 void Decimate::fdct(uint16_t *block)
488         int i, j;
489         double s;
490         double tmp[64];
492         for(i = 0; i < 8; i++)
493         for(j = 0; j < 8; j++)
494         {
495                 s = 0.0;
498  *              for(k = 0; k < 8; k++)
499  *                      s += c[j][k] * block[8 * i + k];
500  */
501                 s += c[j][0] * block[8 * i + 0];
502                 s += c[j][1] * block[8 * i + 1];
503                 s += c[j][2] * block[8 * i + 2];
504                 s += c[j][3] * block[8 * i + 3];
505                 s += c[j][4] * block[8 * i + 4];
506                 s += c[j][5] * block[8 * i + 5];
507                 s += c[j][6] * block[8 * i + 6];
508                 s += c[j][7] * block[8 * i + 7];
510                 tmp[8 * i + j] = s;
511         }
513         for(j = 0; j < 8; j++)
514         for(i = 0; i < 8; i++)
515         {
516                 s = 0.0;
519  *              for(k = 0; k < 8; k++)
520  *                  s += c[i][k] * tmp[8 * k + j];
521  */
522                 s += c[i][0] * tmp[8 * 0 + j];
523                 s += c[i][1] * tmp[8 * 1 + j];
524                 s += c[i][2] * tmp[8 * 2 + j];
525                 s += c[i][3] * tmp[8 * 3 + j];
526                 s += c[i][4] * tmp[8 * 4 + j];
527                 s += c[i][5] * tmp[8 * 5 + j];
528                 s += c[i][6] * tmp[8 * 6 + j];
529                 s += c[i][7] * tmp[8 * 7 + j];
531                 block[8 * i + j] = (int)floor(s + 0.499999);
533  * reason for adding 0.499999 instead of 0.5:
534  * s is quite often x.5 (at least for i and/or j = 0 or 4)
535  * and setting the rounding threshold exactly to 0.5 leads to an
536  * extremely high arithmetic implementation dependency of the result;
537  * s being between x.5 and x.500001 (which is now incorrectly rounded
538  * downwards instead of upwards) is assumed to occur less often
539  * (if at all)
540  */
541       }
545 #define CALCULATE_DCT(type, components) \
546 { \
547         uint16_t *output = temp; \
548         for(int k = 0; k < 8; k++) \
549         { \
550                 type *input = (type*)frame->get_rows()[i + k] + j * components; \
551                 for(int l = 0; l < 8; l++) \
552                 { \
553                         *output = (*input << 8) | *input; \
554                         output++; \
555                         input += components; \
556                 } \
557         } \
558         fdct(temp); \
561 int64_t Decimate::calculate_fdct(VFrame *frame)
563         if(!fdct_ready)
564         {
565                 init_fdct();
566                 fdct_ready = 1;
567         }
569         uint16_t temp[64];
570         uint64_t result[64];
571         bzero(result, sizeof(int64_t) * 64);
572         int w = frame->get_w();
573         int h = frame->get_h();
576         for(int i = 0; i < h - 8; i += 8)
577         {
578                 for(int j = 0; j < w - 8; j += 8)
579                 {
580                         CALCULATE_DCT(unsigned char, 3)
581 // Add result to accumulation of transforms
582                         for(int k = 0; k < 64; k++)
583                         {
584                                 result[k] += temp[k];
585                         }
586                 }
587         }
589         uint64_t max_result = 0;
590         int highest = 0;
591         for(int i = 0; i < 64; i++)
592         {
593                 if(result[i] > max_result)
594                 {
595                         max_result = result[i];
596                         highest = i;
597                 }
598         }
600         return highest;
603 void Decimate::decimate_frame()
605         int64_t min_difference = 0x7fffffffffffffffLL;
606         int64_t max_difference2 = 0x0;
607         int result = -1;
609         if(!lookahead_size) return;
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         }
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;
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         }
635         frames[lookahead_size - 1] = temp;
636         lookahead_size--;
637         send_render_gui(&result);
640 void Decimate::fill_lookahead(double frame_rate,
641         int64_t start_position)
643 // Lookahead rate changed
644         if(!EQUIV(config.input_rate, lookahead_rate))
645         {
646                 lookahead_size = 0;
647         }
649         lookahead_rate = config.input_rate;
651 // Start position is not contiguous with last request
652         if(last_position + 1 != start_position)
653         {
654                 lookahead_size = 0;
655         }
657         last_position = start_position;
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         }
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 // Fill difference buffer
675                 if(lookahead_size > 0)
676                         differences[lookahead_size] = 
677                                 calculate_difference(frames[lookahead_size - 1], 
678                                         frames[lookahead_size]);
680 // Increase counters relative to input rate
681                 lookahead_size++;
682                 lookahead_end++;
684 // Decimate one if last frame in buffer and lookahead_end is behind predicted
685 // end.
686                 int64_t decimated_end = (int64_t)((double)(start_position + TOTAL_FRAMES) *
687                         config.input_rate / 
688                         frame_rate);
689                 if(lookahead_size >= TOTAL_FRAMES &&
690                         lookahead_end < decimated_end)
691                 {
692                         decimate_frame();
693                 }
694         }
698 int Decimate::process_buffer(VFrame *frame,
699         int64_t start_position,
700         double frame_rate)
703 //printf("Decimate::process_buffer 1 %lld %f\n", start_position, frame_rate);
704         load_configuration();
706         if(!frames[0])
707         {
708                 for(int i = 0; i < TOTAL_FRAMES; i++)
709                 {
710                         frames[i] = new VFrame(0,
711                                 frame->get_w(),
712                                 frame->get_h(),
713                                 frame->get_color_model(),
714                                 -1);
715                 }
716         }
719 // Fill lookahead buffer at input rate with decimation
720         fill_lookahead(frame_rate, start_position);
722 // printf("Decimate::process_buffer");
723 // for(int i = 0; i < TOTAL_FRAMES; i++)
724 // printf(" %lld", differences[i]);
725 // printf("\n");
728 // Pull first frame off lookahead
729         frame->copy_from(frames[0]);
730         VFrame *temp = frames[0];
731         for(int i = 0; i < TOTAL_FRAMES - 1; i++)
732         {
733                 frames[i] = frames[i + 1];
734                 differences[i] = differences[i + 1];
735         }
736         frames[TOTAL_FRAMES - 1] = temp;
737         lookahead_size--;
738         return 0;
743 char* Decimate::plugin_title() { return N_("Decimate"); }
744 int Decimate::is_realtime() { return 1; }
746 NEW_PICON_MACRO(Decimate) 
748 SHOW_GUI_MACRO(Decimate, DecimateThread)
750 RAISE_WINDOW_MACRO(Decimate)
752 SET_STRING_MACRO(Decimate);
754 int Decimate::load_configuration()
756         KeyFrame *prev_keyframe;
757         DecimateConfig old_config;
758         old_config.copy_from(&config);
759         prev_keyframe = get_prev_keyframe(get_source_position());
760         read_data(prev_keyframe);
761         return !old_config.equivalent(&config);
764 int Decimate::load_defaults()
766         char directory[BCTEXTLEN];
767 // set the default directory
768         sprintf(directory, "%sdecimate.rc", BCASTDIR);
770 // load the defaults
771         defaults = new Defaults(directory);
772         defaults->load();
774         config.input_rate = defaults->get("INPUT_RATE", config.input_rate);
775 //      config.averaged_frames = defaults->get("AVERAGED_FRAMES", config.averaged_frames);
776 //      config.least_difference = defaults->get("LEAST_DIFFERENCE", config.least_difference);
777         config.input_rate = Units::fix_framerate(config.input_rate);
778         return 0;
781 int Decimate::save_defaults()
783         defaults->update("INPUT_RATE", config.input_rate);
784 //      defaults->update("AVERAGED_FRAMES", config.averaged_frames);
785 //      defaults->update("LEAST_DIFFERENCE", config.least_difference);
786         defaults->save();
787         return 0;
790 void Decimate::save_data(KeyFrame *keyframe)
792         FileXML output;
794 // cause data to be stored directly in text
795         output.set_shared_string(keyframe->data, MESSAGESIZE);
796         output.tag.set_title("DECIMATE");
797         output.tag.set_property("INPUT_RATE", config.input_rate);
798 //      output.tag.set_property("AVERAGED_FRAMES", config.averaged_frames);
799 //      output.tag.set_property("LEAST_DIFFERENCE", config.least_difference);
800         output.append_tag();
801         output.terminate_string();
804 void Decimate::read_data(KeyFrame *keyframe)
806         FileXML input;
808         input.set_shared_string(keyframe->data, strlen(keyframe->data));
810         int result = 0;
812         while(!input.read_tag())
813         {
814                 if(input.tag.title_is("DECIMATE"))
815                 {
816                         config.input_rate = input.tag.get_property("INPUT_RATE", config.input_rate);
817 //                      config.averaged_frames = input.tag.get_property("AVERAGED_FRAMES", config.averaged_frames);
818 //                      config.least_difference = input.tag.get_property("LEAST_DIFFERENCE", config.least_difference);
819                         config.input_rate = Units::fix_framerate(config.input_rate);
820                 }
821         }
824 void Decimate::update_gui()
826         if(thread)
827         {
828                 if(load_configuration())
829                 {
830                         thread->window->lock_window("Decimate::update_gui");
831                         thread->window->rate->update((float)config.input_rate);
832 //              thread->window->difference->update(config.least_difference);
833 //              thread->window->avg_difference->update(config.averaged_frames);
834                         thread->window->unlock_window();
835                 }
836         }
839 void Decimate::render_gui(void *data)
841         if(thread)
842         {
843                 thread->window->lock_window("Decimate::render_gui");
845                 int dropped = *(int*)data;
846                 char string[BCTEXTLEN];
848                 sprintf(string, "%d", dropped);
849                 thread->window->last_dropped->update(string);
851                 thread->window->unlock_window();
852         }