Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / 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
105
106
107
108 int VModule::import_frame(VFrame *output, VEdit *current_edit,
109         int64_t input_position, double frame_rate, int direction, int use_opengl)
110 {
111         int64_t direction_position;
112 // Translation of edit
113         float in_x, in_y, in_w, in_h;
114         float out_x, out_y, out_w, out_h;
115         int result = 0;
116         const int debug = 0;
117         double edl_rate = get_edl()->session->frame_rate;
118
119         int64_t input_position_project = Units::to_int64(input_position *
120                 edl_rate / frame_rate + 0.001);
121
122         if(!output) printf("VModule::import_frame %d output=%p\n", __LINE__, output);
123         //output->dump_params();
124
125         if(debug) printf("VModule::import_frame %d this=%p input_position=%lld direction=%d\n",
126                 __LINE__, this, (long long)input_position, direction);
127
128 // Convert to position corrected for direction
129         direction_position = input_position;
130         if(direction == PLAY_REVERSE) {
131                 if( direction_position > 0 ) direction_position--;
132                 if( input_position_project > 0 ) input_position_project--;
133         }
134         if(!output) printf("VModule::import_frame %d output=%p\n", __LINE__, output);
135
136         VDeviceX11 *x11_device = 0;
137         if(use_opengl)
138         {
139                 if(renderengine && renderengine->video)
140                 {
141                         x11_device = (VDeviceX11*)renderengine->video->get_output_base();
142                         output->set_opengl_state(VFrame::RAM);
143                         if(!x11_device) use_opengl = 0;
144                 }
145         }
146
147         if(!output) printf("VModule::import_frame %d output=%p x11_device=%p nested_edl=%p\n",
148                 __LINE__, output, x11_device, nested_edl);
149
150         if(debug) printf("VModule::import_frame %d current_edit=%p\n",
151                 __LINE__, current_edit);
152
153 // Load frame into output
154
155 // Create objects for nested EDL
156         if(current_edit && current_edit->nested_edl) {
157                 int command;
158                 if(debug) printf("VModule::import_frame %d nested_edl=%p current_edit->nested_edl=%p\n",
159                         __LINE__, nested_edl, current_edit->nested_edl);
160
161 // Convert requested direction to command
162                 if( renderengine->command->command == CURRENT_FRAME ||
163                     renderengine->command->command == LAST_FRAME )
164                 {
165                         command = renderengine->command->command;
166                 }
167                 else
168                 if(direction == PLAY_REVERSE)
169                 {
170                         if(renderengine->command->single_frame())
171                                 command = SINGLE_FRAME_REWIND;
172                         else
173                                 command = NORMAL_REWIND;
174                 }
175                 else
176                 {
177                         if(renderengine->command->single_frame())
178                                 command = SINGLE_FRAME_FWD;
179                         else
180                                 command = NORMAL_FWD;
181                 }
182
183                 if(!nested_edl || nested_edl->id != current_edit->nested_edl->id)
184                 {
185                         nested_edl = current_edit->nested_edl;
186                         if(nested_renderengine)
187                         {
188                                 delete nested_renderengine;
189                                 nested_renderengine = 0;
190                         }
191
192                         if(!nested_command)
193                         {
194                                 nested_command = new TransportCommand;
195                         }
196
197
198                         if(!nested_renderengine)
199                         {
200                                 nested_command->command = command;
201                                 nested_command->get_edl()->copy_all(nested_edl);
202                                 nested_command->change_type = CHANGE_ALL;
203                                 nested_command->realtime = renderengine->command->realtime;
204                                 nested_renderengine = new RenderEngine(0, get_preferences(), 0, 1);
205                                 nested_renderengine->set_vcache(get_cache());
206                                 nested_renderengine->arm_command(nested_command);
207                         }
208                 }
209                 else
210                 {
211
212 // Update nested command
213                         nested_renderengine->command->command = command;
214                         nested_command->realtime = renderengine->command->realtime;
215                 }
216
217 // Update nested video driver for opengl
218                 nested_renderengine->video = renderengine->video;
219         }
220         else
221         {
222                 nested_edl = 0;
223         }
224         if(debug) printf("VModule::import_frame %d\n", __LINE__);
225
226         if( output ) {
227                 if( use_opengl )
228                         x11_device->clear_input(output);
229                 else
230                         output->clear_frame();
231         }
232         else
233                 printf("VModule::import_frame %d output=%p\n", __LINE__, output);
234
235         if(current_edit &&
236                 (current_edit->asset ||
237                 (current_edit->nested_edl && nested_renderengine->vrender)))
238         {
239                 File *file = 0;
240
241 //printf("VModule::import_frame %d cache=%p\n", __LINE__, get_cache());
242                 if( current_edit->asset ) {
243                         get_cache()->age();
244                         file = get_cache()->check_out(current_edit->asset,
245                                 get_edl());
246 //                      get_cache()->dump();
247                 }
248
249 // File found
250                 if(file || nested_edl)
251                 {
252 // Make all positions based on requested frame rate.
253                         int64_t edit_startproject = Units::to_int64(current_edit->startproject *
254                                 frame_rate /
255                                 edl_rate);
256                         int64_t edit_startsource = Units::to_int64(current_edit->startsource *
257                                 frame_rate /
258                                 edl_rate);
259 // Source position going forward
260                         uint64_t position = direction_position -
261                                 edit_startproject +
262                                 edit_startsource;
263                         int64_t nested_position = 0;
264
265
266
267
268
269 // apply speed curve to source position so the timeline agrees with the playback
270                         if(track->has_speed())
271                         {
272 // integrate position from start of edit.
273                                 double speed_position = edit_startsource;
274                                 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
275                                 speed_position += speed_autos->automation_integral(edit_startproject,
276                                                 direction_position-edit_startproject, PLAY_FORWARD);
277 //printf("VModule::import_frame %d %lld %lld\n", __LINE__, position, (int64_t)speed_position);
278                                 position = (int64_t)speed_position;
279                         }
280
281
282
283
284
285                         int asset_w;
286                         int asset_h;
287                         if(debug) printf("VModule::import_frame %d\n", __LINE__);
288
289
290 // maybe apply speed curve here, so timeline reflects actual playback
291
292
293
294 // if we hit the end of stream, freeze at last frame
295                         uint64_t max_position = 0;
296                         if(file)
297                         {
298                                 max_position = Units::to_int64((double)file->get_video_length() *
299                                         frame_rate /
300                                         current_edit->asset->frame_rate - 1);
301                         }
302                         else
303                         {
304                                 max_position = Units::to_int64(nested_edl->tracks->total_length() *
305                                         frame_rate - 1);
306                         }
307
308
309                         if(position > max_position) position = max_position;
310                         else
311                         if(position < 0) position = 0;
312
313                         int use_cache = renderengine &&
314                                 renderengine->command->single_frame();
315 //                      int use_asynchronous = !use_cache &&
316 //                              renderengine &&
317 // Try to make rendering go faster.
318 // But converts some formats to YUV420, which may degrade input format.
319 ////                            renderengine->command->realtime &&
320 //                              renderengine->get_edl()->session->video_asynchronous;
321
322                         if(file)
323                         {
324                                 if(debug) printf("VModule::import_frame %d\n", __LINE__);
325 //                              if(use_asynchronous)
326 //                                      file->start_video_decode_thread();
327 //                              else
328                                         file->stop_video_thread();
329
330                                 int64_t normalized_position = Units::to_int64(position *
331                                         current_edit->asset->frame_rate /
332                                         frame_rate);
333 // printf("VModule::import_frame %d %lld %lld\n",
334 // __LINE__,
335 // position,
336 // normalized_position);
337                                 file->set_layer(current_edit->channel);
338                                 file->set_video_position(normalized_position,
339                                         0);
340                                 asset_w = current_edit->asset->width;
341                                 asset_h = current_edit->asset->height;
342 //printf("VModule::import_frame %d normalized_position=%lld\n", __LINE__, normalized_position);
343                         }
344                         else
345                         {
346                                 if(debug) printf("VModule::import_frame %d\n", __LINE__);
347                                 asset_w = nested_edl->session->output_w;
348                                 asset_h = nested_edl->session->output_h;
349 // Get source position in nested frame rate in direction of playback.
350                                 nested_position = Units::to_int64(position *
351                                         nested_edl->session->frame_rate /
352                                         frame_rate);
353                                 if(direction == PLAY_REVERSE)
354                                         nested_position++;
355                         }
356
357
358 // Auto scale if required
359                         if(output->get_params()->get("AUTOSCALE", 0))
360                         {
361                                 float autoscale_w = output->get_params()->get("AUTOSCALE_W", 1024);
362                                 float autoscale_h = output->get_params()->get("AUTOSCALE_H", 1024);
363                                 float x_scale = autoscale_w / asset_w;
364                                 float y_scale = autoscale_h / asset_h;
365
366 // Overriding camera
367                                 in_x = 0;
368                                 in_y = 0;
369                                 in_w = asset_w;
370                                 in_h = asset_h;
371
372                                 if(x_scale < y_scale)
373                                 {
374                                         out_w = in_w * x_scale;
375                                         out_h = in_h * x_scale;
376                                 }
377                                 else
378                                 {
379                                         out_w = in_w * y_scale;
380                                         out_h = in_h * y_scale;
381                                 }
382
383                                 out_x = track->track_w / 2 - out_w / 2;
384                                 out_y = track->track_h / 2 - out_h / 2;
385                         }
386                         else
387 // Apply camera
388                         {
389                                 ((VTrack*)track)->calculate_input_transfer(asset_w,
390                                         asset_h,
391                                         input_position_project,
392                                         direction,
393                                         in_x,
394                                         in_y,
395                                         in_w,
396                                         in_h,
397                                         out_x,
398                                         out_y,
399                                         out_w,
400                                         out_h);
401                         }
402
403 // printf("VModule::import_frame %d %f %d %f %d\n",
404 // __LINE__,
405 // in_w,
406 // asset_w,
407 // in_h,
408 // asset_h);
409 //
410 //                      printf("VModule::import_frame 1 [ilace] Project: mode (%d) Asset: autofixoption (%d), mode (%d), method (%d)\n",
411 //                      get_edl()->session->interlace_mode,
412 //                      current_edit->asset->interlace_autofixoption,
413 //                      current_edit->asset->interlace_mode,
414 //                      current_edit->asset->interlace_fixmethod);
415
416                         // Determine the interlacing method to use.
417                         int interlace_fixmethod = !current_edit->asset ? ILACE_FIXMETHOD_NONE :
418                                  ilaceautofixmethod2(get_edl()->session->interlace_mode,
419                                         current_edit->asset->interlace_autofixoption,
420                                         current_edit->asset->interlace_mode,
421                                         current_edit->asset->interlace_fixmethod);
422 //
423 //                      char string[BCTEXTLEN];
424 //                      ilacefixmethod_to_text(string,interlace_fixmethod);
425 //                      printf("VModule::import_frame 1 [ilace] Compensating by using: '%s'\n",string);
426
427                         // Compensate for the said interlacing...
428                         switch (interlace_fixmethod) {
429                                 case ILACE_FIXMETHOD_NONE:
430
431                                 break;
432                                 case ILACE_FIXMETHOD_UPONE:
433                                         out_y--;
434                                 break;
435                                 case ILACE_FIXMETHOD_DOWNONE:
436                                         out_y++;
437                                 break;
438                                 default:
439                                         printf("vmodule::importframe WARNING - unknown fix method for interlacing, no compensation in effect\n");
440                         }
441
442 // file -> temp -> output
443                         if( !EQUIV(in_x, 0) ||
444                                 !EQUIV(in_y, 0) ||
445                                 !EQUIV(in_w, track->track_w) ||
446                                 !EQUIV(in_h, track->track_h) ||
447                                 !EQUIV(out_x, 0) ||
448                                 !EQUIV(out_y, 0) ||
449                                 !EQUIV(out_w, track->track_w) ||
450                                 !EQUIV(out_h, track->track_h) ||
451                                 !EQUIV(in_w, asset_w) ||
452                                 !EQUIV(in_h, asset_h))
453                         {
454 //printf("VModule::import_frame %d file -> temp -> output\n", __LINE__);
455
456
457
458
459 // Get temporary input buffer
460                                 VFrame **input = 0;
461 // Realtime playback
462                                 if(commonrender)
463                                 {
464                                         VRender *vrender = (VRender*)commonrender;
465 //printf("VModule::import_frame %d vrender->input_temp=%p\n", __LINE__, vrender->input_temp);
466                                         input = &vrender->input_temp;
467                                 }
468                                 else
469 // Menu effect
470                                 {
471                                         input = &input_temp;
472                                 }
473
474
475                                 if((*input) &&
476                                         ((*input)->get_w() != asset_w ||
477                                         (*input)->get_h() != asset_h))
478                                 {
479                                         delete (*input);
480                                         (*input) = 0;
481                                 }
482
483
484
485
486
487                                 if(!(*input))
488                                 {
489                                         (*input) =
490                                                 new VFrame(asset_w, asset_h,
491                                                         get_edl()->session->color_model);
492                                 }
493
494
495
496                                 (*input)->copy_stacks(output);
497
498 // file -> temp
499 // Cache for single frame only
500                                 if(file)
501                                 {
502                                         if(debug) printf("VModule::import_frame %d this=%p file=%s\n",
503                                                 __LINE__,
504                                                 this,
505                                                 current_edit->asset->path);
506                                         if(use_cache) file->set_cache_frames(1);
507                                         result = file->read_frame((*input));
508                                         if(use_cache) file->set_cache_frames(0);
509                                         (*input)->set_opengl_state(VFrame::RAM);
510                                 }
511                                 else
512                                 if(nested_edl)
513                                 {
514 // If the colormodels differ, change input to nested colormodel
515                                         int nested_cmodel = nested_renderengine->get_edl()->session->color_model;
516                                         int current_cmodel = output->get_color_model();
517                                         int output_w = output->get_w();
518                                         int output_h = output->get_h();
519                                         VFrame *input2 = (*input);
520
521                                         if(nested_cmodel != current_cmodel)
522                                         {
523 // If opengl, input -> input -> output
524                                                 if(use_opengl)
525                                                 {
526                                                 }
527                                                 else
528                                                 {
529 // If software, input2 -> input -> output
530 // Use output as a temporary.
531                                                         input2 = output;
532                                                 }
533
534                                                 if(debug) printf("VModule::import_frame %d this=%p nested_cmodel=%d\n",
535                                                         __LINE__,
536                                                         this,
537                                                         nested_cmodel);
538                                                 input2->dump();
539                                                 input2->reallocate(0,
540                                                         -1,
541                                                         0,
542                                                         0,
543                                                         0,
544                                                         (*input)->get_w(),
545                                                         (*input)->get_h(),
546                                                         nested_cmodel,
547                                                         -1);
548                                                 input2->dump();
549                                         }
550
551
552                                         if(debug) printf("VModule::import_frame %d this=%p nested_edl=%s input2=%p\n",
553                                                 __LINE__,
554                                                 this,
555                                                 nested_edl->path,
556                                                 input2);
557
558                                         result = nested_renderengine->vrender->process_buffer(
559                                                 input2,
560                                                 nested_position,
561                                                 use_opengl);
562
563                                         if(debug) printf("VModule::import_frame %d this=%p nested_edl=%s\n",
564                                                 __LINE__,
565                                                 this,
566                                                 nested_edl->path);
567
568                                         if(nested_cmodel != current_cmodel)
569                                         {
570                                                 if(debug) printf("VModule::import_frame %d\n", __LINE__);
571                                                 if(use_opengl)
572                                                 {
573 // Change colormodel in hardware.
574                                                         if(debug) printf("VModule::import_frame %d\n", __LINE__);
575                                                         x11_device->convert_cmodel(input2,
576                                                                 current_cmodel);
577
578 // The converted color model is now in hardware, so return the input2 buffer
579 // to the expected color model.
580                                                         input2->reallocate(0,
581                                                                 -1,
582                                                                 0,
583                                                                 0,
584                                                                 0,
585                                                                 (*input)->get_w(),
586                                                                 (*input)->get_h(),
587                                                                 current_cmodel,
588                                                                 -1);
589                                                 }
590                                                 else
591                                                 {
592 // Transfer from input2 to input
593 if(debug) printf("VModule::import_frame %d nested_cmodel=%d current_cmodel=%d input2=%p input=%p output=%p\n",
594 __LINE__,
595 nested_cmodel,
596 current_cmodel,
597 input2,
598 (*input),
599 output);
600                                                         BC_CModels::transfer((*input)->get_rows(),
601                                                                 input2->get_rows(),
602                                                                 0,
603                                                                 0,
604                                                                 0,
605                                                                 0,
606                                                                 0,
607                                                                 0,
608                                                                 0,
609                                                                 0,
610                                                             input2->get_w(),
611                                                             input2->get_h(),
612                                                                 0,
613                                                                 0,
614                                                                 (*input)->get_w(),
615                                                                 (*input)->get_h(),
616                                                                 nested_cmodel,
617                                                                 current_cmodel,
618                                                                 0,
619                                                                 input2->get_w(),
620                                                                 (*input)->get_w());
621 //printf("VModule::import_frame %d\n", __LINE__);
622
623 // input2 was the output buffer, so it must be restored
624                                                 input2->reallocate(0,
625                                                         -1,
626                                                         0,
627                                                         0,
628                                                         0,
629                                                         output_w,
630                                                         output_h,
631                                                         current_cmodel,
632                                                         -1);
633 //printf("VModule::import_frame %d\n", __LINE__);
634                                                 }
635                                         }
636
637                                 }
638
639 // Find an overlayer object to perform the camera transformation
640                                 OverlayFrame *overlayer = 0;
641
642 // OpenGL playback uses hardware
643                                 if(use_opengl)
644                                 {
645 //printf("VModule::import_frame %d\n", __LINE__);
646                                 }
647                                 else
648 // Realtime playback
649                                 if(commonrender)
650                                 {
651                                         VRender *vrender = (VRender*)commonrender;
652                                         overlayer = vrender->overlayer;
653                                 }
654                                 else
655 // Menu effect
656                                 {
657                                         if(!plugin_array)
658                                                 printf("VModule::import_frame neither plugin_array nor commonrender is defined.\n");
659                                         if(!overlay_temp)
660                                         {
661                                                 overlay_temp = new OverlayFrame(plugin_array->mwindow->preferences->processors);
662                                         }
663
664                                         overlayer = overlay_temp;
665                                 }
666 // printf("VModule::import_frame 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
667 //      in_x,
668 //      in_y,
669 //      in_w,
670 //      in_h,
671 //      out_x,
672 //      out_y,
673 //      out_w,
674 //      out_h);
675
676 // temp -> output
677 // for(int j = 0; j < output->get_w() * 3 * 5; j++)
678 //      output->get_rows()[0][j] = 255;
679
680                                 if(use_opengl)
681                                 {
682                                         x11_device->do_camera(output,
683                                                 (*input),
684                                                 in_x,
685                                                 in_y,
686                                                 in_x + in_w,
687                                                 in_y + in_h,
688                                                 out_x,
689                                                 out_y,
690                                                 out_x + out_w,
691                                                 out_y + out_h);
692 if(debug) printf("VModule::import_frame %d %d %d\n",
693 __LINE__,
694 output->get_opengl_state(),
695 (*input)->get_opengl_state());
696                                 }
697                                 else
698                                 {
699
700
701
702                                         output->clear_frame();
703
704
705 // get_cache()->check_in(current_edit->asset);
706 // return;
707
708 // TRANSFER_REPLACE is the fastest transfer mode but it has the disadvantage
709 // of producing green borders in floating point translation of YUV
710                                         int mode = TRANSFER_REPLACE;
711                                         if(get_edl()->session->interpolation_type != NEAREST_NEIGHBOR &&
712                                                 BC_CModels::is_yuv(output->get_color_model()))
713                                                 mode = TRANSFER_NORMAL;
714
715                                         if(debug) printf("VModule::import_frame %d temp -> output\n", __LINE__);
716                                         overlayer->overlay(output,
717                                                 (*input),
718                                                 in_x,
719                                                 in_y,
720                                                 in_x + in_w,
721                                                 in_y + in_h,
722                                                 out_x,
723                                                 out_y,
724                                                 out_x + out_w,
725                                                 out_y + out_h,
726                                                 1,
727                                                 mode,
728                                                 get_edl()->session->interpolation_type);
729                                 }
730                                 result = 1;
731                                 
732                                 output->copy_stacks((*input));
733                                 
734                                 
735 //printf("VModule::import_frame %d\n", __LINE__); 
736 //(*input)->dump_params();
737 //output->dump_params();
738                         }
739                         else
740 // file -> output
741                         {
742                                 if(debug) printf("VModule::import_frame %d file -> output nested_edl=%p file=%p\n",
743                                         __LINE__,
744                                         nested_edl,
745                                         file);
746                                 if(nested_edl)
747                                 {
748                                         VFrame **input = &output;
749 // If colormodels differ, reallocate output in nested colormodel.
750                                         int nested_cmodel = nested_renderengine->get_edl()->session->color_model;
751                                         int current_cmodel = output->get_color_model();
752
753 if(debug) printf("VModule::import_frame %d nested_cmodel=%d current_cmodel=%d\n",
754 __LINE__,
755 nested_cmodel,
756 current_cmodel);
757
758                                         if(nested_cmodel != current_cmodel)
759                                         {
760                                                 if(use_opengl)
761                                                 {
762                                                 }
763                                                 else
764                                                 {
765                                                         if(commonrender)
766                                                         {
767                                                                 input = &((VRender*)commonrender)->input_temp;
768                                                         }
769                                                         else
770                                                         {
771                                                                 input = &input_temp;
772                                                         }
773
774                                                         if(!(*input)) (*input) = new VFrame;
775                                                 }
776
777                                                 (*input)->reallocate(0,
778                                                         -1,
779                                                         0,
780                                                         0,
781                                                         0,
782                                                         output->get_w(),
783                                                         output->get_h(),
784                                                         nested_cmodel,
785                                                         -1);
786 if(debug) printf("VModule::import_frame %d\n",
787 __LINE__);
788 //(*input)->dump();
789 //(*input)->clear_frame();
790                                         }
791
792 if(debug) printf("VModule::import_frame %d %p %p\n",
793 __LINE__,
794 (*input)->get_rows(),
795 (*input));
796                                         result = nested_renderengine->vrender->process_buffer(
797                                                 (*input),
798                                                 nested_position,
799                                                 use_opengl);
800 if(debug) printf("VModule::import_frame %d\n",
801 __LINE__);
802
803 // If colormodels differ, change colormodels in opengl if possible.
804 // Swap output for temp if not possible.
805                                         if(nested_cmodel != current_cmodel)
806                                         {
807                                                 if(use_opengl)
808                                                 {
809                                                         x11_device->convert_cmodel(output,
810                                                                 current_cmodel);
811
812 // The color model was changed in place, so return output buffer
813                                                         output->reallocate(0,
814                                                                 -1,
815                                                                 0,
816                                                                 0,
817                                                                 0,
818                                                                 output->get_w(),
819                                                                 output->get_h(),
820                                                                 current_cmodel,
821                                                                 -1);
822                                                 }
823                                                 else
824                                                 {
825 // Transfer from temporary to output
826 if(debug) printf("VModule::import_frame %d %d %d %d %d %d %d\n",
827 __LINE__,
828 (*input)->get_w(),
829 (*input)->get_h(),
830 output->get_w(),
831 output->get_h(),
832 nested_cmodel,
833 current_cmodel);
834                                                         BC_CModels::transfer(output->get_rows(),
835                                                                 (*input)->get_rows(),
836                                                                 0,
837                                                                 0,
838                                                                 0,
839                                                                 0,
840                                                                 0,
841                                                                 0,
842                                                                 0,
843                                                                 0,
844                                                                 (*input)->get_w(),
845                                                                 (*input)->get_h(),
846                                                                 0,
847                                                                 0,
848                                                                 output->get_w(),
849                                                                 output->get_h(),
850                                                                 nested_cmodel,
851                                                                 current_cmodel,
852                                                                 0,
853                                                                 (*input)->get_w(),
854                                                                 output->get_w());
855                                                 }
856
857                                         }
858
859                                 }
860                                 else
861                                 if(file)
862                                 {
863 // Cache single frames
864 //memset(output->get_rows()[0], 0xff, 1024);
865                                         if(use_cache) file->set_cache_frames(1);
866                                         result = file->read_frame(output);
867                                         if(use_cache) file->set_cache_frames(0);
868                                         output->set_opengl_state(VFrame::RAM);
869                                 }
870                         }
871
872                         if(file)
873                         {
874                                 get_cache()->check_in(current_edit->asset);
875                                 file = 0;
876                         }
877                 }
878                 else
879 // Source not found
880                 {
881                         result = 1;
882                 }
883
884 //              printf("VModule::import_frame %d cache=%p\n", 
885 //                      __LINE__,
886 //                      get_cache());
887
888         }
889         else
890 // Source is silence
891         {
892                 if(debug) printf("VModule::import_frame %d\n", __LINE__);
893                 if(use_opengl)
894                 {
895                         x11_device->clear_input(output);
896                 }
897                 else
898                 {
899                         output->clear_frame();
900                 }
901         }
902
903         if(debug) printf("VModule::import_frame %d done\n", __LINE__);
904
905         return result;
906 }
907
908
909
910 int VModule::render(VFrame *output,
911         int64_t start_position,
912         int direction,
913         double frame_rate,
914         int use_nudge,
915         int debug_render,
916         int use_opengl)
917 {
918         int result = 0;
919         double edl_rate = get_edl()->session->frame_rate;
920
921 //printf("VModule::render %d %ld\n", __LINE__, start_position);
922
923         if(use_nudge) start_position += Units::to_int64(track->nudge *
924                 frame_rate / edl_rate);
925
926         int64_t start_position_project = Units::to_int64(start_position *
927                 edl_rate / frame_rate + 0.5);
928
929         update_transition(start_position_project,
930                 direction);
931
932         VEdit* current_edit = (VEdit*)track->edits->editof(start_position_project,
933                 direction,
934                 0);
935         VEdit* previous_edit = 0;
936 //printf("VModule::render %d %p %ld %d\n", __LINE__, current_edit, start_position_project, direction);
937
938         if(debug_render)
939                 printf("    VModule::render %d %d %jd %s transition=%p opengl=%d current_edit=%p output=%p\n",
940                         __LINE__,
941                         use_nudge,
942                         start_position_project,
943                         track->title,
944                         transition,
945                         use_opengl,
946                         current_edit,
947                         output);
948
949         if(!current_edit)
950         {
951                 output->clear_frame();
952                 // We do not apply mask here, since alpha is 0, and neither substracting nor multypling changes it
953                 // Another mask mode - "addition" should be added to be able to create mask from empty frames
954                 // in this case we would call masking here too...
955                 return 0;
956         }
957
958
959
960
961 // Process transition
962         if(transition && transition->on)
963         {
964
965 // Get temporary buffer
966                 VFrame **transition_input = 0;
967                 if(commonrender)
968                 {
969                         VRender *vrender = (VRender*)commonrender;
970                         transition_input = &vrender->transition_temp;
971                 }
972                 else
973                 {
974                         transition_input = &transition_temp;
975                 }
976
977                 if((*transition_input) &&
978                         ((*transition_input)->get_w() != track->track_w ||
979                         (*transition_input)->get_h() != track->track_h))
980                 {
981                         delete (*transition_input);
982                         (*transition_input) = 0;
983                 }
984
985 // Load incoming frame
986                 if(!(*transition_input))
987                 {
988                         (*transition_input) =
989                                 new VFrame(track->track_w, track->track_h,
990                                         get_edl()->session->color_model);
991                 }
992
993                 (*transition_input)->copy_stacks(output);
994
995 //printf("VModule::render %d\n", __LINE__);
996                 result = import_frame((*transition_input),
997                         current_edit,
998                         start_position,
999                         frame_rate,
1000                         direction,
1001                         use_opengl);
1002
1003
1004 // Load transition buffer
1005                 previous_edit = (VEdit*)current_edit->previous;
1006
1007                 result |= import_frame(output,
1008                         previous_edit,
1009                         start_position,
1010                         frame_rate,
1011                         direction,
1012                         use_opengl);
1013 //printf("VModule::render %d\n", __LINE__);
1014
1015 // printf("VModule::render %d %p %p %p %p\n",
1016 // __LINE__,
1017 // (*transition_input),
1018 // (*transition_input)->get_pbuffer(),
1019 // output,
1020 // output->get_pbuffer());
1021
1022
1023 // Execute plugin with transition_input and output here
1024                 if(renderengine)
1025                         transition_server->set_use_opengl(use_opengl, renderengine->video);
1026                 transition_server->process_transition((*transition_input),
1027                         output,
1028                         (direction == PLAY_FORWARD) ?
1029                                 (start_position_project - current_edit->startproject) :
1030                                 (start_position_project - current_edit->startproject - 1),
1031                         transition->length);
1032         }
1033         else
1034         {
1035 // Load output buffer
1036                 result = import_frame(output,
1037                         current_edit,
1038                         start_position,
1039                         frame_rate,
1040                         direction,
1041                         use_opengl);
1042         }
1043
1044         Auto *current = 0;
1045         MaskAutos *keyframe_set =
1046                 (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
1047         int64_t mask_position = !renderengine ? start_position :
1048                 renderengine->vrender->current_position;
1049         MaskAuto *keyframe =
1050                 (MaskAuto*)keyframe_set->get_prev_auto(mask_position, direction, current);
1051
1052         if( keyframe->apply_before_plugins ) {
1053                 VDeviceX11 *x11_device = 0;
1054                 if(use_opengl && renderengine && renderengine->video) {
1055                         x11_device = (VDeviceX11*)renderengine->video->get_output_base();
1056                         if( !x11_device->can_mask(mask_position, keyframe_set) )
1057                                 use_opengl = 0;
1058                 }
1059                 if( use_opengl && x11_device ) {
1060                         x11_device->do_mask(output, mask_position, keyframe_set,
1061                                         keyframe, keyframe);
1062                 }
1063                 else {
1064                         if( !masker ) {
1065                                 int cpus = renderengine ?
1066                                         renderengine->preferences->processors :
1067                                         plugin_array->mwindow->preferences->processors;
1068                                 masker = new MaskEngine(cpus);
1069                         }
1070                         masker->do_mask(output, mask_position, keyframe_set, keyframe, keyframe);
1071                 }
1072         }
1073
1074         return result;
1075 }
1076
1077
1078
1079
1080
1081
1082 void VModule::create_objects()
1083 {
1084         Module::create_objects();
1085 }
1086
1087
1088
1089
1090
1091