add 1:1 convert, add es.po: thx sergio, cwdw zoom tweak, add done beep pots, bd forma...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / vmodule.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009-2013 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 "asset.h"
23 #include "bchash.h"
24 #include "bcpbuffer.h"
25 #include "bcsignals.h"
26 #include "cache.h"
27 #include "clip.h"
28 #include "commonrender.h"
29 #include "edits.h"
30 #include "edl.h"
31 #include "edlsession.h"
32 #include "file.h"
33 #include "filexml.h"
34 #include "floatautos.h"
35 #include "maskauto.h"
36 #include "maskautos.h"
37 #include "mwindow.h"
38 #include "overlayframe.h"
39 #include "patch.h"
40 #include "pluginarray.h"
41 #include "preferences.h"
42 #include "renderengine.h"
43 #include "sharedlocation.h"
44 #include "tracks.h"
45 #include "transition.h"
46 #include "transportque.h"
47 #include "units.h"
48 #include "vattachmentpoint.h"
49 #include "vdevicex11.h"
50 #include "vedit.h"
51 #include "vframe.h"
52 #include "videodevice.h"
53 #include "virtualvconsole.h"
54 #include "vmodule.h"
55 #include "vrender.h"
56 #include "vplugin.h"
57 #include "vtrack.h"
58 #include <string.h>
59 #include "maskengine.h"
60 #include "automation.h"
61
62 VModule::VModule(RenderEngine *renderengine,
63         CommonRender *commonrender,
64         PluginArray *plugin_array,
65         Track *track)
66  : Module(renderengine, commonrender, plugin_array, track)
67 {
68         data_type = TRACK_VIDEO;
69         overlay_temp = 0;
70         input_temp = 0;
71         transition_temp = 0;
72         masker = 0;
73 }
74
75 VModule::~VModule()
76 {
77         if( overlay_temp ) delete overlay_temp;
78         if( input_temp ) delete input_temp;
79         if( transition_temp ) delete transition_temp;
80         delete masker;
81 }
82
83
84 AttachmentPoint* VModule::new_attachment(Plugin *plugin)
85 {
86         return new VAttachmentPoint(renderengine, plugin);
87 }
88
89 int VModule::get_buffer_size()
90 {
91         return 1;
92 }
93
94 CICache* VModule::get_cache()
95 {
96         if( renderengine )
97                 return renderengine->get_vcache();
98         else
99                 return cache;
100 }
101
102
103 int VModule::import_frame(VFrame *output, VEdit *current_edit,
104         int64_t input_position, double frame_rate, int direction, int use_opengl)
105 {
106         int64_t direction_position;
107 // Translation of edit
108         float in_x, in_y, in_w, in_h;
109         float out_x, out_y, out_w, out_h;
110         int result = 0;
111         const int debug = 0;
112         double edl_rate = get_edl()->session->frame_rate;
113
114         int64_t input_position_project = Units::to_int64(input_position *
115                 edl_rate / frame_rate + 0.001);
116
117         if( !output ) printf("VModule::import_frame %d output=%p\n", __LINE__, output);
118         //output->dump_params();
119
120         if( debug ) printf("VModule::import_frame %d this=%p input_position=%lld direction=%d\n",
121                 __LINE__, this, (long long)input_position, direction);
122
123 // Convert to position corrected for direction
124         direction_position = input_position;
125         if( direction == PLAY_REVERSE ) {
126                 if( direction_position > 0 ) direction_position--;
127                 if( input_position_project > 0 ) input_position_project--;
128         }
129         if( !output ) printf("VModule::import_frame %d output=%p\n", __LINE__, output);
130
131         VDeviceX11 *x11_device = 0;
132         if( use_opengl ) {
133                 if( renderengine && renderengine->video ) {
134                         x11_device = (VDeviceX11*)renderengine->video->get_output_base();
135                         output->set_opengl_state(VFrame::RAM);
136                         if( !x11_device ) use_opengl = 0;
137                 }
138         }
139
140         if( !output ) printf("VModule::import_frame %d output=%p x11_device=%p nested_edl=%p\n",
141                 __LINE__, output, x11_device, nested_edl);
142
143         if( debug ) printf("VModule::import_frame %d current_edit=%p\n",
144                 __LINE__, current_edit);
145
146 // Load frame into output
147
148 // Create objects for nested EDL
149         if( current_edit && current_edit->nested_edl ) {
150                 int command;
151                 if( debug ) printf("VModule::import_frame %d nested_edl=%p current_edit->nested_edl=%p\n",
152                         __LINE__, nested_edl, current_edit->nested_edl);
153
154 // Convert requested direction to command
155                 if( renderengine->command->command == CURRENT_FRAME ||
156                     renderengine->command->command == LAST_FRAME ) {
157                         command = renderengine->command->command;
158                 }
159                 else
160                 if( direction == PLAY_REVERSE ) {
161                         if( renderengine->command->single_frame() )
162                                 command = SINGLE_FRAME_REWIND;
163                         else
164                                 command = NORMAL_REWIND;
165                 }
166                 else {
167                         if( renderengine->command->single_frame() )
168                                 command = SINGLE_FRAME_FWD;
169                         else
170                                 command = NORMAL_FWD;
171                 }
172
173                 if( !nested_edl || nested_edl->id != current_edit->nested_edl->id ) {
174                         nested_edl = current_edit->nested_edl;
175                         if( nested_renderengine ) {
176                                 delete nested_renderengine;
177                                 nested_renderengine = 0;
178                         }
179
180                         if( !nested_command ) {
181                                 nested_command = new TransportCommand;
182                         }
183
184
185                         if( !nested_renderengine ) {
186                                 nested_command->command = command;
187                                 nested_command->get_edl()->copy_all(nested_edl);
188                                 nested_command->change_type = CHANGE_ALL;
189                                 nested_command->realtime = renderengine->command->realtime;
190                                 nested_renderengine = new RenderEngine(0, get_preferences(), 0, 1);
191                                 nested_renderengine->set_vcache(get_cache());
192                                 nested_renderengine->arm_command(nested_command);
193                         }
194                 }
195                 else {
196
197 // Update nested command
198                         nested_renderengine->command->command = command;
199                         nested_command->realtime = renderengine->command->realtime;
200                 }
201
202 // Update nested video driver for opengl
203                 nested_renderengine->video = renderengine->video;
204         }
205         else {
206                 nested_edl = 0;
207         }
208         if( debug ) printf("VModule::import_frame %d\n", __LINE__);
209
210         if( output ) {
211                 if( use_opengl )
212                         x11_device->clear_input(output);
213                 else
214                         output->clear_frame();
215         }
216         else
217                 printf("VModule::import_frame %d output=%p\n", __LINE__, output);
218
219         if( current_edit &&
220                 (current_edit->asset ||
221                 (current_edit->nested_edl && nested_renderengine->vrender)) ) {
222                 File *file = 0;
223
224 //printf("VModule::import_frame %d cache=%p\n", __LINE__, get_cache());
225                 if( current_edit->asset ) {
226                         get_cache()->age();
227                         file = get_cache()->check_out(current_edit->asset,
228                                 get_edl());
229 //                      get_cache()->dump();
230                 }
231
232 // File found
233                 if( file || nested_edl ) {
234 // Make all positions based on requested frame rate.
235                         int64_t edit_startproject = Units::to_int64(current_edit->startproject *
236                                 frame_rate /
237                                 edl_rate);
238                         int64_t edit_startsource = Units::to_int64(current_edit->startsource *
239                                 frame_rate /
240                                 edl_rate);
241 // Source position going forward
242                         uint64_t position = direction_position -
243                                 edit_startproject +
244                                 edit_startsource;
245                         int64_t nested_position = 0;
246
247
248
249
250
251 // apply speed curve to source position so the timeline agrees with the playback
252                         if( track->has_speed() ) {
253 // integrate position from start of edit.
254                                 double speed_position = edit_startsource;
255                                 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
256                                 speed_position += speed_autos->automation_integral(edit_startproject,
257                                                 direction_position-edit_startproject, PLAY_FORWARD);
258 //printf("VModule::import_frame %d %lld %lld\n", __LINE__, position, (int64_t)speed_position);
259                                 position = (int64_t)speed_position;
260                         }
261
262
263
264
265
266                         int asset_w;
267                         int asset_h;
268                         if( debug ) printf("VModule::import_frame %d\n", __LINE__);
269
270
271 // maybe apply speed curve here, so timeline reflects actual playback
272
273
274
275 // if we hit the end of stream, freeze at last frame
276                         uint64_t max_position = 0;
277                         if( file ) {
278                                 max_position = Units::to_int64((double)file->get_video_length() *
279                                         frame_rate /
280                                         current_edit->asset->frame_rate - 1);
281                         }
282                         else {
283                                 max_position = Units::to_int64(nested_edl->tracks->total_length() *
284                                         frame_rate - 1);
285                         }
286
287
288                         if( position > max_position ) position = max_position;
289                         else
290                         if( position < 0 ) position = 0;
291
292                         int use_cache = renderengine &&
293                                 renderengine->command->single_frame();
294 //                      int use_asynchronous = !use_cache &&
295 //                              renderengine &&
296 // Try to make rendering go faster.
297 // But converts some formats to YUV420, which may degrade input format.
298 ////                            renderengine->command->realtime &&
299 //                              renderengine->get_edl()->session->video_asynchronous;
300
301                         if( file ) {
302                                 if( debug ) printf("VModule::import_frame %d\n", __LINE__);
303 //                              if( use_asynchronous )
304 //                                      file->start_video_decode_thread();
305 //                              else
306                                         file->stop_video_thread();
307
308                                 int64_t normalized_position = Units::to_int64(position *
309                                         current_edit->asset->frame_rate /
310                                         frame_rate);
311 // printf("VModule::import_frame %d %lld %lld\n",
312 // __LINE__,
313 // position,
314 // normalized_position);
315                                 file->set_layer(current_edit->channel);
316                                 file->set_video_position(normalized_position,
317                                         0);
318                                 asset_w = current_edit->asset->width;
319                                 asset_h = current_edit->asset->height;
320 //printf("VModule::import_frame %d normalized_position=%lld\n", __LINE__, normalized_position);
321                         }
322                         else {
323                                 if( debug ) printf("VModule::import_frame %d\n", __LINE__);
324                                 asset_w = nested_edl->session->output_w;
325                                 asset_h = nested_edl->session->output_h;
326 // Get source position in nested frame rate in direction of playback.
327                                 nested_position = Units::to_int64(position *
328                                         nested_edl->session->frame_rate /
329                                         frame_rate);
330                                 if( direction == PLAY_REVERSE )
331                                         nested_position++;
332                         }
333
334
335 // Auto scale if required
336                         if( output->get_params()->get("AUTOSCALE", 0) ) {
337                                 float autoscale_w = output->get_params()->get("AUTOSCALE_W", 1024);
338                                 float autoscale_h = output->get_params()->get("AUTOSCALE_H", 1024);
339                                 float x_scale = autoscale_w / asset_w;
340                                 float y_scale = autoscale_h / asset_h;
341
342 // Overriding camera
343                                 in_x = 0;
344                                 in_y = 0;
345                                 in_w = asset_w;
346                                 in_h = asset_h;
347
348                                 if( x_scale < y_scale ) {
349                                         out_w = in_w * x_scale;
350                                         out_h = in_h * x_scale;
351                                 }
352                                 else {
353                                         out_w = in_w * y_scale;
354                                         out_h = in_h * y_scale;
355                                 }
356
357                                 out_x = track->track_w / 2 - out_w / 2;
358                                 out_y = track->track_h / 2 - out_h / 2;
359                         }
360                         else {
361 // Apply camera
362                                 ((VTrack*)track)->calculate_input_transfer(asset_w,
363                                         asset_h, input_position_project, direction,
364                                         in_x, in_y, in_w, in_h,
365                                         out_x, out_y, out_w, out_h);
366                         }
367
368 // printf("VModule::import_frame %d %f %d %f %d\n",
369 // __LINE__, in_w, asset_w, in_h, asset_h);
370
371 // file -> temp -> output
372                         if( !EQUIV(in_x, 0) ||
373                                 !EQUIV(in_y, 0) ||
374                                 !EQUIV(in_w, track->track_w) ||
375                                 !EQUIV(in_h, track->track_h) ||
376                                 !EQUIV(out_x, 0) ||
377                                 !EQUIV(out_y, 0) ||
378                                 !EQUIV(out_w, track->track_w) ||
379                                 !EQUIV(out_h, track->track_h) ||
380                                 !EQUIV(in_w, asset_w) ||
381                                 !EQUIV(in_h, asset_h)) {
382 //printf("VModule::import_frame %d file -> temp -> output\n", __LINE__);
383 // Get temporary input buffer
384                                 VFrame **input = 0;
385 // Realtime playback
386                                 if( commonrender ) {
387                                         VRender *vrender = (VRender*)commonrender;
388 //printf("VModule::import_frame %d vrender->input_temp=%p\n", __LINE__, vrender->input_temp);
389                                         input = &vrender->input_temp;
390                                 }
391                                 else {
392 // Menu effect
393                                         input = &input_temp;
394                                 }
395
396
397                                 if( (*input) &&
398                                    ((*input)->get_w() != asset_w ||
399                                    (*input)->get_h() != asset_h) ) {
400                                         delete (*input);
401                                         (*input) = 0;
402                                 }
403
404                                 if( !(*input) ) {
405                                         (*input) =
406                                                 new VFrame(asset_w, asset_h,
407                                                         get_edl()->session->color_model);
408                                 }
409                                 (*input)->copy_stacks(output);
410
411 // file -> temp
412 // Cache for single frame only
413                                 if( file ) {
414                                         if( debug ) printf("VModule::import_frame %d this=%p file=%s\n",
415                                                 __LINE__,
416                                                 this,
417                                                 current_edit->asset->path);
418                                         if( use_cache ) file->set_cache_frames(1);
419                                         result = file->read_frame((*input));
420                                         if( use_cache ) file->set_cache_frames(0);
421                                         (*input)->set_opengl_state(VFrame::RAM);
422                                 }
423                                 else
424                                 if( nested_edl ) {
425 // If the colormodels differ, change input to nested colormodel
426                                         int nested_cmodel = nested_renderengine->get_edl()->session->color_model;
427                                         int current_cmodel = output->get_color_model();
428                                         int output_w = output->get_w();
429                                         int output_h = output->get_h();
430                                         VFrame *input2 = (*input);
431
432                                         if( nested_cmodel != current_cmodel ) {
433 // If opengl, input -> input -> output
434                                                 if( use_opengl ) { }
435                                                 else {
436 // If software, input2 -> input -> output
437 // Use output as a temporary.
438                                                         input2 = output;
439                                                 }
440
441                                                 if( debug ) printf("VModule::import_frame %d this=%p nested_cmodel=%d\n",
442                                                         __LINE__,
443                                                         this,
444                                                         nested_cmodel);
445                                                 input2->dump();
446                                                 input2->reallocate(0, -1, 0, 0, 0,
447                                                         (*input)->get_w(), (*input)->get_h(),
448                                                         nested_cmodel, -1);
449                                                 input2->dump();
450                                         }
451
452
453                                         if( debug ) printf("VModule::import_frame %d this=%p nested_edl=%s input2=%p\n",
454                                                 __LINE__, this, nested_edl->path, input2);
455
456                                         result = nested_renderengine->vrender->process_buffer(
457                                                 input2, nested_position, use_opengl);
458
459                                         if( debug ) printf("VModule::import_frame %d this=%p nested_edl=%s\n",
460                                                 __LINE__,
461                                                 this,
462                                                 nested_edl->path);
463
464                                         if( nested_cmodel != current_cmodel ) {
465                                                 if( debug ) printf("VModule::import_frame %d\n", __LINE__);
466                                                 if( use_opengl ) {
467 // Change colormodel in hardware.
468                                                         if( debug ) printf("VModule::import_frame %d\n", __LINE__);
469                                                         x11_device->convert_cmodel(input2,
470                                                                 current_cmodel);
471
472 // The converted color model is now in hardware, so return the input2 buffer
473 // to the expected color model.
474                                                         input2->reallocate(0, -1, 0, 0, 0,
475                                                                 (*input)->get_w(), (*input)->get_h(),
476                                                                 current_cmodel, -1);
477                                                 }
478                                                 else {
479 // Transfer from input2 to input
480 if( debug ) printf("VModule::import_frame %d nested_cmodel=%d current_cmodel=%d input2=%p input=%p output=%p\n",
481   __LINE__, nested_cmodel, current_cmodel, input2, (*input), output);
482                                                         BC_CModels::transfer((*input)->get_rows(), input2->get_rows(),
483                                                                 0, 0, 0, 0, 0, 0,
484                                                                 0, 0, input2->get_w(), input2->get_h(),
485                                                                 0, 0, (*input)->get_w(), (*input)->get_h(),
486                                                                 nested_cmodel, current_cmodel, 0,
487                                                                 input2->get_w(), (*input)->get_w());
488 //printf("VModule::import_frame %d\n", __LINE__);
489
490 // input2 was the output buffer, so it must be restored
491                                                 input2->reallocate(0, -1, 0, 0, 0,
492                                                         output_w, output_h, current_cmodel, -1);
493 //printf("VModule::import_frame %d\n", __LINE__);
494                                                 }
495                                         }
496
497                                 }
498
499 // Find an overlayer object to perform the camera transformation
500                                 OverlayFrame *overlayer = 0;
501
502 // OpenGL playback uses hardware
503                                 if( use_opengl ) {
504 //printf("VModule::import_frame %d\n", __LINE__);
505                                 }
506                                 else if( commonrender ) {
507 // Realtime playback
508                                         VRender *vrender = (VRender*)commonrender;
509                                         overlayer = vrender->overlayer;
510                                 }
511                                 else {
512 // Menu effect
513                                         if( !plugin_array )
514                                                 printf("VModule::import_frame neither plugin_array nor commonrender is defined.\n");
515                                         if( !overlay_temp ) {
516                                                 overlay_temp = new OverlayFrame(plugin_array->mwindow->preferences->processors);
517                                         }
518
519                                         overlayer = overlay_temp;
520                                 }
521 // printf("VModule::import_frame 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
522 //   in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h);
523
524 // temp -> output
525 // for( int j = 0; j < output->get_w() * 3 * 5; j++ )
526 //      output->get_rows()[0][j] = 255;
527
528                                 if( use_opengl ) {
529                                         x11_device->do_camera(output, (*input),
530                                                 in_x, in_y, in_x + in_w, in_y + in_h,
531                                                 out_x, out_y, out_x + out_w, out_y + out_h);
532 if( debug ) printf("VModule::import_frame %d %d %d\n",
533  __LINE__, output->get_opengl_state(), (*input)->get_opengl_state());
534                                 }
535                                 else {
536                                         output->clear_frame();
537 // get_cache()->check_in(current_edit->asset);
538 // return;
539
540 // TRANSFER_REPLACE is the fastest transfer mode but it has the disadvantage
541 // of producing green borders in floating point translation of YUV
542                                         int mode = TRANSFER_REPLACE;
543                                         if( get_edl()->session->interpolation_type != NEAREST_NEIGHBOR &&
544                                                 BC_CModels::is_yuv(output->get_color_model()) )
545                                                 mode = TRANSFER_NORMAL;
546
547                                         if( debug ) printf("VModule::import_frame %d temp -> output\n", __LINE__);
548                                         overlayer->overlay(output, (*input),
549                                                 in_x, in_y, in_x + in_w, in_y + in_h,
550                                                 out_x, out_y, out_x + out_w, out_y + out_h,
551                                                 1, mode, get_edl()->session->interpolation_type);
552                                 }
553                                 result = 1;
554                                 
555                                 output->copy_stacks((*input));
556                                 
557                                 
558 //printf("VModule::import_frame %d\n", __LINE__); 
559 //(*input)->dump_params();
560 //output->dump_params();
561                         }
562                         else {
563 // file -> output
564                                 if( debug ) printf("VModule::import_frame %d file -> output nested_edl=%p file=%p\n",
565                                         __LINE__, nested_edl, file);
566                                 if( nested_edl ) {
567                                         VFrame **input = &output;
568 // If colormodels differ, reallocate output in nested colormodel.
569                                         int nested_cmodel = nested_renderengine->get_edl()->session->color_model;
570                                         int current_cmodel = output->get_color_model();
571
572 if( debug ) printf("VModule::import_frame %d nested_cmodel=%d current_cmodel=%d\n",
573 __LINE__,
574 nested_cmodel,
575 current_cmodel);
576
577                                         if( nested_cmodel != current_cmodel ) {
578                                                 if( use_opengl ) { }
579                                                 else {
580                                                         if( commonrender ) {
581                                                                 input = &((VRender*)commonrender)->input_temp;
582                                                         }
583                                                         else {
584                                                                 input = &input_temp;
585                                                         }
586
587                                                         if( !(*input) ) (*input) = new VFrame;
588                                                 }
589
590                                                 (*input)->reallocate(0, -1, 0, 0, 0,
591                                                         output->get_w(), output->get_h(),
592                                                         nested_cmodel, -1);
593 if( debug ) printf("VModule::import_frame %d\n", __LINE__);
594 //(*input)->dump();
595 //(*input)->clear_frame();
596                                         }
597
598 if( debug ) printf("VModule::import_frame %d %p %p\n",
599  __LINE__, (*input)->get_rows(), (*input));
600                                         result = nested_renderengine->vrender->process_buffer(
601                                                 (*input), nested_position, use_opengl);
602 if( debug ) printf("VModule::import_frame %d\n",
603 __LINE__);
604
605 // If colormodels differ, change colormodels in opengl if possible.
606 // Swap output for temp if not possible.
607                                         if( nested_cmodel != current_cmodel ) {
608                                                 if( use_opengl ) {
609                                                         x11_device->convert_cmodel(output,
610                                                                 current_cmodel);
611
612 // The color model was changed in place, so return output buffer
613                                                         output->reallocate(0, -1, 0, 0, 0,
614                                                                 output->get_w(), output->get_h(),
615                                                                 current_cmodel, -1);
616                                                 }
617                                                 else {
618 // Transfer from temporary to output
619 if( debug ) printf("VModule::import_frame %d %d %d %d %d %d %d\n",
620   __LINE__, (*input)->get_w(), (*input)->get_h(),
621   output->get_w(), output->get_h(), nested_cmodel, current_cmodel);
622                                                         BC_CModels::transfer(output->get_rows(), (*input)->get_rows(),
623                                                                 0, 0, 0, 0, 0, 0,
624                                                                 0, 0, (*input)->get_w(), (*input)->get_h(),
625                                                                 0, 0, output->get_w(), output->get_h(),
626                                                                 nested_cmodel, current_cmodel, 0,
627                                                                 (*input)->get_w(), output->get_w());
628                                                 }
629
630                                         }
631                                 }
632                                 else if( file ) {
633 // Cache single frames
634 //memset(output->get_rows()[0], 0xff, 1024);
635                                         if( use_cache ) file->set_cache_frames(1);
636                                         result = file->read_frame(output);
637                                         if( use_cache ) file->set_cache_frames(0);
638                                         output->set_opengl_state(VFrame::RAM);
639                                 }
640                         }
641
642                         if( file ) {
643                                 get_cache()->check_in(current_edit->asset);
644                                 file = 0;
645                         }
646                 }
647                 else {
648 // Source not found
649                         result = 1;
650                 }
651
652 //              printf("VModule::import_frame %d cache=%p\n", 
653 //                      __LINE__,
654 //                      get_cache());
655
656         }
657         else {
658 // Source is silence
659                 if( debug ) printf("VModule::import_frame %d\n", __LINE__);
660                 if( use_opengl ) {
661                         x11_device->clear_input(output);
662                 }
663                 else {
664                         output->clear_frame();
665                 }
666         }
667
668         if( debug ) printf("VModule::import_frame %d done\n", __LINE__);
669
670         return result;
671 }
672
673
674 int VModule::render(VFrame *output,
675         int64_t start_position, int direction, double frame_rate,
676         int use_nudge, int debug_render, int use_opengl)
677 {
678         int result = 0;
679         double edl_rate = get_edl()->session->frame_rate;
680
681 //printf("VModule::render %d %ld\n", __LINE__, start_position);
682
683         if( use_nudge ) start_position += Units::to_int64(track->nudge *
684                 frame_rate / edl_rate);
685
686         int64_t start_position_project = Units::to_int64(start_position *
687                 edl_rate / frame_rate + 0.5);
688
689         update_transition(start_position_project, direction);
690
691         VEdit* current_edit = (VEdit*)track->edits->editof(start_position_project,
692                 direction, 0);
693         VEdit* previous_edit = 0;
694 //printf("VModule::render %d %p %ld %d\n", __LINE__, current_edit, start_position_project, direction);
695
696         if( debug_render )
697                 printf("    VModule::render %d %d %jd %s transition=%p opengl=%d current_edit=%p output=%p\n",
698                         __LINE__, use_nudge, start_position_project, track->title,
699                         transition, use_opengl, current_edit, output);
700
701         if( !current_edit ) {
702                 output->clear_frame();
703                 // We do not apply mask here, since alpha is 0, and neither substracting nor multypling changes it
704                 // Another mask mode - "addition" should be added to be able to create mask from empty frames
705                 // in this case we would call masking here too...
706                 return 0;
707         }
708
709
710
711
712 // Process transition
713         if( transition && transition->on ) {
714
715 // Get temporary buffer
716                 VFrame **transition_input = 0;
717                 if( commonrender ) {
718                         VRender *vrender = (VRender*)commonrender;
719                         transition_input = &vrender->transition_temp;
720                 }
721                 else {
722                         transition_input = &transition_temp;
723                 }
724
725                 if( (*transition_input) &&
726                         ((*transition_input)->get_w() != track->track_w ||
727                         (*transition_input)->get_h() != track->track_h) ) {
728                         delete (*transition_input);
729                         (*transition_input) = 0;
730                 }
731
732 // Load incoming frame
733                 if( !(*transition_input) ) {
734                         (*transition_input) =
735                                 new VFrame(track->track_w, track->track_h,
736                                         get_edl()->session->color_model);
737                 }
738
739                 (*transition_input)->copy_stacks(output);
740
741 //printf("VModule::render %d\n", __LINE__);
742                 result = import_frame((*transition_input),
743                         current_edit, start_position, frame_rate,
744                         direction, use_opengl);
745
746
747 // Load transition buffer
748                 previous_edit = (VEdit*)current_edit->previous;
749
750                 result |= import_frame(output,
751                         previous_edit, start_position, frame_rate,
752                         direction, use_opengl);
753 //printf("VModule::render %d %p %p %p %p\n", __LINE__,
754 // (*transition_input), (*transition_input)->get_pbuffer(),
755 // output, output->get_pbuffer());
756
757 // Execute plugin with transition_input and output here
758                 if( renderengine )
759                         transition_server->set_use_opengl(use_opengl, renderengine->video);
760                 transition_server->process_transition((*transition_input), output,
761                         (direction == PLAY_FORWARD) ?
762                                 (start_position_project - current_edit->startproject) :
763                                 (start_position_project - current_edit->startproject - 1),
764                         transition->length);
765         }
766         else {
767 // Load output buffer
768                 result = import_frame(output,
769                         current_edit, start_position, frame_rate,
770                         direction, use_opengl);
771         }
772
773         Auto *current = 0;
774         MaskAutos *keyframe_set =
775                 (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
776         int64_t mask_position = !renderengine ? start_position :
777                 renderengine->vrender->current_position;
778         MaskAuto *keyframe =
779                 (MaskAuto*)keyframe_set->get_prev_auto(mask_position, direction, current);
780
781         if( keyframe->apply_before_plugins && keyframe->has_active_mask() ) {
782                 VDeviceX11 *x11_device = 0;
783                 if( use_opengl && renderengine && renderengine->video ) {
784                         x11_device = (VDeviceX11*)renderengine->video->get_output_base();
785                         if( !x11_device->can_mask(mask_position, keyframe_set) ) {
786                                 if( output->get_opengl_state() != VFrame::RAM ) {
787                                         int w = output->get_w(), h = output->get_h();
788                                         x11_device->do_camera(output, output,
789                                                 0,0,w,h, 0,0,w,h); // copy to ram
790                                 }
791                                 use_opengl = 0;
792                         }
793                 }
794                 if( use_opengl && x11_device ) {
795                         x11_device->do_mask(output, mask_position, keyframe_set,
796                                         keyframe, keyframe);
797                 }
798                 else {
799                         if( !masker ) {
800                                 int cpus = renderengine ?
801                                         renderengine->preferences->processors :
802                                         plugin_array->mwindow->preferences->processors;
803                                 masker = new MaskEngine(cpus);
804                         }
805                         masker->do_mask(output, mask_position, keyframe_set, keyframe, keyframe);
806                 }
807         }
808
809         return result;
810 }
811
812
813 void VModule::create_objects()
814 {
815         Module::create_objects();
816 }
817