3 * Copyright (C) 1997-2015 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcsignals.h"
26 #include "edgewindow.h"
28 #include "transportque.inc"
31 // Edge detection from the Gimp
35 EdgeConfig::EdgeConfig()
40 int EdgeConfig::equivalent(EdgeConfig &that)
42 if(this->amount != that.amount) return 0;
46 void EdgeConfig::copy_from(EdgeConfig &that)
48 this->amount = that.amount;
51 void EdgeConfig::interpolate(
61 void EdgeConfig::limits()
67 Edge::Edge(PluginServer *server)
68 : PluginVClient(server)
76 if(engine) delete engine;
80 const char* Edge::plugin_title() { return _("Edge"); }
81 int Edge::is_realtime() { return 1; }
83 NEW_WINDOW_MACRO(Edge, EdgeWindow);
84 LOAD_CONFIGURATION_MACRO(Edge, EdgeConfig)
86 void Edge::save_data(KeyFrame *keyframe)
90 // cause data to be stored directly in text
91 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
93 output.tag.set_title("EDGE");
94 output.tag.set_property("AMOUNT", config.amount);
96 output.append_newline();
97 output.tag.set_title("/EDGE");
99 output.append_newline();
100 output.terminate_string();
103 void Edge::read_data(KeyFrame *keyframe)
107 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
112 result = input.read_tag();
116 if(input.tag.title_is("EDGE"))
118 config.amount = input.tag.get_property("AMOUNT", config.amount);
123 if(input.tag.title_is("/EDGE"))
132 void Edge::update_gui()
136 if(load_configuration())
138 thread->window->lock_window("Edge::update_gui");
139 EdgeWindow *window = (EdgeWindow*)thread->window;
141 thread->window->unlock_window();
148 int Edge::process_buffer(VFrame *frame,
149 int64_t start_position,
153 // int need_reconfigure =
154 load_configuration();
155 int w = frame->get_w();
156 int h = frame->get_h();
157 int color_model = frame->get_color_model();
159 // initialize everything
162 engine = new EdgeEngine(this,
163 PluginClient::get_project_smp() + 1,
164 PluginClient::get_project_smp() + 1);
180 engine->process(temp, frame);
181 frame->copy_from(temp);
189 EdgePackage::EdgePackage()
194 EdgeUnit::EdgeUnit(EdgeEngine *server) : LoadClient(server)
196 this->server = server;
199 EdgeUnit::~EdgeUnit()
204 float EdgeUnit::edge_detect(float *data, float max, int do_max)
206 const float v_kernel[9] = { 0, 0, 0,
209 const float h_kernel[9] = { 0, 0, 0,
213 float v_grad, h_grad;
214 float amount = server->plugin->config.amount;
216 for (i = 0, v_grad = 0, h_grad = 0; i < 9; i++)
218 v_grad += v_kernel[i] * data[i];
219 h_grad += h_kernel[i] * data[i];
222 float result = sqrt (v_grad * v_grad * amount +
223 h_grad * h_grad * amount);
225 CLAMP(result, 0, max);
229 #define EDGE_MACRO(type, max, components, is_yuv) \
231 type **input_rows = (type**)server->src->get_rows(); \
232 type **output_rows = (type**)server->dst->get_rows(); \
233 int comps = MIN(components, 3); \
234 for(int y = pkg->y1; y < pkg->y2; y++) \
236 for(int x = 0; x < w; x++) \
238 /* kernel is in bounds */ \
239 if(y > 0 && x > 0 && y < h - 2 && x < w - 2) \
241 for(int chan = 0; chan < comps; chan++) \
244 for(int kernel_y = 0; kernel_y < 3; kernel_y++) \
246 for(int kernel_x = 0; kernel_x < 3; kernel_x++) \
248 kernel[3 * kernel_y + kernel_x] = \
249 (type)input_rows[y - 1 + kernel_y][(x - 1 + kernel_x) * components + chan]; \
251 if(is_yuv && chan > 0) \
253 kernel[3 * kernel_y + kernel_x] -= 0x80; \
258 /* do the business */ \
259 output_rows[y][x * components + chan] = edge_detect(kernel, max, sizeof(type) < 4); \
260 if(is_yuv && chan > 0) \
262 output_rows[y][x * components + chan] += 0x80; \
267 if(components == 4) output_rows[y][x * components + 3] = \
268 input_rows[y][x * components + 3]; \
272 for(int chan = 0; chan < comps; chan++) \
275 for(int kernel_y = 0; kernel_y < 3; kernel_y++) \
277 for(int kernel_x = 0; kernel_x < 3; kernel_x++) \
279 int in_y = y - 1 + kernel_y; \
280 int in_x = x - 1 + kernel_x; \
281 CLAMP(in_y, 0, h - 1); \
282 CLAMP(in_x, 0, w - 1); \
283 kernel[3 * kernel_y + kernel_x] = \
284 (type)input_rows[in_y][in_x * components + chan]; \
285 if(is_yuv && chan > 0) \
287 kernel[3 * kernel_y + kernel_x] -= 0x80; \
291 /* do the business */ \
292 output_rows[y][x * components + chan] = edge_detect(kernel, max, sizeof(type) < 4); \
293 if(is_yuv && chan > 0) \
295 output_rows[y][x * components + chan] += 0x80; \
298 if(components == 4) output_rows[y][x * components + 3] = \
299 input_rows[y][x * components + 3]; \
306 void EdgeUnit::process_package(LoadPackage *package)
308 EdgePackage *pkg = (EdgePackage*)package;
309 int w = server->src->get_w();
310 int h = server->src->get_h();
313 switch(server->src->get_color_model())
316 EDGE_MACRO(float, 1, 3, 0);
319 EDGE_MACRO(float, 1, 4, 0);
322 EDGE_MACRO(unsigned char, 0xff, 3, 0);
325 EDGE_MACRO(unsigned char, 0xff, 3, 1);
328 EDGE_MACRO(unsigned char, 0xff, 4, 0);
331 EDGE_MACRO(unsigned char, 0xff, 4, 1);
337 EdgeEngine::EdgeEngine(Edge *plugin,
340 : LoadServer(total_clients, total_packages)
342 this->plugin = plugin;
345 EdgeEngine::~EdgeEngine()
350 void EdgeEngine::init_packages()
352 for(int i = 0; i < get_total_packages(); i++)
354 EdgePackage *pkg = (EdgePackage*)get_package(i);
355 pkg->y1 = plugin->get_input(0)->get_h() * i / LoadServer::get_total_packages();
356 pkg->y2 = plugin->get_input(0)->get_h() * (i + 1) / LoadServer::get_total_packages();
360 void EdgeEngine::process(VFrame *dst, VFrame *src)
368 LoadClient* EdgeEngine::new_client()
370 return new EdgeUnit(this);
373 LoadPackage* EdgeEngine::new_package()
375 return new EdgePackage;