4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "automation.h"
23 #include "bcsignals.h"
27 #include "edlsession.h"
28 #include "fadeengine.h"
29 #include "floatauto.h"
30 #include "floatautos.h"
35 #include "maskautos.h"
36 #include "maskengine.h"
39 #include "overlayframe.h"
41 #include "preferences.h"
42 #include "renderengine.h"
43 #include "transition.h"
44 #include "transportque.h"
45 #include "vattachmentpoint.h"
46 #include "vdevicex11.h"
48 #include "videodevice.h"
49 #include "virtualvconsole.h"
50 #include "virtualvnode.h"
58 VirtualVNode::VirtualVNode(RenderEngine *renderengine,
59 VirtualConsole *vconsole, Module *real_module,
60 Plugin *real_plugin, Track *track,
61 VirtualNode *parent_node)
62 : VirtualNode(renderengine, vconsole, real_module, real_plugin,
65 //VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
66 fader = new FadeEngine(renderengine->preferences->processors);
67 masker = new MaskEngine(renderengine->preferences->processors);
71 VirtualVNode::~VirtualVNode()
77 VirtualNode* VirtualVNode::create_module(Plugin *real_plugin,
81 return new VirtualVNode(renderengine, vconsole,
82 real_module, 0, track, this);
86 VirtualNode* VirtualVNode::create_plugin(Plugin *real_plugin)
88 return new VirtualVNode(renderengine, vconsole,
89 0, real_plugin, track, this);
92 int VirtualVNode::read_data(VFrame *output_temp,
93 int64_t start_position, double frame_rate, int use_opengl)
95 VirtualNode *previous_plugin = 0;
99 printf("VirtualVNode::read_data output_temp=%p\n", output_temp);
101 if(vconsole->debug_tree)
102 printf(" VirtualVNode::read_data position=" _LD " rate=%f title=%s opengl=%d\n",
103 start_position, frame_rate, track->title, use_opengl);
105 // If there is a parent module but the parent module has no data source,
106 // use our own data source.
107 // Current edit in parent track
108 VEdit *parent_edit = 0;
109 if(parent_node && parent_node->track && renderengine)
111 double edl_rate = renderengine->get_edl()->session->frame_rate;
112 int64_t start_position_project = (int64_t)(start_position *
113 edl_rate / frame_rate + 0.5);
114 parent_edit = (VEdit*)parent_node->track->edits->editof(start_position_project,
115 renderengine->command->get_direction(), 0);
119 // This is a plugin on parent module with a preceeding effect.
120 // Get data from preceeding effect on parent module.
121 if(parent_node && (previous_plugin = parent_node->get_previous_plugin(this)))
123 result = ((VirtualVNode*)previous_plugin)->render(output_temp,
124 start_position, frame_rate, use_opengl);
127 // The current node is the first plugin on parent module.
128 // The parent module has an edit to read from or the current node
129 // has no source to read from.
130 // Read data from parent module
131 if(parent_node && (parent_edit || !real_module))
133 result = ((VirtualVNode*)parent_node)->read_data(output_temp,
134 start_position, frame_rate, use_opengl);
139 // This is the first node in the tree
140 result = ((VModule*)real_module)->render(output_temp,
141 start_position, renderengine->command->get_direction(),
142 frame_rate, 0, vconsole->debug_tree, use_opengl);
149 int VirtualVNode::render(VFrame *output_temp,
150 int64_t start_position,
154 VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
157 render_as_module(vrender->video_out, output_temp,
158 start_position, frame_rate, use_opengl);
163 render_as_plugin(output_temp,
164 start_position, frame_rate, use_opengl);
169 void VirtualVNode::render_as_plugin(VFrame *output_temp,
170 int64_t start_position,
174 if(!attachment || !real_plugin || !real_plugin->on) return;
177 if(vconsole->debug_tree)
178 printf(" VirtualVNode::render_as_plugin title=%s use_opengl=%d\n",
179 track->title, use_opengl);
181 ((VAttachmentPoint*)attachment)->render(
182 output_temp, plugin_buffer_number, start_position,
183 frame_rate, vconsole->debug_tree, use_opengl);
187 int VirtualVNode::render_as_module(VFrame *video_out,
189 int64_t start_position,
194 int direction = renderengine->command->get_direction();
195 double edl_rate = renderengine->get_edl()->session->frame_rate;
201 // Get position relative to project, compensated for direction
202 int64_t start_position_project = (int64_t)(start_position *
205 if(direction == PLAY_REVERSE) start_position_project--;
209 if(track->has_speed())
211 // integrate position from start of track. 1/speed is duration of each frame
215 if(vconsole->debug_tree)
216 printf(" VirtualVNode::render_as_module title=%s use_opengl=%d video_out=%p output_temp=%p\n",
217 track->title, use_opengl, video_out, output_temp);
219 output_temp->push_next_effect("VirtualVNode::render_as_module");
221 // Process last subnode. This propogates up the chain of subnodes and finishes
225 VirtualVNode *node = (VirtualVNode*)subnodes.values[subnodes.total - 1];
226 node->render(output_temp, start_position, frame_rate, use_opengl);
229 // Read data from previous entity
231 read_data(output_temp, start_position, frame_rate, use_opengl);
234 output_temp->pop_next_effect();
236 render_fade(output_temp, start_position,
237 frame_rate, track->automation->autos[AUTOMATION_FADE],
238 direction, use_opengl);
240 render_mask(output_temp, start_position_project, use_opengl);
243 // overlay on the final output
246 int mute_fragment = 1;
250 get_mute_fragment(start_position, mute_constant, mute_fragment,
251 (Autos*)((VTrack*)track)->automation->autos[AUTOMATION_MUTE],
257 render_projector(output_temp, video_out, start_position,
258 frame_rate, use_opengl);
261 output_temp->push_prev_effect("VirtualVNode::render_as_module");
262 //printf("VirtualVNode::render_as_module\n");
263 //output_temp->dump_stacks();
268 int VirtualVNode::render_fade(VFrame *output,
269 // start of input fragment in project if forward / end of input fragment if reverse
270 // relative to requested frame rate
271 int64_t start_position, double frame_rate,
272 Autos *autos, int direction, int use_opengl)
274 FloatAuto *previous = 0;
276 double edl_rate = renderengine->get_edl()->session->frame_rate;
277 int64_t start_position_project =
278 (int64_t)(start_position * edl_rate / frame_rate);
280 if(vconsole->debug_tree)
281 printf(" VirtualVNode::render_fade title=%s\n", track->title);
283 double intercept = ((FloatAutos*)autos)->get_value(start_position_project,
284 direction, previous, next);
286 // CLAMP(intercept, 0, 100);
290 // Can't use overlay here because overlayer blends the frame with itself.
291 // The fade engine can compensate for lack of alpha channels by multiplying the
292 // color components by alpha.
293 if(!EQUIV(intercept / 100, 1))
296 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_fade(
300 fader->do_fade(output, output, intercept / 100);
303 alpha = intercept / 100;
311 void VirtualVNode::render_mask(VFrame *output_temp,
312 int64_t start_position_project,
315 MaskAutos *keyframe_set =
316 (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
319 // MaskAuto *default_auto = (MaskAuto*)keyframe_set->default_auto;
320 MaskAuto *keyframe = (MaskAuto*)keyframe_set->get_prev_auto(start_position_project,
324 int total_points = 0;
325 for(int i = 0; i < keyframe->masks.total; i++)
327 SubMask *mask = keyframe->get_submask(i);
328 int submask_points = mask->points.total;
329 if(submask_points > 1) total_points += submask_points;
332 //printf("VirtualVNode::render_mask 1 %d %d\n", total_points, keyframe->value);
333 // Ignore certain masks
334 if(total_points <= 2 ||
335 (keyframe->value == 0 && keyframe->mode == MASK_SUBTRACT_ALPHA))
340 // Fake certain masks
341 if(keyframe->value == 0 && keyframe->mode == MASK_MULTIPLY_ALPHA)
343 output_temp->clear_frame();
349 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_mask(
350 output_temp, start_position_project,
351 keyframe_set, keyframe, keyframe);
355 // Revert to software
356 masker->do_mask(output_temp, start_position_project,
357 keyframe_set, keyframe, keyframe);
362 // Start of input fragment in project if forward.
363 // End of input fragment if reverse.
364 int VirtualVNode::render_projector(VFrame *input, VFrame *output,
365 int64_t start_position, double frame_rate,
368 float in_x1, in_y1, in_x2, in_y2;
369 float out_x1, out_y1, out_x2, out_y2;
370 double edl_rate = renderengine->get_edl()->session->frame_rate;
371 int64_t start_position_project = (int64_t)(start_position *
374 VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
375 if(vconsole->debug_tree)
376 printf(" VirtualVNode::render_projector input=%p output=%p cmodel=%d title=%s\n",
377 input, output, output->get_color_model(), track->title);
381 ((VTrack*)track)->calculate_output_transfer(start_position_project,
382 renderengine->command->get_direction(),
383 in_x1, in_y1, in_x2, in_y2,
384 out_x1, out_y1, out_x2, out_y2);
386 in_x2 += in_x1; in_y2 += in_y1;
387 out_x2 += out_x1; out_y2 += out_y1;
389 //for(int j = 0; j < input->get_w() * 3 * 5; j++)
390 // input->get_rows()[0][j] = 255;
392 if(out_x2 > out_x1 && out_y2 > out_y1 &&
393 in_x2 > in_x1 && in_y2 > in_y1)
395 int direction = renderengine->command->get_direction();
396 IntAuto *mode_keyframe = 0;
398 (IntAuto*)track->automation->autos[AUTOMATION_MODE]->get_prev_auto(
399 start_position_project, direction, (Auto* &)mode_keyframe);
401 int mode = mode_keyframe->value;
403 // Fade is performed in render_fade so as to allow this module
404 // to be chained in another module, thus only 4 component colormodels
405 // can do dissolves, although a blend equation is still required for 3 component
406 // colormodels since fractional translation requires blending.
408 // If this is the first playable video track and the mode_keyframe is "src_over"
409 // the mode may be overridden with "replace". Replace is faster.
410 if(mode == TRANSFER_NORMAL &&
411 vconsole->current_exit_node == vconsole->total_exit_nodes - 1)
412 mode = TRANSFER_REPLACE;
416 // Nested EDL's overlay on a PBuffer instead of a screen
417 // is_nested < 0 ? flatten alpha channel, last draw before driver render
418 int is_nested = renderengine->is_nested ? 1 :
419 vconsole->current_exit_node == 0 ? -1 : 0;
420 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->overlay(
422 in_x1, in_y1, in_x2, in_y2,
423 out_x1, out_y1, out_x2, out_y2,
425 renderengine->get_edl(),
430 vrender->overlayer->overlay(output, input,
431 in_x1, in_y1, in_x2, in_y2,
432 out_x1, out_y1, out_x2, out_y2,
434 renderengine->get_edl()->session->interpolation_type);