r864: Merge 2.1:
[cinelerra_cv/ct.git] / plugins / framefield / framefield.C
blobd7506144d82546cd69c121cdd396b478b20134fd
1 #include "bcdisplayinfo.h"
2 #include "bcsignals.h"
3 #include "bchash.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 "transportque.inc"
11 #include "vframe.h"
12 #include "transportque.h"
14 #include <string.h>
15 #include <stdint.h>
18 #define TOP_FIELD_FIRST 0
19 #define BOTTOM_FIELD_FIRST 1
21 class FrameField;
22 class FrameFieldWindow;
30 class FrameFieldConfig
32 public:
33         FrameFieldConfig();
34         int equivalent(FrameFieldConfig &src);
35         int field_dominance;
41 class FrameFieldTop : public BC_Radial
43 public:
44         FrameFieldTop(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
45         int handle_event();
46         FrameField *plugin;
47         FrameFieldWindow *gui;
51 class FrameFieldBottom : public BC_Radial
53 public:
54         FrameFieldBottom(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
55         int handle_event();
56         FrameField *plugin;
57         FrameFieldWindow *gui;
61 class FrameFieldDouble : public BC_CheckBox
63 public:
64         FrameFieldDouble(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
65         int handle_event();
66         FrameField *plugin;
67         FrameFieldWindow *gui;
70 class FrameFieldShift : public BC_CheckBox
72 public:
73         FrameFieldShift(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
74         int handle_event();
75         FrameField *plugin;
76         FrameFieldWindow *gui;
79 class FrameFieldAvg : public BC_CheckBox
81 public:
82         FrameFieldAvg(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
83         int handle_event();
84         FrameField *plugin;
85         FrameFieldWindow *gui;
88 class FrameFieldWindow : public BC_Window
90 public:
91         FrameFieldWindow(FrameField *plugin, int x, int y);
92         void create_objects();
93         int close_event();
94         FrameField *plugin;
95         FrameFieldTop *top;
96         FrameFieldBottom *bottom;
100 PLUGIN_THREAD_HEADER(FrameField, FrameFieldThread, FrameFieldWindow)
104 class FrameField : public PluginVClient
106 public:
107         FrameField(PluginServer *server);
108         ~FrameField();
110         PLUGIN_CLASS_MEMBERS(FrameFieldConfig, FrameFieldThread);
112         int process_buffer(VFrame *frame,
113                 int64_t start_position,
114                 double frame_rate);
115         int is_realtime();
116         int load_defaults();
117         int save_defaults();
118         void save_data(KeyFrame *keyframe);
119         void read_data(KeyFrame *keyframe);
120         void update_gui();
122 // Constructs odd or even rows from the average of the surrounding rows.
123         void average_rows(int offset, VFrame *frame);
125 // Last frame requested
126         int64_t last_frame;
127 // Field needed
128         int64_t field_number;
129 // Frame needed
130         int64_t current_frame_number;
131 // Frame stored
132         int64_t src_frame_number;
133         VFrame *src_frame;
144 REGISTER_PLUGIN(FrameField)
148 FrameFieldConfig::FrameFieldConfig()
150         field_dominance = TOP_FIELD_FIRST;
153 int FrameFieldConfig::equivalent(FrameFieldConfig &src)
155         return src.field_dominance == field_dominance;
165 FrameFieldWindow::FrameFieldWindow(FrameField *plugin, int x, int y)
166  : BC_Window(plugin->gui_string, 
167         x, 
168         y, 
169         210, 
170         160, 
171         200, 
172         160, 
173         0, 
174         0,
175         1)
177         this->plugin = plugin;
180 void FrameFieldWindow::create_objects()
182         int x = 10, y = 10;
183         add_subwindow(top = new FrameFieldTop(plugin, this, x, y));
184         y += top->get_h() + 5;
185         add_subwindow(bottom = new FrameFieldBottom(plugin, this, x, y));
186         y += bottom->get_h() + 5;
187         show_window();
188         flush();
191 WINDOW_CLOSE_EVENT(FrameFieldWindow)
204 FrameFieldTop::FrameFieldTop(FrameField *plugin, 
205         FrameFieldWindow *gui, 
206         int x, 
207         int y)
208  : BC_Radial(x, 
209         y, 
210         plugin->config.field_dominance == TOP_FIELD_FIRST,
211         _("Top field first"))
213         this->plugin = plugin;
214         this->gui = gui;
217 int FrameFieldTop::handle_event()
219         plugin->config.field_dominance = TOP_FIELD_FIRST;
220         gui->bottom->update(0);
221         plugin->send_configure_change();
222         return 1;
229 FrameFieldBottom::FrameFieldBottom(FrameField *plugin, 
230         FrameFieldWindow *gui, 
231         int x, 
232         int y)
233  : BC_Radial(x, 
234         y, 
235         plugin->config.field_dominance == BOTTOM_FIELD_FIRST,
236         _("Bottom field first"))
238         this->plugin = plugin;
239         this->gui = gui;
242 int FrameFieldBottom::handle_event()
244         plugin->config.field_dominance = BOTTOM_FIELD_FIRST;
245         gui->top->update(0);
246         plugin->send_configure_change();
247         return 1;
256 PLUGIN_THREAD_OBJECT(FrameField, FrameFieldThread, FrameFieldWindow)
273 FrameField::FrameField(PluginServer *server)
274  : PluginVClient(server)
276         PLUGIN_CONSTRUCTOR_MACRO
277         field_number = 0;
278         src_frame = 0;
279         src_frame_number = -1;
280         last_frame = -1;
284 FrameField::~FrameField()
286         PLUGIN_DESTRUCTOR_MACRO
288         if(src_frame) delete src_frame;
292 // 0 - current frame field 0, prev frame field 1
293 // 1 - current frame field 0, current frame field 1, copy current to prev
294 // 2 - current frame field 0, prev frame field 1
296 int FrameField::process_buffer(VFrame *frame,
297         int64_t start_position,
298         double frame_rate)
300         load_configuration();
302         int row_size = VFrame::calculate_bytes_per_pixel(frame->get_color_model()) * 
303                 frame->get_w();
304         int start_row;
306         if(src_frame &&
307                 src_frame->get_color_model() != frame->get_color_model())
308         {
309                 delete src_frame;
310                 src_frame = 0;
311         }
312         if(!src_frame)
313         {
314                 src_frame = new VFrame(0, 
315                         frame->get_w(), 
316                         frame->get_h(), 
317                         frame->get_color_model());
318         }
320         unsigned char **src_rows = src_frame->get_rows();
321         unsigned char **output_rows = frame->get_rows();
323 // Calculate current field based on absolute position so the algorithm isn't
324 // relative to where playback started.
325         field_number = get_source_position() % 2;
327         if (get_direction() == PLAY_REVERSE)
328         {
329                 start_position += 1;
330                 field_number = (field_number + 1) % 2;
331         }
334         current_frame_number = start_position / 2;
335 // Import source frame at half frame rate
336         if(current_frame_number != src_frame_number ||
337 // If same frame was requested, assume it was a configuration change and reprocess.
338                 start_position == last_frame)
339         {
340                 read_frame(src_frame, 
341                         0, 
342                         current_frame_number, 
343                         frame_rate / 2);
344                 src_frame_number = current_frame_number;
345         }
348 // Even field
349         if(field_number == 0)
350         {
351                 if(config.field_dominance == TOP_FIELD_FIRST) 
352                 {
353                         for(int i = 0; i < frame->get_h() - 1; i += 2)
354                         {
355 // Copy even lines of src to both lines of output
356                                 memcpy(output_rows[i], 
357                                         src_rows[i], 
358                                         row_size);
359                         }
361 // Average empty rows
362                         /* if(config.avg) */ average_rows(0, frame);
363                 }
364                 else
365                 {
366                         for(int i = 0; i < frame->get_h() - 1; i += 2)
367                         {
368 // Copy odd lines of current to both lines of output with shift up.
369                                 memcpy(output_rows[i + 1], 
370                                         src_rows[i + 1], 
371                                         row_size);
372                         }
374 // Average empty rows
375                         /* if(config.avg) */ average_rows(1, frame);
376                 }
377         }
378         else
379 // Odd field
380         {
381                 if(config.field_dominance == TOP_FIELD_FIRST)
382                 {
383                         for(int i = 0; i < frame->get_h() - 1; i += 2)
384                         {
385 // Copy odd lines of src to both lines of output
386                                 memcpy(output_rows[i + 1], 
387                                         src_rows[i + 1], 
388                                         row_size);
389                         }
391 // Average empty rows
392                         /* if(config.avg) */ average_rows(1, frame);
393                 }
394                 else
395                 {
396                         for(int i = 0; i < frame->get_h() - 1; i += 2)
397                         {
398 // Copy even lines of src to both lines of output.
399                                 memcpy(output_rows[i], 
400                                         src_rows[i], 
401                                         row_size);
402                         }
404 // Average empty rows
405                         /* if(config.avg) */ average_rows(0, frame);
406                 }
407         }
409         last_frame = start_position;
410         return 0;
414 // Averaging 2 pixels
415 #define AVERAGE(type, temp_type, components, offset) \
416 { \
417         type **rows = (type**)frame->get_rows(); \
418         int w = frame->get_w(); \
419         int h = frame->get_h(); \
420         int row_size = components * w; \
421         for(int i = offset; i < h - 3; i += 2) \
422         { \
423                 type *row1 = rows[i]; \
424                 type *row2 = rows[i + 1]; \
425                 type *row3 = rows[i + 2]; \
426                 for(int j = 0; j < row_size; j++) \
427                 { \
428                         temp_type sum = (temp_type)*row1++ + (temp_type)*row3++; \
429                         *row2++ = (sum / 2); \
430                 } \
431         } \
434 // Averaging 6 pixels
435 #define AVERAGE_BAK(type, components, offset) \
436 { \
437         type **rows = (type**)frame->get_rows(); \
438         int w = frame->get_w(); \
439         int h = frame->get_h(); \
440         int row_size = w; \
441         for(int i = offset; i < h - 3; i += 2) \
442         { \
443                 type *row1 = rows[i]; \
444                 type *row2 = rows[i + 1]; \
445                 type *row3 = rows[i + 2]; \
446                 int64_t sum; \
447                 int64_t pixel1[4], pixel2[4], pixel3[4]; \
448                 int64_t pixel4[4], pixel5[4], pixel6[4]; \
450 /* First pixel */ \
451                 for(int j = 0; j < components; j++) \
452                 { \
453                         pixel1[j] = *row1++; \
454                         pixel4[j] = *row3++; \
455                         *row2++ = (pixel1[j] + pixel4[j]) >> 1; \
456                 } \
458                 for(int j = 2; j < row_size; j++) \
459                 { \
460                         for(int k = 0; k < components; k++) \
461                         { \
462                                 pixel2[k] = *row1++; \
463                                 pixel5[k] = *row3++; \
464                         } \
466                         for(int k = 0; k < components; k++) \
467                         { \
468                                 pixel3[k] = *row1; \
469                                 pixel6[k] = *row3; \
470                                 *row2++ = (pixel1[k] + \
471                                         pixel2[k] + \
472                                         pixel3[k] + \
473                                         pixel4[k] + \
474                                         pixel5[k] + \
475                                         pixel6[k]) / 6; \
476                                 pixel1[k] = pixel2[k]; \
477                                 pixel4[k] = pixel5[k]; \
478                         } \
479                 } \
481 /* Last pixel */ \
482                 for(int j = 0; j < components; j++) \
483                 { \
484                         *row2++ = (pixel3[j] + pixel6[j]) >> 1; \
485                 } \
486         } \
489 void FrameField::average_rows(int offset, VFrame *frame)
491 //printf("FrameField::average_rows 1 %d\n", offset);
492         switch(frame->get_color_model())
493         {
494                 case BC_RGB888:
495                 case BC_YUV888:
496                         AVERAGE(unsigned char, int64_t, 3, offset);
497                         break;
498                 case BC_RGB_FLOAT:
499                         AVERAGE(float, float, 3, offset);
500                         break;
501                 case BC_RGBA8888:
502                 case BC_YUVA8888:
503                         AVERAGE(unsigned char, int64_t, 4, offset);
504                         break;
505                 case BC_RGBA_FLOAT:
506                         AVERAGE(float, float, 4, offset);
507                         break;
508                 case BC_RGB161616:
509                 case BC_YUV161616:
510                         AVERAGE(uint16_t, int64_t, 3, offset);
511                         break;
512                 case BC_RGBA16161616:
513                 case BC_YUVA16161616:
514                         AVERAGE(uint16_t, int64_t, 4, offset);
515                         break;
516         }
521 char* FrameField::plugin_title() { return N_("Frames to fields"); }
522 int FrameField::is_realtime() { return 1; }
524 NEW_PICON_MACRO(FrameField) 
526 SHOW_GUI_MACRO(FrameField, FrameFieldThread)
528 RAISE_WINDOW_MACRO(FrameField)
530 SET_STRING_MACRO(FrameField);
532 int FrameField::load_configuration()
534         KeyFrame *prev_keyframe;
535         FrameFieldConfig old_config = config;
537         prev_keyframe = get_prev_keyframe(get_source_position());
538         read_data(prev_keyframe);
540         return !old_config.equivalent(config);
543 int FrameField::load_defaults()
545         char directory[BCTEXTLEN];
546 // set the default directory
547         sprintf(directory, "%sframefield.rc", BCASTDIR);
549 // load the defaults
550         defaults = new BC_Hash(directory);
551         defaults->load();
553         config.field_dominance = defaults->get("DOMINANCE", config.field_dominance);
554         return 0;
557 int FrameField::save_defaults()
559         defaults->update("DOMINANCE", config.field_dominance);
560         defaults->save();
561         return 0;
564 void FrameField::save_data(KeyFrame *keyframe)
566         FileXML output;
568 // cause data to be stored directly in text
569         output.set_shared_string(keyframe->data, MESSAGESIZE);
570         output.tag.set_title("FRAME_FIELD");
571         output.tag.set_property("DOMINANCE", config.field_dominance);
572         output.append_tag();
573         output.terminate_string();
576 void FrameField::read_data(KeyFrame *keyframe)
578         FileXML input;
580         input.set_shared_string(keyframe->data, strlen(keyframe->data));
582         int result = 0;
584         while(!input.read_tag())
585         {
586                 if(input.tag.title_is("FRAME_FIELD"))
587                 {
588                         config.field_dominance = input.tag.get_property("DOMINANCE", config.field_dominance);
589                 }
590         }
593 void FrameField::update_gui()
595         if(thread)
596         {
597                 if(load_configuration())
598                 {
599                         thread->window->lock_window();
600                         thread->window->top->update(config.field_dominance == TOP_FIELD_FIRST);
601                         thread->window->bottom->update(config.field_dominance == BOTTOM_FIELD_FIRST);
602                         thread->window->unlock_window();
603                 }
604         }