r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / framefield / framefield.C
blob0114505d7376f46e80af6136b3e7515046d56b52
1 #include "bcdisplayinfo.h"
2 #include "defaults.h"
3 #include "filexml.h"
4 #include "guicast.h"
5 #include "keyframe.h"
6 #include "picon_png.h"
7 #include "pluginvclient.h"
8 #include "vframe.h"
10 #include <string.h>
11 #include <stdint.h>
13 #include <libintl.h>
14 #define _(String) gettext(String)
15 #define gettext_noop(String) String
16 #define N_(String) gettext_noop (String)
18 #define TOP_FIELD_FIRST 0
19 #define BOTTOM_FIELD_FIRST 1
21 class FrameField;
22 class FrameFieldWindow;
25 class FrameFieldConfig
27 public:
28         FrameFieldConfig();
29         int field_dominance;
30         int avg;
36 class FrameFieldTop : public BC_Radial
38 public:
39         FrameFieldTop(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
40         int handle_event();
41         FrameField *plugin;
42         FrameFieldWindow *gui;
46 class FrameFieldBottom : public BC_Radial
48 public:
49         FrameFieldBottom(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
50         int handle_event();
51         FrameField *plugin;
52         FrameFieldWindow *gui;
56 class FrameFieldDouble : public BC_CheckBox
58 public:
59         FrameFieldDouble(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
60         int handle_event();
61         FrameField *plugin;
62         FrameFieldWindow *gui;
65 class FrameFieldShift : public BC_CheckBox
67 public:
68         FrameFieldShift(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
69         int handle_event();
70         FrameField *plugin;
71         FrameFieldWindow *gui;
74 class FrameFieldAvg : public BC_CheckBox
76 public:
77         FrameFieldAvg(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
78         int handle_event();
79         FrameField *plugin;
80         FrameFieldWindow *gui;
83 class FrameFieldWindow : public BC_Window
85 public:
86         FrameFieldWindow(FrameField *plugin, int x, int y);
87         void create_objects();
88         int close_event();
89         FrameField *plugin;
90         FrameFieldTop *top;
91         FrameFieldBottom *bottom;
92         FrameFieldAvg *avg;
96 PLUGIN_THREAD_HEADER(FrameField, FrameFieldThread, FrameFieldWindow)
100 class FrameField : public PluginVClient
102 public:
103         FrameField(PluginServer *server);
104         ~FrameField();
106         int process_realtime(VFrame *input, VFrame *output);
107         int is_realtime();
108         char* plugin_title();
109         VFrame* new_picon();
110         int show_gui();
111         void load_configuration();
112         int set_string();
113         int load_defaults();
114         int save_defaults();
115         void save_data(KeyFrame *keyframe);
116         void read_data(KeyFrame *keyframe);
117         void raise_window();
118         void update_gui();
121         void average_rows(int offset, VFrame *frame);
123         int current_frame;
124         VFrame *prev_frame;
125         FrameFieldThread *thread;
126         FrameFieldConfig config;
127         Defaults *defaults;
141 FrameFieldConfig::FrameFieldConfig()
143         field_dominance = TOP_FIELD_FIRST;
144         avg = 1;
155 FrameFieldWindow::FrameFieldWindow(FrameField *plugin, int x, int y)
156  : BC_Window(plugin->gui_string, 
157         x, 
158         y, 
159         210, 
160         160, 
161         200, 
162         160, 
163         0, 
164         0,
165         1)
167         this->plugin = plugin;
170 void FrameFieldWindow::create_objects()
172         int x = 10, y = 10;
173         add_subwindow(top = new FrameFieldTop(plugin, this, x, y));
174         y += 30;
175         add_subwindow(bottom = new FrameFieldBottom(plugin, this, x, y));
176         y += 30;
177         add_subwindow(avg = new FrameFieldAvg(plugin, this, x, y));
178         show_window();
179         flush();
182 int FrameFieldWindow::close_event()
184         set_done(1);
185         return 1;
199 FrameFieldTop::FrameFieldTop(FrameField *plugin, 
200         FrameFieldWindow *gui, 
201         int x, 
202         int y)
203  : BC_Radial(x, 
204         y, 
205         plugin->config.field_dominance == TOP_FIELD_FIRST,
206         _("Top field first"))
208         this->plugin = plugin;
209         this->gui = gui;
212 int FrameFieldTop::handle_event()
214         plugin->config.field_dominance = TOP_FIELD_FIRST;
215         gui->bottom->update(0);
216         plugin->send_configure_change();
217         return 1;
224 FrameFieldBottom::FrameFieldBottom(FrameField *plugin, 
225         FrameFieldWindow *gui, 
226         int x, 
227         int y)
228  : BC_Radial(x, 
229         y, 
230         plugin->config.field_dominance == BOTTOM_FIELD_FIRST,
231         _("Bottom field first"))
233         this->plugin = plugin;
234         this->gui = gui;
237 int FrameFieldBottom::handle_event()
239         plugin->config.field_dominance = BOTTOM_FIELD_FIRST;
240         gui->top->update(0);
241         plugin->send_configure_change();
242         return 1;
249 FrameFieldAvg::FrameFieldAvg(FrameField *plugin, 
250         FrameFieldWindow *gui, 
251         int x, 
252         int y)
253  : BC_CheckBox(x, 
254         y, 
255         plugin->config.avg,
256         _("Average empty rows"))
258         this->plugin = plugin;
259         this->gui = gui;
262 int FrameFieldAvg::handle_event()
264         plugin->config.avg = get_value();
265         plugin->send_configure_change();
266         return 1;
271 PLUGIN_THREAD_OBJECT(FrameField, FrameFieldThread, FrameFieldWindow)
282 REGISTER_PLUGIN(FrameField)
289 FrameField::FrameField(PluginServer *server)
290  : PluginVClient(server)
292         prev_frame = 0;
293         thread = 0;
294         current_frame = 0;
295         load_defaults();
299 FrameField::~FrameField()
301         if(thread)
302         {
303                 thread->window->set_done(0);
304                 thread->completion.lock();
305                 delete thread;
306         }
308         save_defaults();
309         delete defaults;
311         if(prev_frame) delete prev_frame;
315 // 0 - current frame field 0, prev frame field 1
316 // 1 - current frame field 0, current frame field 1, copy current to prev
317 // 2 - current frame field 0, prev frame field 1
319 int FrameField::process_realtime(VFrame *input, VFrame *output)
321         load_configuration();
322         
323         int row_size = VFrame::calculate_bytes_per_pixel(input->get_color_model()) * input->get_w();
324         int start_row;
326         if(!prev_frame)
327         {
328                 prev_frame = new VFrame(0, 
329                         input->get_w(), 
330                         input->get_h(), 
331                         input->get_color_model());
332         }
334         unsigned char **current_rows = input->get_rows();
335         unsigned char **prev_rows = prev_frame->get_rows();
336         unsigned char **output_rows = output->get_rows();
338 // Calculate current frame based on absolute position so the algorithm isn't
339 // relative to where playback started.
340         current_frame = get_source_position() % 2;
342         if(current_frame == 0)
343         {
344                 if(config.field_dominance == TOP_FIELD_FIRST) 
345                 {
346                         for(int i = 0; i < input->get_h() - 1; i += 2)
347                         {
348 // Copy even lines of current to both lines of output
349                                 memcpy(output_rows[i], current_rows[i], row_size);
350                                 if(!config.avg) memcpy(output_rows[i + 1], current_rows[i], row_size);
351                         }
353 // Average empty rows
354                         if(config.avg) average_rows(0, output);
355                 }
356                 else
357                 {
358                         for(int i = 0; i < input->get_h() - 1; i += 2)
359                         {
360 // Copy odd lines of current to both lines of output with shift up.
361                                 memcpy(output_rows[i + 1], current_rows[i + 1], row_size);
362                                 if(i < input->get_h() - 2 && !config.avg)
363                                         memcpy(output_rows[i + 2], current_rows[i + 1], row_size);
364                         }
366 // Average empty rows
367                         if(config.avg) average_rows(1, output);
368                 }
369         }
370         else
371 // Odd frame
372 // Copy input frame to prev_frame after the calculations using temp rows
373         {
374                 unsigned char *temp_row1 = new unsigned char[row_size];
375                 unsigned char *temp_row2 = new unsigned char[row_size];
377                 if(config.field_dominance == TOP_FIELD_FIRST)
378                 {
379                         for(int i = 0; i < input->get_h() - 1; i += 2)
380                         {
381 // Copy lines to temporary for prev_frame
382                                 memcpy(temp_row1, output_rows[i], row_size);
383                                 memcpy(temp_row2, output_rows[i + 1], row_size);
386 // Copy odd lines of input to both lines of output
387                                 memcpy(output_rows[i + 1], current_rows[i + 1], row_size);
388                                 if(i < input->get_h() - 2 && !config.avg)
389                                         memcpy(output_rows[i + 2], current_rows[i + 1], row_size);
391 // Copy temporary to prev_frame
392                                 memcpy(prev_rows[i], temp_row1, row_size);
393                                 memcpy(prev_rows[i + 1], temp_row2, row_size);
394                         }
396 // Average empty rows
397                         if(config.avg) average_rows(1, output);
398                 }
399                 else
400                 {
401                         for(int i = 0; i < input->get_h() - 1; i += 2)
402                         {
403 // Copy lines to temporary for prev_frame
404                                 memcpy(temp_row1, output_rows[i], row_size);
405                                 memcpy(temp_row2, output_rows[i + 1], row_size);
407 // Copy even lines of input to both lines of output.
408                                 memcpy(output_rows[i], current_rows[i], row_size);
409                                 if(!config.avg) memcpy(output_rows[i + 1], current_rows[i], row_size);
411 // Copy temporary to prev_frame
412                                 memcpy(prev_rows[i], temp_row1, row_size);
413                                 memcpy(prev_rows[i + 1], temp_row2, row_size);
414                         }
416 // Average empty rows
417                         if(config.avg) average_rows(0, output);
418                 }
419                 delete [] temp_row1;
420                 delete [] temp_row2;
421         }
423         current_frame = !current_frame;
426 #define AVERAGE(type, components, offset) \
427 { \
428         type **rows = (type**)frame->get_rows(); \
429         int w = frame->get_w(); \
430         int h = frame->get_h(); \
431         int row_size = components * w; \
432         for(int i = offset; i < h - 3; i += 2) \
433         { \
434                 type *row1 = rows[i]; \
435                 type *row2 = rows[i + 1]; \
436                 type *row3 = rows[i + 2]; \
437                 for(int j = 0; j < row_size; j++) \
438                 { \
439                         int64_t sum = (int64_t)*row1++ + (int64_t)*row3++; \
440                         *row2++ = (sum >> 1); \
441                 } \
442         } \
445 void FrameField::average_rows(int offset, VFrame *frame)
447 //printf("FrameField::average_rows 1 %d\n", offset);
448         switch(frame->get_color_model())
449         {
450                 case BC_RGB888:
451                 case BC_YUV888:
452                         AVERAGE(unsigned char, 3, offset);
453                         break;
454                 case BC_RGBA8888:
455                 case BC_YUVA8888:
456                         AVERAGE(unsigned char, 4, offset);
457                         break;
458                 case BC_RGB161616:
459                 case BC_YUV161616:
460                         AVERAGE(uint16_t, 3, offset);
461                         break;
462                 case BC_RGBA16161616:
463                 case BC_YUVA16161616:
464                         AVERAGE(uint16_t, 4, offset);
465                         break;
466         }
470 int FrameField::is_realtime()
472         return 1;
475 char* FrameField::plugin_title()
477         return _("Frames to fields");
480 NEW_PICON_MACRO(FrameField) 
482 SHOW_GUI_MACRO(FrameField, FrameFieldThread)
484 RAISE_WINDOW_MACRO(FrameField)
486 SET_STRING_MACRO(FrameField);
488 void FrameField::load_configuration()
490         KeyFrame *prev_keyframe;
491         prev_keyframe = get_prev_keyframe(get_source_position());
492         read_data(prev_keyframe);
495 int FrameField::load_defaults()
497         char directory[BCTEXTLEN];
498 // set the default directory
499         sprintf(directory, "%sframefield.rc", BCASTDIR);
501 // load the defaults
502         defaults = new Defaults(directory);
503         defaults->load();
505         config.field_dominance = defaults->get("DOMINANCE", config.field_dominance);
506         config.avg = defaults->get("AVG", config.avg);
507         return 0;
510 int FrameField::save_defaults()
512         defaults->update("DOMINANCE", config.field_dominance);
513         defaults->update("AVG", config.avg);
514         defaults->save();
515         return 0;
518 void FrameField::save_data(KeyFrame *keyframe)
520         FileXML output;
522 // cause data to be stored directly in text
523         output.set_shared_string(keyframe->data, MESSAGESIZE);
524         output.tag.set_title("FRAME_FIELD");
525         output.tag.set_property("DOMINANCE", config.field_dominance);
526         output.tag.set_property("AVG", config.avg);
527         output.append_tag();
528         output.terminate_string();
531 void FrameField::read_data(KeyFrame *keyframe)
533         FileXML input;
535         input.set_shared_string(keyframe->data, strlen(keyframe->data));
537         int result = 0;
539         while(!input.read_tag())
540         {
541                 if(input.tag.title_is("FRAME_FIELD"))
542                 {
543                         config.field_dominance = input.tag.get_property("DOMINANCE", config.field_dominance);
544                         config.avg = input.tag.get_property("AVG", config.avg);
545                 }
546         }
549 void FrameField::update_gui()
551         if(thread)
552         {
553                 thread->window->lock_window();
554                 thread->window->top->update(config.field_dominance == TOP_FIELD_FIRST);
555                 thread->window->bottom->update(config.field_dominance == BOTTOM_FIELD_FIRST);
556                 thread->window->unlock_window();
557         }