9 #include "edlsession.h"
11 #include "interlacemodes.h"
12 #include "localsession.h"
13 #include "mainsession.h"
15 #include "overlayframe.h"
16 #include "playabletracks.h"
17 #include "playbackengine.h"
18 #include "preferences.h"
19 #include "preferencesthread.h"
20 #include "renderengine.h"
21 #include "strategies.inc"
23 #include "transportque.h"
27 #include "videoconfig.h"
28 #include "videodevice.h"
29 #include "virtualconsole.h"
30 #include "virtualvconsole.h"
39 VRender::VRender(RenderEngine *renderengine)
40 : CommonRender(renderengine)
42 data_type = TRACK_VIDEO;
44 overlayer = new OverlayFrame(renderengine->preferences->processors);
50 if(input_temp) delete input_temp;
51 if(transition_temp) delete transition_temp;
52 if(overlayer) delete overlayer;
56 VirtualConsole* VRender::new_vconsole_object()
58 return new VirtualVConsole(renderengine, this);
61 int VRender::get_total_tracks()
63 return renderengine->edl->tracks->total_video_tracks();
66 Module* VRender::new_module(Track *track)
68 return new VModule(renderengine, this, 0, track);
71 int VRender::flash_output()
73 return renderengine->video->write_buffer(video_out, renderengine->edl);
76 int VRender::process_buffer(VFrame *video_out,
77 int64_t input_position,
80 // process buffer for non realtime
82 int64_t render_len = 1;
86 this->video_out = video_out;
87 this->last_playback = last_buffer;
89 current_position = input_position;
91 // test for automation configuration and shorten the fragment len if necessary
92 reconfigure = vconsole->test_reconfigure(input_position,
96 if(reconfigure) restart_playback();
97 return process_buffer(input_position);
101 int VRender::process_buffer(int64_t input_position)
104 Edit *playable_edit = 0;
106 int use_vconsole = 1;
109 int use_cache = renderengine->command->single_frame();
110 int use_asynchronous =
111 renderengine->command->realtime &&
112 renderengine->edl->session->video_asynchronous;
115 // Determine the rendering strategy for this frame.
116 use_vconsole = get_use_vconsole(playable_edit,
120 // Negotiate color model
121 colormodel = get_colormodel(playable_edit, use_vconsole, use_brender);
123 // Get output buffer from device
124 if(renderengine->command->realtime)
125 renderengine->video->new_output_buffer(&video_out, colormodel);
128 // printf("VRender::process_buffer use_vconsole=%d colormodel=%d video_out=%p\n",
132 // Read directly from file to video_out
139 Asset *asset = renderengine->preferences->brender_asset;
140 File *file = renderengine->get_vcache()->check_out(asset,
144 int64_t corrected_position = current_position;
145 if(renderengine->command->get_direction() == PLAY_REVERSE)
146 corrected_position--;
148 // Cache single frames only
150 file->start_video_decode_thread();
152 file->stop_video_thread();
153 if(use_cache) file->set_cache_frames(1);
154 file->set_video_position(corrected_position,
155 renderengine->edl->session->frame_rate);
156 file->read_frame(video_out);
157 if(use_cache) file->set_cache_frames(0);
158 renderengine->get_vcache()->check_in(asset);
165 result = ((VEdit*)playable_edit)->read_frame(video_out,
167 renderengine->command->get_direction(),
168 renderengine->get_vcache(),
172 /* Insert timecode */
173 if(renderengine->show_tc)
174 insert_timecode(playable_edit,
180 // Read into virtual console
183 // process this buffer now in the virtual console
184 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position);
191 // Determine if virtual console is needed
192 int VRender::get_use_vconsole(Edit* &playable_edit,
196 Track *playable_track;
199 // Background rendering completed
200 if((use_brender = renderengine->brender_available(position,
201 renderengine->command->get_direction())) != 0)
206 // Total number of playable tracks is 1
207 if(vconsole->total_exit_nodes != 1) return 1;
209 playable_track = vconsole->playable_tracks->values[0];
211 // Test mutual conditions between render.C and this.
212 if(!playable_track->direct_copy_possible(position,
213 renderengine->command->get_direction(),
217 playable_edit = playable_track->edits->editof(position,
218 renderengine->command->get_direction(),
220 // No edit at current location
221 if(!playable_edit) return 1;
224 if(!playable_edit->asset) return 1;
226 // Asset and output device must have the same dimensions
227 if(playable_edit->asset->width != renderengine->edl->session->output_w ||
228 playable_edit->asset->height != renderengine->edl->session->output_h)
231 // Asset and output device must have same resulting de-interlacing method
232 if (ilaceautofixmethod2(renderengine->edl->session->interlace_mode,
233 playable_edit->asset->interlace_autofixoption,
234 playable_edit->asset->interlace_mode,
235 playable_edit->asset->interlace_fixmethod)
236 != BC_ILACE_FIXMETHOD_NONE)
239 // If we get here the frame is going to be directly copied. Whether it is
240 // decompressed in hardware depends on the colormodel.
245 int VRender::insert_timecode(Edit* &playable_edit,
249 EDLSession *session = renderengine->edl->session;
250 /* Create a vframe with TC and SRC timecode in white
251 * with a black border */
252 VFrame *input = new VFrame(0,
254 MIN(output->get_h(), 50),
255 output->get_color_model(),
256 output->get_bytes_per_line());
259 int src_position = 0;
261 TRACE("VRender::insert_timecode 10")
265 (renderengine->vrender->current_position +
266 session->get_frame_offset()) / session->frame_rate,
267 session->time_format,
268 session->sample_rate,
270 session->frames_per_foot);
272 TRACE("VRender::insert_timecode 20")
276 TRACE("VRender::insert_timecode 30")
277 src_position = renderengine->vrender->current_position -
278 playable_edit->startproject +
279 playable_edit->startsource +
280 playable_edit->asset->tcstart;
281 TRACE("VRender::insert_timecode 40")
283 src_position / playable_edit->asset->frame_rate,
284 session->time_format,
285 session->sample_rate,
286 playable_edit->asset->frame_rate,
287 session->frames_per_foot);
291 TRACE("VRender::insert_timecode 50")
294 // (renderengine->vrender->current_position - position) / session->frame_rate,
295 session->time_format,
296 session->sample_rate,
298 session->frames_per_foot);
300 TRACE("VRender::insert_timecode 60")
302 //printf("re position %i position %i\n",
303 // renderengine->vrender->current_position, position);
304 //printf("SRC %s TC %s\n", srctc, etc);
306 /* Insert the timecode data onto the input frame */
311 vrender->overlayer->overlay(output,
323 renderengine->edl->session->interpolation_type);
330 int VRender::get_colormodel(Edit* &playable_edit,
334 int colormodel = renderengine->edl->session->color_model;
336 if(!use_vconsole && !renderengine->command->single_frame())
338 // Get best colormodel supported by the file
339 int driver = renderengine->config->vconfig->driver;
345 asset = renderengine->preferences->brender_asset;
349 asset = playable_edit->asset;
352 file = renderengine->get_vcache()->check_out(asset,
357 colormodel = file->get_best_colormodel(driver);
358 renderengine->get_vcache()->check_in(asset);
375 // Want to know how many samples rendering each frame takes.
376 // Then use this number to predict the next frame that should be rendered.
377 // Be suspicious of frames that render late so have a countdown
378 // before we start dropping.
379 int64_t current_sample, start_sample, end_sample; // Absolute counts.
380 int64_t next_frame; // Actual position.
381 int64_t last_delay = 0; // delay used before last frame
382 int64_t skip_countdown = VRENDER_THRESHOLD; // frames remaining until drop
383 int64_t delay_countdown = VRENDER_THRESHOLD; // Frames remaining until delay
384 // Number of frames before next reconfigure
385 int64_t current_input_length;
386 // Number of frames to skip.
387 int64_t frame_step = 1;
391 // Number of frames since start of rendering
393 framerate_counter = 0;
394 framerate_timer.update();
396 start_lock->unlock();
400 !renderengine->video->interrupt &&
403 // Perform the most time consuming part of frame decompression now.
404 // Want the condition before, since only 1 frame is rendered
405 // and the number of frames skipped after this frame varies.
406 current_input_length = 1;
408 reconfigure = vconsole->test_reconfigure(current_position,
409 current_input_length,
412 if(reconfigure) restart_playback();
415 process_buffer(current_position);
418 if(renderengine->command->single_frame())
425 // Perform synchronization
428 // Determine the delay until the frame needs to be shown.
429 current_sample = (int64_t)(renderengine->sync_position() *
430 renderengine->command->get_speed());
431 // latest sample at which the frame can be shown.
432 end_sample = Units::tosamples(session_frame,
433 renderengine->edl->session->sample_rate,
434 renderengine->edl->session->frame_rate);
435 // earliest sample by which the frame needs to be shown.
436 start_sample = Units::tosamples(session_frame - 1,
437 renderengine->edl->session->sample_rate,
438 renderengine->edl->session->frame_rate);
441 if(first_frame || end_sample < current_sample)
444 // Frame rendered late or this is the first frame. Flash it now.
448 if(renderengine->edl->session->video_every_frame)
450 // User wants every frame.
454 if(skip_countdown > 0)
456 // Maybe just a freak.
462 // Get the frames to skip.
463 delay_countdown = VRENDER_THRESHOLD;
465 frame_step += (int64_t)Units::toframes(current_sample,
466 renderengine->edl->session->sample_rate,
467 renderengine->edl->session->frame_rate);
468 frame_step -= (int64_t)Units::toframes(end_sample,
469 renderengine->edl->session->sample_rate,
470 renderengine->edl->session->frame_rate);
475 // Frame rendered early or just in time.
479 if(delay_countdown > 0)
481 // Maybe just a freak
486 skip_countdown = VRENDER_THRESHOLD;
487 if(start_sample > current_sample)
490 int64_t delay_time = (int64_t)((float)(start_sample - current_sample) *
492 renderengine->edl->session->sample_rate);
494 timer.delay(delay_time);
499 // Came after the earliest sample so keep going
510 // Trigger audio to start
513 renderengine->first_frame_lock->unlock();
515 renderengine->reset_sync_position();
518 session_frame += frame_step;
520 // advance position in project
521 current_input_length = frame_step;
524 // Subtract frame_step in a loop to allow looped playback to drain
525 while(frame_step && current_input_length && !last_playback)
527 // set last_playback if necessary and trim current_input_length to range
528 get_boundaries(current_input_length);
530 advance_position(current_input_length);
531 frame_step -= current_input_length;
532 current_input_length = frame_step;
536 if(renderengine->command->realtime &&
537 renderengine->playback_engine &&
538 renderengine->command->command != CURRENT_FRAME)
540 renderengine->playback_engine->update_tracking(fromunits(current_position));
543 // Calculate the framerate counter
545 if(framerate_counter >= renderengine->edl->session->frame_rate &&
546 renderengine->command->realtime)
548 renderengine->update_framerate((float)framerate_counter /
549 ((float)framerate_timer.get_difference() / 1000));
550 framerate_counter = 0;
551 framerate_timer.update();
556 // In case we were interrupted before the first loop
557 renderengine->first_frame_lock->unlock();
584 VRender::VRender(MWindow *mwindow, RenderEngine *renderengine)
585 : CommonRender(mwindow, renderengine)
588 vmodule_render_fragment = 0;
591 asynchronous = 0; // render 1 frame at a time
592 framerate_counter = 0;
594 render_strategy = -1;
597 int VRender::init_device_buffers()
599 // allocate output buffer if there is a video device
600 if(renderengine->video)
603 render_strategy = -1;
607 int VRender::get_datatype()
613 int VRender::start_playback()
615 // start reading input and sending to vrenderthread
616 // use a thread only if there's a video device
617 if(renderengine->command->realtime)
623 int VRender::wait_for_startup()
633 int64_t VRender::tounits(double position, int round)
636 return Units::round(position * renderengine->edl->session->frame_rate);
638 return Units::to_int64(position * renderengine->edl->session->frame_rate);
641 double VRender::fromunits(int64_t position)
643 return (double)position / renderengine->edl->session->frame_rate;