00001 #include "1080to540.h"
00002 #include "clip.h"
00003 #include "bchash.h"
00004 #include "filexml.h"
00005 #include "bcdisplayinfo.h"
00006 #include "keyframe.h"
00007 #include "language.h"
00008 #include "overlayframe.h"
00009 #include "picon_png.h"
00010 #include "vframe.h"
00011
00012
00013
00014
00015
00016
00017 #include <stdint.h>
00018 #include <string.h>
00019
00020
00021 REGISTER_PLUGIN(_1080to540Main)
00022
00023
00024
00025
00026 _1080to540Config::_1080to540Config()
00027 {
00028 first_field = 0;
00029 }
00030
00031 int _1080to540Config::equivalent(_1080to540Config &that)
00032 {
00033 return first_field == that.first_field;
00034 }
00035
00036 void _1080to540Config::copy_from(_1080to540Config &that)
00037 {
00038 first_field = that.first_field;
00039 }
00040
00041 void _1080to540Config::interpolate(_1080to540Config &prev,
00042 _1080to540Config &next,
00043 long prev_frame,
00044 long next_frame,
00045 long current_frame)
00046 {
00047 copy_from(prev);
00048 }
00049
00050
00051
00052
00053
00054 _1080to540Window::_1080to540Window(_1080to540Main *client, int x, int y)
00055 : BC_Window(client->gui_string,
00056 x,
00057 y,
00058 200,
00059 100,
00060 200,
00061 100,
00062 0,
00063 0,
00064 1)
00065 {
00066 this->client = client;
00067 }
00068
00069
00070 _1080to540Window::~_1080to540Window()
00071 {
00072 }
00073
00074 int _1080to540Window::create_objects()
00075 {
00076 int x = 10, y = 10;
00077
00078 add_tool(odd_first = new _1080to540Option(client, this, 1, x, y, _("Odd field first")));
00079 y += 25;
00080 add_tool(even_first = new _1080to540Option(client, this, 0, x, y, _("Even field first")));
00081
00082 show_window();
00083 flush();
00084 return 0;
00085 }
00086
00087 WINDOW_CLOSE_EVENT(_1080to540Window)
00088
00089 int _1080to540Window::set_first_field(int first_field, int send_event)
00090 {
00091 odd_first->update(first_field == 1);
00092 even_first->update(first_field == 0);
00093
00094
00095 if(send_event)
00096 {
00097 client->config.first_field = first_field;
00098 client->send_configure_change();
00099 }
00100 return 0;
00101 }
00102
00103
00104
00105
00106 _1080to540Option::_1080to540Option(_1080to540Main *client,
00107 _1080to540Window *window,
00108 int output,
00109 int x,
00110 int y,
00111 char *text)
00112 : BC_Radial(x,
00113 y,
00114 client->config.first_field == output,
00115 text)
00116 {
00117 this->client = client;
00118 this->window = window;
00119 this->output = output;
00120 }
00121
00122 int _1080to540Option::handle_event()
00123 {
00124 window->set_first_field(output, 1);
00125 return 1;
00126 }
00127
00128
00129
00130 PLUGIN_THREAD_OBJECT(_1080to540Main, _1080to540Thread, _1080to540Window)
00131
00132
00133
00134
00135
00136
00137
00138 _1080to540Main::_1080to540Main(PluginServer *server)
00139 : PluginVClient(server)
00140 {
00141 PLUGIN_CONSTRUCTOR_MACRO
00142 temp = 0;
00143 }
00144
00145 _1080to540Main::~_1080to540Main()
00146 {
00147 PLUGIN_DESTRUCTOR_MACRO
00148 if(temp) delete temp;
00149 }
00150
00151 char* _1080to540Main::plugin_title() { return N_("1080 to 540"); }
00152 int _1080to540Main::is_realtime() { return 1; }
00153
00154 SHOW_GUI_MACRO(_1080to540Main, _1080to540Thread)
00155 RAISE_WINDOW_MACRO(_1080to540Main)
00156 SET_STRING_MACRO(_1080to540Main)
00157 NEW_PICON_MACRO(_1080to540Main)
00158 LOAD_CONFIGURATION_MACRO(_1080to540Main, _1080to540Config)
00159
00160
00161 #define TEMP_W 854
00162 #define TEMP_H 540
00163 #define OUT_ROWS 270
00164
00165 void _1080to540Main::reduce_field(VFrame *output, VFrame *input, int src_field, int dst_field)
00166 {
00167 int w = input->get_w();
00168 int h = input->get_h();
00169
00170 if(h > output->get_h()) h = output->get_h();
00171 if(w > output->get_w()) h = output->get_w();
00172
00173 #define REDUCE_MACRO(type, temp, components) \
00174 for(int i = 0; i < OUT_ROWS; i++) \
00175 { \
00176 int in_number1 = dst_field * 2 + src_field + (int)(i * 2) * 2; \
00177 int in_number2 = in_number1 + 2; \
00178 int in_number3 = in_number2 + 2; \
00179 int in_number4 = in_number3 + 2; \
00180 int out_number = dst_field + i * 2; \
00181 \
00182 if(in_number1 >= h) in_number1 = h - 1; \
00183 if(in_number2 >= h) in_number2 = h - 1; \
00184 if(in_number3 >= h) in_number3 = h - 1; \
00185 if(in_number4 >= h) in_number4 = h - 1; \
00186 if(out_number >= h) out_number = h - 1; \
00187 \
00188 type *in_row1 = (type*)input->get_rows()[in_number1]; \
00189 type *in_row2 = (type*)input->get_rows()[in_number2]; \
00190 type *in_row3 = (type*)input->get_rows()[in_number3]; \
00191 type *in_row4 = (type*)input->get_rows()[in_number4]; \
00192 type *out_row = (type*)output->get_rows()[out_number]; \
00193 \
00194 for(int j = 0; j < w * components; j++) \
00195 { \
00196 *out_row++ = ((temp)*in_row1++ + \
00197 (temp)*in_row2++ + \
00198 (temp)*in_row3++ + \
00199 (temp)*in_row4++) / 4; \
00200 } \
00201 }
00202
00203 switch(input->get_color_model())
00204 {
00205 case BC_RGB888:
00206 case BC_YUV888:
00207 REDUCE_MACRO(unsigned char, int64_t, 3);
00208 break;
00209 case BC_RGB_FLOAT:
00210 REDUCE_MACRO(float, float, 3);
00211 break;
00212 case BC_RGBA8888:
00213 case BC_YUVA8888:
00214 REDUCE_MACRO(unsigned char, int64_t, 4);
00215 break;
00216 case BC_RGBA_FLOAT:
00217 REDUCE_MACRO(float, float, 4);
00218 break;
00219 case BC_RGB161616:
00220 case BC_YUV161616:
00221 REDUCE_MACRO(uint16_t, int64_t, 3);
00222 break;
00223 case BC_RGBA16161616:
00224 case BC_YUVA16161616:
00225 REDUCE_MACRO(uint16_t, int64_t, 4);
00226 break;
00227 }
00228
00229 }
00230
00231 int _1080to540Main::process_realtime(VFrame *input, VFrame *output)
00232 {
00233 load_configuration();
00234 if(!temp)
00235 {
00236 temp = new VFrame(0,
00237 input->get_w(),
00238 input->get_h(),
00239 input->get_color_model());
00240 temp->clear_frame();
00241 }
00242
00243 reduce_field(temp, input, config.first_field == 0 ? 0 : 1, 0);
00244 reduce_field(temp, input, config.first_field == 0 ? 1 : 0, 1);
00245
00246 output->copy_from(temp);
00247
00248 return 0;
00249 }
00250
00251
00252 int _1080to540Main::load_defaults()
00253 {
00254 char directory[BCTEXTLEN], string[BCTEXTLEN];
00255 sprintf(directory, "%s1080to540.rc", BCASTDIR);
00256
00257 defaults = new BC_Hash(directory);
00258 defaults->load();
00259 config.first_field = defaults->get("FIRST_FIELD", config.first_field);
00260 return 0;
00261 }
00262
00263
00264 int _1080to540Main::save_defaults()
00265 {
00266 defaults->update("FIRST_FIELD", config.first_field);
00267 defaults->save();
00268 return 0;
00269 }
00270
00271 void _1080to540Main::save_data(KeyFrame *keyframe)
00272 {
00273 FileXML output;
00274 output.set_shared_string(keyframe->data, MESSAGESIZE);
00275 output.tag.set_title("1080TO540");
00276 output.tag.set_property("FIRST_FIELD", config.first_field);
00277 output.append_tag();
00278 output.tag.set_title("/1080TO540");
00279 output.append_tag();
00280 output.terminate_string();
00281 }
00282
00283 void _1080to540Main::read_data(KeyFrame *keyframe)
00284 {
00285 FileXML input;
00286 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00287
00288 while(!input.read_tag())
00289 {
00290 if(input.tag.title_is("1080TO540"))
00291 {
00292 config.first_field = input.tag.get_property("FIRST_FIELD", config.first_field);
00293 }
00294 }
00295 }
00296
00297 void _1080to540Main::update_gui()
00298 {
00299 if(thread)
00300 {
00301 load_configuration();
00302 thread->window->lock_window();
00303 thread->window->set_first_field(config.first_field, 0);
00304 thread->window->unlock_window();
00305 }
00306 }
00307