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