1 #include "bcdisplayinfo.h"
9 #include "pluginvclient.h"
16 #define TOP_FIELD_FIRST 0
17 #define BOTTOM_FIELD_FIRST 1
18 #define TOTAL_FRAMES 10
28 void copy_from(DecimateConfig *config);
29 int equivalent(DecimateConfig *config);
32 // Averaged frames is useless. Some of the frames are permanently
33 // destroyed in conversion from PAL to NTSC.
41 class DecimateRate : public BC_TextBox
44 DecimateRate(Decimate *plugin,
53 class DecimateRateMenu : public BC_ListBox
56 DecimateRateMenu(Decimate *plugin,
65 class DecimateDifference : public BC_CheckBox
68 DecimateDifference(Decimate *plugin,
75 class DecimateAvgDifference : public BC_CheckBox
78 DecimateAvgDifference(Decimate *plugin,
86 class DecimateWindow : public BC_Window
89 DecimateWindow(Decimate *plugin, int x, int y);
92 void create_objects();
95 ArrayList<BC_ListBoxItem*> frame_rates;
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
112 Decimate(PluginServer *server);
115 int process_buffer(VFrame *frame,
116 int64_t start_position,
119 char* plugin_title();
122 int load_configuration();
126 void save_data(KeyFrame *keyframe);
127 void read_data(KeyFrame *keyframe);
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();
137 void fdct(uint16_t *block);
138 int64_t calculate_fdct(VFrame *frame);
144 // each difference is the difference between the previous frame and the
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
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;
175 DecimateConfig::DecimateConfig()
177 input_rate = (double)30000 / 1001;
178 least_difference = 1;
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,
214 this->plugin = plugin;
217 DecimateWindow::~DecimateWindow()
219 frame_rates.remove_all_objects();
222 void DecimateWindow::create_objects()
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"));
241 add_subwindow(title = new BC_Title(x, y, "Input frames per second:"));
243 add_subwindow(rate = new DecimateRate(plugin,
247 add_subwindow(rate_menu = new DecimateRateMenu(plugin,
249 x + rate->get_w() + 5,
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, ""));
256 // add_subwindow(difference = new DecimateDifference(plugin,
260 // add_subwindow(avg_difference = new DecimateAvgDifference(plugin,
267 WINDOW_CLOSE_EVENT(DecimateWindow)
280 DecimateRate::DecimateRate(Decimate *plugin,
288 (float)plugin->config.input_rate)
290 this->plugin = plugin;
294 int DecimateRate::handle_event()
296 plugin->config.input_rate = Units::atoframerate(get_text());
297 plugin->send_configure_change();
303 // DecimateDifference::DecimateDifference(Decimate *plugin,
306 // : BC_CheckBox(x, y, plugin->config.least_difference, "Drop least difference")
308 // this->plugin = plugin;
310 // int DecimateDifference::handle_event()
312 // plugin->config.least_difference = get_value();
313 // plugin->send_configure_change();
320 // DecimateAvgDifference::DecimateAvgDifference(Decimate *plugin,
323 // : BC_CheckBox(x, y, plugin->config.averaged_frames, "Drop averaged frames")
325 // this->plugin = plugin;
328 // int DecimateAvgDifference::handle_event()
330 // plugin->config.averaged_frames = get_value();
331 // plugin->send_configure_change();
338 DecimateRateMenu::DecimateRateMenu(Decimate *plugin,
354 this->plugin = plugin;
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();
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++)
409 Decimate::~Decimate()
411 PLUGIN_DESTRUCTOR_MACRO
414 for(int i = 0; i < TOTAL_FRAMES; i++)
421 #define DIFFERENCE_MACRO(type, temp_type, components) \
423 temp_type result2 = 0; \
424 for(int i = 0; i < h; i++) \
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++) \
430 temp_type temp = *row1 - *row2; \
431 result2 += (temp > 0 ? temp : -temp); \
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();
444 switch(frame1->get_color_model())
448 DIFFERENCE_MACRO(unsigned char, int64_t, 3);
451 DIFFERENCE_MACRO(float, double, 3);
455 DIFFERENCE_MACRO(unsigned char, int64_t, 4);
458 DIFFERENCE_MACRO(float, double, 4);
462 DIFFERENCE_MACRO(uint16_t, int64_t, 3);
464 case BC_RGBA16161616:
465 case BC_YUVA16161616:
466 DIFFERENCE_MACRO(uint16_t, int64_t, 4);
472 void Decimate::init_fdct()
479 s = (i==0) ? sqrt(0.125) : 0.5;
482 c[i][j] = s * cos((M_PI/8.0)*i*(j+0.5));
486 void Decimate::fdct(uint16_t *block)
492 for(i = 0; i < 8; i++)
493 for(j = 0; j < 8; j++)
498 * for(k = 0; k < 8; k++)
499 * s += c[j][k] * block[8 * i + k];
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];
513 for(j = 0; j < 8; j++)
514 for(i = 0; i < 8; i++)
519 * for(k = 0; k < 8; k++)
520 * s += c[i][k] * tmp[8 * k + j];
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
545 #define CALCULATE_DCT(type, components) \
547 uint16_t *output = temp; \
548 for(int k = 0; k < 8; k++) \
550 type *input = (type*)frame->get_rows()[i + k] + j * components; \
551 for(int l = 0; l < 8; l++) \
553 *output = (*input << 8) | *input; \
555 input += components; \
561 int64_t Decimate::calculate_fdct(VFrame *frame)
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)
578 for(int j = 0; j < w - 8; j += 8)
580 CALCULATE_DCT(unsigned char, 3)
581 // Add result to accumulation of transforms
582 for(int k = 0; k < 64; k++)
584 result[k] += temp[k];
589 uint64_t max_result = 0;
591 for(int i = 0; i < 64; i++)
593 if(result[i] > max_result)
595 max_result = result[i];
603 void Decimate::decimate_frame()
605 int64_t min_difference = 0x7fffffffffffffffLL;
606 int64_t max_difference2 = 0x0;
609 if(!lookahead_size) return;
611 for(int i = 0; i < lookahead_size; i++)
613 // Drop least different frame from sequence
614 if(config.least_difference &&
615 differences[i] >= 0 &&
616 differences[i] < min_difference)
618 min_difference = differences[i];
623 // If all the frames had differences of 0, like a pure black screen, delete
625 if(result < 0) result = 0;
627 VFrame *temp = frames[result];
628 for(int i = result; i < lookahead_size - 1; i++)
630 frames[i] = frames[i + 1];
631 differences[i] = differences[i + 1];
635 frames[lookahead_size - 1] = temp;
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))
649 lookahead_rate = config.input_rate;
651 // Start position is not contiguous with last request
652 if(last_position + 1 != start_position)
657 last_position = start_position;
659 // Normalize requested position to input rate
662 lookahead_end = (int64_t)((double)start_position *
667 while(lookahead_size < TOTAL_FRAMES)
669 // Import frame into next lookahead slot
670 read_frame(frames[lookahead_size],
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
684 // Decimate one if last frame in buffer and lookahead_end is behind predicted
686 int64_t decimated_end = (int64_t)((double)(start_position + TOTAL_FRAMES) *
689 if(lookahead_size >= TOTAL_FRAMES &&
690 lookahead_end < decimated_end)
698 int Decimate::process_buffer(VFrame *frame,
699 int64_t start_position,
703 //printf("Decimate::process_buffer 1 %lld %f\n", start_position, frame_rate);
704 load_configuration();
708 for(int i = 0; i < TOTAL_FRAMES; i++)
710 frames[i] = new VFrame(0,
713 frame->get_color_model(),
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]);
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++)
733 frames[i] = frames[i + 1];
734 differences[i] = differences[i + 1];
736 frames[TOTAL_FRAMES - 1] = temp;
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);
771 defaults = new Defaults(directory);
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);
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);
790 void Decimate::save_data(KeyFrame *keyframe)
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);
801 output.terminate_string();
804 void Decimate::read_data(KeyFrame *keyframe)
808 input.set_shared_string(keyframe->data, strlen(keyframe->data));
812 while(!input.read_tag())
814 if(input.tag.title_is("DECIMATE"))
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);
824 void Decimate::update_gui()
828 if(load_configuration())
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();
839 void Decimate::render_gui(void *data)
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();