4 * Copyright (C) 2009 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
23 #include "bcsignals.h"
26 #include "condition.h"
30 #include "edlsession.h"
32 #include "localsession.h"
33 #include "mainsession.h"
35 #include "overlayframe.h"
36 #include "playabletracks.h"
37 #include "playbackengine.h"
38 #include "preferences.h"
39 #include "preferencesthread.h"
40 #include "renderengine.h"
41 #include "strategies.inc"
43 #include "transportque.h"
47 #include "videoconfig.h"
48 #include "videodevice.h"
49 #include "virtualconsole.h"
50 #include "virtualvconsole.h"
59 VRender::VRender(RenderEngine *renderengine)
60 : CommonRender(renderengine)
62 data_type = TRACK_VIDEO;
64 overlayer = new OverlayFrame(renderengine->preferences->processors);
66 vmodule_render_fragment = 0;
69 asynchronous = 0; // render 1 frame at a time
70 framerate_counter = 0;
77 if(input_temp) delete input_temp;
78 if(transition_temp) delete transition_temp;
79 if(overlayer) delete overlayer;
83 VirtualConsole* VRender::new_vconsole_object()
85 return new VirtualVConsole(renderengine, this);
88 int VRender::get_total_tracks()
90 return renderengine->get_edl()->tracks->total_video_tracks();
93 Module* VRender::new_module(Track *track)
95 return new VModule(renderengine, this, 0, track);
98 int VRender::flash_output()
101 return renderengine->video->write_buffer(video_out, renderengine->get_edl());
106 int VRender::process_buffer(VFrame *video_out,
107 int64_t input_position,
110 // process buffer for non realtime
111 int64_t render_len = 1;
115 this->video_out = video_out;
117 current_position = input_position;
119 reconfigure = vconsole->test_reconfigure(input_position,
122 if(reconfigure) restart_playback();
123 return process_buffer(input_position, use_opengl);
127 int VRender::process_buffer(int64_t input_position,
130 VEdit *playable_edit = 0;
132 int use_vconsole = 1;
135 int use_cache = renderengine->command->single_frame();
136 int use_asynchronous =
137 renderengine->command->realtime &&
138 renderengine->get_edl()->session->video_every_frame &&
139 renderengine->get_edl()->session->video_asynchronous;
142 // Determine the rendering strategy for this frame.
143 use_vconsole = get_use_vconsole(&playable_edit, input_position, use_brender);
144 if(debug) printf("VRender::process_buffer %d use_vconsole=%d\n", __LINE__, use_vconsole);
146 // Negotiate color model
147 colormodel = get_colormodel(playable_edit, use_vconsole, use_brender);
148 if(debug) printf("VRender::process_buffer %d\n", __LINE__);
151 // Get output buffer from device
152 if(renderengine->command->realtime && !renderengine->is_nested)
154 renderengine->video->new_output_buffer(&video_out, colormodel);
157 if(debug) printf("VRender::process_buffer %d video_out=%p\n", __LINE__, video_out);
159 // printf("VRender::process_buffer use_vconsole=%d colormodel=%d video_out=%p\n",
163 // Read directly from file to video_out
169 Asset *asset = renderengine->preferences->brender_asset;
170 File *file = renderengine->get_vcache()->check_out(asset,
171 renderengine->get_edl());
175 int64_t corrected_position = current_position;
176 if(renderengine->command->get_direction() == PLAY_REVERSE)
177 corrected_position--;
179 // Cache single frames only
181 file->start_video_decode_thread();
183 file->stop_video_thread();
184 if(use_cache) file->set_cache_frames(1);
185 int64_t normalized_position = (int64_t)(corrected_position *
187 renderengine->get_edl()->session->frame_rate);
189 file->set_video_position(normalized_position,
191 file->read_frame(video_out);
194 if(use_cache) file->set_cache_frames(0);
195 renderengine->get_vcache()->check_in(asset);
202 if(debug) printf("VRender::process_buffer %d\n", __LINE__);
203 result = ((VEdit*)playable_edit)->read_frame(video_out,
205 renderengine->command->get_direction(),
206 renderengine->get_vcache(),
210 if(debug) printf("VRender::process_buffer %d\n", __LINE__);
215 video_out->set_opengl_state(VFrame::RAM);
218 // Read into virtual console
221 // process this buffer now in the virtual console
222 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position,
229 // Determine if virtual console is needed
230 int VRender::get_use_vconsole(VEdit **playable_edit,
231 int64_t position, int &use_brender)
235 // Background rendering completed
236 if((use_brender = renderengine->brender_available(position,
237 renderengine->command->get_direction())) != 0)
240 // Descend into EDL nest
241 return renderengine->get_edl()->get_use_vconsole(playable_edit,
242 position, renderengine->command->get_direction(),
243 vconsole->playable_tracks);
247 int VRender::get_colormodel(VEdit *playable_edit,
248 int use_vconsole, int use_brender)
250 int colormodel = renderengine->get_edl()->session->color_model;
252 if(!use_vconsole && !renderengine->command->single_frame())
254 // Get best colormodel supported by the file
255 int driver = renderengine->config->vconfig->driver;
261 asset = renderengine->preferences->brender_asset;
265 int64_t source_position = 0;
266 asset = playable_edit->get_nested_asset(&source_position,
268 renderengine->command->get_direction());
270 // ffmpeg files are side effected by color_model, affects colorspace,color_range
271 if( asset && asset->format != FILE_FFMPEG )
273 file = renderengine->get_vcache()->check_out(asset,
274 renderengine->get_edl());
278 colormodel = file->get_best_colormodel(driver);
279 renderengine->get_vcache()->check_in(asset);
298 // Want to know how many samples rendering each frame takes.
299 // Then use this number to predict the next frame that should be rendered.
300 // Be suspicious of frames that render late so have a countdown
301 // before we start dropping.
302 int64_t current_sample, start_sample, end_sample; // Absolute counts.
303 int64_t skip_countdown = VRENDER_THRESHOLD; // frames remaining until drop
304 int64_t delay_countdown = 0; // Frames remaining until delay
305 // Number of frames before next reconfigure
306 int64_t current_input_length;
307 // Number of frames to skip.
308 int64_t frame_step = 1;
309 int use_opengl = (renderengine->video &&
310 renderengine->video->out_config->driver == PLAYBACK_X11_GL);
314 // Number of frames since start of rendering
316 framerate_counter = 0;
317 framerate_timer.update();
319 start_lock->unlock();
320 if(debug) printf("VRender::run %d\n", __LINE__);
323 while(!done && !interrupt )
325 // Perform the most time consuming part of frame decompression now.
326 // Want the condition before, since only 1 frame is rendered
327 // and the number of frames skipped after this frame varies.
328 current_input_length = 1;
330 reconfigure = vconsole->test_reconfigure(current_position,
331 current_input_length);
334 if(debug) printf("VRender::run %d\n", __LINE__);
335 if(reconfigure) restart_playback();
337 if(debug) printf("VRender::run %d\n", __LINE__);
338 process_buffer(current_position, use_opengl);
341 if(debug) printf("VRender::run %d\n", __LINE__);
343 if(renderengine->command->single_frame())
345 if(debug) printf("VRender::run %d\n", __LINE__);
351 // Perform synchronization
353 // Determine the delay until the frame needs to be shown.
354 current_sample = (int64_t)(renderengine->sync_position() *
355 renderengine->command->get_speed());
356 // latest sample at which the frame can be shown.
357 end_sample = Units::tosamples(session_frame + 1,
358 renderengine->get_edl()->session->sample_rate,
359 renderengine->get_edl()->session->frame_rate);
360 // earliest sample by which the frame needs to be shown.
361 start_sample = Units::tosamples(session_frame,
362 renderengine->get_edl()->session->sample_rate,
363 renderengine->get_edl()->session->frame_rate);
365 if(first_frame || end_sample < current_sample)
367 // Frame rendered late or this is the first frame. Flash it now.
368 //printf("VRender::run %d\n", __LINE__);
371 if(renderengine->get_edl()->session->video_every_frame)
373 // User wants every frame.
377 if(skip_countdown > 0)
379 // Maybe just a freak.
385 // Get the frames to skip.
386 delay_countdown = VRENDER_THRESHOLD;
388 frame_step += (int64_t)Units::toframes(current_sample,
389 renderengine->get_edl()->session->sample_rate,
390 renderengine->get_edl()->session->frame_rate);
391 frame_step -= (int64_t)Units::toframes(end_sample,
392 renderengine->get_edl()->session->sample_rate,
393 renderengine->get_edl()->session->frame_rate);
398 // Frame rendered early or just in time.
401 if(delay_countdown > 0)
403 // Maybe just a freak
408 skip_countdown = VRENDER_THRESHOLD;
409 if(start_sample > current_sample)
411 int64_t delay_time = (int64_t)((float)(start_sample - current_sample) *
412 1000 / renderengine->get_edl()->session->sample_rate);
413 if( delay_time > 1000 ) delay_time = 1000;
414 timer.delay(delay_time);
418 // Came after the earliest sample so keep going
423 //printf("VRender::run %d %jd\n", __LINE__, current_input_length);
427 if(debug) printf("VRender::run %d\n", __LINE__);
429 // Trigger audio to start
432 renderengine->first_frame_lock->unlock();
434 renderengine->reset_sync_position();
436 if(debug) printf("VRender::run %d\n", __LINE__);
438 session_frame += frame_step;
440 // advance position in project
441 current_input_length = frame_step;
444 // Subtract frame_step in a loop to allow looped playback to drain
445 // printf("VRender::run %d %d %d %d\n",
449 // current_input_length);
450 while(frame_step && current_input_length)
452 // trim current_input_length to range
453 get_boundaries(current_input_length);
455 advance_position(current_input_length);
456 frame_step -= current_input_length;
457 current_input_length = frame_step;
459 // printf("VRender::run %d %d %d %d\n",
463 // current_input_length);
466 if(debug) printf("VRender::run %d current_position=%jd done=%d\n",
467 __LINE__, current_position, done);
470 if(renderengine->command->realtime &&
471 renderengine->playback_engine &&
472 renderengine->command->command != CURRENT_FRAME)
474 renderengine->playback_engine->update_tracking(fromunits(current_position));
476 if(debug) printf("VRender::run %d\n", __LINE__);
478 // Calculate the framerate counter
480 if(framerate_counter >= renderengine->get_edl()->session->frame_rate &&
481 renderengine->command->realtime)
483 renderengine->update_framerate((float)framerate_counter /
484 ((float)framerate_timer.get_difference() / 1000));
485 framerate_counter = 0;
486 framerate_timer.update();
488 if(debug) printf("VRender::run %d done=%d\n", __LINE__, done);
490 interrupt = renderengine->video->interrupt;
494 // In case we were interrupted before the first loop
495 renderengine->first_frame_lock->unlock();
497 if(debug) printf("VRender::run %d done=%d\n", __LINE__, done);
500 int VRender::start_playback()
502 // start reading input and sending to vrenderthread
503 // use a thread only if there's a video device
504 if(renderengine->command->realtime)
511 int64_t VRender::tounits(double position, int round)
514 return Units::round(position * renderengine->get_edl()->session->frame_rate);
516 return Units::to_int64(position * renderengine->get_edl()->session->frame_rate);
519 double VRender::fromunits(int64_t position)
521 return (double)position / renderengine->get_edl()->session->frame_rate;