1 #include "bcdisplayinfo.h"
7 #include "pluginvclient.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
22 class FrameFieldWindow;
25 class FrameFieldConfig
36 class FrameFieldTop : public BC_Radial
39 FrameFieldTop(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
42 FrameFieldWindow *gui;
46 class FrameFieldBottom : public BC_Radial
49 FrameFieldBottom(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
52 FrameFieldWindow *gui;
56 class FrameFieldDouble : public BC_CheckBox
59 FrameFieldDouble(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
62 FrameFieldWindow *gui;
65 class FrameFieldShift : public BC_CheckBox
68 FrameFieldShift(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
71 FrameFieldWindow *gui;
74 class FrameFieldAvg : public BC_CheckBox
77 FrameFieldAvg(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
80 FrameFieldWindow *gui;
83 class FrameFieldWindow : public BC_Window
86 FrameFieldWindow(FrameField *plugin, int x, int y);
87 void create_objects();
91 FrameFieldBottom *bottom;
96 PLUGIN_THREAD_HEADER(FrameField, FrameFieldThread, FrameFieldWindow)
100 class FrameField : public PluginVClient
103 FrameField(PluginServer *server);
106 int process_realtime(VFrame *input, VFrame *output);
108 char* plugin_title();
111 void load_configuration();
115 void save_data(KeyFrame *keyframe);
116 void read_data(KeyFrame *keyframe);
121 void average_rows(int offset, VFrame *frame);
125 FrameFieldThread *thread;
126 FrameFieldConfig config;
141 FrameFieldConfig::FrameFieldConfig()
143 field_dominance = TOP_FIELD_FIRST;
155 FrameFieldWindow::FrameFieldWindow(FrameField *plugin, int x, int y)
156 : BC_Window(plugin->gui_string,
167 this->plugin = plugin;
170 void FrameFieldWindow::create_objects()
173 add_subwindow(top = new FrameFieldTop(plugin, this, x, y));
175 add_subwindow(bottom = new FrameFieldBottom(plugin, this, x, y));
177 add_subwindow(avg = new FrameFieldAvg(plugin, this, x, y));
182 int FrameFieldWindow::close_event()
199 FrameFieldTop::FrameFieldTop(FrameField *plugin,
200 FrameFieldWindow *gui,
205 plugin->config.field_dominance == TOP_FIELD_FIRST,
206 _("Top field first"))
208 this->plugin = plugin;
212 int FrameFieldTop::handle_event()
214 plugin->config.field_dominance = TOP_FIELD_FIRST;
215 gui->bottom->update(0);
216 plugin->send_configure_change();
224 FrameFieldBottom::FrameFieldBottom(FrameField *plugin,
225 FrameFieldWindow *gui,
230 plugin->config.field_dominance == BOTTOM_FIELD_FIRST,
231 _("Bottom field first"))
233 this->plugin = plugin;
237 int FrameFieldBottom::handle_event()
239 plugin->config.field_dominance = BOTTOM_FIELD_FIRST;
241 plugin->send_configure_change();
249 FrameFieldAvg::FrameFieldAvg(FrameField *plugin,
250 FrameFieldWindow *gui,
256 _("Average empty rows"))
258 this->plugin = plugin;
262 int FrameFieldAvg::handle_event()
264 plugin->config.avg = get_value();
265 plugin->send_configure_change();
271 PLUGIN_THREAD_OBJECT(FrameField, FrameFieldThread, FrameFieldWindow)
282 REGISTER_PLUGIN(FrameField)
289 FrameField::FrameField(PluginServer *server)
290 : PluginVClient(server)
299 FrameField::~FrameField()
303 thread->window->set_done(0);
304 thread->completion.lock();
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();
323 int row_size = VFrame::calculate_bytes_per_pixel(input->get_color_model()) * input->get_w();
328 prev_frame = new VFrame(0,
331 input->get_color_model());
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)
344 if(config.field_dominance == TOP_FIELD_FIRST)
346 for(int i = 0; i < input->get_h() - 1; i += 2)
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);
353 // Average empty rows
354 if(config.avg) average_rows(0, output);
358 for(int i = 0; i < input->get_h() - 1; i += 2)
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);
366 // Average empty rows
367 if(config.avg) average_rows(1, output);
372 // Copy input frame to prev_frame after the calculations using temp rows
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)
379 for(int i = 0; i < input->get_h() - 1; i += 2)
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);
396 // Average empty rows
397 if(config.avg) average_rows(1, output);
401 for(int i = 0; i < input->get_h() - 1; i += 2)
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);
416 // Average empty rows
417 if(config.avg) average_rows(0, output);
423 current_frame = !current_frame;
426 #define AVERAGE(type, components, offset) \
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) \
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++) \
439 int64_t sum = (int64_t)*row1++ + (int64_t)*row3++; \
440 *row2++ = (sum >> 1); \
445 void FrameField::average_rows(int offset, VFrame *frame)
447 //printf("FrameField::average_rows 1 %d\n", offset);
448 switch(frame->get_color_model())
452 AVERAGE(unsigned char, 3, offset);
456 AVERAGE(unsigned char, 4, offset);
460 AVERAGE(uint16_t, 3, offset);
462 case BC_RGBA16161616:
463 case BC_YUVA16161616:
464 AVERAGE(uint16_t, 4, offset);
470 int FrameField::is_realtime()
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);
502 defaults = new Defaults(directory);
505 config.field_dominance = defaults->get("DOMINANCE", config.field_dominance);
506 config.avg = defaults->get("AVG", config.avg);
510 int FrameField::save_defaults()
512 defaults->update("DOMINANCE", config.field_dominance);
513 defaults->update("AVG", config.avg);
518 void FrameField::save_data(KeyFrame *keyframe)
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);
528 output.terminate_string();
531 void FrameField::read_data(KeyFrame *keyframe)
535 input.set_shared_string(keyframe->data, strlen(keyframe->data));
539 while(!input.read_tag())
541 if(input.tag.title_is("FRAME_FIELD"))
543 config.field_dominance = input.tag.get_property("DOMINANCE", config.field_dominance);
544 config.avg = input.tag.get_property("AVG", config.avg);
549 void FrameField::update_gui()
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();