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