4 * Copyright (C) 2008-2012 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
27 #include "bcprogressbox.h"
31 #include "loadbalance.h"
32 #include "localsession.h"
33 #include "mainsession.h"
35 #include "pluginserver.h"
37 #include "timeblurwindow.h"
40 REGISTER_PLUGIN(TimeBlurMain)
43 TimeBlurConfig::TimeBlurConfig()
48 int TimeBlurConfig::equivalent(TimeBlurConfig &that)
50 return frames != that.frames ? 0 : 1;
53 void TimeBlurConfig::copy_from(TimeBlurConfig &that)
58 void TimeBlurConfig::interpolate(TimeBlurConfig &prev, TimeBlurConfig &next,
59 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
65 TimeBlurMain::TimeBlurMain(PluginServer *server)
66 : PluginVClient(server)
75 TimeBlurMain::~TimeBlurMain()
82 const char* TimeBlurMain::plugin_title() { return N_("TimeBlur"); }
83 int TimeBlurMain::is_realtime() { return 1; }
87 NEW_WINDOW_MACRO(TimeBlurMain, TimeBlurWindow)
89 LOAD_CONFIGURATION_MACRO(TimeBlurMain, TimeBlurConfig)
92 void TimeBlurMain::save_data(KeyFrame *keyframe)
96 // cause data to be stored directly in text
97 output.set_shared_output(keyframe->xbuf);
98 output.tag.set_title("TIMEBLUR");
100 output.tag.set_property("FRAMES", config.frames);
102 output.tag.set_title("/TIMEBLUR");
104 output.append_newline();
105 output.terminate_string();
108 void TimeBlurMain::read_data(KeyFrame *keyframe)
112 input.set_shared_input(keyframe->xbuf);
115 while( !(result = input.read_tag()) ) {
116 if( input.tag.title_is("TIMEBLUR") ) {
117 config.frames = input.tag.get_property("FRAMES", config.frames);
122 int TimeBlurMain::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
124 load_configuration();
126 int cpus = input->get_w() * input->get_h() / 0x80000 + 2;
127 int smps = get_project_smp();
128 if( cpus > smps ) cpus = smps;
129 int frames = config.frames;
131 MWindow *mwindow = server->mwindow;
132 if( frames > 1 && (!mwindow || // dont scan during SELECT_REGION
133 mwindow->session->current_operation != SELECT_REGION ||
134 mwindow->edl->local_session->get_selectionstart() ==
135 mwindow->edl->local_session->get_selectionend() ) ) {
137 stripe_engine = new TimeBlurStripeEngine(this, cpus, cpus);
138 int fw = frame->get_w(), fh =frame->get_h();
139 new_temp(fw, fh, BC_RGB_FLOAT);
140 MWindow *mwindow = server->mwindow;
141 if( (mwindow && mwindow->session->current_operation == SELECT_REGION) ||
142 ( last_frames == frames && last_position-1 == start_position &&
143 fframe && fframe->get_w() == fw && fframe->get_h() == fh ) ) {
144 read_frame(temp, 0, start_position, frame_rate, use_opengl);
145 stripe_engine->process_packages(ADD_FFRM);
146 frame->transfer_from(temp);
148 else if( last_frames != frames || last_position != start_position ||
149 !fframe || fframe->get_w() != fw || fframe->get_h() != fh ) {
150 last_frames = frames;
151 last_position = start_position;
152 VFrame::get_temp(fframe, fw, fh, BC_RGB_FLOAT);
153 read_frame(fframe, 0, start_position+1, frame_rate, use_opengl);
154 BC_ProgressBox *progress = 0;
155 const char *progress_title = _("TimeBlur: scanning\n");
157 for( int i=2; i<frames; ++i ) {
158 read_frame(temp, 0, start_position+i, frame_rate, use_opengl);
159 stripe_engine->process_packages(ADD_TEMP);
160 if( !progress && gui_open() && frames > 2*frame_rate ) {
161 progress = new BC_ProgressBox(-1, -1, progress_title, frames);
164 if( progress && timer.get_difference() > 100 ) {
166 progress->update(i, 1);
167 char string[BCTEXTLEN];
168 sprintf(string, "%sframe: %d", progress_title, i);
169 progress->update_title(string, 1);
170 if( progress->is_cancelled() ) break;
172 if( progress && !gui_open() ) {
173 progress->stop_progress();
174 delete progress; progress = 0;
177 read_frame(temp, 0, start_position, frame_rate, use_opengl);
178 stripe_engine->process_packages(ADD_FFRMS);
179 frame->transfer_from(temp);
181 progress->stop_progress();
187 read_frame(temp, 0, start_position+frames-1, frame_rate, use_opengl);
188 stripe_engine->process_packages(ADD_TEMPS);
189 frame->transfer_from(fframe);
190 read_frame(temp, 0, start_position, frame_rate, use_opengl);
191 stripe_engine->process_packages(SUB_TEMPS);
196 read_frame(frame, 0, start_position, frame_rate, use_opengl);
201 TimeBlurStripePackage::TimeBlurStripePackage()
206 TimeBlurStripeUnit::TimeBlurStripeUnit(TimeBlurStripeEngine *server, TimeBlurMain *plugin)
209 this->plugin = plugin;
210 this->server = server;
213 void TimeBlurStripeUnit::process_package(LoadPackage *package)
215 TimeBlurStripePackage *pkg = (TimeBlurStripePackage*)package;
216 int frames = plugin->config.frames;
217 float scale = 1. / frames;
218 int iy0 = pkg->y0, iy1 = pkg->y1;
219 int fw = plugin->fframe->get_w();
220 uint8_t **frows = plugin->fframe->get_rows();
221 uint8_t **trows = plugin->temp->get_rows();
222 switch( server->operation ) {
223 case ADD_TEMP: // add temp to fframe
224 for( int iy=iy0; iy<iy1; ++iy ) {
225 float *trow = (float *)trows[iy];
226 float *frow = (float *)frows[iy];
227 for( int ix=0; ix<fw; ++ix ) {
234 case ADD_FFRM: // add fframe to scaled temp
235 for( int iy=iy0; iy<iy1; ++iy ) {
236 float *trow = (float *)trows[iy];
237 float *frow = (float *)frows[iy];
238 for( int ix=0; ix<fw; ++ix ) {
239 *trow = *trow * scale + *frow++; ++trow;
240 *trow = *trow * scale + *frow++; ++trow;
241 *trow = *trow * scale + *frow++; ++trow;
245 case ADD_FFRMS: // add fframe to temp, scale temp, scale fframe
246 for( int iy=iy0; iy<iy1; ++iy ) {
247 float *trow = (float *)trows[iy];
248 float *frow = (float *)frows[iy];
249 for( int ix=0; ix<fw; ++ix ) {
250 *trow += *frow; *trow++ *= scale; *frow++ *= scale;
251 *trow += *frow; *trow++ *= scale; *frow++ *= scale;
252 *trow += *frow; *trow++ *= scale; *frow++ *= scale;
256 case ADD_TEMPS: // add scaled temp to fframe
257 for( int iy=iy0; iy<iy1; ++iy ) {
258 float *trow = (float *)trows[iy];
259 float *frow = (float *)frows[iy];
260 for( int ix=0; ix<fw; ++ix ) {
261 *frow++ += *trow++ * scale;
262 *frow++ += *trow++ * scale;
263 *frow++ += *trow++ * scale;
267 case SUB_TEMPS: // sub scaled temp from frame
268 for( int iy=iy0; iy<iy1; ++iy ) {
269 float *trow = (float *)trows[iy];
270 float *frow = (float *)frows[iy];
271 for( int ix=0; ix<fw; ++ix ) {
272 *frow++ -= *trow++ * scale;
273 *frow++ -= *trow++ * scale;
274 *frow++ -= *trow++ * scale;
281 TimeBlurStripeEngine::TimeBlurStripeEngine(TimeBlurMain *plugin,
282 int total_clients, int total_packages)
283 : LoadServer(total_clients, total_packages)
285 this->plugin = plugin;
287 void TimeBlurStripeEngine::init_packages()
289 int ih = plugin->input->get_h(), iy0 = 0;
290 for( int i=0,n=get_total_packages(); i<n; ) {
291 TimeBlurStripePackage *pkg = (TimeBlurStripePackage*)get_package(i);
292 int iy1 = (ih * ++i) / n;
293 pkg->y0 = iy0; pkg->y1 = iy1;
298 LoadClient* TimeBlurStripeEngine::new_client()
300 return new TimeBlurStripeUnit(this, plugin);
303 LoadPackage* TimeBlurStripeEngine::new_package()
305 return new TimeBlurStripePackage();
308 void TimeBlurStripeEngine::process_packages(int operation)
310 this->operation = operation;
311 LoadServer::process_packages();