+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
- *
- * 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 "bcsignals.h"
-#include "cache.h"
-#include "condition.h"
-#include "datatype.h"
-#include "edits.h"
-#include "edl.h"
-#include "edlsession.h"
-#include "file.h"
-#include "format.inc"
-#include "localsession.h"
-#include "mainsession.h"
-#include "mwindow.h"
-#include "overlayframe.h"
-#include "playabletracks.h"
-#include "playbackengine.h"
-#include "preferences.h"
-#include "preferencesthread.h"
-#include "renderengine.h"
-#include "strategies.inc"
-#include "tracks.h"
-#include "transportque.h"
-#include "units.h"
-#include "vedit.h"
-#include "vframe.h"
-#include "videoconfig.h"
-#include "videodevice.h"
-#include "virtualconsole.h"
-#include "virtualvconsole.h"
-#include "vmodule.h"
-#include "vrender.h"
-#include "vtrack.h"
-
-
-
-
-
-VRender::VRender(RenderEngine *renderengine)
- : CommonRender(renderengine)
-{
- data_type = TRACK_VIDEO;
- transition_temp = 0;
- overlayer = new OverlayFrame(renderengine->preferences->processors);
- input_temp = 0;
- vmodule_render_fragment = 0;
- playback_buffer = 0;
- session_frame = 0;
- asynchronous = 0; // render 1 frame at a time
- framerate_counter = 0;
- video_out = 0;
- render_strategy = -1;
-}
-
-VRender::~VRender()
-{
- if(input_temp) delete input_temp;
- if(transition_temp) delete transition_temp;
- if(overlayer) delete overlayer;
-}
-
-
-VirtualConsole* VRender::new_vconsole_object()
-{
- return new VirtualVConsole(renderengine, this);
-}
-
-int VRender::get_total_tracks()
-{
- return renderengine->get_edl()->tracks->total_video_tracks();
-}
-
-Module* VRender::new_module(Track *track)
-{
- return new VModule(renderengine, this, 0, track);
-}
-
-int VRender::flash_output()
-{
- if(video_out)
- return renderengine->video->write_buffer(video_out, renderengine->get_edl());
- else
- return 0;
-}
-
-int VRender::process_buffer(VFrame *video_out,
- int64_t input_position,
- int use_opengl)
-{
-// process buffer for non realtime
- int64_t render_len = 1;
- int reconfigure = 0;
-
-
- this->video_out = video_out;
-
- current_position = input_position;
-
- reconfigure = vconsole->test_reconfigure(input_position,
- render_len);
-
- if(reconfigure) restart_playback();
- return process_buffer(input_position, use_opengl);
-}
-
-
-int VRender::process_buffer(int64_t input_position,
- int use_opengl)
-{
- VEdit *playable_edit = 0;
- int colormodel;
- int use_vconsole = 1;
- int use_brender = 0;
- int result = 0;
- int use_cache = renderengine->command->single_frame();
- int use_asynchronous =
- renderengine->command->realtime &&
- renderengine->get_edl()->session->video_every_frame &&
- renderengine->get_edl()->session->video_asynchronous;
- const int debug = 0;
-
-// Determine the rendering strategy for this frame.
- use_vconsole = get_use_vconsole(&playable_edit,
- input_position,
- use_brender);
- if(debug) printf("VRender::process_buffer %d use_vconsole=%d\n", __LINE__, use_vconsole);
-
-// Negotiate color model
- colormodel = get_colormodel(playable_edit, use_vconsole, use_brender);
- if(debug) printf("VRender::process_buffer %d\n", __LINE__);
-
-
-
-
-// Get output buffer from device
- if(renderengine->command->realtime &&
- !renderengine->is_nested)
- {
- renderengine->video->new_output_buffer(&video_out, colormodel);
- }
-
- if(debug) printf("VRender::process_buffer %d video_out=%p\n", __LINE__, video_out);
-
-// printf("VRender::process_buffer use_vconsole=%d colormodel=%d video_out=%p\n",
-// use_vconsole,
-// colormodel,
-// video_out);
-// Read directly from file to video_out
- if(!use_vconsole)
- {
-
- if(use_brender)
- {
- Asset *asset = renderengine->preferences->brender_asset;
- File *file = renderengine->get_vcache()->check_out(asset,
- renderengine->get_edl());
-
- if(file)
- {
- int64_t corrected_position = current_position;
- if(renderengine->command->get_direction() == PLAY_REVERSE)
- corrected_position--;
-
-// Cache single frames only
- if(use_asynchronous)
- file->start_video_decode_thread();
- else
- file->stop_video_thread();
- if(use_cache) file->set_cache_frames(1);
- int64_t normalized_position = (int64_t)(corrected_position *
- asset->frame_rate /
- renderengine->get_edl()->session->frame_rate);
-
- file->set_video_position(normalized_position,
- 0);
- file->read_frame(video_out);
-
-
- if(use_cache) file->set_cache_frames(0);
- renderengine->get_vcache()->check_in(asset);
- }
-
- }
- else
- if(playable_edit)
- {
- if(debug) printf("VRender::process_buffer %d\n", __LINE__);
- result = ((VEdit*)playable_edit)->read_frame(video_out,
- current_position,
- renderengine->command->get_direction(),
- renderengine->get_vcache(),
- 1,
- use_cache,
- use_asynchronous);
- if(debug) printf("VRender::process_buffer %d\n", __LINE__);
- }
-
-
-
- video_out->set_opengl_state(VFrame::RAM);
- }
- else
-// Read into virtual console
- {
-
-// process this buffer now in the virtual console
- result = ((VirtualVConsole*)vconsole)->process_buffer(input_position,
- use_opengl);
- }
-
- return result;
-}
-
-// Determine if virtual console is needed
-int VRender::get_use_vconsole(VEdit* *playable_edit,
- int64_t position, int &use_brender)
-{
- *playable_edit = 0;
-
-// Background rendering completed
- if((use_brender = renderengine->brender_available(position,
- renderengine->command->get_direction())) != 0)
- return 0;
-
-// Descend into EDL nest
- return renderengine->get_edl()->get_use_vconsole(playable_edit,
- position,
- renderengine->command->get_direction(),
- vconsole->playable_tracks);
-}
-
-int VRender::get_colormodel(VEdit *playable_edit,
- int use_vconsole, int use_brender)
-{
- int colormodel = renderengine->get_edl()->session->color_model;
-
- if(!use_vconsole && !renderengine->command->single_frame())
- {
-// Get best colormodel supported by the file
- int driver = renderengine->config->vconfig->driver;
- File *file;
- Asset *asset;
-
- if(use_brender)
- {
- asset = renderengine->preferences->brender_asset;
- }
- else
- {
- int64_t source_position = 0;
- asset = playable_edit->get_nested_asset(&source_position,
- current_position,
- renderengine->command->get_direction());
- }
-
- if(asset)
- {
- file = renderengine->get_vcache()->check_out(asset,
- renderengine->get_edl());
-
- if(file)
- {
- colormodel = file->get_best_colormodel(driver);
- renderengine->get_vcache()->check_in(asset);
- }
- }
- }
-
- return colormodel;
-}
-
-
-
-
-
-
-
-void VRender::run()
-{
- int reconfigure;
- const int debug = 0;
-
-// Want to know how many samples rendering each frame takes.
-// Then use this number to predict the next frame that should be rendered.
-// Be suspicious of frames that render late so have a countdown
-// before we start dropping.
- int64_t current_sample, start_sample, end_sample; // Absolute counts.
- int64_t skip_countdown = VRENDER_THRESHOLD; // frames remaining until drop
- int64_t delay_countdown = VRENDER_THRESHOLD; // Frames remaining until delay
-// Number of frames before next reconfigure
- int64_t current_input_length;
-// Number of frames to skip.
- int64_t frame_step = 1;
- int use_opengl = (renderengine->video &&
- renderengine->video->out_config->driver == PLAYBACK_X11_GL);
-
- first_frame = 1;
-
-// Number of frames since start of rendering
- session_frame = 0;
- framerate_counter = 0;
- framerate_timer.update();
-
- start_lock->unlock();
- if(debug) printf("VRender::run %d\n", __LINE__);
-
-
- while(!done && !interrupt )
- {
-// Perform the most time consuming part of frame decompression now.
-// Want the condition before, since only 1 frame is rendered
-// and the number of frames skipped after this frame varies.
- current_input_length = 1;
-
- reconfigure = vconsole->test_reconfigure(current_position,
- current_input_length);
-
-
- if(debug) printf("VRender::run %d\n", __LINE__);
- if(reconfigure) restart_playback();
-
- if(debug) printf("VRender::run %d\n", __LINE__);
- process_buffer(current_position, use_opengl);
-
-
- if(debug) printf("VRender::run %d\n", __LINE__);
-
- if(renderengine->command->single_frame())
- {
- if(debug) printf("VRender::run %d\n", __LINE__);
- flash_output();
- frame_step = 1;
- done = 1;
- }
- else
-// Perform synchronization
- {
-// Determine the delay until the frame needs to be shown.
- current_sample = (int64_t)(renderengine->sync_position() *
- renderengine->command->get_speed());
-// latest sample at which the frame can be shown.
- end_sample = Units::tosamples(session_frame,
- renderengine->get_edl()->session->sample_rate,
- renderengine->get_edl()->session->frame_rate);
-// earliest sample by which the frame needs to be shown.
- start_sample = Units::tosamples(session_frame - 1,
- renderengine->get_edl()->session->sample_rate,
- renderengine->get_edl()->session->frame_rate);
-
- if(first_frame || end_sample < current_sample)
- {
-// Frame rendered late or this is the first frame. Flash it now.
-//printf("VRender::run %d\n", __LINE__);
- flash_output();
-
- if(renderengine->get_edl()->session->video_every_frame)
- {
-// User wants every frame.
- frame_step = 1;
- }
- else
- if(skip_countdown > 0)
- {
-// Maybe just a freak.
- frame_step = 1;
- skip_countdown--;
- }
- else
- {
-// Get the frames to skip.
- delay_countdown = VRENDER_THRESHOLD;
- frame_step = 1;
- frame_step += (int64_t)Units::toframes(current_sample,
- renderengine->get_edl()->session->sample_rate,
- renderengine->get_edl()->session->frame_rate);
- frame_step -= (int64_t)Units::toframes(end_sample,
- renderengine->get_edl()->session->sample_rate,
- renderengine->get_edl()->session->frame_rate);
- }
- }
- else
- {
-// Frame rendered early or just in time.
- frame_step = 1;
-
- if(delay_countdown > 0)
- {
-// Maybe just a freak
- delay_countdown--;
- }
- else
- {
- skip_countdown = VRENDER_THRESHOLD;
- if(start_sample > current_sample)
- {
- int64_t delay_time = (int64_t)((float)(start_sample - current_sample) *
- 1000 / renderengine->get_edl()->session->sample_rate);
- if( delay_time > 1000 ) delay_time = 1000;
- timer.delay(delay_time);
- }
- else
- {
-// Came after the earliest sample so keep going
- }
- }
-
-// Flash frame now.
-//printf("VRender::run %d " _LD "\n", __LINE__, current_input_length);
- flash_output();
- }
- }
- if(debug) printf("VRender::run %d\n", __LINE__);
-
-// Trigger audio to start
- if(first_frame)
- {
- renderengine->first_frame_lock->unlock();
- first_frame = 0;
- renderengine->reset_sync_position();
- }
- if(debug) printf("VRender::run %d\n", __LINE__);
-
- session_frame += frame_step;
-
-// advance position in project
- current_input_length = frame_step;
-
-
-// Subtract frame_step in a loop to allow looped playback to drain
-// printf("VRender::run %d %d %d %d\n",
-// __LINE__,
-// done,
-// frame_step,
-// current_input_length);
- while(frame_step && current_input_length)
- {
-// trim current_input_length to range
- get_boundaries(current_input_length);
-// advance 1 frame
- advance_position(current_input_length);
- frame_step -= current_input_length;
- current_input_length = frame_step;
- if(done) break;
-// printf("VRender::run %d %d %d %d\n",
-// __LINE__,
-// done,
-// frame_step,
-// current_input_length);
- }
-
- if(debug) printf("VRender::run %d current_position=" _LD " done=%d\n",
- __LINE__, current_position, done);
-
-// Update tracking.
- if(renderengine->command->realtime &&
- renderengine->playback_engine &&
- renderengine->command->command != CURRENT_FRAME)
- {
- renderengine->playback_engine->update_tracking(fromunits(current_position));
- }
- if(debug) printf("VRender::run %d\n", __LINE__);
-
-// Calculate the framerate counter
- framerate_counter++;
- if(framerate_counter >= renderengine->get_edl()->session->frame_rate &&
- renderengine->command->realtime)
- {
- renderengine->update_framerate((float)framerate_counter /
- ((float)framerate_timer.get_difference() / 1000));
- framerate_counter = 0;
- framerate_timer.update();
- }
- if(debug) printf("VRender::run %d done=%d\n", __LINE__, done);
- if( !interrupt )
- interrupt = renderengine->video->interrupt;
- }
-
-
-// In case we were interrupted before the first loop
- renderengine->first_frame_lock->unlock();
- stop_plugins();
- if(debug) printf("VRender::run %d done=%d\n", __LINE__, done);
-}
-
-int VRender::start_playback()
-{
-// start reading input and sending to vrenderthread
-// use a thread only if there's a video device
- if(renderengine->command->realtime)
- {
- start();
- }
- return 0;
-}
-
-int64_t VRender::tounits(double position, int round)
-{
- if(round)
- return Units::round(position * renderengine->get_edl()->session->frame_rate);
- else
- return Units::to_int64(position * renderengine->get_edl()->session->frame_rate);
-}
-
-double VRender::fromunits(int64_t position)
-{
- return (double)position / renderengine->get_edl()->session->frame_rate;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-