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