r373: Merged the official release 1.2.1.
[cinelerra_cv.git] / plugins / interpolatevideo / interpolatevideo.C
blob9480584402e322a127da2a44ddc23cebb0e2f2be
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 "theme.h"
11 #include "transportque.inc"
12 #include "vframe.h"
14 #include <string.h>
15 #include <stdint.h>
19 class InterpolateVideo;
20 class InterpolateVideoWindow;
23 class InterpolateVideoConfig
25 public:
26         InterpolateVideoConfig();
28         void copy_from(InterpolateVideoConfig *config);
29         int equivalent(InterpolateVideoConfig *config);
31 // Frame rate of input
32         double input_rate;
33 // If 1, use the keyframes as beginning and end frames and ignore input rate
34         int use_keyframes;
40 class InterpolateVideoRate : public BC_TextBox
42 public:
43         InterpolateVideoRate(InterpolateVideo *plugin, 
44                 InterpolateVideoWindow *gui, 
45                 int x, 
46                 int y);
47         int handle_event();
48         InterpolateVideo *plugin;
49         InterpolateVideoWindow *gui;
52 class InterpolateVideoRateMenu : public BC_ListBox
54 public:
55         InterpolateVideoRateMenu(InterpolateVideo *plugin, 
56                 InterpolateVideoWindow *gui, 
57                 int x, 
58                 int y);
59         int handle_event();
60         InterpolateVideo *plugin;
61         InterpolateVideoWindow *gui;
64 class InterpolateVideoKeyframes : public BC_CheckBox
66 public:
67         InterpolateVideoKeyframes(InterpolateVideo *plugin,
68                 int x, 
69                 int y);
70         int handle_event();
71         InterpolateVideo *plugin;
74 class InterpolateVideoWindow : public BC_Window
76 public:
77         InterpolateVideoWindow(InterpolateVideo *plugin, int x, int y);
78         ~InterpolateVideoWindow();
80         void create_objects();
81         int close_event();
83         ArrayList<BC_ListBoxItem*> frame_rates;
84         InterpolateVideo *plugin;
86         InterpolateVideoRate *rate;
87         InterpolateVideoRateMenu *rate_menu;
88         InterpolateVideoKeyframes *keyframes;
92 PLUGIN_THREAD_HEADER(InterpolateVideo, InterpolateVideoThread, InterpolateVideoWindow)
96 class InterpolateVideo : public PluginVClient
98 public:
99         InterpolateVideo(PluginServer *server);
100         ~InterpolateVideo();
102         PLUGIN_CLASS_MEMBERS(InterpolateVideoConfig, InterpolateVideoThread)
104         int process_buffer(VFrame *frame,
105                 int64_t start_position,
106                 double frame_rate);
107         int is_realtime();
108         int load_defaults();
109         int save_defaults();
110         void save_data(KeyFrame *keyframe);
111         void read_data(KeyFrame *keyframe);
112         void update_gui();
114         void fill_border(double frame_rate, int64_t start_position);
116 // beginning and end frames
117         VFrame *frames[2];
118 // Last requested positions
119         int64_t frame_number[2];
120 // Last output position
121         int64_t last_position;
122         double last_rate;
124 // Current requested positions
125         int64_t range_start;
126         int64_t range_end;
141 InterpolateVideoConfig::InterpolateVideoConfig()
143         input_rate = (double)30000 / 1001;
144         use_keyframes = 0;
147 void InterpolateVideoConfig::copy_from(InterpolateVideoConfig *config)
149         this->input_rate = config->input_rate;
150         this->use_keyframes = config->use_keyframes;
153 int InterpolateVideoConfig::equivalent(InterpolateVideoConfig *config)
155         return EQUIV(this->input_rate, config->input_rate) &&
156                 (this->use_keyframes == config->use_keyframes);
167 InterpolateVideoWindow::InterpolateVideoWindow(InterpolateVideo *plugin, int x, int y)
168  : BC_Window(plugin->gui_string, 
169         x, 
170         y, 
171         210, 
172         160, 
173         200, 
174         160, 
175         0, 
176         0,
177         1)
179         this->plugin = plugin;
182 InterpolateVideoWindow::~InterpolateVideoWindow()
186 void InterpolateVideoWindow::create_objects()
188         int x = 10, y = 10;
190         BC_Title *title;
191         add_subwindow(title = new BC_Title(x, y, "Input frames per second:"));
192         y += 30;
193         add_subwindow(rate = new InterpolateVideoRate(plugin, 
194                 this, 
195                 x, 
196                 y));
197         add_subwindow(rate_menu = new InterpolateVideoRateMenu(plugin, 
198                 this, 
199                 x + rate->get_w() + 5, 
200                 y));
201         y += 30;
202         add_subwindow(keyframes = new InterpolateVideoKeyframes(plugin,
203                 x, 
204                 y));
206         show_window();
207         flush();
210 WINDOW_CLOSE_EVENT(InterpolateVideoWindow)
223 InterpolateVideoRate::InterpolateVideoRate(InterpolateVideo *plugin, 
224         InterpolateVideoWindow *gui, 
225         int x, 
226         int y)
227  : BC_TextBox(x, 
228         y, 
229         90,
230         1,
231         (float)plugin->config.input_rate)
233         this->plugin = plugin;
234         this->gui = gui;
237 int InterpolateVideoRate::handle_event()
239         plugin->config.input_rate = Units::atoframerate(get_text());
240         plugin->send_configure_change();
241         return 1;
247 InterpolateVideoRateMenu::InterpolateVideoRateMenu(InterpolateVideo *plugin, 
248         InterpolateVideoWindow *gui, 
249         int x, 
250         int y)
251  : BC_ListBox(x,
252         y,
253         100,
254         200,
255         LISTBOX_TEXT,
256         &plugin->get_theme()->frame_rates,
257         0,
258         0,
259         1,
260         0,
261         1)
263         this->plugin = plugin;
264         this->gui = gui;
267 int InterpolateVideoRateMenu::handle_event()
269         char *text = get_selection(0, 0)->get_text();
270         plugin->config.input_rate = atof(text);
271         gui->rate->update(text);
272         plugin->send_configure_change();
273         return 1;
279 InterpolateVideoKeyframes::InterpolateVideoKeyframes(InterpolateVideo *plugin,
280         int x, 
281         int y)
282  : BC_CheckBox(x, 
283         y, 
284         plugin->config.use_keyframes, 
285         "Use keyframes as input")
287         this->plugin = plugin;
289 int InterpolateVideoKeyframes::handle_event()
291         plugin->config.use_keyframes = get_value();
292         plugin->send_configure_change();
293         return 1;
304 PLUGIN_THREAD_OBJECT(InterpolateVideo, InterpolateVideoThread, InterpolateVideoWindow)
315 REGISTER_PLUGIN(InterpolateVideo)
322 InterpolateVideo::InterpolateVideo(PluginServer *server)
323  : PluginVClient(server)
325         PLUGIN_CONSTRUCTOR_MACRO
326         bzero(frames, sizeof(VFrame*) * 2);
327         for(int i = 0; i < 2; i++)
328                 frame_number[i] = -1;
329         last_position = -1;
330         last_rate = -1;
334 InterpolateVideo::~InterpolateVideo()
336         PLUGIN_DESTRUCTOR_MACRO
337         if(frames[0]) delete frames[0];
338         if(frames[1]) delete frames[1];
342 void InterpolateVideo::fill_border(double frame_rate, int64_t start_position)
344 // A border frame changed or the start position is identical to the last 
345 // start position.
346         if(range_start != frame_number[0] || 
347                 last_position != start_position ||
348                 !EQUIV(last_rate, frame_rate))
349         {
350                 read_frame(frames[0], 
351                         0, 
352                         range_start + (get_direction() == PLAY_REVERSE ? 1 : 0), 
353                         config.input_rate);
354         }
356         if(range_end != frame_number[1] || 
357                 last_position != start_position ||
358                 !EQUIV(last_rate, frame_rate))
359         {
360                 read_frame(frames[1], 
361                         0, 
362                         range_end + (get_direction() == PLAY_REVERSE ? 1 : 0), 
363                         config.input_rate);
364         }
366         last_position = start_position;
367         last_rate = frame_rate;
368         frame_number[0] = range_start;
369         frame_number[1] = range_end;
373 #define AVERAGE(type, temp_type,components, max) \
374 { \
375         temp_type fraction0 = (temp_type)(lowest_fraction * max); \
376         temp_type fraction1 = (temp_type)(max - fraction0); \
378         for(int i = 0; i < h; i++) \
379         { \
380                 type *in_row0 = (type*)frames[0]->get_rows()[i]; \
381                 type *in_row1 = (type*)frames[1]->get_rows()[i]; \
382                 type *out_row = (type*)frame->get_rows()[i]; \
383                 for(int j = 0; j < w * components; j++) \
384                 { \
385                         *out_row++ = (*in_row0++ * fraction0 + *in_row1++ * fraction1) / max; \
386                 } \
387         } \
394 int InterpolateVideo::process_buffer(VFrame *frame,
395         int64_t start_position,
396         double frame_rate)
398         if(get_direction() == PLAY_REVERSE) start_position--;
399         load_configuration();
401         if(!frames[0])
402         {
403                 for(int i = 0; i < 2; i++)
404                 {
405                         frames[i] = new VFrame(0,
406                                 frame->get_w(),
407                                 frame->get_h(),
408                                 frame->get_color_model(),
409                                 -1);
410                 }
411         }
414         if(range_start == range_end)
415         {
416                 read_frame(frame, 
417                         0, 
418                         range_start, 
419                         config.input_rate);
420                 return 0;
421         }
422         else
423         {
425 // Fill border frames
426                 fill_border(frame_rate, start_position);
428 // Fraction of lowest frame in output
429                 int64_t requested_range_start = (int64_t)((double)range_start * 
430                         frame_rate / 
431                         config.input_rate);
432                 int64_t requested_range_end = (int64_t)((double)range_end * 
433                         frame_rate / 
434                         config.input_rate);
435                 float highest_fraction = (float)(start_position - requested_range_start) /
436                         (requested_range_end - requested_range_start);
438 // Fraction of highest frame in output
439                 float lowest_fraction = 1.0 - highest_fraction;
440                 CLAMP(highest_fraction, 0, 1);
441                 CLAMP(lowest_fraction, 0, 1);
443 // printf("InterpolateVideo::process_buffer %lld %lld %lld %f %f %lld %lld %f %f\n",
444 // range_start,
445 // range_end,
446 // requested_range_start,
447 // requested_range_end,
448 // start_position,
449 // config.input_rate,
450 // frame_rate,
451 // lowest_fraction,
452 // highest_fraction);
454                 int w = frame->get_w();
455                 int h = frame->get_h();
456                 switch(frame->get_color_model())
457                 {
458                         case BC_RGB_FLOAT:
459                                 AVERAGE(float, float, 3, 1);
460                                 break;
461                         case BC_RGB888:
462                         case BC_YUV888:
463                                 AVERAGE(unsigned char, int, 3, 0xff);
464                                 break;
465                         case BC_RGBA_FLOAT:
466                                 AVERAGE(float, float, 4, 1);
467                                 break;
468                         case BC_RGBA8888:
469                         case BC_YUVA8888:
470                                 AVERAGE(unsigned char, int, 4, 0xff);
471                                 break;
472                         case BC_RGB161616:
473                         case BC_YUV161616:
474                                 AVERAGE(uint16_t, int, 3, 0xffff);
475                                 break;
476                         case BC_RGBA16161616:
477                         case BC_YUVA16161616:
478                                 AVERAGE(uint16_t, int, 4, 0xffff);
479                                 break;
480                 }
481         }
482         return 0;
487 int InterpolateVideo::is_realtime()
489         return 1;
492 char* InterpolateVideo::plugin_title()
494         return N_("Interpolate");
497 NEW_PICON_MACRO(InterpolateVideo) 
499 SHOW_GUI_MACRO(InterpolateVideo, InterpolateVideoThread)
501 RAISE_WINDOW_MACRO(InterpolateVideo)
503 SET_STRING_MACRO(InterpolateVideo)
505 int InterpolateVideo::load_configuration()
507         KeyFrame *prev_keyframe, *next_keyframe;
508         InterpolateVideoConfig old_config;
509         old_config.copy_from(&config);
511         next_keyframe = get_next_keyframe(get_source_position());
512         prev_keyframe = get_prev_keyframe(get_source_position());
513 // Previous keyframe stays in config object.
514         read_data(prev_keyframe);
517         int64_t prev_position = edl_to_local(prev_keyframe->position);
518         int64_t next_position = edl_to_local(next_keyframe->position);
519         if(prev_position == 0 && next_position == 0)
520         {
521                 next_position = prev_position = get_source_start();
522         }
523 // printf("InterpolateVideo::load_configuration 1 %lld %lld %lld %lld\n",
524 // prev_keyframe->position,
525 // next_keyframe->position,
526 // prev_position,
527 // next_position);
529 // Get range to average in requested rate
530         range_start = prev_position;
531         range_end = next_position;
534 // Use keyframes to determine range
535         if(config.use_keyframes)
536         {
537 // Between keyframe and edge of range or no keyframes
538                 if(range_start == range_end)
539                 {
540 // Between first keyframe and start of effect
541                         if(get_source_position() >= get_source_start() &&
542                                 get_source_position() < range_start)
543                         {
544                                 range_start = get_source_start();
545                         }
546                         else
547 // Between last keyframe and end of effect
548                         if(get_source_position() >= range_start &&
549                                 get_source_position() < get_source_start() + get_total_len())
550                         {
551 // Last frame should be inclusive of current effect
552                                 range_end = get_source_start() + get_total_len() - 1;
553                         }
554                         else
555                         {
556 // Should never get here
557                                 ;
558                         }
559                 }
561 // Convert requested rate to input rate
562                 range_start = (int64_t)((double)range_start / get_framerate() * config.input_rate + 0.5);
563                 range_end = (int64_t)((double)range_end / get_framerate() * config.input_rate + 0.5);
564         }
565         else
566 // Use frame rate
567         {
568 // Convert to input frame rate
569                 range_start = (int64_t)(get_source_position() / 
570                         get_framerate() *
571                         config.input_rate);
572                 range_end = (int64_t)(get_source_position() / 
573                         get_framerate() *
574                         config.input_rate) + 1;
575         }
577 // printf("InterpolateVideo::load_configuration 1 %lld %lld %lld %lld %lld %lld\n",
578 // prev_keyframe->position,
579 // next_keyframe->position,
580 // prev_position,
581 // next_position,
582 // range_start,
583 // range_end);
586         return !config.equivalent(&old_config);
589 int InterpolateVideo::load_defaults()
591         char directory[BCTEXTLEN];
592 // set the default directory
593         sprintf(directory, "%sinterpolatevideo.rc", BCASTDIR);
595 // load the defaults
596         defaults = new Defaults(directory);
597         defaults->load();
599         config.input_rate = defaults->get("INPUT_RATE", config.input_rate);
600         config.input_rate = Units::fix_framerate(config.input_rate);
601         config.use_keyframes = defaults->get("USE_KEYFRAMES", config.use_keyframes);
602         return 0;
605 int InterpolateVideo::save_defaults()
607         defaults->update("INPUT_RATE", config.input_rate);
608         defaults->update("USE_KEYFRAMES", config.use_keyframes);
609         defaults->save();
610         return 0;
613 void InterpolateVideo::save_data(KeyFrame *keyframe)
615         FileXML output;
617 // cause data to be stored directly in text
618         output.set_shared_string(keyframe->data, MESSAGESIZE);
619         output.tag.set_title("INTERPOLATEVIDEO");
620         output.tag.set_property("INPUT_RATE", config.input_rate);
621         output.tag.set_property("USE_KEYFRAMES", config.use_keyframes);
622         output.append_tag();
623         output.terminate_string();
626 void InterpolateVideo::read_data(KeyFrame *keyframe)
628         FileXML input;
630         input.set_shared_string(keyframe->data, strlen(keyframe->data));
632         int result = 0;
634         while(!input.read_tag())
635         {
636                 if(input.tag.title_is("INTERPOLATEVIDEO"))
637                 {
638                         config.input_rate = input.tag.get_property("INPUT_RATE", config.input_rate);
639                         config.input_rate = Units::fix_framerate(config.input_rate);
640                         config.use_keyframes = input.tag.get_property("USE_KEYFRAMES", config.use_keyframes);
641                 }
642         }
645 void InterpolateVideo::update_gui()
647         if(thread)
648         {
649                 if(load_configuration())
650                 {
651                         thread->window->lock_window("InterpolateVideo::update_gui");
652                         thread->window->rate->update((float)config.input_rate);
653                         thread->window->keyframes->update(config.use_keyframes);
654                         thread->window->unlock_window();
655                 }
656         }