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"
33 EdgeConfig::EdgeConfig()
38 int EdgeConfig::equivalent(EdgeConfig &that)
40 if(this->amount != that.amount) return 0;
44 void EdgeConfig::copy_from(EdgeConfig &that)
46 this->amount = that.amount;
49 void EdgeConfig::interpolate( EdgeConfig &prev, EdgeConfig &next,
50 long prev_frame, long next_frame, long current_frame)
55 void EdgeConfig::limits()
61 Edge::Edge(PluginServer *server)
62 : PluginVClient(server)
74 const char* Edge::plugin_title() { return N_("Edge"); }
75 int Edge::is_realtime() { return 1; }
77 NEW_WINDOW_MACRO(Edge, EdgeWindow);
78 LOAD_CONFIGURATION_MACRO(Edge, EdgeConfig)
80 void Edge::save_data(KeyFrame *keyframe)
84 // cause data to be stored directly in text
85 output.set_shared_output(keyframe->xbuf);
87 output.tag.set_title("EDGE");
88 output.tag.set_property("AMOUNT", config.amount);
90 output.append_newline();
91 output.tag.set_title("/EDGE");
93 output.append_newline();
94 output.terminate_string();
97 void Edge::read_data(KeyFrame *keyframe)
100 input.set_shared_input(keyframe->xbuf);
103 while( !(result=input.read_tag()) ) {
104 if(input.tag.title_is("EDGE")) {
105 config.amount = input.tag.get_property("AMOUNT", config.amount);
108 else if(input.tag.title_is("/EDGE")) {
115 void Edge::update_gui()
117 if( !thread ) return;
118 if( !load_configuration() ) return;
119 thread->window->lock_window("Edge::update_gui");
120 EdgeWindow *window = (EdgeWindow*)thread->window;
122 thread->window->unlock_window();
125 int Edge::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
127 load_configuration();
129 w = src->get_w(), h = src->get_h();
130 color_model = frame->get_color_model();
131 bpp = BC_CModels::calculate_pixelsize(color_model);
133 if( dst && (dst->get_w() != w || dst->get_h() != h ||
134 dst->get_color_model() != color_model ) ) {
138 dst = new VFrame(w, h, color_model, 0);
141 engine = new EdgeEngine(this,
142 PluginClient::get_project_smp() + 1,
143 PluginClient::get_project_smp() + 1);
145 read_frame(frame, 0, start_position, frame_rate, 0);
146 engine->process_packages();
147 frame->copy_from(dst);
152 EdgePackage::EdgePackage()
157 EdgeUnit::EdgeUnit(EdgeEngine *server) : LoadClient(server)
159 this->server = server;
162 EdgeUnit::~EdgeUnit()
166 #define EDGE_MACRO(type, max, components, is_yuv) \
168 int comps = MIN(components, 3); \
169 float amounts = amount * amount / max; \
170 for( int y=y1; y<y2; ++y ) { \
171 uint8_t *row0 = input_rows[y], *row1 = input_rows[y+1]; \
172 uint8_t *outp = output_rows[y]; \
173 for( int x=x1; x<x2; ++x ) { \
174 type *r0 = (type *)row0, *r1 = (type *)row1, *op = (type *)outp; \
175 float h_grad = 0, v_grad = 0; \
176 for( int i=0; i<comps; ++i,++r0,++r1 ) { \
177 float dh = -r0[0] - r0[components] + r1[0] + r1[components]; \
178 if( (dh*=dh) > h_grad ) h_grad = dh; \
179 float dv = r0[0] - r0[components] + r1[0] - r1[components]; \
180 if( (dv*=dv) > v_grad ) v_grad = dv; \
182 float v = (h_grad + v_grad) * amounts; \
183 type t = v > max ? max : v; \
185 *op++ = t; *op++ = 0x80; *op++ = 0x80; \
188 for( int i=0; i<comps; ++i ) *op++ = t; \
190 if( components == 4 ) *op = *r0; \
191 row0 += bpp; row1 += bpp; outp += bpp; \
197 void EdgeUnit::process_package(LoadPackage *package)
199 VFrame *src = server->plugin->src;
200 uint8_t **input_rows = src->get_rows();
201 VFrame *dst = server->plugin->dst;
202 uint8_t **output_rows = dst->get_rows();
203 float amount = (float)server->plugin->config.amount;
204 EdgePackage *pkg = (EdgePackage*)package;
205 int x1 = 0, x2 = server->plugin->w-1, bpp = server->plugin->bpp;
206 int y1 = pkg->y1, y2 = pkg->y2;
208 switch( server->plugin->color_model ) {
209 case BC_RGB_FLOAT: EDGE_MACRO(float, 1, 3, 0);
210 case BC_RGBA_FLOAT: EDGE_MACRO(float, 1, 4, 0);
211 case BC_RGB888: EDGE_MACRO(unsigned char, 0xff, 3, 0);
212 case BC_YUV888: EDGE_MACRO(unsigned char, 0xff, 3, 1);
213 case BC_RGBA8888: EDGE_MACRO(unsigned char, 0xff, 4, 0);
214 case BC_YUVA8888: EDGE_MACRO(unsigned char, 0xff, 4, 1);
219 EdgeEngine::EdgeEngine(Edge *plugin, int total_clients, int total_packages)
220 : LoadServer(total_clients, total_packages)
222 this->plugin = plugin;
225 EdgeEngine::~EdgeEngine()
230 void EdgeEngine::init_packages()
232 int y = 0, h1 = plugin->h-1;
233 for(int i = 0; i < get_total_packages(); ) {
234 EdgePackage *pkg = (EdgePackage*)get_package(i++);
236 y = h1 * i / LoadServer::get_total_packages();
241 LoadClient* EdgeEngine::new_client()
243 return new EdgeUnit(this);
246 LoadPackage* EdgeEngine::new_package()
248 return new EdgePackage;