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