r956: README.BUILD - add more library recommendations
[cinelerra_cv/ct.git] / cinelerra / vmodule.C
blobbc6bcf3170b224f6248d86f12db3db57bfd12b53
1 #include "asset.h"
2 #include "bcsignals.h"
3 #include "cache.h"
4 #include "clip.h"
5 #include "commonrender.h"
6 #include "edits.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "file.h"
10 #include "filexml.h"
11 #include "floatautos.h"
12 #include "mwindow.h"
13 #include "overlayframe.h"
14 #include "patch.h"
15 #include "pluginarray.h"
16 #include "preferences.h"
17 #include "renderengine.h"
18 #include "sharedlocation.h"
19 #include "transition.h"
20 #include "transportque.h"
21 #include "units.h"
22 #include "vattachmentpoint.h"
23 #include "vdevicex11.h"
24 #include "vedit.h"
25 #include "vframe.h"
26 #include "videodevice.h"
27 #include "vmodule.h"
28 #include "vrender.h"
29 #include "vplugin.h"
30 #include "vtrack.h"
31 #include <string.h>
32 #include "interlacemodes.h"
33 #include "maskengine.h"
34 #include "automation.h"
36 VModule::VModule(RenderEngine *renderengine, 
37         CommonRender *commonrender, 
38         PluginArray *plugin_array,
39         Track *track)
40  : Module(renderengine, commonrender, plugin_array, track)
42         data_type = TRACK_VIDEO;
43         overlay_temp = 0;
44         input_temp = 0;
45         transition_temp = 0;
46         if (renderengine)
47                 masker = new MaskEngine(renderengine->preferences->processors);
48         else
49                 masker = new MaskEngine(plugin_array->mwindow->preferences->processors);
50         
53 VModule::~VModule()
55         if(overlay_temp) delete overlay_temp;
56         if(input_temp) delete input_temp;
57         if(transition_temp) delete transition_temp;
58         delete masker;
62 AttachmentPoint* VModule::new_attachment(Plugin *plugin)
64         return new VAttachmentPoint(renderengine, plugin);
67 int VModule::get_buffer_size()
69         return 1;
72 CICache* VModule::get_cache()
74         if(renderengine) 
75                 return renderengine->get_vcache();
76         else
77                 return cache;
80 int VModule::import_frame(VFrame *output,
81         VEdit *current_edit,
82         int64_t input_position,
83         double frame_rate,
84         int direction,
85         int use_opengl)
87         int64_t corrected_position;
88         int64_t corrected_position_project;
89 // Translation of edit
90         float in_x1;
91         float in_y1;
92         float in_w1;
93         float in_h1;
94         float out_x1;
95         float out_y1;
96         float out_w1;
97         float out_h1;
98         int result = 0;
99         double edl_rate = get_edl()->session->frame_rate;
100         int64_t input_position_project = (int64_t)(input_position * 
101                 edl_rate / 
102                 frame_rate + 
103                 0.001);
104         if(!output) printf("VModule::import_frame 10 output=%p\n", output);
106         corrected_position = input_position;
107         corrected_position_project = input_position_project;
108         if(direction == PLAY_REVERSE)
109         {
110                 corrected_position--;
111                 input_position_project--;
112         }
114         VDeviceX11 *x11_device = 0;
115         if(use_opengl)
116         {
117                 if(renderengine && renderengine->video)
118                 {
119                         x11_device = (VDeviceX11*)renderengine->video->get_output_base();
120                         output->set_opengl_state(VFrame::RAM);
121                 }
122         }
125 // Load frame into output
126         if(current_edit &&
127                 current_edit->asset)
128         {
129                 get_cache()->age();
130                 File *source = get_cache()->check_out(current_edit->asset,
131                         get_edl());
132 //              get_cache()->dump();
134                 if(source)
135                 {
136                         int64_t edit_startproject = (int64_t)(current_edit->startproject * 
137                                 frame_rate / 
138                                 edl_rate);
139                         int64_t edit_startsource = (int64_t)(current_edit->startsource *
140                                 frame_rate /
141                                 edl_rate);
142                         uint64_t position = corrected_position - 
143                                 edit_startproject + 
144                                 edit_startsource;
145                         // if we hit the end of stream, freeze at last frame
146                         uint64_t max_position = source->get_video_length(frame_rate) - 1;
147                         if (position > max_position) position = max_position;
148                         int use_cache = renderengine && 
149                                 renderengine->command->single_frame();
150                         int use_asynchronous = !use_cache && renderengine &&
151                                 renderengine->command->realtime &&
152                                 renderengine->edl->session->video_asynchronous;
154                         if(use_asynchronous)
155                                 source->start_video_decode_thread();
156                         else
157                                 source->stop_video_thread();
159                         source->set_video_position(position, frame_rate);
160                         source->set_layer(current_edit->channel);
162                         ((VTrack*)track)->calculate_input_transfer(current_edit->asset, 
163                                 input_position_project, 
164                                 direction, 
165                                 in_x1, 
166                                 in_y1, 
167                                 in_w1, 
168                                 in_h1,
169                                 out_x1, 
170                                 out_y1, 
171                                 out_w1, 
172                                 out_h1);
175 //                      printf("VModule::import_frame 1 [ilace] Project: mode (%d) Asset: autofixoption (%d), mode (%d), method (%d)\n", 
176 //                      get_edl()->session->interlace_mode,
177 //                      current_edit->asset->interlace_autofixoption,
178 //                      current_edit->asset->interlace_mode,
179 //                      current_edit->asset->interlace_fixmethod);
181                         // Determine the interlacing method to use.
182                         int interlace_fixmethod = ilaceautofixmethod2(get_edl()->session->interlace_mode,
183                                         current_edit->asset->interlace_autofixoption,
184                                         current_edit->asset->interlace_mode,
185                                         current_edit->asset->interlace_fixmethod);
187 //                      char string[BCTEXTLEN];
188 //                      ilacefixmethod_to_text(string,interlace_fixmethod);
189 //                      printf("VModule::import_frame 1 [ilace] Compensating by using: '%s'\n",string);
191                         // Compensate for the said interlacing...
192                         switch (interlace_fixmethod) {
193                                 case BC_ILACE_FIXMETHOD_NONE:
194                                 
195                                 break;
196                                 case BC_ILACE_FIXMETHOD_UPONE:
197                                         out_y1--;
198                                 break;
199                                 case BC_ILACE_FIXMETHOD_DOWNONE:
200                                         out_y1++;
201                                 break;
202                                 default:
203                                         printf("vmodule::importframe WARNING - unknown fix method for interlacing, no compensation in effect\n");
204                         }
207 // file -> temp -> output
208                         if( !EQUIV(in_x1, 0) || 
209                                 !EQUIV(in_y1, 0) || 
210                                 !EQUIV(in_w1, track->track_w) || 
211                                 !EQUIV(in_h1, track->track_h) || 
212                                 !EQUIV(out_x1, 0) ||
213                                 !EQUIV(out_y1, 0) ||
214                                 !EQUIV(out_w1, track->track_w) ||
215                                 !EQUIV(out_h1, track->track_h) ||
216                                 !EQUIV(in_w1, current_edit->asset->width) ||
217                                 !EQUIV(in_h1, current_edit->asset->height))
218                         {
223 // Get temporary input buffer
224                                 VFrame **input = 0;
225 // Realtime playback
226                                 if(commonrender)
227                                 {
228                                         VRender *vrender = (VRender*)commonrender;
229                                         input = &vrender->input_temp;
230                                 }
231                                 else
232 // Menu effect
233                                 {
234                                         input = &input_temp;
235                                 }
238                                 if((*input) && 
239                                         ((*input)->get_w() != current_edit->asset->width ||
240                                         (*input)->get_h() != current_edit->asset->height))
241                                 {
242                                         delete (*input);
243                                         (*input) = 0;
244                                 }
250                                 if(!(*input))
251                                 {
252                                         (*input) = new VFrame(0,
253                                                 current_edit->asset->width,
254                                                 current_edit->asset->height,
255                                                 get_edl()->session->color_model,
256                                                 -1);
257                                 }
261                                 (*input)->copy_stacks(output);
263 // file -> temp
264 // Cache for single frame only
265                                 if(use_cache) source->set_cache_frames(1);
266                                 result = source->read_frame((*input));
267                                 if(use_cache) source->set_cache_frames(0);
268                                 (*input)->set_opengl_state(VFrame::RAM);
270 //printf("VModule::import_frame 1 %lld %f\n", input_position, frame_rate);
272 // Find an overlayer object to perform the camera transformation
273                                 OverlayFrame *overlayer = 0;
275 // OpenGL playback uses hardware
276                                 if(use_opengl)
277                                 {
278                                 }
279                                 else
280 // Realtime playback
281                                 if(commonrender)
282                                 {
283                                         VRender *vrender = (VRender*)commonrender;
284                                         overlayer = vrender->overlayer;
285                                 }
286                                 else
287 // Menu effect
288                                 {
289                                         if(!plugin_array)
290                                                 printf("VModule::import_frame neither plugin_array nor commonrender is defined.\n");
291                                         if(!overlay_temp)
292                                         {
293                                                 overlay_temp = new OverlayFrame(plugin_array->mwindow->preferences->processors);
294                                         }
296                                         overlayer = overlay_temp;
297                                 }
298 // printf("VModule::import_frame 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n", 
299 //      in_x1, 
300 //      in_y1, 
301 //      in_w1, 
302 //      in_h1, 
303 //      out_x1, 
304 //      out_y1, 
305 //      out_w1, 
306 //      out_h1);
308 // temp -> output
309 // for(int j = 0; j < output->get_w() * 3 * 5; j++)
310 //      output->get_rows()[0][j] = 255;
312                                 if(use_opengl)
313                                 {
314                                         x11_device->do_camera(output,
315                                                 (*input), 
316                                                 in_x1,
317                                                 in_y1,
318                                                 in_x1 + in_w1,
319                                                 in_y1 + in_h1,
320                                                 out_x1,
321                                                 out_y1,
322                                                 out_x1 + out_w1,
323                                                 out_y1 + out_h1);
324                                 }
325                                 else
326                                 {
327                                         output->clear_frame();
330 // get_cache()->check_in(current_edit->asset);
331 // return;
333 // TRANSFER_REPLACE is the fastest transfer mode but it has the disadvantage
334 // of producing green borders in floating point translation of YUV
335                                         int mode = TRANSFER_REPLACE;
336                                         if(get_edl()->session->interpolation_type != NEAREST_NEIGHBOR &&
337                                                 cmodel_is_yuv(output->get_color_model()))
338                                                 mode = TRANSFER_NORMAL;
340                                         overlayer->overlay(output,
341                                                 (*input), 
342                                                 in_x1,
343                                                 in_y1,
344                                                 in_x1 + in_w1,
345                                                 in_y1 + in_h1,
346                                                 out_x1,
347                                                 out_y1,
348                                                 out_x1 + out_w1,
349                                                 out_y1 + out_h1,
350                                                 1,
351                                                 mode,
352                                                 get_edl()->session->interpolation_type);
353                                 }
354                                 result = 1;
355                                 output->copy_stacks((*input));
356                         }
357                         else
358 // file -> output
359                         {
360 // Cache single frames only
361                                 if(use_cache) source->set_cache_frames(1);
362                                 result = source->read_frame(output);
363                                 if(use_cache) source->set_cache_frames(0);
364                                 output->set_opengl_state(VFrame::RAM);
365                         }
367                         get_cache()->check_in(current_edit->asset);
368                 }
369                 else
370                 {
371                         if(use_opengl)
372                         {
373                                 x11_device->clear_input(output);
374                         }
375                         else
376                         {
377                                 output->clear_frame();
378                         }
379                         result = 1;
380                 }
381         }
382         else
383 // Silence
384         {
385                 if(use_opengl)
386                 {
387                         x11_device->clear_input(output);
388                 }
389                 else
390                 {
391                         output->clear_frame();
392                 }
393         }
396         return result;
401 int VModule::render(VFrame *output,
402         int64_t start_position,
403         int direction,
404         double frame_rate,
405         int use_nudge,
406         int debug_render,
407         int use_opengl)
409         int result = 0;
410         double edl_rate = get_edl()->session->frame_rate;
412         if(use_nudge) start_position += (int64_t)(track->nudge * 
413                 frame_rate / 
414                 edl_rate);
416         int64_t start_position_project = (int64_t)(start_position *
417                 edl_rate /
418                 frame_rate + 
419                 0.5);
421         update_transition(start_position_project, 
422                 direction);
424         VEdit* current_edit = (VEdit*)track->edits->editof(start_position_project, 
425                 direction,
426                 0);
427         VEdit* previous_edit = 0;
429         if(debug_render)
430                 printf("    VModule::render %d %lld %s transition=%p opengl=%d current_edit=%p output=%p\n", 
431                         use_nudge, 
432                         start_position_project,
433                         track->title,
434                         transition,
435                         use_opengl,
436                         current_edit,
437                         output);
439         if(!current_edit)
440         {
441                 output->clear_frame();
442                 // We do not apply mask here, since alpha is 0, and neither substracting nor multypling changes it
443                 // Another mask mode - "addition" should be added to be able to create mask from empty frames
444                 // in this case we would call masking here too...
445                 return 0;
446         }
451 // Process transition
452         if(transition && transition->on)
453         {
455 // Get temporary buffer
456                 VFrame **transition_input = 0;
457                 if(commonrender)
458                 {
459                         VRender *vrender = (VRender*)commonrender;
460                         transition_input = &vrender->transition_temp;
461                 }
462                 else
463                 {
464                         transition_input = &transition_temp;
465                 }
467                 if((*transition_input) &&
468                         ((*transition_input)->get_w() != track->track_w ||
469                         (*transition_input)->get_h() != track->track_h))
470                 {
471                         delete (*transition_input);
472                         (*transition_input) = 0;
473                 }
475 // Load incoming frame
476                 if(!(*transition_input))
477                 {
478                         (*transition_input) = new VFrame(0,
479                                 track->track_w,
480                                 track->track_h,
481                                 get_edl()->session->color_model,
482                                 -1);
483                 }
485                 result = import_frame((*transition_input), 
486                         current_edit, 
487                         start_position,
488                         frame_rate,
489                         direction,
490                         use_opengl);
493 // Load transition buffer
494                 previous_edit = (VEdit*)current_edit->previous;
496                 result |= import_frame(output, 
497                         previous_edit, 
498                         start_position,
499                         frame_rate,
500                         direction,
501                         use_opengl);
503 // Execute plugin with transition_input and output here
504                 if(renderengine) 
505                         transition_server->set_use_opengl(use_opengl, renderengine->video);
506                 transition_server->process_transition((*transition_input), 
507                         output,
508                         (direction == PLAY_FORWARD) ? 
509                                 (start_position_project - current_edit->startproject) :
510                                 (start_position_project - current_edit->startproject - 1),
511                         transition->length);
512         }
513         else
514         {
515 // Load output buffer
516                 result = import_frame(output, 
517                         current_edit, 
518                         start_position,
519                         frame_rate,
520                         direction,
521                         use_opengl);
522         }
523         
524         int64_t mask_position;
525         if (renderengine)
526                 mask_position = renderengine->vrender->current_position;
527         else 
528                 mask_position = start_position;
529         masker->do_mask(output, 
530                 mask_position,
531                 edl_rate,
532                 edl_rate,
533                 (MaskAutos*)track->automation->autos[AUTOMATION_MASK], 
534                 direction,
535                 1);      // we are calling before plugins
538         return result;
546 void VModule::create_objects()
548         Module::create_objects();