4 * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcdisplayinfo.h"
24 #include "photoscale.h"
40 PhotoScaleWindow::PhotoScaleWindow(PhotoScaleMain *plugin)
41 : PluginClientWindow(plugin,
48 this->plugin = plugin;
51 PhotoScaleWindow::~PhotoScaleWindow()
55 void PhotoScaleWindow::create_objects()
60 int x2 = x + BC_Title::calculate_w(this, _("Height:")) + plugin->get_theme()->widget_border;
61 add_subwindow(title = new BC_Title(x,
65 y += title->get_h() + plugin->get_theme()->widget_border;
66 add_subwindow(title = new BC_Title(x, y, _("Width:")));
67 add_subwindow(output_size[0] = new PhotoScaleSizeText(
73 &(plugin->config.width)));
75 y += output_size[0]->get_h() + plugin->get_theme()->widget_border;
76 add_subwindow(title = new BC_Title(x, y, _("Height:")));
77 add_subwindow(output_size[1] = new PhotoScaleSizeText(
83 &(plugin->config.height)));
85 FrameSizePulldown *pulldown;
86 add_subwindow(pulldown = new FrameSizePulldown(plugin->get_theme(),
89 x + title->get_w() + output_size[1]->get_w() + plugin->get_theme()->widget_border,
92 add_subwindow(new PhotoScaleSwapExtents(
95 x + title->get_w() + output_size[1]->get_w() + plugin->get_theme()->widget_border + pulldown->get_w(),
98 y += pulldown->get_h() + plugin->get_theme()->widget_border;
99 add_subwindow(file = new PhotoScaleFile(plugin,
104 y += file->get_h() + plugin->get_theme()->widget_border;
105 add_subwindow(scan = new PhotoScaleScan(plugin,
116 PhotoScaleSizeText::PhotoScaleSizeText(PhotoScaleMain *plugin,
117 PhotoScaleWindow *gui,
122 : BC_TextBox(x, y, w, 1, *output)
124 this->plugin = plugin;
126 this->output = output;
129 PhotoScaleSizeText::~PhotoScaleSizeText()
133 int PhotoScaleSizeText::handle_event()
135 *output = atol(get_text());
138 if(*output <= 0) *output = 2;
139 if(*output > 10000) *output = 10000;
140 plugin->send_configure_change();
146 PhotoScaleFile::PhotoScaleFile(PhotoScaleMain *plugin,
147 PhotoScaleWindow *gui,
150 : BC_Radial(x, y, plugin->config.use_file, _("Override camera"))
152 this->plugin = plugin;
156 int PhotoScaleFile::handle_event()
158 plugin->config.use_file = 1;
159 gui->scan->update(0);
160 plugin->send_configure_change();
165 PhotoScaleScan::PhotoScaleScan(PhotoScaleMain *plugin,
166 PhotoScaleWindow *gui,
169 : BC_Radial(x, y, !plugin->config.use_file, _("Use alpha/black level"))
171 this->plugin = plugin;
175 int PhotoScaleScan::handle_event()
177 plugin->config.use_file = 0;
178 gui->file->update(0);
179 plugin->send_configure_change();
190 PhotoScaleSwapExtents::PhotoScaleSwapExtents(PhotoScaleMain *plugin,
191 PhotoScaleWindow *gui,
194 : BC_Button(x, y, plugin->get_theme()->get_image_set("swap_extents"))
196 this->plugin = plugin;
198 set_tooltip(_("Swap dimensions"));
201 int PhotoScaleSwapExtents::handle_event()
203 int w = plugin->config.width;
204 int h = plugin->config.height;
205 gui->output_size[0]->update((int64_t)h);
206 gui->output_size[1]->update((int64_t)w);
207 plugin->config.width = h;
208 plugin->config.height = w;
209 plugin->send_configure_change();
232 PhotoScaleConfig::PhotoScaleConfig()
239 int PhotoScaleConfig::equivalent(PhotoScaleConfig &that)
241 return (width == that.width &&
242 height == that.height &&
243 use_file == that.use_file);
246 void PhotoScaleConfig::copy_from(PhotoScaleConfig &that)
249 height = that.height;
250 use_file = that.use_file;
253 void PhotoScaleConfig::interpolate(PhotoScaleConfig &prev,
254 PhotoScaleConfig &next,
257 int64_t current_frame)
267 REGISTER_PLUGIN(PhotoScaleMain)
276 PhotoScaleMain::PhotoScaleMain(PluginServer *server)
277 : PluginVClient(server)
279 need_reconfigure = 1;
284 PhotoScaleMain::~PhotoScaleMain()
286 //printf("PhotoScaleMain::~PhotoScaleMain 1\n");
287 if(overlayer) delete overlayer;
288 if(engine) delete engine;
291 const char* PhotoScaleMain::plugin_title() { return N_("Auto Scale"); }
292 int PhotoScaleMain::is_realtime() { return 1; }
295 NEW_WINDOW_MACRO(PhotoScaleMain, PhotoScaleWindow)
297 LOAD_CONFIGURATION_MACRO(PhotoScaleMain, PhotoScaleConfig)
302 int PhotoScaleMain::process_buffer(VFrame *frame,
303 int64_t start_position,
306 load_configuration();
310 frame->get_params()->update("AUTOSCALE", 1);
311 frame->get_params()->update("AUTOSCALE_W", config.width);
312 frame->get_params()->update("AUTOSCALE_H", config.height);
322 frame->get_params()->update("AUTOSCALE", 0);
332 if(!engine) engine = new PhotoScaleEngine(this,
333 PluginClient::get_project_smp() + 1);
334 engine->process_packages();
336 // printf("PhotoScaleMain::process_buffer %d %d %d %d %d\n",
338 // engine->top_border,
339 // engine->bottom_border,
340 // engine->left_border,
341 // engine->right_border);
343 int in_width = engine->right_border - engine->left_border;
344 int in_height = engine->bottom_border - engine->top_border;
347 (engine->top_border > 0 ||
348 engine->left_border > 0 ||
349 engine->bottom_border < frame->get_h() ||
350 engine->right_border < frame->get_w()))
352 VFrame *temp_frame = new_temp(frame->get_w(),
354 frame->get_color_model());
355 temp_frame->copy_from(frame);
358 overlayer = new OverlayFrame(PluginClient::get_project_smp() + 1);
361 float scale1 = (float)config.width / in_width;
362 float scale2 = (float)config.height / in_height;
368 // printf("PhotoScaleMain::process_buffer %d %d %d %d %d\n",
370 // engine->left_border,
371 // engine->top_border,
372 // engine->right_border,
373 // engine->bottom_border);
374 // printf("PhotoScaleMain::process_buffer %d %f %f\n", __LINE__, scale1, scale2);
377 out_x1 = (float)frame->get_w() / 2 - config.width / 2;
378 out_y1 = (float)frame->get_h() / 2 - in_height * scale1 / 2;
379 out_x2 = (float)frame->get_w() / 2 + config.width / 2;
380 out_y2 = (float)frame->get_h() / 2 + in_height * scale1 / 2;
384 out_x1 = (float)frame->get_w() / 2 - in_width * scale2 / 2;
385 out_y1 = (float)frame->get_h() / 2 - config.height / 2;
386 out_x2 = (float)frame->get_w() / 2 + in_width * scale2 / 2;
387 out_y2 = (float)frame->get_h() / 2 + config.height / 2;
390 // printf("PhotoScaleMain::process_buffer %d %d %d %d %d\n",
396 frame->clear_frame();
397 overlayer->overlay(frame,
399 (float)engine->left_border,
400 (float)engine->top_border,
401 (float)engine->right_border,
402 (float)engine->bottom_border,
409 get_interpolation_type());
417 void PhotoScaleMain::update_gui()
421 int reconfigure = load_configuration();
424 PhotoScaleWindow *window = (PhotoScaleWindow*)thread->window;
425 window->lock_window("PhotoScaleMain::update_gui");
426 window->output_size[0]->update((int64_t)config.width);
427 window->output_size[1]->update((int64_t)config.height);
428 window->file->update(config.use_file);
429 window->scan->update(!config.use_file);
430 window->unlock_window();
437 void PhotoScaleMain::save_data(KeyFrame *keyframe)
441 // cause data to be stored directly in text
442 output.set_shared_output(keyframe->xbuf);
443 output.tag.set_title("PHOTOSCALE");
444 output.tag.set_property("WIDTH", config.width);
445 output.tag.set_property("HEIGHT", config.height);
446 output.tag.set_property("USE_FILE", config.use_file);
448 output.tag.set_title("/PHOTOSCALE");
450 output.append_newline();
451 output.terminate_string();
454 void PhotoScaleMain::read_data(KeyFrame *keyframe)
458 input.set_shared_input(keyframe->xbuf);
464 result = input.read_tag();
468 if(input.tag.title_is("PHOTOSCALE"))
470 config.width = input.tag.get_property("WIDTH", config.width);
471 config.height = input.tag.get_property("HEIGHT", config.height);
472 config.use_file = input.tag.get_property("USE_FILE", config.use_file);
482 PhotoScaleEngine::PhotoScaleEngine(PhotoScaleMain *plugin, int cpus)
483 : LoadServer(cpus, 4)
485 this->plugin = plugin;
488 PhotoScaleEngine::~PhotoScaleEngine()
492 void PhotoScaleEngine::init_packages()
494 for(int i = 0; i < get_total_packages(); i++)
496 PhotoScalePackage *package = (PhotoScalePackage*)get_package(i);
506 LoadClient* PhotoScaleEngine::new_client()
508 return new PhotoScaleUnit(this);
511 LoadPackage* PhotoScaleEngine::new_package()
513 return new PhotoScalePackage;
522 PhotoScalePackage::PhotoScalePackage()
535 PhotoScaleUnit::PhotoScaleUnit(PhotoScaleEngine *server)
538 this->server = server;
541 PhotoScaleUnit::~PhotoScaleUnit()
545 #define TEST_PIXEL(components, is_yuv) \
546 (components == 4 && pixel[3] > 0) || \
547 (components == 3 && is_yuv && pixel[0] > 0) || \
548 (components == 3 && !is_yuv && (pixel[0] > 0 || pixel[1] > 0 || pixel[2] > 0))
550 #define SCAN_BORDER(type, components, is_yuv) \
552 type **rows = (type**)input->get_rows(); \
557 for(int i = 0; i < h / 2; i++) \
559 type *row = rows[i]; \
560 for(int j = 0; j < w; j++) \
562 type *pixel = row + j * components; \
563 if(TEST_PIXEL(components, is_yuv)) \
565 server->top_border = i; \
575 for(int i = h - 1; i >= h / 2; i--) \
577 type *row = rows[i]; \
578 for(int j = 0; j < w; j++) \
580 type *pixel = row + j * components; \
581 if(TEST_PIXEL(components, is_yuv)) \
583 server->bottom_border = i + 1; \
593 for(int i = 0; i < w / 2; i++) \
595 for(int j = 0; j < h; j++) \
597 type *row = rows[j]; \
598 type *pixel = row + i * components; \
599 if(TEST_PIXEL(components, is_yuv)) \
601 server->left_border = i; \
610 for(int i = w - 1; i >= w / 2; i--) \
612 for(int j = 0; j < h; j++) \
614 type *row = rows[j]; \
615 type *pixel = row + i * components; \
616 if(TEST_PIXEL(components, is_yuv)) \
618 server->right_border = i + 1; \
627 void PhotoScaleUnit::process_package(LoadPackage *package)
629 PhotoScalePackage *pkg = (PhotoScalePackage*)package;
630 VFrame *input = server->plugin->get_input();
631 int w = input->get_w();
632 int h = input->get_h();
635 switch(input->get_color_model())
638 SCAN_BORDER(float, 3, 0);
641 SCAN_BORDER(float, 4, 0);
644 SCAN_BORDER(unsigned char, 3, 0);
647 SCAN_BORDER(unsigned char, 3, 1);
651 SCAN_BORDER(unsigned char, 4, 0);