histogram rework to add sum_frames, update suv/cakewalk autorange icons, add new...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / timeblur / timeblur.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2012 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include <math.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "bcprogressbox.h"
28 #include "edl.h"
29 #include "filexml.h"
30 #include "language.h"
31 #include "loadbalance.h"
32 #include "localsession.h"
33 #include "mainsession.h"
34 #include "mwindow.h"
35 #include "pluginserver.h"
36 #include "timeblur.h"
37 #include "timeblurwindow.h"
38 #include "vframe.h"
39
40 REGISTER_PLUGIN(TimeBlurMain)
41
42
43 TimeBlurConfig::TimeBlurConfig()
44 {
45         frames = 0;
46 }
47
48 int TimeBlurConfig::equivalent(TimeBlurConfig &that)
49 {
50         return frames != that.frames ? 0 : 1;
51 }
52
53 void TimeBlurConfig::copy_from(TimeBlurConfig &that)
54 {
55         frames = that.frames;
56 }
57
58 void TimeBlurConfig::interpolate(TimeBlurConfig &prev, TimeBlurConfig &next,
59                 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
60 {
61         frames = prev.frames;
62 }
63
64
65 TimeBlurMain::TimeBlurMain(PluginServer *server)
66  : PluginVClient(server)
67 {
68         stripe_engine = 0;
69         input = 0;
70         fframe = 0;
71         last_frames = 0;
72         last_position = -1;
73 }
74
75 TimeBlurMain::~TimeBlurMain()
76 {
77
78         delete stripe_engine;
79         delete fframe;
80 }
81
82 const char* TimeBlurMain::plugin_title() { return N_("TimeBlur"); }
83 int TimeBlurMain::is_realtime() { return 1; }
84
85
86
87 NEW_WINDOW_MACRO(TimeBlurMain, TimeBlurWindow)
88
89 LOAD_CONFIGURATION_MACRO(TimeBlurMain, TimeBlurConfig)
90
91
92 void TimeBlurMain::save_data(KeyFrame *keyframe)
93 {
94         FileXML output;
95
96 // cause data to be stored directly in text
97         output.set_shared_output(keyframe->xbuf);
98         output.tag.set_title("TIMEBLUR");
99
100         output.tag.set_property("FRAMES", config.frames);
101         output.append_tag();
102         output.tag.set_title("/TIMEBLUR");
103         output.append_tag();
104         output.append_newline();
105         output.terminate_string();
106 }
107
108 void TimeBlurMain::read_data(KeyFrame *keyframe)
109 {
110         FileXML input;
111
112         input.set_shared_input(keyframe->xbuf);
113
114         int result = 0;
115         while( !(result = input.read_tag()) ) {
116                 if( input.tag.title_is("TIMEBLUR") ) {
117                         config.frames = input.tag.get_property("FRAMES", config.frames);
118                 }
119         }
120 }
121
122 int TimeBlurMain::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
123 {
124         load_configuration();
125         this->input = frame;
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;
130         int use_opengl = 0;
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() ) ) {
136                 if( !stripe_engine )
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);
147                 }
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");
156                         Timer timer;
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);
162                                         progress->start();
163                                 }
164                                 if( progress && timer.get_difference() > 100 ) {
165                                         timer.update();
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;
171                                 }
172                                 if( progress && !gui_open() ) {
173                                         progress->stop_progress();
174                                         delete progress;  progress = 0;
175                                 }
176                         }
177                         read_frame(temp, 0, start_position, frame_rate, use_opengl);
178                         stripe_engine->process_packages(ADD_FFRMS);
179                         frame->transfer_from(temp);
180                         if( progress ) {
181                                 progress->stop_progress();
182                                 delete progress;
183                         }
184                         ++last_position;
185                 }
186                 else {
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);
192                         ++last_position;
193                 }
194         }
195         else
196                 read_frame(frame, 0, start_position, frame_rate, use_opengl);
197         return 0;
198 }
199
200
201 TimeBlurStripePackage::TimeBlurStripePackage()
202  : LoadPackage()
203 {
204 }
205
206 TimeBlurStripeUnit::TimeBlurStripeUnit(TimeBlurStripeEngine *server, TimeBlurMain *plugin)
207  : LoadClient(server)
208 {
209         this->plugin = plugin;
210         this->server = server;
211 }
212
213 void TimeBlurStripeUnit::process_package(LoadPackage *package)
214 {
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 ) {
228                                 *frow++ += *trow++;
229                                 *frow++ += *trow++;
230                                 *frow++ += *trow++;
231                         }
232                 }
233                 break;
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;
242                         }
243                 }
244                 break;
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;
253                         }
254                 }
255                 break;
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;
264                         }
265                 }
266                 break;
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;
275                         }
276                 }
277                 break;
278         }
279 }
280
281 TimeBlurStripeEngine::TimeBlurStripeEngine(TimeBlurMain *plugin,
282         int total_clients, int total_packages)
283  : LoadServer(total_clients, total_packages)
284 {
285         this->plugin = plugin;
286 }
287 void TimeBlurStripeEngine::init_packages()
288 {
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;
294                 iy0 = iy1;
295         }
296 }
297
298 LoadClient* TimeBlurStripeEngine::new_client()
299 {
300         return new TimeBlurStripeUnit(this, plugin);
301 }
302
303 LoadPackage* TimeBlurStripeEngine::new_package()
304 {
305         return new TimeBlurStripePackage();
306 }
307
308 void TimeBlurStripeEngine::process_packages(int operation)
309 {
310         this->operation = operation;
311         LoadServer::process_packages();
312 }
313