r1053: Add Russian translation.
[cinelerra_cv.git] / cinelerra / virtualvnode.C
blobb4d0adf9548821613268326118a4d8ce048f9859
1 #include "asset.h"
2 #include "automation.h"
3 #include "bcsignals.h"
4 #include "clip.h"
5 #include "edits.h"
6 #include "edl.h"
7 #include "edlsession.h"
8 #include "fadeengine.h"
9 #include "floatauto.h"
10 #include "floatautos.h"
11 #include "intauto.h"
12 #include "intautos.h"
13 #include "maskauto.h"
14 #include "maskautos.h"
15 #include "maskengine.h"
16 #include "mwindow.h"
17 #include "module.h"
18 #include "overlayframe.h"
19 #include "playabletracks.h"
20 #include "plugin.h"
21 #include "preferences.h"
22 #include "renderengine.h"
23 #include "transition.h"
24 #include "transportque.h"
25 #include "vattachmentpoint.h"
26 #include "vdevicex11.h"
27 #include "vframe.h"
28 #include "videodevice.h"
29 #include "virtualvconsole.h"
30 #include "virtualvnode.h"
31 #include "vmodule.h"
32 #include "vrender.h"
33 #include "vtrack.h"
35 #include <string.h>
38 VirtualVNode::VirtualVNode(RenderEngine *renderengine, 
39                 VirtualConsole *vconsole, 
40                 Module *real_module, 
41                 Plugin *real_plugin,
42                 Track *track, 
43                 VirtualNode *parent_node)
44  : VirtualNode(renderengine, 
45                 vconsole, 
46                 real_module, 
47                 real_plugin,
48                 track, 
49                 parent_node)
51         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
52         fader = new FadeEngine(renderengine->preferences->processors);
53         masker = new MaskEngine(renderengine->preferences->processors);
56 VirtualVNode::~VirtualVNode()
58         delete fader;
59         delete masker;
62 VirtualNode* VirtualVNode::create_module(Plugin *real_plugin, 
63                                                         Module *real_module, 
64                                                         Track *track)
66         return new VirtualVNode(renderengine, 
67                 vconsole, 
68                 real_module,
69                 0,
70                 track,
71                 this);
75 VirtualNode* VirtualVNode::create_plugin(Plugin *real_plugin)
77         return new VirtualVNode(renderengine, 
78                 vconsole, 
79                 0,
80                 real_plugin,
81                 track,
82                 this);
85 int VirtualVNode::read_data(VFrame *output_temp,
86         int64_t start_position,
87         double frame_rate,
88         int use_opengl)
90         VirtualNode *previous_plugin = 0;
91         int result = 0;
93         if(!output_temp) 
94                 printf("VirtualVNode::read_data output_temp=%p\n", output_temp);
96         if(vconsole->debug_tree) 
97                 printf("  VirtualVNode::read_data position=%lld rate=%f title=%s opengl=%d\n", 
98                         start_position,
99                         frame_rate,
100                         track->title, 
101                         use_opengl);
103 // If there is a parent module but the parent module has no data source,
104 // use our own data source.
105 // Current edit in parent track
106         VEdit *parent_edit = 0;
107         if(parent_node && parent_node->track && renderengine)
108         {
109                 double edl_rate = renderengine->edl->session->frame_rate;
110                 int64_t start_position_project = (int64_t)(start_position *
111                         edl_rate /
112                         frame_rate + 
113                         0.5);
114                 parent_edit = (VEdit*)parent_node->track->edits->editof(start_position_project, 
115                         renderengine->command->get_direction(),
116                         0);
117         }
120 // This is a plugin on parent module with a preceeding effect.
121 // Get data from preceeding effect on parent module.
122         if(parent_node && (previous_plugin = parent_node->get_previous_plugin(this)))
123         {
124                 result = ((VirtualVNode*)previous_plugin)->render(output_temp,
125                         start_position,
126                         frame_rate,
127                         use_opengl);
128         }
129         else
130 // The current node is the first plugin on parent module.
131 // The parent module has an edit to read from or the current node
132 // has no source to read from.
133 // Read data from parent module
134         if(parent_node && (parent_edit || !real_module))
135         {
136                 result = ((VirtualVNode*)parent_node)->read_data(output_temp,
137                         start_position,
138                         frame_rate,
139                         use_opengl);
140         }
141         else
142         if(real_module)
143         {
144 // This is the first node in the tree
145                 result = ((VModule*)real_module)->render(output_temp,
146                         start_position,
147                         renderengine->command->get_direction(),
148                         frame_rate,
149                         0,
150                         vconsole->debug_tree,
151                         use_opengl);
152         }
154         return result;
158 int VirtualVNode::render(VFrame *output_temp, 
159         int64_t start_position,
160         double frame_rate,
161         int use_opengl)
163         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
164         if(real_module)
165         {
166                 render_as_module(vrender->video_out, 
167                         output_temp,
168                         start_position,
169                         frame_rate,
170                         use_opengl);
171         }
172         else
173         if(real_plugin)
174         {
175                 render_as_plugin(output_temp,
176                         start_position,
177                         frame_rate,
178                         use_opengl);
179         }
180         return 0;
183 void VirtualVNode::render_as_plugin(VFrame *output_temp, 
184         int64_t start_position,
185         double frame_rate,
186         int use_opengl)
188         if(!attachment ||
189                 !real_plugin ||
190                 !real_plugin->on) return;
193         if(vconsole->debug_tree) 
194                 printf("  VirtualVNode::render_as_plugin title=%s use_opengl=%d\n", 
195                         track->title,
196                         use_opengl);
198         ((VAttachmentPoint*)attachment)->render(
199                 output_temp,
200                 plugin_buffer_number,
201                 start_position,
202                 frame_rate,
203                 vconsole->debug_tree,
204                 use_opengl);
208 int VirtualVNode::render_as_module(VFrame *video_out, 
209         VFrame *output_temp,
210         int64_t start_position,
211         double frame_rate,
212         int use_opengl)
215         int direction = renderengine->command->get_direction();
216         double edl_rate = renderengine->edl->session->frame_rate;
217 // Get position relative to project, compensated for direction
218         int64_t start_position_project = (int64_t)(start_position *
219                 edl_rate / 
220                 frame_rate);
221         if(direction == PLAY_REVERSE) start_position_project--;
223         if(vconsole->debug_tree) 
224                 printf("  VirtualVNode::render_as_module title=%s use_opengl=%d video_out=%p output_temp=%p\n", 
225                         track->title,
226                         use_opengl,
227                         video_out,
228                         output_temp);
230         output_temp->push_next_effect("VirtualVNode::render_as_module");
232 // Process last subnode.  This propogates up the chain of subnodes and finishes
233 // the chain.
234         if(subnodes.total)
235         {
236                 VirtualVNode *node = (VirtualVNode*)subnodes.values[subnodes.total - 1];
237                 node->render(output_temp,
238                         start_position,
239                         frame_rate,
240                         use_opengl);
241         }
242         else
243 // Read data from previous entity
244         {
245                 read_data(output_temp,
246                         start_position,
247                         frame_rate,
248                         use_opengl);
249         }
251         output_temp->pop_next_effect();
253         render_fade(output_temp,
254                                 start_position,
255                                 frame_rate,
256                                 track->automation->autos[AUTOMATION_FADE],
257                                 direction);
259         render_mask(output_temp, start_position_project, frame_rate, use_opengl);
262 // overlay on the final output
263 // Get mute status
264         int mute_constant;
265         int mute_fragment = 1;
266         int64_t mute_position = 0;
269 // Is frame muted?
270         get_mute_fragment(start_position,
271                         mute_constant, 
272                         mute_fragment, 
273                         (Autos*)((VTrack*)track)->automation->autos[AUTOMATION_MUTE],
274                         direction,
275                         0);
277         if(!mute_constant)
278         {
279 // Frame is playable
280                 render_projector(output_temp,
281                         video_out,
282                         start_position,
283                         frame_rate);
284         }
286         output_temp->push_prev_effect("VirtualVNode::render_as_module");
287 //printf("VirtualVNode::render_as_module\n");
288 //output_temp->dump_stacks();
290         Edit *edit = 0;
291         if(renderengine->show_tc)
292                 renderengine->vrender->insert_timecode(edit,
293                         start_position,
294                         output_temp);
296         return 0;
299 int VirtualVNode::render_fade(VFrame *output,        
300 // start of input fragment in project if forward / end of input fragment if reverse
301 // relative to requested frame rate
302                         int64_t start_position, 
303                         double frame_rate, 
304                         Autos *autos,
305                         int direction)
307         double slope, intercept;
308         int64_t slope_len = 1;
309         FloatAuto *previous = 0;
310         FloatAuto *next = 0;
311         double edl_rate = renderengine->edl->session->frame_rate;
312         int64_t start_position_project = (int64_t)(start_position * 
313                 edl_rate /
314                 frame_rate);
316         if(vconsole->debug_tree) 
317                 printf("  VirtualVNode::render_fade title=%s\n", track->title);
319         intercept = ((FloatAutos*)autos)->get_value(start_position_project, 
320                 direction,
321                 previous,
322                 next);
325         CLAMP(intercept, 0, 100);
328 // Can't use overlay here because overlayer blends the frame with itself.
329 // The fade engine can compensate for lack of alpha channels by multiplying the 
330 // color components by alpha.
331         if(!EQUIV(intercept / 100, 1))
332         {
333                 if(((VirtualVConsole*)vconsole)->use_opengl)
334                         ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_fade(
335                                 output, 
336                                 intercept / 100);
337                 else
338                         fader->do_fade(output, output, intercept / 100);
339         }
341         return 0;
346 void VirtualVNode::render_mask(VFrame *output_temp,
347         int64_t start_position_project,
348         double frame_rate,
349         int use_opengl)
351         MaskAutos *keyframe_set = 
352                 (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
354         Auto *current = 0;
355         MaskAuto *default_auto = (MaskAuto*)keyframe_set->default_auto;
356         MaskAuto *keyframe = (MaskAuto*)keyframe_set->get_prev_auto(start_position_project, 
357                 PLAY_FORWARD,
358                 current);
360         int total_points = 0;
361         for(int i = 0; i < keyframe->masks.total; i++)
362         {
363                 SubMask *mask = keyframe->get_submask(i);
364                 int submask_points = mask->points.total;
365                 if(submask_points > 1) total_points += submask_points;
366         }
368 //printf("VirtualVNode::render_mask 1 %d %d\n", total_points, keyframe->value);
369 // Ignore certain masks
370         if(total_points <= 2 || 
371                 (keyframe->value == 0 && default_auto->mode == MASK_SUBTRACT_ALPHA))
372         {
373                 return;
374         }
376 // Fake certain masks
377         if(keyframe->value == 0 && default_auto->mode == MASK_MULTIPLY_ALPHA)
378         {
379                 output_temp->clear_frame();
380                 return;
381         }
383         if(((VirtualVConsole*)vconsole)->use_opengl)
384         {
385                 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_mask(
386                         output_temp, 
387                         start_position_project,
388                         keyframe_set, 
389                         keyframe,
390                         default_auto);
391         }
392         else
393         {
394 // Revert to software
395                 int direction = renderengine->command->get_direction();
396                 double edl_rate = renderengine->edl->session->frame_rate;
397                 masker->do_mask(output_temp, 
398                         start_position_project,
399                         frame_rate,
400                         edl_rate,
401                         keyframe_set, 
402                         direction,
403                         0);
404         }
408 // Start of input fragment in project if forward.  End of input fragment if reverse.
409 int VirtualVNode::render_projector(VFrame *input,
410                         VFrame *output,
411                         int64_t start_position,
412                         double frame_rate)
414         float in_x1, in_y1, in_x2, in_y2;
415         float out_x1, out_y1, out_x2, out_y2;
416         double edl_rate = renderengine->edl->session->frame_rate;
417         int64_t start_position_project = (int64_t)(start_position * 
418                 edl_rate /
419                 frame_rate);
420         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
421         if(vconsole->debug_tree) 
422                 printf("  VirtualVNode::render_projector input=%p output=%p title=%s\n", 
423                         input, output, track->title);
425         if(output)
426         {
427                 ((VTrack*)track)->calculate_output_transfer(start_position_project,
428                         renderengine->command->get_direction(),
429                         in_x1, 
430                         in_y1, 
431                         in_x2, 
432                         in_y2,
433                         out_x1, 
434                         out_y1, 
435                         out_x2, 
436                         out_y2);
438                 in_x2 += in_x1;
439                 in_y2 += in_y1;
440                 out_x2 += out_x1;
441                 out_y2 += out_y1;
443 //for(int j = 0; j < input->get_w() * 3 * 5; j++)
444 //      input->get_rows()[0][j] = 255;
445 // 
446                 if(out_x2 > out_x1 && 
447                         out_y2 > out_y1 && 
448                         in_x2 > in_x1 && 
449                         in_y2 > in_y1)
450                 {
451                         int direction = renderengine->command->get_direction();
452                         IntAuto *mode_keyframe = 0;
453                         mode_keyframe = 
454                                 (IntAuto*)track->automation->autos[AUTOMATION_MODE]->get_prev_auto(
455                                         start_position_project, 
456                                         direction,
457                                         (Auto* &)mode_keyframe);
459                         int mode = mode_keyframe->value;
461 // Fade is performed in render_fade so as to allow this module
462 // to be chained in another module, thus only 4 component colormodels
463 // can do dissolves, although a blend equation is still required for 3 component
464 // colormodels since fractional translation requires blending.
466 // If this is the first playable video track and the mode_keyframe is "normal"
467 // the mode may be overridden with "replace".  Replace is faster.
468                         if(mode == TRANSFER_NORMAL &&
469                                 vconsole->current_exit_node == vconsole->total_exit_nodes - 1)
470                                 mode = TRANSFER_REPLACE;
472                         if(((VirtualVConsole*)vconsole)->use_opengl)
473                         {
474                                 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->overlay(
475                                         output,
476                                         input,
477                                         in_x1, 
478                                         in_y1, 
479                                         in_x2, 
480                                         in_y2,
481                                         out_x1, 
482                                         out_y1, 
483                                         out_x2, 
484                                         out_y2, 
485                                         1,
486                                         mode, 
487                                         renderengine->edl);
488                         }
489                         else
490                         {
491                                 vrender->overlayer->overlay(output, 
492                                         input,
493                                         in_x1, 
494                                         in_y1, 
495                                         in_x2, 
496                                         in_y2,
497                                         out_x1, 
498                                         out_y1, 
499                                         out_x2, 
500                                         out_y2, 
501                                         1,
502                                         mode, 
503                                         renderengine->edl->session->interpolation_type);
504                         }
505                 }
506         }
507         return 0;