4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
29 #include "pluginvclient.h"
36 #define TOP_FIELD_FIRST 0
37 #define BOTTOM_FIELD_FIRST 1
38 #define TOTAL_FRAMES 10
48 void copy_from(DecimateConfig *config);
49 int equivalent(DecimateConfig *config);
52 // Averaged frames is useless. Some of the frames are permanently
53 // destroyed in conversion from PAL to NTSC.
61 class DecimateRate : public BC_TextBox
64 DecimateRate(Decimate *plugin,
73 class DecimateRateMenu : public BC_ListBox
76 DecimateRateMenu(Decimate *plugin,
85 class DecimateDifference : public BC_CheckBox
88 DecimateDifference(Decimate *plugin,
95 class DecimateAvgDifference : public BC_CheckBox
98 DecimateAvgDifference(Decimate *plugin,
106 class DecimateWindow : public PluginClientWindow
109 DecimateWindow(Decimate *plugin);
112 void create_objects();
114 ArrayList<BC_ListBoxItem*> frame_rates;
117 DecimateRateMenu *rate_menu;
118 BC_Title *last_dropped;
119 // DecimateDifference *difference;
120 // DecimateAvgDifference *avg_difference;
127 class Decimate : public PluginVClient
130 Decimate(PluginServer *server);
133 PLUGIN_CLASS_MEMBERS(DecimateConfig)
135 int process_buffer(VFrame *frame,
136 int64_t start_position,
139 void save_data(KeyFrame *keyframe);
140 void read_data(KeyFrame *keyframe);
142 void render_gui(void *data);
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();
149 void fdct(uint16_t *block);
150 int64_t calculate_fdct(VFrame *frame);
156 // each difference is the difference between the previous frame and the
158 int64_t differences[TOTAL_FRAMES];
160 // read ahead number of frames
161 VFrame *frames[TOTAL_FRAMES];
162 // Number of frames in the lookahead buffer
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;
184 DecimateConfig::DecimateConfig()
186 input_rate = (double)30000 / 1001;
187 least_difference = 1;
191 void DecimateConfig::copy_from(DecimateConfig *config)
193 this->input_rate = config->input_rate;
194 this->least_difference = config->least_difference;
195 this->averaged_frames = config->averaged_frames;
198 int DecimateConfig::equivalent(DecimateConfig *config)
200 return EQUIV(this->input_rate, config->input_rate);
211 DecimateWindow::DecimateWindow(Decimate *plugin)
212 : PluginClientWindow(plugin,
219 this->plugin = plugin;
222 DecimateWindow::~DecimateWindow()
224 frame_rates.remove_all_objects();
227 void DecimateWindow::create_objects()
230 int x = xS(10), y = yS(10);
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"));
247 add_subwindow(title = new BC_Title(x, y, _("Input frames per second:")));
249 add_subwindow(rate = new DecimateRate(plugin,
253 add_subwindow(rate_menu = new DecimateRateMenu(plugin,
255 x + rate->get_w() + xS(5),
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, ""));
262 // add_subwindow(difference = new DecimateDifference(plugin,
266 // add_subwindow(avg_difference = new DecimateAvgDifference(plugin,
285 DecimateRate::DecimateRate(Decimate *plugin,
289 : BC_TextBox(x, y, xS(90), 1,
290 (float)plugin->config.input_rate)
292 this->plugin = plugin;
296 int DecimateRate::handle_event()
298 plugin->config.input_rate = Units::atoframerate(get_text());
299 plugin->send_configure_change();
305 // DecimateDifference::DecimateDifference(Decimate *plugin,
308 // : BC_CheckBox(x, y, plugin->config.least_difference, "Drop least difference")
310 // this->plugin = plugin;
312 // int DecimateDifference::handle_event()
314 // plugin->config.least_difference = get_value();
315 // plugin->send_configure_change();
322 // DecimateAvgDifference::DecimateAvgDifference(Decimate *plugin,
325 // : BC_CheckBox(x, y, plugin->config.averaged_frames, "Drop averaged frames")
327 // this->plugin = plugin;
330 // int DecimateAvgDifference::handle_event()
332 // plugin->config.averaged_frames = get_value();
333 // plugin->send_configure_change();
340 DecimateRateMenu::DecimateRateMenu(Decimate *plugin,
356 this->plugin = plugin;
360 int DecimateRateMenu::handle_event()
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();
389 REGISTER_PLUGIN(Decimate)
396 Decimate::Decimate(PluginServer *server)
397 : PluginVClient(server)
400 bzero(frames, sizeof(VFrame*) * TOTAL_FRAMES);
401 for(int i = 0; i < TOTAL_FRAMES; i++)
410 Decimate::~Decimate()
415 for(int i = 0; i < TOTAL_FRAMES; i++)
422 #define DIFFERENCE_MACRO(type, temp_type, components) \
424 temp_type result2 = 0; \
425 for(int i = 0; i < h; i++) \
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++) \
431 temp_type temp = *row1 - *row2; \
432 result2 += (temp > 0 ? temp : -temp); \
437 result = (int64_t)result2; \
440 int64_t Decimate::calculate_difference(VFrame *frame1, VFrame *frame2)
442 int w = frame1->get_w();
443 int h = frame1->get_h();
445 switch(frame1->get_color_model())
449 DIFFERENCE_MACRO(unsigned char, int64_t, 3);
452 DIFFERENCE_MACRO(float, double, 3);
456 DIFFERENCE_MACRO(unsigned char, int64_t, 4);
459 DIFFERENCE_MACRO(float, double, 4);
463 DIFFERENCE_MACRO(uint16_t, int64_t, 3);
465 case BC_RGBA16161616:
466 case BC_YUVA16161616:
467 DIFFERENCE_MACRO(uint16_t, int64_t, 4);
473 void Decimate::init_fdct()
480 s = (i==0) ? sqrt(0.125) : 0.5;
483 c[i][j] = s * cos((M_PI/8.0)*i*(j+0.5));
487 void Decimate::fdct(uint16_t *block)
493 for(i = 0; i < 8; i++)
494 for(j = 0; j < 8; j++)
499 * for(k = 0; k < 8; k++)
500 * s += c[j][k] * block[8 * i + k];
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];
514 for(j = 0; j < 8; j++)
515 for(i = 0; i < 8; i++)
520 * for(k = 0; k < 8; k++)
521 * s += c[i][k] * tmp[8 * k + j];
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];
532 block[8 * i + j] = (int)floor(s + 0.499999);
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
546 #define CALCULATE_DCT(type, components) \
548 uint16_t *output = temp; \
549 for(int k = 0; k < 8; k++) \
551 type *input = (type*)frame->get_rows()[i + k] + j * components; \
552 for(int l = 0; l < 8; l++) \
554 *output = (*input << 8) | *input; \
556 input += components; \
562 int64_t Decimate::calculate_fdct(VFrame *frame)
572 bzero(result, sizeof(int64_t) * 64);
573 int w = frame->get_w();
574 int h = frame->get_h();
577 for(int i = 0; i < h - 8; i += 8)
579 for(int j = 0; j < w - 8; j += 8)
581 CALCULATE_DCT(unsigned char, 3)
582 // Add result to accumulation of transforms
583 for(int k = 0; k < 64; k++)
585 result[k] += temp[k];
590 uint64_t max_result = 0;
592 for(int i = 0; i < 64; i++)
594 if(result[i] > max_result)
596 max_result = result[i];
604 void Decimate::decimate_frame()
606 int64_t min_difference = 0x7fffffffffffffffLL;
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],
675 // Fill difference buffer
676 if(lookahead_size > 0)
677 differences[lookahead_size] =
678 calculate_difference(frames[lookahead_size - 1],
679 frames[lookahead_size]);
681 // Increase counters relative to input rate
685 // Decimate one if last frame in buffer and lookahead_end is behind predicted
687 int64_t decimated_end = (int64_t)((double)(start_position + TOTAL_FRAMES) *
690 if(lookahead_size >= TOTAL_FRAMES &&
691 lookahead_end < decimated_end)
699 int Decimate::process_buffer(VFrame *frame,
700 int64_t start_position,
704 //printf("Decimate::process_buffer 1 %lld %f\n", start_position, frame_rate);
705 load_configuration();
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);
716 // Fill lookahead buffer at input rate with decimation
717 fill_lookahead(frame_rate, start_position);
719 // printf("Decimate::process_buffer");
720 // for(int i = 0; i < TOTAL_FRAMES; i++)
721 // printf(" %lld", differences[i]);
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++)
730 frames[i] = frames[i + 1];
731 differences[i] = differences[i + 1];
733 frames[TOTAL_FRAMES - 1] = temp;
740 const char* Decimate::plugin_title() { return N_("Decimate"); }
741 int Decimate::is_realtime() { return 1; }
743 NEW_WINDOW_MACRO(Decimate, DecimateWindow)
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);
757 void Decimate::save_data(KeyFrame *keyframe)
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);
768 output.tag.set_title("/DECIMATE");
770 output.append_newline();
771 output.terminate_string();
774 void Decimate::read_data(KeyFrame *keyframe)
778 input.set_shared_input(keyframe->xbuf);
780 while(!input.read_tag())
782 if(input.tag.title_is("DECIMATE"))
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);
792 void Decimate::update_gui()
796 if(load_configuration())
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();
807 void Decimate::render_gui(void *data)
811 ((DecimateWindow*)thread->window)->lock_window("Decimate::render_gui");
813 int dropped = *(int*)data;
814 char string[BCTEXTLEN];
816 sprintf(string, "%d", dropped);
817 ((DecimateWindow*)thread->window)->last_dropped->update(string);
819 ((DecimateWindow*)thread->window)->unlock_window();