1 #include "bcdisplayinfo.h"
9 #include "pluginvclient.h"
10 #include "transportque.inc"
12 #include "transportque.h"
18 #define TOP_FIELD_FIRST 0
19 #define BOTTOM_FIELD_FIRST 1
22 class FrameFieldWindow;
30 class FrameFieldConfig
34 int equivalent(FrameFieldConfig &src);
41 class FrameFieldTop : public BC_Radial
44 FrameFieldTop(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
47 FrameFieldWindow *gui;
51 class FrameFieldBottom : public BC_Radial
54 FrameFieldBottom(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
57 FrameFieldWindow *gui;
61 class FrameFieldDouble : public BC_CheckBox
64 FrameFieldDouble(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
67 FrameFieldWindow *gui;
70 class FrameFieldShift : public BC_CheckBox
73 FrameFieldShift(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
76 FrameFieldWindow *gui;
79 class FrameFieldAvg : public BC_CheckBox
82 FrameFieldAvg(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
85 FrameFieldWindow *gui;
88 class FrameFieldWindow : public BC_Window
91 FrameFieldWindow(FrameField *plugin, int x, int y);
92 void create_objects();
96 FrameFieldBottom *bottom;
100 PLUGIN_THREAD_HEADER(FrameField, FrameFieldThread, FrameFieldWindow)
104 class FrameField : public PluginVClient
107 FrameField(PluginServer *server);
110 PLUGIN_CLASS_MEMBERS(FrameFieldConfig, FrameFieldThread);
112 int process_buffer(VFrame *frame,
113 int64_t start_position,
118 void save_data(KeyFrame *keyframe);
119 void read_data(KeyFrame *keyframe);
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
128 int64_t field_number;
130 int64_t current_frame_number;
132 int64_t src_frame_number;
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,
177 this->plugin = plugin;
180 void FrameFieldWindow::create_objects()
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;
191 WINDOW_CLOSE_EVENT(FrameFieldWindow)
204 FrameFieldTop::FrameFieldTop(FrameField *plugin,
205 FrameFieldWindow *gui,
210 plugin->config.field_dominance == TOP_FIELD_FIRST,
211 _("Top field first"))
213 this->plugin = plugin;
217 int FrameFieldTop::handle_event()
219 plugin->config.field_dominance = TOP_FIELD_FIRST;
220 gui->bottom->update(0);
221 plugin->send_configure_change();
229 FrameFieldBottom::FrameFieldBottom(FrameField *plugin,
230 FrameFieldWindow *gui,
235 plugin->config.field_dominance == BOTTOM_FIELD_FIRST,
236 _("Bottom field first"))
238 this->plugin = plugin;
242 int FrameFieldBottom::handle_event()
244 plugin->config.field_dominance = BOTTOM_FIELD_FIRST;
246 plugin->send_configure_change();
256 PLUGIN_THREAD_OBJECT(FrameField, FrameFieldThread, FrameFieldWindow)
273 FrameField::FrameField(PluginServer *server)
274 : PluginVClient(server)
276 PLUGIN_CONSTRUCTOR_MACRO
279 src_frame_number = -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,
300 load_configuration();
302 int row_size = VFrame::calculate_bytes_per_pixel(frame->get_color_model()) *
307 src_frame->get_color_model() != frame->get_color_model())
314 src_frame = new VFrame(0,
317 frame->get_color_model());
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)
330 field_number = (field_number + 1) % 2;
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)
340 read_frame(src_frame,
342 current_frame_number,
344 src_frame_number = current_frame_number;
349 if(field_number == 0)
351 if(config.field_dominance == TOP_FIELD_FIRST)
353 for(int i = 0; i < frame->get_h() - 1; i += 2)
355 // Copy even lines of src to both lines of output
356 memcpy(output_rows[i],
361 // Average empty rows
362 /* if(config.avg) */ average_rows(0, frame);
366 for(int i = 0; i < frame->get_h() - 1; i += 2)
368 // Copy odd lines of current to both lines of output with shift up.
369 memcpy(output_rows[i + 1],
374 // Average empty rows
375 /* if(config.avg) */ average_rows(1, frame);
381 if(config.field_dominance == TOP_FIELD_FIRST)
383 for(int i = 0; i < frame->get_h() - 1; i += 2)
385 // Copy odd lines of src to both lines of output
386 memcpy(output_rows[i + 1],
391 // Average empty rows
392 /* if(config.avg) */ average_rows(1, frame);
396 for(int i = 0; i < frame->get_h() - 1; i += 2)
398 // Copy even lines of src to both lines of output.
399 memcpy(output_rows[i],
404 // Average empty rows
405 /* if(config.avg) */ average_rows(0, frame);
409 last_frame = start_position;
414 // Averaging 2 pixels
415 #define AVERAGE(type, temp_type, components, offset) \
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) \
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++) \
428 temp_type sum = (temp_type)*row1++ + (temp_type)*row3++; \
429 *row2++ = (sum / 2); \
434 // Averaging 6 pixels
435 #define AVERAGE_BAK(type, components, offset) \
437 type **rows = (type**)frame->get_rows(); \
438 int w = frame->get_w(); \
439 int h = frame->get_h(); \
441 for(int i = offset; i < h - 3; i += 2) \
443 type *row1 = rows[i]; \
444 type *row2 = rows[i + 1]; \
445 type *row3 = rows[i + 2]; \
447 int64_t pixel1[4], pixel2[4], pixel3[4]; \
448 int64_t pixel4[4], pixel5[4], pixel6[4]; \
451 for(int j = 0; j < components; j++) \
453 pixel1[j] = *row1++; \
454 pixel4[j] = *row3++; \
455 *row2++ = (pixel1[j] + pixel4[j]) >> 1; \
458 for(int j = 2; j < row_size; j++) \
460 for(int k = 0; k < components; k++) \
462 pixel2[k] = *row1++; \
463 pixel5[k] = *row3++; \
466 for(int k = 0; k < components; k++) \
470 *row2++ = (pixel1[k] + \
476 pixel1[k] = pixel2[k]; \
477 pixel4[k] = pixel5[k]; \
482 for(int j = 0; j < components; j++) \
484 *row2++ = (pixel3[j] + pixel6[j]) >> 1; \
489 void FrameField::average_rows(int offset, VFrame *frame)
491 //printf("FrameField::average_rows 1 %d\n", offset);
492 switch(frame->get_color_model())
496 AVERAGE(unsigned char, int64_t, 3, offset);
499 AVERAGE(float, float, 3, offset);
503 AVERAGE(unsigned char, int64_t, 4, offset);
506 AVERAGE(float, float, 4, offset);
510 AVERAGE(uint16_t, int64_t, 3, offset);
512 case BC_RGBA16161616:
513 case BC_YUVA16161616:
514 AVERAGE(uint16_t, int64_t, 4, offset);
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);
550 defaults = new BC_Hash(directory);
553 config.field_dominance = defaults->get("DOMINANCE", config.field_dominance);
557 int FrameField::save_defaults()
559 defaults->update("DOMINANCE", config.field_dominance);
564 void FrameField::save_data(KeyFrame *keyframe)
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);
573 output.terminate_string();
576 void FrameField::read_data(KeyFrame *keyframe)
580 input.set_shared_string(keyframe->data, strlen(keyframe->data));
584 while(!input.read_tag())
586 if(input.tag.title_is("FRAME_FIELD"))
588 config.field_dominance = input.tag.get_property("DOMINANCE", config.field_dominance);
593 void FrameField::update_gui()
597 if(load_configuration())
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();