r854: Merge 2.1:
[cinelerra_cv/ct.git] / cinelerra / vmodule.C
blob985405373dde238b135088443219dd1ff1d652b5
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_cache()->dump();
133                 if(source)
134                 {
135                         int64_t edit_startproject = (int64_t)(current_edit->startproject * 
136                                 frame_rate / 
137                                 edl_rate);
138                         int64_t edit_startsource = (int64_t)(current_edit->startsource *
139                                 frame_rate /
140                                 edl_rate);
141                         uint64_t position = corrected_position - 
142                                 edit_startproject + 
143                                 edit_startsource;
144                         // if we hit the end of stream, freeze at last frame
145                         uint64_t max_position = source->get_video_length(frame_rate) - 1;
146                         if (position > max_position) position = max_position;
147                         source->set_video_position(position,
148                                 frame_rate);
149                         source->set_layer(current_edit->channel);
151                         ((VTrack*)track)->calculate_input_transfer(current_edit->asset, 
152                                 input_position_project, 
153                                 direction, 
154                                 in_x1, 
155                                 in_y1, 
156                                 in_w1, 
157                                 in_h1,
158                                 out_x1, 
159                                 out_y1, 
160                                 out_w1, 
161                                 out_h1);
164 //                      printf("VModule::import_frame 1 [ilace] Project: mode (%d) Asset: autofixoption (%d), mode (%d), method (%d)\n", 
165 //                      get_edl()->session->interlace_mode,
166 //                      current_edit->asset->interlace_autofixoption,
167 //                      current_edit->asset->interlace_mode,
168 //                      current_edit->asset->interlace_fixmethod);
170                         // Determine the interlacing method to use.
171                         int interlace_fixmethod = ilaceautofixmethod2(get_edl()->session->interlace_mode,
172                                         current_edit->asset->interlace_autofixoption,
173                                         current_edit->asset->interlace_mode,
174                                         current_edit->asset->interlace_fixmethod);
176 //                      char string[BCTEXTLEN];
177 //                      ilacefixmethod_to_text(string,interlace_fixmethod);
178 //                      printf("VModule::import_frame 1 [ilace] Compensating by using: '%s'\n",string);
180                         // Compensate for the said interlacing...
181                         switch (interlace_fixmethod) {
182                                 case BC_ILACE_FIXMETHOD_NONE:
183                                 
184                                 break;
185                                 case BC_ILACE_FIXMETHOD_UPONE:
186                                         out_y1--;
187                                 break;
188                                 case BC_ILACE_FIXMETHOD_DOWNONE:
189                                         out_y1++;
190                                 break;
191                                 default:
192                                         printf("vmodule::importframe WARNING - unknown fix method for interlacing, no compensation in effect\n");
193                         }
196 // file -> temp -> output
197                         if( !EQUIV(in_x1, 0) || 
198                                 !EQUIV(in_y1, 0) || 
199                                 !EQUIV(in_w1, track->track_w) || 
200                                 !EQUIV(in_h1, track->track_h) || 
201                                 !EQUIV(out_x1, 0) ||
202                                 !EQUIV(out_y1, 0) ||
203                                 !EQUIV(out_w1, track->track_w) ||
204                                 !EQUIV(out_h1, track->track_h) ||
205                                 !EQUIV(in_w1, current_edit->asset->width) ||
206                                 !EQUIV(in_h1, current_edit->asset->height))
207                         {
212 // Get temporary input buffer
213                                 VFrame **input = 0;
214 // Realtime playback
215                                 if(commonrender)
216                                 {
217                                         VRender *vrender = (VRender*)commonrender;
218                                         input = &vrender->input_temp;
219                                 }
220                                 else
221 // Menu effect
222                                 {
223                                         input = &input_temp;
224                                 }
227                                 if((*input) && 
228                                         ((*input)->get_w() != current_edit->asset->width ||
229                                         (*input)->get_h() != current_edit->asset->height))
230                                 {
231                                         delete (*input);
232                                         (*input) = 0;
233                                 }
239                                 if(!(*input))
240                                 {
241                                         (*input) = new VFrame(0,
242                                                 current_edit->asset->width,
243                                                 current_edit->asset->height,
244                                                 get_edl()->session->color_model,
245                                                 -1);
246                                 }
250                                 (*input)->copy_stacks(output);
252 // file -> temp
253 // Cache for single frame only
254 //                              if(renderengine && renderengine->command->single_frame())
255                                         source->set_cache_frames(1);
256                                 result = source->read_frame((*input));
257 //                              if(renderengine && renderengine->command->single_frame())
258                                         source->set_cache_frames(0);
259                                 (*input)->set_opengl_state(VFrame::RAM);
261 //printf("VModule::import_frame 1 %lld %f\n", input_position, frame_rate);
263 // Find an overlayer object to perform the camera transformation
264                                 OverlayFrame *overlayer = 0;
266 // OpenGL playback uses hardware
267                                 if(use_opengl)
268                                 {
269                                 }
270                                 else
271 // Realtime playback
272                                 if(commonrender)
273                                 {
274                                         VRender *vrender = (VRender*)commonrender;
275                                         overlayer = vrender->overlayer;
276                                 }
277                                 else
278 // Menu effect
279                                 {
280                                         if(!plugin_array)
281                                                 printf("VModule::import_frame neither plugin_array nor commonrender is defined.\n");
282                                         if(!overlay_temp)
283                                         {
284                                                 overlay_temp = new OverlayFrame(plugin_array->mwindow->preferences->processors);
285                                         }
287                                         overlayer = overlay_temp;
288                                 }
289 // printf("VModule::import_frame 1 %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n", 
290 //      in_x1, 
291 //      in_y1, 
292 //      in_w1, 
293 //      in_h1, 
294 //      out_x1, 
295 //      out_y1, 
296 //      out_w1, 
297 //      out_h1);
299 // temp -> output
300 // for(int j = 0; j < output->get_w() * 3 * 5; j++)
301 //      output->get_rows()[0][j] = 255;
303                                 if(use_opengl)
304                                 {
305                                         x11_device->do_camera(output,
306                                                 (*input), 
307                                                 in_x1,
308                                                 in_y1,
309                                                 in_x1 + in_w1,
310                                                 in_y1 + in_h1,
311                                                 out_x1,
312                                                 out_y1,
313                                                 out_x1 + out_w1,
314                                                 out_y1 + out_h1);
315                                 }
316                                 else
317                                 {
318                                         output->clear_frame();
321 // get_cache()->check_in(current_edit->asset);
322 // return;
324 // TRANSFER_REPLACE is the fastest transfer mode but it has the disadvantage
325 // of producing green borders in floating point translation of YUV
326                                         int mode = TRANSFER_REPLACE;
327                                         if(get_edl()->session->interpolation_type != NEAREST_NEIGHBOR &&
328                                                 cmodel_is_yuv(output->get_color_model()))
329                                                 mode = TRANSFER_NORMAL;
331                                         overlayer->overlay(output,
332                                                 (*input), 
333                                                 in_x1,
334                                                 in_y1,
335                                                 in_x1 + in_w1,
336                                                 in_y1 + in_h1,
337                                                 out_x1,
338                                                 out_y1,
339                                                 out_x1 + out_w1,
340                                                 out_y1 + out_h1,
341                                                 1,
342                                                 mode,
343                                                 get_edl()->session->interpolation_type);
344                                 }
345                                 result = 1;
346                                 output->copy_stacks((*input));
347                         }
348                         else
349 // file -> output
350                         {
351 // Cache single frames only
352 //                              if(renderengine && renderengine->command->single_frame())
353                                         source->set_cache_frames(1);
354                                 result = source->read_frame(output);
355 //                              if(renderengine && renderengine->command->single_frame())
356                                         source->set_cache_frames(0);
357                                 output->set_opengl_state(VFrame::RAM);
358                         }
360                         get_cache()->check_in(current_edit->asset);
361                 }
362                 else
363                 {
364                         if(use_opengl)
365                         {
366                                 x11_device->clear_input(output);
367                         }
368                         else
369                         {
370                                 output->clear_frame();
371                         }
372                         result = 1;
373                 }
374         }
375         else
376 // Silence
377         {
378                 if(use_opengl)
379                 {
380                         x11_device->clear_input(output);
381                 }
382                 else
383                 {
384                         output->clear_frame();
385                 }
386         }
389         return result;
394 int VModule::render(VFrame *output,
395         int64_t start_position,
396         int direction,
397         double frame_rate,
398         int use_nudge,
399         int debug_render,
400         int use_opengl)
402         int result = 0;
403         double edl_rate = get_edl()->session->frame_rate;
405         if(use_nudge) start_position += (int64_t)(track->nudge * 
406                 frame_rate / 
407                 edl_rate);
409         int64_t start_position_project = (int64_t)(start_position *
410                 edl_rate /
411                 frame_rate + 
412                 0.5);
414         update_transition(start_position_project, 
415                 direction);
417         VEdit* current_edit = (VEdit*)track->edits->editof(start_position_project, 
418                 direction,
419                 0);
420         VEdit* previous_edit = 0;
422         if(debug_render)
423                 printf("    VModule::render %d %lld %s transition=%p opengl=%d current_edit=%p output=%p\n", 
424                         use_nudge, 
425                         start_position_project,
426                         track->title,
427                         transition,
428                         use_opengl,
429                         current_edit,
430                         output);
432         if(!current_edit)
433         {
434                 output->clear_frame();
435                 // We do not apply mask here, since alpha is 0, and neither substracting nor multypling changes it
436                 // Another mask mode - "addition" should be added to be able to create mask from empty frames
437                 // in this case we would call masking here too...
438                 return 0;
439         }
444 // Process transition
445         if(transition)
446         {
448 // Get temporary buffer
449                 VFrame **transition_input = 0;
450                 if(commonrender)
451                 {
452                         VRender *vrender = (VRender*)commonrender;
453                         transition_input = &vrender->transition_temp;
454                 }
455                 else
456                 {
457                         transition_input = &transition_temp;
458                 }
460                 if((*transition_input) &&
461                         ((*transition_input)->get_w() != track->track_w ||
462                         (*transition_input)->get_h() != track->track_h))
463                 {
464                         delete (*transition_input);
465                         (*transition_input) = 0;
466                 }
468 // Load incoming frame
469                 if(!(*transition_input))
470                 {
471                         (*transition_input) = new VFrame(0,
472                                 track->track_w,
473                                 track->track_h,
474                                 get_edl()->session->color_model,
475                                 -1);
476                 }
478                 result = import_frame((*transition_input), 
479                         current_edit, 
480                         start_position,
481                         frame_rate,
482                         direction,
483                         use_opengl);
486 // Load transition buffer
487                 previous_edit = (VEdit*)current_edit->previous;
489                 result |= import_frame(output, 
490                         previous_edit, 
491                         start_position,
492                         frame_rate,
493                         direction,
494                         use_opengl);
496 // Execute plugin with transition_input and output here
497                 if(renderengine) 
498                         transition_server->set_use_opengl(use_opengl, renderengine->video);
499                 transition_server->process_transition((*transition_input), 
500                         output,
501                         (direction == PLAY_FORWARD) ? 
502                                 (start_position_project - current_edit->startproject) :
503                                 (start_position_project - current_edit->startproject - 1),
504                         transition->length);
505         }
506         else
507         {
508 // Load output buffer
509                 result = import_frame(output, 
510                         current_edit, 
511                         start_position,
512                         frame_rate,
513                         direction,
514                         use_opengl);
515         }
516         
517         int64_t mask_position;
518         if (renderengine)
519                 mask_position = renderengine->vrender->current_position;
520         else 
521                 mask_position = start_position;
522         masker->do_mask(output, 
523                 mask_position,
524                 edl_rate,
525                 edl_rate,
526                 (MaskAutos*)track->automation->autos[AUTOMATION_MASK], 
527                 direction,
528                 1);      // we are calling before plugins
531         return result;
539 void VModule::create_objects()
541         Module::create_objects();