00001 #include "bcdisplayinfo.h"
00002 #include "bcsignals.h"
00003 #include "bchash.h"
00004 #include "filexml.h"
00005 #include "guicast.h"
00006 #include "keyframe.h"
00007 #include "language.h"
00008 #include "picon_png.h"
00009 #include "pluginvclient.h"
00010 #include "transportque.inc"
00011 #include "vframe.h"
00012
00013 #include <string.h>
00014 #include <stdint.h>
00015
00016
00017 #define TOP_FIELD_FIRST 0
00018 #define BOTTOM_FIELD_FIRST 1
00019
00020 class FrameField;
00021 class FrameFieldWindow;
00022
00023
00024
00025
00026
00027
00028
00029
00030 class FrameFieldConfig
00031 {
00032 public:
00033 FrameFieldConfig();
00034 int equivalent(FrameFieldConfig &src);
00035 int field_dominance;
00036 };
00037
00038
00039
00040
00041 class FrameFieldTop : public BC_Radial
00042 {
00043 public:
00044 FrameFieldTop(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
00045 int handle_event();
00046 FrameField *plugin;
00047 FrameFieldWindow *gui;
00048 };
00049
00050
00051 class FrameFieldBottom : public BC_Radial
00052 {
00053 public:
00054 FrameFieldBottom(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
00055 int handle_event();
00056 FrameField *plugin;
00057 FrameFieldWindow *gui;
00058 };
00059
00060
00061 class FrameFieldDouble : public BC_CheckBox
00062 {
00063 public:
00064 FrameFieldDouble(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
00065 int handle_event();
00066 FrameField *plugin;
00067 FrameFieldWindow *gui;
00068 };
00069
00070 class FrameFieldShift : public BC_CheckBox
00071 {
00072 public:
00073 FrameFieldShift(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
00074 int handle_event();
00075 FrameField *plugin;
00076 FrameFieldWindow *gui;
00077 };
00078
00079 class FrameFieldAvg : public BC_CheckBox
00080 {
00081 public:
00082 FrameFieldAvg(FrameField *plugin, FrameFieldWindow *gui, int x, int y);
00083 int handle_event();
00084 FrameField *plugin;
00085 FrameFieldWindow *gui;
00086 };
00087
00088 class FrameFieldWindow : public BC_Window
00089 {
00090 public:
00091 FrameFieldWindow(FrameField *plugin, int x, int y);
00092 void create_objects();
00093 int close_event();
00094 FrameField *plugin;
00095 FrameFieldTop *top;
00096 FrameFieldBottom *bottom;
00097 };
00098
00099
00100 PLUGIN_THREAD_HEADER(FrameField, FrameFieldThread, FrameFieldWindow)
00101
00102
00103
00104 class FrameField : public PluginVClient
00105 {
00106 public:
00107 FrameField(PluginServer *server);
00108 ~FrameField();
00109
00110 PLUGIN_CLASS_MEMBERS(FrameFieldConfig, FrameFieldThread);
00111
00112 int process_buffer(VFrame *frame,
00113 int64_t start_position,
00114 double frame_rate);
00115 int is_realtime();
00116 int load_defaults();
00117 int save_defaults();
00118 void save_data(KeyFrame *keyframe);
00119 void read_data(KeyFrame *keyframe);
00120 void update_gui();
00121
00122
00123 void average_rows(int offset, VFrame *frame);
00124
00125 int handle_opengl();
00126
00127
00128 int64_t last_frame;
00129
00130 int64_t field_number;
00131
00132 int64_t current_frame_number;
00133
00134 int64_t src_frame_number;
00135 VFrame *src_frame;
00136
00137
00138 BC_Texture *src_texture;
00139
00140 int new_frame;
00141
00142
00143 int aggregate_rgb601;
00144 int rgb601_direction;
00145 };
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 REGISTER_PLUGIN(FrameField)
00156
00157
00158
00159 FrameFieldConfig::FrameFieldConfig()
00160 {
00161 field_dominance = TOP_FIELD_FIRST;
00162 }
00163
00164 int FrameFieldConfig::equivalent(FrameFieldConfig &src)
00165 {
00166 return src.field_dominance == field_dominance;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176 FrameFieldWindow::FrameFieldWindow(FrameField *plugin, int x, int y)
00177 : BC_Window(plugin->gui_string,
00178 x,
00179 y,
00180 210,
00181 160,
00182 200,
00183 160,
00184 0,
00185 0,
00186 1)
00187 {
00188 this->plugin = plugin;
00189 }
00190
00191 void FrameFieldWindow::create_objects()
00192 {
00193 int x = 10, y = 10;
00194 add_subwindow(top = new FrameFieldTop(plugin, this, x, y));
00195 y += top->get_h() + 5;
00196 add_subwindow(bottom = new FrameFieldBottom(plugin, this, x, y));
00197 y += bottom->get_h() + 5;
00198 show_window();
00199 flush();
00200 }
00201
00202 WINDOW_CLOSE_EVENT(FrameFieldWindow)
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 FrameFieldTop::FrameFieldTop(FrameField *plugin,
00216 FrameFieldWindow *gui,
00217 int x,
00218 int y)
00219 : BC_Radial(x,
00220 y,
00221 plugin->config.field_dominance == TOP_FIELD_FIRST,
00222 _("Top field first"))
00223 {
00224 this->plugin = plugin;
00225 this->gui = gui;
00226 }
00227
00228 int FrameFieldTop::handle_event()
00229 {
00230 plugin->config.field_dominance = TOP_FIELD_FIRST;
00231 gui->bottom->update(0);
00232 plugin->send_configure_change();
00233 return 1;
00234 }
00235
00236
00237
00238
00239
00240 FrameFieldBottom::FrameFieldBottom(FrameField *plugin,
00241 FrameFieldWindow *gui,
00242 int x,
00243 int y)
00244 : BC_Radial(x,
00245 y,
00246 plugin->config.field_dominance == BOTTOM_FIELD_FIRST,
00247 _("Bottom field first"))
00248 {
00249 this->plugin = plugin;
00250 this->gui = gui;
00251 }
00252
00253 int FrameFieldBottom::handle_event()
00254 {
00255 plugin->config.field_dominance = BOTTOM_FIELD_FIRST;
00256 gui->top->update(0);
00257 plugin->send_configure_change();
00258 return 1;
00259 }
00260
00261
00262
00263
00264
00265
00266
00267 PLUGIN_THREAD_OBJECT(FrameField, FrameFieldThread, FrameFieldWindow)
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 FrameField::FrameField(PluginServer *server)
00285 : PluginVClient(server)
00286 {
00287 PLUGIN_CONSTRUCTOR_MACRO
00288 field_number = 0;
00289 src_frame = 0;
00290 src_frame_number = -1;
00291 last_frame = -1;
00292 src_texture = 0;
00293 aggregate_rgb601 = 0;
00294 rgb601_direction = 0;
00295 }
00296
00297
00298 FrameField::~FrameField()
00299 {
00300 PLUGIN_DESTRUCTOR_MACRO
00301
00302 if(src_frame) delete src_frame;
00303 if(src_texture) delete src_texture;
00304 }
00305
00306
00307
00308
00309
00310
00311 int FrameField::process_buffer(VFrame *frame,
00312 int64_t start_position,
00313 double frame_rate)
00314 {
00315 load_configuration();
00316
00317 new_frame = 0;
00318
00319
00320
00321 field_number = get_source_position() % 2;
00322
00323 if (get_direction() == PLAY_REVERSE)
00324 {
00325 start_position++;
00326 field_number = (field_number + 1) % 2;
00327 }
00328
00329
00330 current_frame_number = start_position / 2;
00331
00332 VFrame *ptr = frame;
00333 if(get_use_opengl())
00334 {
00335
00336 }
00337 else
00338 {
00339
00340 if(src_frame &&
00341 src_frame->get_color_model() != frame->get_color_model())
00342 {
00343 delete src_frame;
00344 src_frame = 0;
00345 }
00346
00347 if(!src_frame)
00348 {
00349 src_frame = new VFrame(0,
00350 frame->get_w(),
00351 frame->get_h(),
00352 frame->get_color_model());
00353 }
00354 ptr = src_frame;
00355 }
00356
00357
00358
00359 if(current_frame_number != src_frame_number ||
00360
00361 start_position == last_frame)
00362 {
00363 read_frame(ptr,
00364 0,
00365 current_frame_number,
00366 frame_rate / 2,
00367 get_use_opengl());
00368 src_frame_number = current_frame_number;
00369 new_frame = 1;
00370 }
00371
00372
00373 if(get_use_opengl())
00374 {
00375 run_opengl();
00376 return 0;
00377 }
00378
00379 int row_size = VFrame::calculate_bytes_per_pixel(frame->get_color_model()) *
00380 frame->get_w();
00381 int start_row;
00382
00383 unsigned char **src_rows = src_frame->get_rows();
00384 unsigned char **output_rows = frame->get_rows();
00385
00386
00387
00388 if(field_number == 0)
00389 {
00390 if(config.field_dominance == TOP_FIELD_FIRST)
00391 {
00392 for(int i = 0; i < frame->get_h() - 1; i += 2)
00393 {
00394
00395 memcpy(output_rows[i],
00396 src_rows[i],
00397 row_size);
00398 }
00399
00400
00401 average_rows(0, frame);
00402 }
00403 else
00404 {
00405 for(int i = 0; i < frame->get_h() - 1; i += 2)
00406 {
00407
00408 memcpy(output_rows[i + 1],
00409 src_rows[i + 1],
00410 row_size);
00411 }
00412
00413
00414 average_rows(1, frame);
00415 }
00416 }
00417 else
00418
00419 {
00420 if(config.field_dominance == TOP_FIELD_FIRST)
00421 {
00422 for(int i = 0; i < frame->get_h() - 1; i += 2)
00423 {
00424
00425 memcpy(output_rows[i + 1],
00426 src_rows[i + 1],
00427 row_size);
00428 }
00429
00430
00431 average_rows(1, frame);
00432 }
00433 else
00434 {
00435 for(int i = 0; i < frame->get_h() - 1; i += 2)
00436 {
00437
00438 memcpy(output_rows[i],
00439 src_rows[i],
00440 row_size);
00441 }
00442
00443
00444 average_rows(0, frame);
00445 }
00446 }
00447
00448 last_frame = start_position;
00449 return 0;
00450 }
00451
00452
00453
00454 #define AVERAGE(type, temp_type, components, offset) \
00455 { \
00456 type **rows = (type**)frame->get_rows(); \
00457 int w = frame->get_w(); \
00458 int h = frame->get_h(); \
00459 int row_size = components * w; \
00460 for(int i = offset; i < h - 3; i += 2) \
00461 { \
00462 type *row1 = rows[i]; \
00463 type *row2 = rows[i + 1]; \
00464 type *row3 = rows[i + 2]; \
00465 for(int j = 0; j < row_size; j++) \
00466 { \
00467 temp_type sum = (temp_type)*row1++ + (temp_type)*row3++; \
00468 *row2++ = (sum / 2); \
00469 } \
00470 } \
00471 }
00472
00473
00474 #define AVERAGE_BAK(type, components, offset) \
00475 { \
00476 type **rows = (type**)frame->get_rows(); \
00477 int w = frame->get_w(); \
00478 int h = frame->get_h(); \
00479 int row_size = w; \
00480 for(int i = offset; i < h - 3; i += 2) \
00481 { \
00482 type *row1 = rows[i]; \
00483 type *row2 = rows[i + 1]; \
00484 type *row3 = rows[i + 2]; \
00485 int64_t sum; \
00486 int64_t pixel1[4], pixel2[4], pixel3[4]; \
00487 int64_t pixel4[4], pixel5[4], pixel6[4]; \
00488 \
00489 \
00490 for(int j = 0; j < components; j++) \
00491 { \
00492 pixel1[j] = *row1++; \
00493 pixel4[j] = *row3++; \
00494 *row2++ = (pixel1[j] + pixel4[j]) >> 1; \
00495 } \
00496 \
00497 for(int j = 2; j < row_size; j++) \
00498 { \
00499 for(int k = 0; k < components; k++) \
00500 { \
00501 pixel2[k] = *row1++; \
00502 pixel5[k] = *row3++; \
00503 } \
00504 \
00505 for(int k = 0; k < components; k++) \
00506 { \
00507 pixel3[k] = *row1; \
00508 pixel6[k] = *row3; \
00509 *row2++ = (pixel1[k] + \
00510 pixel2[k] + \
00511 pixel3[k] + \
00512 pixel4[k] + \
00513 pixel5[k] + \
00514 pixel6[k]) / 6; \
00515 pixel1[k] = pixel2[k]; \
00516 pixel4[k] = pixel5[k]; \
00517 } \
00518 } \
00519 \
00520 \
00521 for(int j = 0; j < components; j++) \
00522 { \
00523 *row2++ = (pixel3[j] + pixel6[j]) >> 1; \
00524 } \
00525 } \
00526 }
00527
00528 void FrameField::average_rows(int offset, VFrame *frame)
00529 {
00530
00531 switch(frame->get_color_model())
00532 {
00533 case BC_RGB888:
00534 case BC_YUV888:
00535 AVERAGE(unsigned char, int64_t, 3, offset);
00536 break;
00537 case BC_RGB_FLOAT:
00538 AVERAGE(float, float, 3, offset);
00539 break;
00540 case BC_RGBA8888:
00541 case BC_YUVA8888:
00542 AVERAGE(unsigned char, int64_t, 4, offset);
00543 break;
00544 case BC_RGBA_FLOAT:
00545 AVERAGE(float, float, 4, offset);
00546 break;
00547 case BC_RGB161616:
00548 case BC_YUV161616:
00549 AVERAGE(uint16_t, int64_t, 3, offset);
00550 break;
00551 case BC_RGBA16161616:
00552 case BC_YUVA16161616:
00553 AVERAGE(uint16_t, int64_t, 4, offset);
00554 break;
00555 }
00556 }
00557
00558
00559
00560 char* FrameField::plugin_title() { return N_("Frames to fields"); }
00561 int FrameField::is_realtime() { return 1; }
00562
00563 NEW_PICON_MACRO(FrameField)
00564
00565 SHOW_GUI_MACRO(FrameField, FrameFieldThread)
00566
00567 RAISE_WINDOW_MACRO(FrameField)
00568
00569 SET_STRING_MACRO(FrameField);
00570
00571 int FrameField::load_configuration()
00572 {
00573 KeyFrame *prev_keyframe;
00574 FrameFieldConfig old_config = config;
00575
00576 prev_keyframe = get_prev_keyframe(get_source_position());
00577 read_data(prev_keyframe);
00578
00579 return !old_config.equivalent(config);
00580 }
00581
00582 int FrameField::load_defaults()
00583 {
00584 char directory[BCTEXTLEN];
00585
00586 sprintf(directory, "%sframefield.rc", BCASTDIR);
00587
00588
00589 defaults = new BC_Hash(directory);
00590 defaults->load();
00591
00592 config.field_dominance = defaults->get("DOMINANCE", config.field_dominance);
00593 return 0;
00594 }
00595
00596 int FrameField::save_defaults()
00597 {
00598 defaults->update("DOMINANCE", config.field_dominance);
00599 defaults->save();
00600 return 0;
00601 }
00602
00603 void FrameField::save_data(KeyFrame *keyframe)
00604 {
00605 FileXML output;
00606
00607
00608 output.set_shared_string(keyframe->data, MESSAGESIZE);
00609 output.tag.set_title("FRAME_FIELD");
00610 output.tag.set_property("DOMINANCE", config.field_dominance);
00611 output.append_tag();
00612 output.tag.set_title("/FRAME_FIELD");
00613 output.append_tag();
00614 output.terminate_string();
00615 }
00616
00617 void FrameField::read_data(KeyFrame *keyframe)
00618 {
00619 FileXML input;
00620
00621 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00622
00623 int result = 0;
00624
00625 while(!input.read_tag())
00626 {
00627 if(input.tag.title_is("FRAME_FIELD"))
00628 {
00629 config.field_dominance = input.tag.get_property("DOMINANCE", config.field_dominance);
00630 }
00631 }
00632 }
00633
00634 void FrameField::update_gui()
00635 {
00636 if(thread)
00637 {
00638 if(load_configuration())
00639 {
00640 thread->window->lock_window();
00641 thread->window->top->update(config.field_dominance == TOP_FIELD_FIRST);
00642 thread->window->bottom->update(config.field_dominance == BOTTOM_FIELD_FIRST);
00643 thread->window->unlock_window();
00644 }
00645 }
00646 }
00647
00648 int FrameField::handle_opengl()
00649 {
00650 #ifdef HAVE_GL
00651 static char *field_frag =
00652 "uniform sampler2D tex;\n"
00653 "uniform float double_line_h;\n"
00654 "uniform float y_offset;\n"
00655 "void main()\n"
00656 "{\n"
00657 " vec2 coord = gl_TexCoord[0].st;\n"
00658
00659 " float half_y = (coord.y - y_offset) / double_line_h;\n"
00660
00661 " float line1 = floor(half_y) * double_line_h + y_offset;\n"
00662 " float line2 = line1 + double_line_h;\n"
00663
00664 " float frac = fract(half_y);\n"
00665 " gl_FragColor = mix(\n"
00666 " texture2D(tex, vec2(coord.x, line1)), \n"
00667 " texture2D(tex, vec2(coord.x, line2)), \n"
00668 " frac);\n"
00669 "}\n";
00670
00671 static char *_601_to_rgb_frag =
00672 "void main()\n"
00673 "{\n"
00674 " gl_FragColor.rgb = gl_FragColor.rgb * vec3(1.1644, 1.1644, 1.1644) - vec3(0.0627, 0.0627, 0.0627);\n"
00675 "}\n";
00676
00677 static char *_601_to_yuv_frag =
00678 "void main()\n"
00679 "{\n"
00680 " gl_FragColor.r = gl_FragColor.r * 1.1644 - 0.0627;\n"
00681 "}\n";
00682
00683 static char *rgb_to_601_frag =
00684 "void main()\n"
00685 "{\n"
00686 " gl_FragColor.rgb = gl_FragColor.rgb * vec3(0.8588, 0.8588, 0.8588) + vec3(0.0627, 0.0627, 0.0627);\n"
00687 "}\n";
00688
00689 static char *yuv_to_601_frag =
00690 "void main()\n"
00691 "{\n"
00692 " gl_FragColor.r = gl_FragColor.r * 0.8588 + 0.0627;\n"
00693 "}\n";
00694
00695
00696 if(new_frame)
00697 {
00698 if(get_output()->get_opengl_state() != VFrame::SCREEN)
00699 {
00700
00701 get_output()->to_texture();
00702
00703
00704 get_output()->enable_opengl();
00705 VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
00706 get_output()->bind_texture(0);
00707 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00708 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00709 get_output()->draw_texture();
00710 }
00711
00712 get_output()->enable_opengl();
00713 VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
00714 glActiveTexture(GL_TEXTURE0);
00715 BC_Texture::new_texture(&src_texture,
00716 get_output()->get_w(),
00717 get_output()->get_h(),
00718 get_output()->get_color_model());
00719 src_texture->bind(0);
00720 glCopyTexSubImage2D(GL_TEXTURE_2D,
00721 0,
00722 0,
00723 0,
00724 0,
00725 0,
00726 get_output()->get_w(),
00727 get_output()->get_h());
00728
00729
00730
00731
00732 if(prev_effect_is("RGB - 601") ||
00733 next_effect_is("RGB - 601"))
00734 {
00735 aggregate_rgb601 = 1;
00736 rgb601_direction = get_output()->get_params()->get("RGB601_DIRECTION", 0);
00737 }
00738 else
00739 aggregate_rgb601 = 0;
00740 }
00741 else
00742 {
00743 get_output()->enable_opengl();
00744 }
00745
00746 unsigned int frag = 0;
00747 float y_offset = 0.0;
00748 if(field_number == 0)
00749 {
00750 if(config.field_dominance == BOTTOM_FIELD_FIRST)
00751 y_offset = 1.0;
00752 }
00753 else
00754 {
00755 if(config.field_dominance == TOP_FIELD_FIRST)
00756 y_offset = 1.0;
00757 }
00758
00759 VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
00760 glActiveTexture(GL_TEXTURE0);
00761 BC_Texture::new_texture(&src_texture,
00762 get_output()->get_w(),
00763 get_output()->get_h(),
00764 get_output()->get_color_model());
00765
00766
00767 char *shaders[3] = { 0, 0, 0 };
00768 shaders[0] = field_frag;
00769
00770
00771
00772
00773 if(aggregate_rgb601)
00774 {
00775 if(rgb601_direction == 1)
00776 {
00777 if(cmodel_is_yuv(get_output()->get_color_model()))
00778 shaders[1] = yuv_to_601_frag;
00779 else
00780 shaders[1] = rgb_to_601_frag;
00781 }
00782 else
00783 if(rgb601_direction == 2)
00784 {
00785 if(cmodel_is_yuv(get_output()->get_color_model()))
00786 shaders[1] = _601_to_yuv_frag;
00787 else
00788 shaders[1] = _601_to_rgb_frag;
00789 }
00790 }
00791
00792
00793
00794 frag = VFrame::make_shader(0, shaders[0], shaders[1], shaders[2], 0);
00795
00796
00797 if(frag)
00798 {
00799 glUseProgram(frag);
00800 glUniform1i(glGetUniformLocation(frag, "tex"), 0);
00801 glUniform1f(glGetUniformLocation(frag, "double_line_h"),
00802 2.0 / src_texture->get_texture_h());
00803 glUniform1f(glGetUniformLocation(frag, "y_offset"),
00804 y_offset / src_texture->get_texture_h());
00805 }
00806
00807
00808
00809 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00810 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00811 get_output()->draw_texture();
00812
00813 glUseProgram(0);
00814 get_output()->set_opengl_state(VFrame::SCREEN);
00815
00816
00817 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00818 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00819
00820 #endif
00821 }
00822
00823