X-Git-Url: https://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fvirtualvnode.C;fp=cinelerra-5.1%2Fcinelerra%2Fvirtualvnode.C;h=141a2a0c7b461197bf8ed528740538a0986ce681;hb=30bdb85eb33a8ee7ba675038a86c6be59c43d7bd;hp=0000000000000000000000000000000000000000;hpb=52fcc46226f9df46f9ce9d0566dc568455a7db0b;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.1/cinelerra/virtualvnode.C b/cinelerra-5.1/cinelerra/virtualvnode.C new file mode 100644 index 00000000..141a2a0c --- /dev/null +++ b/cinelerra-5.1/cinelerra/virtualvnode.C @@ -0,0 +1,448 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "asset.h" +#include "automation.h" +#include "bcsignals.h" +#include "clip.h" +#include "edits.h" +#include "edl.h" +#include "edlsession.h" +#include "fadeengine.h" +#include "floatauto.h" +#include "floatautos.h" +#include "intauto.h" +#include "intautos.h" +#include "maskauto.h" +#include "maskautos.h" +#include "maskengine.h" +#include "mwindow.h" +#include "module.h" +#include "overlayframe.h" +#include "playabletracks.h" +#include "plugin.h" +#include "preferences.h" +#include "renderengine.h" +#include "transition.h" +#include "transportque.h" +#include "vattachmentpoint.h" +#include "vdevicex11.h" +#include "vframe.h" +#include "videodevice.h" +#include "virtualvconsole.h" +#include "virtualvnode.h" +#include "vmodule.h" +#include "vrender.h" +#include "vtrack.h" + +#include + + +VirtualVNode::VirtualVNode(RenderEngine *renderengine, + VirtualConsole *vconsole, Module *real_module, + Plugin *real_plugin, Track *track, + VirtualNode *parent_node) + : VirtualNode(renderengine, vconsole, real_module, real_plugin, + track, parent_node) +{ + //VRender *vrender = ((VirtualVConsole*)vconsole)->vrender; + fader = new FadeEngine(renderengine->preferences->processors); + masker = new MaskEngine(renderengine->preferences->processors); + alpha = 1; +} + +VirtualVNode::~VirtualVNode() +{ + delete fader; + delete masker; +} + +VirtualNode* VirtualVNode::create_module(Plugin *real_plugin, + Module *real_module, + Track *track) +{ + return new VirtualVNode(renderengine, vconsole, + real_module, 0, track, this); +} + + +VirtualNode* VirtualVNode::create_plugin(Plugin *real_plugin) +{ + return new VirtualVNode(renderengine, vconsole, + 0, real_plugin, track, this); +} + +int VirtualVNode::read_data(VFrame *output_temp, + int64_t start_position, double frame_rate, int use_opengl) +{ + VirtualNode *previous_plugin = 0; + int result = 0; + + if(!output_temp) + printf("VirtualVNode::read_data output_temp=%p\n", output_temp); + + if(vconsole->debug_tree) + printf(" VirtualVNode::read_data position=%jd rate=%f title=%s opengl=%d\n", + start_position, frame_rate, track->title, use_opengl); + +// If there is a parent module but the parent module has no data source, +// use our own data source. +// Current edit in parent track + VEdit *parent_edit = 0; + if(parent_node && parent_node->track && renderengine) + { + double edl_rate = renderengine->get_edl()->session->frame_rate; + int64_t start_position_project = (int64_t)(start_position * + edl_rate / frame_rate + 0.5); + parent_edit = (VEdit*)parent_node->track->edits->editof(start_position_project, + renderengine->command->get_direction(), 0); + } + + +// This is a plugin on parent module with a preceeding effect. +// Get data from preceeding effect on parent module. + if(parent_node && (previous_plugin = parent_node->get_previous_plugin(this))) + { + result = ((VirtualVNode*)previous_plugin)->render(output_temp, + start_position, frame_rate, use_opengl); + } + else +// The current node is the first plugin on parent module. +// The parent module has an edit to read from or the current node +// has no source to read from. +// Read data from parent module + if(parent_node && (parent_edit || !real_module)) + { + result = ((VirtualVNode*)parent_node)->read_data(output_temp, + start_position, frame_rate, use_opengl); + } + else + if(real_module) + { +// This is the first node in the tree + result = ((VModule*)real_module)->render(output_temp, + start_position, renderengine->command->get_direction(), + frame_rate, 0, vconsole->debug_tree, use_opengl); + } + + return result; +} + + +int VirtualVNode::render(VFrame *output_temp, + int64_t start_position, + double frame_rate, + int use_opengl) +{ + VRender *vrender = ((VirtualVConsole*)vconsole)->vrender; + if(real_module) + { + render_as_module(vrender->video_out, output_temp, + start_position, frame_rate, use_opengl); + } + else + if(real_plugin) + { + render_as_plugin(output_temp, + start_position, frame_rate, use_opengl); + } + return 0; +} + +void VirtualVNode::render_as_plugin(VFrame *output_temp, + int64_t start_position, + double frame_rate, + int use_opengl) +{ + if(!attachment || !real_plugin || !real_plugin->on) return; + + + if(vconsole->debug_tree) + printf(" VirtualVNode::render_as_plugin title=%s use_opengl=%d\n", + track->title, use_opengl); + + ((VAttachmentPoint*)attachment)->render( + output_temp, plugin_buffer_number, start_position, + frame_rate, vconsole->debug_tree, use_opengl); +} + + +int VirtualVNode::render_as_module(VFrame *video_out, + VFrame *output_temp, + int64_t start_position, + double frame_rate, + int use_opengl) +{ + + int direction = renderengine->command->get_direction(); + double edl_rate = renderengine->get_edl()->session->frame_rate; + + + + + +// Get position relative to project, compensated for direction + int64_t start_position_project = (int64_t)(start_position * + edl_rate / + frame_rate); + if(direction == PLAY_REVERSE) start_position_project--; + + +// speed curve + if(track->has_speed()) + { +// integrate position from start of track. 1/speed is duration of each frame + + } + + if(vconsole->debug_tree) + printf(" VirtualVNode::render_as_module title=%s use_opengl=%d video_out=%p output_temp=%p\n", + track->title, use_opengl, video_out, output_temp); + + output_temp->push_next_effect("VirtualVNode::render_as_module"); + +// Process last subnode. This propogates up the chain of subnodes and finishes +// the chain. + if(subnodes.total) + { + VirtualVNode *node = (VirtualVNode*)subnodes.values[subnodes.total - 1]; + node->render(output_temp, start_position, frame_rate, use_opengl); + } + else +// Read data from previous entity + { + read_data(output_temp, start_position, frame_rate, use_opengl); + } + + output_temp->pop_next_effect(); + + render_fade(output_temp, start_position, + frame_rate, track->automation->autos[AUTOMATION_FADE], + direction, use_opengl); + + render_mask(output_temp, start_position_project, frame_rate, use_opengl); + + +// overlay on the final output +// Get mute status + int mute_constant; + int mute_fragment = 1; + + +// Is frame muted? + get_mute_fragment(start_position, mute_constant, mute_fragment, + (Autos*)((VTrack*)track)->automation->autos[AUTOMATION_MUTE], + direction, 0); + + if(!mute_constant) + { +// Frame is playable + render_projector(output_temp, video_out, start_position, + frame_rate, use_opengl); + } + + output_temp->push_prev_effect("VirtualVNode::render_as_module"); +//printf("VirtualVNode::render_as_module\n"); +//output_temp->dump_stacks(); + + Edit *edit = 0; + if(renderengine->show_tc) + renderengine->vrender->insert_timecode(edit, + start_position, + output_temp); + + return 0; +} + +#define EPSILON 1e-6 +int VirtualVNode::render_fade(VFrame *output, +// start of input fragment in project if forward / end of input fragment if reverse +// relative to requested frame rate + int64_t start_position, double frame_rate, + Autos *autos, int direction, int use_opengl) +{ + FloatAuto *previous = 0; + FloatAuto *next = 0; + double edl_rate = renderengine->get_edl()->session->frame_rate; + int64_t start_position_project = + (int64_t)(start_position * edl_rate/frame_rate + EPSILON); + + if(vconsole->debug_tree) + printf(" VirtualVNode::render_fade title=%s\n", track->title); + + double intercept = ((FloatAutos*)autos)->get_value(start_position_project, + direction, previous, next); + + CLAMP(intercept, 0, 100); + + +#if 0 +// Can't use overlay here because overlayer blends the frame with itself. +// The fade engine can compensate for lack of alpha channels by multiplying the +// color components by alpha. + if(!EQUIV(intercept / 100, 1)) + { + if(use_opengl) + ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_fade( + output, + intercept / 100); + else + fader->do_fade(output, output, intercept / 100); + } +#else + alpha = intercept / 100; +#endif + + return 0; +} + + + +void VirtualVNode::render_mask(VFrame *output_temp, + int64_t start_position_project, + double frame_rate, + int use_opengl) +{ + MaskAutos *keyframe_set = + (MaskAutos*)track->automation->autos[AUTOMATION_MASK]; + + Auto *current = 0; +// MaskAuto *default_auto = (MaskAuto*)keyframe_set->default_auto; + MaskAuto *keyframe = (MaskAuto*)keyframe_set-> + get_prev_auto(start_position_project, PLAY_FORWARD, current); + if( keyframe->apply_before_plugins ) return; + + int total_points = 0; + for(int i = 0; i < keyframe->masks.total; i++) + { + SubMask *mask = keyframe->get_submask(i); + int submask_points = mask->points.total; + if(submask_points > 1) total_points += submask_points; + } + +//printf("VirtualVNode::render_mask 1 %d %d\n", total_points, keyframe->value); +// Ignore certain masks + if(total_points <= 2 || + (keyframe->value == 0 && keyframe->mode == MASK_SUBTRACT_ALPHA)) + { + return; + } + +// Fake certain masks + if(keyframe->value == 0 && keyframe->mode == MASK_MULTIPLY_ALPHA) + { + output_temp->clear_frame(); + return; + } + + if(use_opengl) + { + ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_mask( + output_temp, start_position_project, + keyframe_set, keyframe, keyframe); + } + else + { +// Revert to software + masker->do_mask(output_temp, start_position_project, + keyframe_set, keyframe, keyframe); + } +} + + +// Start of input fragment in project if forward. +// End of input fragment if reverse. +int VirtualVNode::render_projector(VFrame *input, VFrame *output, + int64_t start_position, double frame_rate, + int use_opengl) +{ + float in_x1, in_y1, in_x2, in_y2; + float out_x1, out_y1, out_x2, out_y2; + double edl_rate = renderengine->get_edl()->session->frame_rate; + int64_t start_position_project = (int64_t)(start_position * + edl_rate / + frame_rate); + VRender *vrender = ((VirtualVConsole*)vconsole)->vrender; + if(vconsole->debug_tree) + printf(" VirtualVNode::render_projector input=%p output=%p cmodel=%d title=%s\n", + input, output, output->get_color_model(), track->title); + + if(output) + { + ((VTrack*)track)->calculate_output_transfer(start_position_project, + renderengine->command->get_direction(), + in_x1, in_y1, in_x2, in_y2, + out_x1, out_y1, out_x2, out_y2); + + in_x2 += in_x1; in_y2 += in_y1; + out_x2 += out_x1; out_y2 += out_y1; + +//for(int j = 0; j < input->get_w() * 3 * 5; j++) +// input->get_rows()[0][j] = 255; +// + if(out_x2 > out_x1 && out_y2 > out_y1 && + in_x2 > in_x1 && in_y2 > in_y1) + { + int direction = renderengine->command->get_direction(); + IntAuto *mode_keyframe = 0; + mode_keyframe = + (IntAuto*)track->automation->autos[AUTOMATION_MODE]->get_prev_auto( + start_position_project, direction, (Auto* &)mode_keyframe); + + int mode = mode_keyframe->value; + +// Fade is performed in render_fade so as to allow this module +// to be chained in another module, thus only 4 component colormodels +// can do dissolves, although a blend equation is still required for 3 component +// colormodels since fractional translation requires blending. + +// If this is the first playable video track and the mode_keyframe is "src_over" + if(mode == TRANSFER_NORMAL && + vconsole->current_exit_node == vconsole->total_exit_nodes - 1) + mode = TRANSFER_SRC; + + if(use_opengl) + { +// Nested EDL's overlay on a PBuffer instead of a screen +// is_nested < 0 ? flatten alpha channel, last draw before driver render + int is_nested = renderengine->is_nested ? 1 : + vconsole->current_exit_node == 0 ? -1 : 0; + ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->overlay( + output, input, + in_x1, in_y1, in_x2, in_y2, + out_x1, out_y1, out_x2, out_y2, + alpha, mode, + renderengine->get_edl(), + is_nested); + } + else + { + vrender->overlayer->overlay(output, input, + in_x1, in_y1, in_x2, in_y2, + out_x1, out_y1, out_x2, out_y2, + alpha, mode, + renderengine->get_edl()->session->interpolation_type); + } + } + } + return 0; +} +