00001 #include "bcdisplayinfo.h"
00002 #include "clip.h"
00003 #include "bchash.h"
00004 #include "filexml.h"
00005 #include "guicast.h"
00006 #include "keyframe.h"
00007 #include "language.h"
00008 #include "picon_png.h"
00009 #include "pluginvclient.h"
00010 #include "vframe.h"
00011
00012 #include <string.h>
00013 #include <stdint.h>
00014
00015
00016 #define TOP_FIELD_FIRST 0
00017 #define BOTTOM_FIELD_FIRST 1
00018 #define TOTAL_FRAMES 10
00019
00020 class Decimate;
00021 class DecimateWindow;
00022
00023
00024 class DecimateConfig
00025 {
00026 public:
00027 DecimateConfig();
00028 void copy_from(DecimateConfig *config);
00029 int equivalent(DecimateConfig *config);
00030
00031 double input_rate;
00032
00033
00034 int averaged_frames;
00035 int least_difference;
00036 };
00037
00038
00039
00040
00041 class DecimateRate : public BC_TextBox
00042 {
00043 public:
00044 DecimateRate(Decimate *plugin,
00045 DecimateWindow *gui,
00046 int x,
00047 int y);
00048 int handle_event();
00049 Decimate *plugin;
00050 DecimateWindow *gui;
00051 };
00052
00053 class DecimateRateMenu : public BC_ListBox
00054 {
00055 public:
00056 DecimateRateMenu(Decimate *plugin,
00057 DecimateWindow *gui,
00058 int x,
00059 int y);
00060 int handle_event();
00061 Decimate *plugin;
00062 DecimateWindow *gui;
00063 };
00064
00065 class DecimateDifference : public BC_CheckBox
00066 {
00067 public:
00068 DecimateDifference(Decimate *plugin,
00069 int x,
00070 int y);
00071 int handle_event();
00072 Decimate *plugin;
00073 };
00074
00075 class DecimateAvgDifference : public BC_CheckBox
00076 {
00077 public:
00078 DecimateAvgDifference(Decimate *plugin,
00079 int x,
00080 int y);
00081 int handle_event();
00082 Decimate *plugin;
00083 };
00084
00085
00086 class DecimateWindow : public BC_Window
00087 {
00088 public:
00089 DecimateWindow(Decimate *plugin, int x, int y);
00090 ~DecimateWindow();
00091
00092 void create_objects();
00093 int close_event();
00094
00095 ArrayList<BC_ListBoxItem*> frame_rates;
00096 Decimate *plugin;
00097 DecimateRate *rate;
00098 DecimateRateMenu *rate_menu;
00099 BC_Title *last_dropped;
00100
00101
00102 };
00103
00104
00105 PLUGIN_THREAD_HEADER(Decimate, DecimateThread, DecimateWindow)
00106
00107
00108
00109 class Decimate : public PluginVClient
00110 {
00111 public:
00112 Decimate(PluginServer *server);
00113 ~Decimate();
00114
00115 int process_buffer(VFrame *frame,
00116 int64_t start_position,
00117 double frame_rate);
00118 int is_realtime();
00119 char* plugin_title();
00120 VFrame* new_picon();
00121 int show_gui();
00122 int load_configuration();
00123 int set_string();
00124 int load_defaults();
00125 int save_defaults();
00126 void save_data(KeyFrame *keyframe);
00127 void read_data(KeyFrame *keyframe);
00128 void raise_window();
00129 void update_gui();
00130 void render_gui(void *data);
00131
00132 int64_t calculate_difference(VFrame *frame1, VFrame *frame2);
00133 void fill_lookahead(double frame_rate,
00134 int64_t start_position);
00135 void decimate_frame();
00136 void init_fdct();
00137 void fdct(uint16_t *block);
00138 int64_t calculate_fdct(VFrame *frame);
00139
00140
00141 double c[8][8];
00142 int fdct_ready;
00143
00144
00145
00146 int64_t differences[TOTAL_FRAMES];
00147
00148
00149 VFrame *frames[TOTAL_FRAMES];
00150
00151 int lookahead_size;
00152
00153 int64_t lookahead_end;
00154
00155 double lookahead_rate;
00156
00157 int64_t last_position;
00158
00159 DecimateThread *thread;
00160 DecimateConfig config;
00161 BC_Hash *defaults;
00162 };
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 DecimateConfig::DecimateConfig()
00176 {
00177 input_rate = (double)30000 / 1001;
00178 least_difference = 1;
00179 averaged_frames = 0;
00180 }
00181
00182 void DecimateConfig::copy_from(DecimateConfig *config)
00183 {
00184 this->input_rate = config->input_rate;
00185 this->least_difference = config->least_difference;
00186 this->averaged_frames = config->averaged_frames;
00187 }
00188
00189 int DecimateConfig::equivalent(DecimateConfig *config)
00190 {
00191 return EQUIV(this->input_rate, config->input_rate);
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202 DecimateWindow::DecimateWindow(Decimate *plugin, int x, int y)
00203 : BC_Window(plugin->gui_string,
00204 x,
00205 y,
00206 210,
00207 160,
00208 200,
00209 160,
00210 0,
00211 0,
00212 1)
00213 {
00214 this->plugin = plugin;
00215 }
00216
00217 DecimateWindow::~DecimateWindow()
00218 {
00219 frame_rates.remove_all_objects();
00220 }
00221
00222 void DecimateWindow::create_objects()
00223 {
00224 int x = 10, y = 10;
00225
00226 frame_rates.append(new BC_ListBoxItem("1"));
00227 frame_rates.append(new BC_ListBoxItem("5"));
00228 frame_rates.append(new BC_ListBoxItem("10"));
00229 frame_rates.append(new BC_ListBoxItem("12"));
00230 frame_rates.append(new BC_ListBoxItem("15"));
00231 frame_rates.append(new BC_ListBoxItem("23.97"));
00232 frame_rates.append(new BC_ListBoxItem("24"));
00233 frame_rates.append(new BC_ListBoxItem("25"));
00234 frame_rates.append(new BC_ListBoxItem("29.97"));
00235 frame_rates.append(new BC_ListBoxItem("30"));
00236 frame_rates.append(new BC_ListBoxItem("50"));
00237 frame_rates.append(new BC_ListBoxItem("59.94"));
00238 frame_rates.append(new BC_ListBoxItem("60"));
00239
00240 BC_Title *title;
00241 add_subwindow(title = new BC_Title(x, y, _("Input frames per second:")));
00242 y += 30;
00243 add_subwindow(rate = new DecimateRate(plugin,
00244 this,
00245 x,
00246 y));
00247 add_subwindow(rate_menu = new DecimateRateMenu(plugin,
00248 this,
00249 x + rate->get_w() + 5,
00250 y));
00251 y += 30;
00252 add_subwindow(title = new BC_Title(x, y, _("Last frame dropped: ")));
00253 add_subwindow(last_dropped = new BC_Title(x + title->get_w() + 5, y, ""));
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 show_window();
00264 flush();
00265 }
00266
00267 WINDOW_CLOSE_EVENT(DecimateWindow)
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 DecimateRate::DecimateRate(Decimate *plugin,
00281 DecimateWindow *gui,
00282 int x,
00283 int y)
00284 : BC_TextBox(x,
00285 y,
00286 90,
00287 1,
00288 (float)plugin->config.input_rate)
00289 {
00290 this->plugin = plugin;
00291 this->gui = gui;
00292 }
00293
00294 int DecimateRate::handle_event()
00295 {
00296 plugin->config.input_rate = Units::atoframerate(get_text());
00297 plugin->send_configure_change();
00298 return 1;
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 DecimateRateMenu::DecimateRateMenu(Decimate *plugin,
00339 DecimateWindow *gui,
00340 int x,
00341 int y)
00342 : BC_ListBox(x,
00343 y,
00344 100,
00345 200,
00346 LISTBOX_TEXT,
00347 &gui->frame_rates,
00348 0,
00349 0,
00350 1,
00351 0,
00352 1)
00353 {
00354 this->plugin = plugin;
00355 this->gui = gui;
00356 }
00357
00358 int DecimateRateMenu::handle_event()
00359 {
00360 char *text = get_selection(0, 0)->get_text();
00361 plugin->config.input_rate = atof(text);
00362 gui->rate->update(text);
00363 plugin->send_configure_change();
00364 return 1;
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 PLUGIN_THREAD_OBJECT(Decimate, DecimateThread, DecimateWindow)
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 REGISTER_PLUGIN(Decimate)
00389
00390
00391
00392
00393
00394
00395 Decimate::Decimate(PluginServer *server)
00396 : PluginVClient(server)
00397 {
00398 PLUGIN_CONSTRUCTOR_MACRO
00399 bzero(frames, sizeof(VFrame*) * TOTAL_FRAMES);
00400 for(int i = 0; i < TOTAL_FRAMES; i++)
00401 differences[i] = -1;
00402 lookahead_size = 0;
00403 lookahead_end = -1;
00404 last_position = -1;
00405 fdct_ready = 0;
00406 }
00407
00408
00409 Decimate::~Decimate()
00410 {
00411 PLUGIN_DESTRUCTOR_MACRO
00412 if(frames[0])
00413 {
00414 for(int i = 0; i < TOTAL_FRAMES; i++)
00415 {
00416 delete frames[i];
00417 }
00418 }
00419 }
00420
00421 #define DIFFERENCE_MACRO(type, temp_type, components) \
00422 { \
00423 temp_type result2 = 0; \
00424 for(int i = 0; i < h; i++) \
00425 { \
00426 type *row1 = (type*)frame1->get_rows()[i]; \
00427 type *row2 = (type*)frame2->get_rows()[i]; \
00428 for(int j = 0; j < w * components; j++) \
00429 { \
00430 temp_type temp = *row1 - *row2; \
00431 result2 += (temp > 0 ? temp : -temp); \
00432 row1++; \
00433 row2++; \
00434 } \
00435 } \
00436 result = (int64_t)result2; \
00437 }
00438
00439 int64_t Decimate::calculate_difference(VFrame *frame1, VFrame *frame2)
00440 {
00441 int w = frame1->get_w();
00442 int h = frame1->get_h();
00443 int64_t result = 0;
00444 switch(frame1->get_color_model())
00445 {
00446 case BC_RGB888:
00447 case BC_YUV888:
00448 DIFFERENCE_MACRO(unsigned char, int64_t, 3);
00449 break;
00450 case BC_RGB_FLOAT:
00451 DIFFERENCE_MACRO(float, double, 3);
00452 break;
00453 case BC_RGBA8888:
00454 case BC_YUVA8888:
00455 DIFFERENCE_MACRO(unsigned char, int64_t, 4);
00456 break;
00457 case BC_RGBA_FLOAT:
00458 DIFFERENCE_MACRO(float, double, 4);
00459 break;
00460 case BC_RGB161616:
00461 case BC_YUV161616:
00462 DIFFERENCE_MACRO(uint16_t, int64_t, 3);
00463 break;
00464 case BC_RGBA16161616:
00465 case BC_YUVA16161616:
00466 DIFFERENCE_MACRO(uint16_t, int64_t, 4);
00467 break;
00468 }
00469 return result;
00470 }
00471
00472 void Decimate::init_fdct()
00473 {
00474 int i, j;
00475 double s;
00476
00477 for (i=0; i<8; i++)
00478 {
00479 s = (i==0) ? sqrt(0.125) : 0.5;
00480
00481 for (j=0; j<8; j++)
00482 c[i][j] = s * cos((M_PI/8.0)*i*(j+0.5));
00483 }
00484 }
00485
00486 void Decimate::fdct(uint16_t *block)
00487 {
00488 int i, j;
00489 double s;
00490 double tmp[64];
00491
00492 for(i = 0; i < 8; i++)
00493 for(j = 0; j < 8; j++)
00494 {
00495 s = 0.0;
00496
00497
00498
00499
00500
00501 s += c[j][0] * block[8 * i + 0];
00502 s += c[j][1] * block[8 * i + 1];
00503 s += c[j][2] * block[8 * i + 2];
00504 s += c[j][3] * block[8 * i + 3];
00505 s += c[j][4] * block[8 * i + 4];
00506 s += c[j][5] * block[8 * i + 5];
00507 s += c[j][6] * block[8 * i + 6];
00508 s += c[j][7] * block[8 * i + 7];
00509
00510 tmp[8 * i + j] = s;
00511 }
00512
00513 for(j = 0; j < 8; j++)
00514 for(i = 0; i < 8; i++)
00515 {
00516 s = 0.0;
00517
00518
00519
00520
00521
00522 s += c[i][0] * tmp[8 * 0 + j];
00523 s += c[i][1] * tmp[8 * 1 + j];
00524 s += c[i][2] * tmp[8 * 2 + j];
00525 s += c[i][3] * tmp[8 * 3 + j];
00526 s += c[i][4] * tmp[8 * 4 + j];
00527 s += c[i][5] * tmp[8 * 5 + j];
00528 s += c[i][6] * tmp[8 * 6 + j];
00529 s += c[i][7] * tmp[8 * 7 + j];
00530
00531 block[8 * i + j] = (int)floor(s + 0.499999);
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 }
00542 }
00543
00544
00545 #define CALCULATE_DCT(type, components) \
00546 { \
00547 uint16_t *output = temp; \
00548 for(int k = 0; k < 8; k++) \
00549 { \
00550 type *input = (type*)frame->get_rows()[i + k] + j * components; \
00551 for(int l = 0; l < 8; l++) \
00552 { \
00553 *output = (*input << 8) | *input; \
00554 output++; \
00555 input += components; \
00556 } \
00557 } \
00558 fdct(temp); \
00559 }
00560
00561 int64_t Decimate::calculate_fdct(VFrame *frame)
00562 {
00563 if(!fdct_ready)
00564 {
00565 init_fdct();
00566 fdct_ready = 1;
00567 }
00568
00569 uint16_t temp[64];
00570 uint64_t result[64];
00571 bzero(result, sizeof(int64_t) * 64);
00572 int w = frame->get_w();
00573 int h = frame->get_h();
00574
00575
00576 for(int i = 0; i < h - 8; i += 8)
00577 {
00578 for(int j = 0; j < w - 8; j += 8)
00579 {
00580 CALCULATE_DCT(unsigned char, 3)
00581
00582 for(int k = 0; k < 64; k++)
00583 {
00584 result[k] += temp[k];
00585 }
00586 }
00587 }
00588
00589 uint64_t max_result = 0;
00590 int highest = 0;
00591 for(int i = 0; i < 64; i++)
00592 {
00593 if(result[i] > max_result)
00594 {
00595 max_result = result[i];
00596 highest = i;
00597 }
00598 }
00599
00600 return highest;
00601 }
00602
00603 void Decimate::decimate_frame()
00604 {
00605 int64_t min_difference = 0x7fffffffffffffffLL;
00606 int64_t max_difference2 = 0x0;
00607 int result = -1;
00608
00609 if(!lookahead_size) return;
00610
00611 for(int i = 0; i < lookahead_size; i++)
00612 {
00613
00614 if(config.least_difference &&
00615 differences[i] >= 0 &&
00616 differences[i] < min_difference)
00617 {
00618 min_difference = differences[i];
00619 result = i;
00620 }
00621 }
00622
00623
00624
00625 if(result < 0) result = 0;
00626
00627 VFrame *temp = frames[result];
00628 for(int i = result; i < lookahead_size - 1; i++)
00629 {
00630 frames[i] = frames[i + 1];
00631 differences[i] = differences[i + 1];
00632 }
00633
00634
00635 frames[lookahead_size - 1] = temp;
00636 lookahead_size--;
00637 send_render_gui(&result);
00638 }
00639
00640 void Decimate::fill_lookahead(double frame_rate,
00641 int64_t start_position)
00642 {
00643
00644 if(!EQUIV(config.input_rate, lookahead_rate))
00645 {
00646 lookahead_size = 0;
00647 }
00648
00649 lookahead_rate = config.input_rate;
00650
00651
00652 if(last_position + 1 != start_position)
00653 {
00654 lookahead_size = 0;
00655 }
00656
00657 last_position = start_position;
00658
00659
00660 if(!lookahead_size)
00661 {
00662 lookahead_end = (int64_t)((double)start_position *
00663 config.input_rate /
00664 frame_rate);
00665 }
00666
00667 while(lookahead_size < TOTAL_FRAMES)
00668 {
00669
00670 read_frame(frames[lookahead_size],
00671 0,
00672 lookahead_end,
00673 config.input_rate);
00674
00675 if(lookahead_size > 0)
00676 differences[lookahead_size] =
00677 calculate_difference(frames[lookahead_size - 1],
00678 frames[lookahead_size]);
00679
00680
00681 lookahead_size++;
00682 lookahead_end++;
00683
00684
00685
00686 int64_t decimated_end = (int64_t)((double)(start_position + TOTAL_FRAMES) *
00687 config.input_rate /
00688 frame_rate);
00689 if(lookahead_size >= TOTAL_FRAMES &&
00690 lookahead_end < decimated_end)
00691 {
00692 decimate_frame();
00693 }
00694 }
00695 }
00696
00697
00698 int Decimate::process_buffer(VFrame *frame,
00699 int64_t start_position,
00700 double frame_rate)
00701 {
00702
00703
00704 load_configuration();
00705
00706 if(!frames[0])
00707 {
00708 for(int i = 0; i < TOTAL_FRAMES; i++)
00709 {
00710 frames[i] = new VFrame(0,
00711 frame->get_w(),
00712 frame->get_h(),
00713 frame->get_color_model(),
00714 -1);
00715 }
00716 }
00717
00718
00719
00720 fill_lookahead(frame_rate, start_position);
00721
00722
00723
00724
00725
00726
00727
00728
00729 frame->copy_from(frames[0]);
00730 VFrame *temp = frames[0];
00731 for(int i = 0; i < TOTAL_FRAMES - 1; i++)
00732 {
00733 frames[i] = frames[i + 1];
00734 differences[i] = differences[i + 1];
00735 }
00736 frames[TOTAL_FRAMES - 1] = temp;
00737 lookahead_size--;
00738 return 0;
00739 }
00740
00741
00742
00743 char* Decimate::plugin_title() { return N_("Decimate"); }
00744 int Decimate::is_realtime() { return 1; }
00745
00746 NEW_PICON_MACRO(Decimate)
00747
00748 SHOW_GUI_MACRO(Decimate, DecimateThread)
00749
00750 RAISE_WINDOW_MACRO(Decimate)
00751
00752 SET_STRING_MACRO(Decimate);
00753
00754 int Decimate::load_configuration()
00755 {
00756 KeyFrame *prev_keyframe;
00757 DecimateConfig old_config;
00758 old_config.copy_from(&config);
00759 prev_keyframe = get_prev_keyframe(get_source_position());
00760 read_data(prev_keyframe);
00761 return !old_config.equivalent(&config);
00762 }
00763
00764 int Decimate::load_defaults()
00765 {
00766 char directory[BCTEXTLEN];
00767
00768 sprintf(directory, "%sdecimate.rc", BCASTDIR);
00769
00770
00771 defaults = new BC_Hash(directory);
00772 defaults->load();
00773
00774 config.input_rate = defaults->get("INPUT_RATE", config.input_rate);
00775
00776
00777 config.input_rate = Units::fix_framerate(config.input_rate);
00778 return 0;
00779 }
00780
00781 int Decimate::save_defaults()
00782 {
00783 defaults->update("INPUT_RATE", config.input_rate);
00784
00785
00786 defaults->save();
00787 return 0;
00788 }
00789
00790 void Decimate::save_data(KeyFrame *keyframe)
00791 {
00792 FileXML output;
00793
00794
00795 output.set_shared_string(keyframe->data, MESSAGESIZE);
00796 output.tag.set_title("DECIMATE");
00797 output.tag.set_property("INPUT_RATE", config.input_rate);
00798
00799
00800 output.append_tag();
00801 output.tag.set_title("/DECIMATE");
00802 output.append_tag();
00803 output.terminate_string();
00804 }
00805
00806 void Decimate::read_data(KeyFrame *keyframe)
00807 {
00808 FileXML input;
00809
00810 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00811
00812 int result = 0;
00813
00814 while(!input.read_tag())
00815 {
00816 if(input.tag.title_is("DECIMATE"))
00817 {
00818 config.input_rate = input.tag.get_property("INPUT_RATE", config.input_rate);
00819
00820
00821 config.input_rate = Units::fix_framerate(config.input_rate);
00822 }
00823 }
00824 }
00825
00826 void Decimate::update_gui()
00827 {
00828 if(thread)
00829 {
00830 if(load_configuration())
00831 {
00832 thread->window->lock_window("Decimate::update_gui");
00833 thread->window->rate->update((float)config.input_rate);
00834
00835
00836 thread->window->unlock_window();
00837 }
00838 }
00839 }
00840
00841 void Decimate::render_gui(void *data)
00842 {
00843 if(thread)
00844 {
00845 thread->window->lock_window("Decimate::render_gui");
00846
00847 int dropped = *(int*)data;
00848 char string[BCTEXTLEN];
00849
00850 sprintf(string, "%d", dropped);
00851 thread->window->last_dropped->update(string);
00852
00853 thread->window->unlock_window();
00854 }
00855 }
00856
00857
00858