add bluray dv, misc fixes
[goodguy/history.git] / cinelerra-5.1 / cinelerra / virtualvnode.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "automation.h"
24 #include "bcsignals.h"
25 #include "clip.h"
26 #include "edits.h"
27 #include "edl.h"
28 #include "edlsession.h"
29 #include "fadeengine.h"
30 #include "floatauto.h"
31 #include "floatautos.h"
32 #include "intauto.h"
33 #include "intautos.h"
34 #include "maskauto.h"
35 #include "maskautos.h"
36 #include "maskengine.h"
37 #include "mwindow.h"
38 #include "module.h"
39 #include "overlayframe.h"
40 #include "playabletracks.h"
41 #include "plugin.h"
42 #include "preferences.h"
43 #include "renderengine.h"
44 #include "transition.h"
45 #include "transportque.h"
46 #include "vattachmentpoint.h"
47 #include "vdevicex11.h"
48 #include "vframe.h"
49 #include "videodevice.h"
50 #include "virtualvconsole.h"
51 #include "virtualvnode.h"
52 #include "vmodule.h"
53 #include "vrender.h"
54 #include "vtrack.h"
55
56 #include <string.h>
57
58
59 VirtualVNode::VirtualVNode(RenderEngine *renderengine,
60                 VirtualConsole *vconsole, Module *real_module,
61                 Plugin *real_plugin, Track *track,
62                 VirtualNode *parent_node)
63  : VirtualNode(renderengine, vconsole, real_module, real_plugin,
64                 track, parent_node)
65 {
66         //VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
67         fader = new FadeEngine(renderengine->preferences->processors);
68         masker = new MaskEngine(renderengine->preferences->processors);
69         alpha = 1;
70 }
71
72 VirtualVNode::~VirtualVNode()
73 {
74         delete fader;
75         delete masker;
76 }
77
78 VirtualNode* VirtualVNode::create_module(Plugin *real_plugin,
79                                                         Module *real_module,
80                                                         Track *track)
81 {
82         return new VirtualVNode(renderengine, vconsole,
83                 real_module, 0, track, this);
84 }
85
86
87 VirtualNode* VirtualVNode::create_plugin(Plugin *real_plugin)
88 {
89         return new VirtualVNode(renderengine, vconsole,
90                 0, real_plugin, track, this);
91 }
92
93 int VirtualVNode::read_data(VFrame *output_temp,
94         int64_t start_position, double frame_rate, int use_opengl)
95 {
96         VirtualNode *previous_plugin = 0;
97         int result = 0;
98
99         if(!output_temp)
100                 printf("VirtualVNode::read_data output_temp=%p\n", output_temp);
101
102         if(vconsole->debug_tree)
103                 printf("  VirtualVNode::read_data position=%jd rate=%f title=%s opengl=%d\n",
104                         start_position, frame_rate, track->title, use_opengl);
105
106 // If there is a parent module but the parent module has no data source,
107 // use our own data source.
108 // Current edit in parent track
109         VEdit *parent_edit = 0;
110         if(parent_node && parent_node->track && renderengine)
111         {
112                 double edl_rate = renderengine->get_edl()->session->frame_rate;
113                 int64_t start_position_project = (int64_t)(start_position *
114                         edl_rate / frame_rate + 0.5);
115                 parent_edit = (VEdit*)parent_node->track->edits->editof(start_position_project,
116                         renderengine->command->get_direction(), 0);
117         }
118
119
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, frame_rate, use_opengl);
126         }
127         else
128 // The current node is the first plugin on parent module.
129 // The parent module has an edit to read from or the current node
130 // has no source to read from.
131 // Read data from parent module
132         if(parent_node && (parent_edit || !real_module))
133         {
134                 result = ((VirtualVNode*)parent_node)->read_data(output_temp,
135                         start_position, frame_rate, use_opengl);
136         }
137         else
138         if(real_module)
139         {
140 // This is the first node in the tree
141                 result = ((VModule*)real_module)->render(output_temp,
142                         start_position, renderengine->command->get_direction(),
143                         frame_rate, 0, vconsole->debug_tree, use_opengl);
144         }
145
146         return result;
147 }
148
149
150 int VirtualVNode::render(VFrame *output_temp,
151         int64_t start_position,
152         double frame_rate,
153         int use_opengl)
154 {
155         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
156         if(real_module)
157         {
158                 render_as_module(vrender->video_out, output_temp,
159                         start_position, frame_rate, use_opengl);
160         }
161         else
162         if(real_plugin)
163         {
164                 render_as_plugin(output_temp,
165                         start_position, frame_rate, use_opengl);
166         }
167         return 0;
168 }
169
170 void VirtualVNode::render_as_plugin(VFrame *output_temp,
171         int64_t start_position,
172         double frame_rate,
173         int use_opengl)
174 {
175         if(!attachment || !real_plugin || !real_plugin->on) return;
176
177
178         if(vconsole->debug_tree)
179                 printf("  VirtualVNode::render_as_plugin title=%s use_opengl=%d\n",
180                         track->title, use_opengl);
181
182         ((VAttachmentPoint*)attachment)->render(
183                 output_temp, plugin_buffer_number, start_position,
184                 frame_rate, vconsole->debug_tree, use_opengl);
185 }
186
187
188 int VirtualVNode::render_as_module(VFrame *video_out,
189         VFrame *output_temp,
190         int64_t start_position,
191         double frame_rate,
192         int use_opengl)
193 {
194
195         int direction = renderengine->command->get_direction();
196         double edl_rate = renderengine->get_edl()->session->frame_rate;
197
198
199
200
201
202 // Get position relative to project, compensated for direction
203         int64_t start_position_project = (int64_t)(start_position *
204                 edl_rate /
205                 frame_rate);
206         if(direction == PLAY_REVERSE) start_position_project--;
207
208
209 // speed curve
210         if(track->has_speed())
211         {
212 // integrate position from start of track.  1/speed is duration of each frame
213
214         }
215
216         if(vconsole->debug_tree)
217                 printf("  VirtualVNode::render_as_module title=%s use_opengl=%d video_out=%p output_temp=%p\n",
218                         track->title, use_opengl, video_out, output_temp);
219
220         output_temp->push_next_effect("VirtualVNode::render_as_module");
221
222 // Process last subnode.  This propogates up the chain of subnodes and finishes
223 // the chain.
224         if(subnodes.total)
225         {
226                 VirtualVNode *node = (VirtualVNode*)subnodes.values[subnodes.total - 1];
227                 node->render(output_temp, start_position, frame_rate, use_opengl);
228         }
229         else
230 // Read data from previous entity
231         {
232                 read_data(output_temp, start_position, frame_rate, use_opengl);
233         }
234
235         output_temp->pop_next_effect();
236
237         render_fade(output_temp, start_position,
238                 frame_rate, track->automation->autos[AUTOMATION_FADE],
239                 direction, use_opengl);
240
241         render_mask(output_temp, start_position_project, frame_rate, use_opengl);
242
243
244 // overlay on the final output
245 // Get mute status
246         int mute_constant;
247         int mute_fragment = 1;
248
249
250 // Is frame muted?
251         get_mute_fragment(start_position, mute_constant, mute_fragment,
252                         (Autos*)((VTrack*)track)->automation->autos[AUTOMATION_MUTE],
253                         direction, 0);
254
255         if(!mute_constant)
256         {
257 // Frame is playable
258                 render_projector(output_temp, video_out, start_position,
259                         frame_rate, use_opengl);
260         }
261
262         output_temp->push_prev_effect("VirtualVNode::render_as_module");
263 //printf("VirtualVNode::render_as_module\n");
264 //output_temp->dump_stacks();
265
266         Edit *edit = 0;
267         if(renderengine->show_tc)
268                 renderengine->vrender->insert_timecode(edit,
269                         start_position,
270                         output_temp);
271
272         return 0;
273 }
274
275 #define EPSILON 1e-6
276 int VirtualVNode::render_fade(VFrame *output,
277 // start of input fragment in project if forward / end of input fragment if reverse
278 // relative to requested frame rate
279                         int64_t start_position, double frame_rate,
280                         Autos *autos, int direction, int use_opengl)
281 {
282         FloatAuto *previous = 0;
283         FloatAuto *next = 0;
284         double edl_rate = renderengine->get_edl()->session->frame_rate;
285         int64_t start_position_project =
286                 (int64_t)(start_position * edl_rate/frame_rate + EPSILON);
287
288         if(vconsole->debug_tree)
289                 printf("  VirtualVNode::render_fade title=%s\n", track->title);
290
291         double intercept = ((FloatAutos*)autos)->get_value(start_position_project,
292                 direction, previous, next);
293
294         CLAMP(intercept, 0, 100);
295
296
297 #if 0
298 // Can't use overlay here because overlayer blends the frame with itself.
299 // The fade engine can compensate for lack of alpha channels by multiplying the
300 // color components by alpha.
301         if(!EQUIV(intercept / 100, 1))
302         {
303                 if(use_opengl)
304                         ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_fade(
305                                 output,
306                                 intercept / 100);
307                 else
308                         fader->do_fade(output, output, intercept / 100);
309         }
310 #else
311         alpha = intercept / 100;
312 #endif
313
314         return 0;
315 }
316
317
318
319 void VirtualVNode::render_mask(VFrame *output_temp,
320         int64_t start_position_project,
321         double frame_rate,
322         int use_opengl)
323 {
324         MaskAutos *keyframe_set =
325                 (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
326
327         Auto *current = 0;
328 //      MaskAuto *default_auto = (MaskAuto*)keyframe_set->default_auto;
329         MaskAuto *keyframe = (MaskAuto*)keyframe_set->
330                 get_prev_auto(start_position_project, PLAY_FORWARD, current);
331         if( keyframe->apply_before_plugins ) return;
332
333         int total_points = 0;
334         for(int i = 0; i < keyframe->masks.total; i++)
335         {
336                 SubMask *mask = keyframe->get_submask(i);
337                 int submask_points = mask->points.total;
338                 if(submask_points > 1) total_points += submask_points;
339         }
340
341 //printf("VirtualVNode::render_mask 1 %d %d\n", total_points, keyframe->value);
342 // Ignore certain masks
343         if(total_points <= 2 ||
344                 (keyframe->value == 0 && keyframe->mode == MASK_SUBTRACT_ALPHA))
345         {
346                 return;
347         }
348
349 // Fake certain masks
350         if(keyframe->value == 0 && keyframe->mode == MASK_MULTIPLY_ALPHA)
351         {
352                 output_temp->clear_frame();
353                 return;
354         }
355
356         if(use_opengl) {
357                 if( !((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->can_mask(
358                                 start_position_project, keyframe_set) )
359                         use_opengl = 0;
360
361         }
362         if(use_opengl) {
363                 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_mask(
364                                 output_temp, start_position_project, keyframe_set,
365                                 keyframe, keyframe);
366         }
367         else {
368 // Revert to software
369                 masker->do_mask(output_temp, start_position_project,
370                                 keyframe_set, keyframe, keyframe);
371         }
372 }
373
374
375 // Start of input fragment in project if forward.
376 // End of input fragment if reverse.
377 int VirtualVNode::render_projector(VFrame *input, VFrame *output,
378                         int64_t start_position, double frame_rate,
379                         int use_opengl)
380 {
381         float in_x1, in_y1, in_x2, in_y2;
382         float out_x1, out_y1, out_x2, out_y2;
383         double edl_rate = renderengine->get_edl()->session->frame_rate;
384         int64_t start_position_project = (int64_t)(start_position *
385                 edl_rate /
386                 frame_rate);
387         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
388         if(vconsole->debug_tree)
389                 printf("  VirtualVNode::render_projector input=%p output=%p cmodel=%d title=%s\n",
390                         input, output, output->get_color_model(), track->title);
391
392         if(output)
393         {
394                 int direction = renderengine->command->get_direction();
395                 ((VTrack*)track)->calculate_output_transfer(
396                         start_position_project, direction,
397                         in_x1, in_y1, in_x2, in_y2,
398                         out_x1, out_y1, out_x2, out_y2);
399
400                 in_x2 += in_x1;   in_y2 += in_y1;
401                 out_x2 += out_x1; out_y2 += out_y1;
402
403 //for(int j = 0; j < input->get_w() * 3 * 5; j++)
404 //      input->get_rows()[0][j] = 255;
405 //
406                 if(out_x2 > out_x1 && out_y2 > out_y1 &&
407                         in_x2 > in_x1 && in_y2 > in_y1)
408                 {
409                         Auto *auto_keyframe = 0;
410                         IntAuto *mode_keyframe =
411                                 (IntAuto*)track->automation->autos[AUTOMATION_MODE]->get_prev_auto(
412                                         start_position_project, PLAY_FORWARD, auto_keyframe);
413
414                         int mode = mode_keyframe->value;
415
416 // Fade is performed in render_fade so as to allow this module
417 // to be chained in another module, thus only 4 component colormodels
418 // can do dissolves, although a blend equation is still required for 3 component
419 // colormodels since fractional translation requires blending.
420
421 // If this is the first playable video track and the mode_keyframe is "src"
422                         if(mode == TRANSFER_NORMAL &&
423                                 vconsole->current_exit_node == vconsole->total_exit_nodes - 1)
424                                 mode = TRANSFER_SRC;
425
426                         if(use_opengl)
427                         {
428 // Nested EDL's overlay on a PBuffer instead of a screen
429 // is_nested < 0 ? flatten alpha channel, last draw before driver render
430                                 int is_nested = renderengine->is_nested ? 1 :
431                                         vconsole->current_exit_node == 0 ? -1 : 0;
432                                 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->overlay(
433                                         output, input,
434                                         in_x1, in_y1, in_x2, in_y2,
435                                         out_x1, out_y1, out_x2, out_y2,
436                                         alpha, mode,
437                                         renderengine->get_edl(),
438                                         is_nested);
439                         }
440                         else
441                         {
442                                 vrender->overlayer->overlay(output, input,
443                                         in_x1, in_y1, in_x2, in_y2,
444                                         out_x1, out_y1, out_x2, out_y2,
445                                         alpha, mode,
446                                         renderengine->get_edl()->session->interpolation_type);
447                         }
448                 }
449         }
450         return 0;
451 }
452