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 for(i = 0; i < MAX_CHANNELS; i++)
87 this->video_out[i] = video_out[i];
88 this->last_playback = last_buffer;
90 current_position = input_position;
92 // test for automation configuration and shorten the fragment len if necessary
93 reconfigure = vconsole->test_reconfigure(input_position,
97 if(reconfigure) restart_playback();
98 return process_buffer(input_position);
102 int VRender::process_buffer(int64_t input_position)
105 Edit *playable_edit = 0;
107 int use_vconsole = 1;
112 // Determine the rendering strategy for this frame.
113 use_vconsole = get_use_vconsole(playable_edit,
117 // Negotiate color model
118 colormodel = get_colormodel(playable_edit, use_vconsole, use_brender);
120 // Get output buffer from device
121 if(renderengine->command->realtime)
122 renderengine->video->new_output_buffers(video_out, colormodel);
125 // printf("VRender::process_buffer use_vconsole=%d colormodel=%d video_out=%p\n",
129 // Read directly from file to video_out
136 Asset *asset = renderengine->preferences->brender_asset;
137 File *file = renderengine->get_vcache()->check_out(asset);
140 int64_t corrected_position = current_position;
141 if(renderengine->command->get_direction() == PLAY_REVERSE)
142 corrected_position--;
144 // Cache single frames only
145 if(renderengine->command->single_frame())
146 file->set_cache_frames(1);
147 file->set_video_position(corrected_position,
148 renderengine->edl->session->frame_rate);
149 file->read_frame(video_out[0]);
150 if(renderengine->command->single_frame())
151 file->set_cache_frames(0);
152 renderengine->get_vcache()->check_in(asset);
159 result = ((VEdit*)playable_edit)->read_frame(video_out[0],
161 renderengine->command->get_direction(),
162 renderengine->get_vcache(),
164 renderengine->command->single_frame());
165 /* Insert timecode */
166 if(renderengine->show_tc)
167 insert_timecode(playable_edit,
173 // Read into virtual console
176 // process this buffer now in the virtual console
177 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position);
184 // Determine if virtual console is needed
185 int VRender::get_use_vconsole(Edit* &playable_edit,
189 Track *playable_track;
192 // Background rendering completed
193 if((use_brender = renderengine->brender_available(position,
194 renderengine->command->get_direction())) != 0)
199 // Total number of playable tracks is 1
200 if(vconsole->total_entry_nodes != 1) return 1;
202 playable_track = vconsole->playable_tracks->values[0];
204 // Test mutual conditions between render.C and this.
205 if(!playable_track->direct_copy_possible(position,
206 renderengine->command->get_direction(),
210 playable_edit = playable_track->edits->editof(position,
211 renderengine->command->get_direction(),
213 // No edit at current location
214 if(!playable_edit) return 1;
217 if(!playable_edit->asset) return 1;
219 // Asset and output device must have the same dimensions
220 if(playable_edit->asset->width != renderengine->edl->session->output_w ||
221 playable_edit->asset->height != renderengine->edl->session->output_h)
224 // Asset and output device must have same resulting de-interlacing method
225 if (ilaceautofixmethod2(renderengine->edl->session->interlace_mode,
226 playable_edit->asset->interlace_autofixoption,
227 playable_edit->asset->interlace_mode,
228 playable_edit->asset->interlace_fixmethod)
229 != BC_ILACE_FIXMETHOD_NONE)
232 // If we get here the frame is going to be directly copied. Whether it is
233 // decompressed in hardware depends on the colormodel.
238 int VRender::insert_timecode(Edit* &playable_edit,
242 EDLSession *session = renderengine->edl->session;
243 /* Create a vframe with TC and SRC timecode in white
244 * with a black border */
245 VFrame *input = new VFrame(0,
247 MIN(output->get_h(), 50),
248 output->get_color_model(),
249 output->get_bytes_per_line());
252 int src_position = 0;
254 TRACE("VRender::insert_timecode 10")
258 (renderengine->vrender->current_position +
259 session->get_frame_offset()) / session->frame_rate,
260 session->time_format,
261 session->sample_rate,
263 session->frames_per_foot);
265 TRACE("VRender::insert_timecode 20")
269 TRACE("VRender::insert_timecode 30")
270 src_position = renderengine->vrender->current_position -
271 playable_edit->startproject +
272 playable_edit->startsource +
273 playable_edit->asset->tcstart;
274 TRACE("VRender::insert_timecode 40")
276 src_position / playable_edit->asset->frame_rate,
277 session->time_format,
278 session->sample_rate,
279 playable_edit->asset->frame_rate,
280 session->frames_per_foot);
284 TRACE("VRender::insert_timecode 50")
287 // (renderengine->vrender->current_position - position) / session->frame_rate,
288 session->time_format,
289 session->sample_rate,
291 session->frames_per_foot);
293 TRACE("VRender::insert_timecode 60")
295 //printf("re position %i position %i\n",
296 // renderengine->vrender->current_position, position);
297 //printf("SRC %s TC %s\n", srctc, etc);
299 /* Insert the timecode data onto the input frame */
304 vrender->overlayer->overlay(output,
316 renderengine->edl->session->interpolation_type);
323 int VRender::get_colormodel(Edit* &playable_edit,
327 int colormodel = renderengine->edl->session->color_model;
329 if(!use_vconsole && !renderengine->command->single_frame())
331 // Get best colormodel supported by the file
332 int driver = renderengine->config->vconfig->driver;
338 asset = renderengine->preferences->brender_asset;
342 asset = playable_edit->asset;
345 file = renderengine->get_vcache()->check_out(asset);
349 colormodel = file->get_best_colormodel(driver);
350 renderengine->get_vcache()->check_in(asset);
367 // Want to know how many samples rendering each frame takes.
368 // Then use this number to predict the next frame that should be rendered.
369 // Be suspicious of frames that render late so have a countdown
370 // before we start dropping.
371 int64_t current_sample, start_sample, end_sample; // Absolute counts.
372 int64_t next_frame; // Actual position.
373 int64_t last_delay = 0; // delay used before last frame
374 int64_t skip_countdown = VRENDER_THRESHOLD; // frames remaining until drop
375 int64_t delay_countdown = VRENDER_THRESHOLD; // Frames remaining until delay
376 // Number of frames before next reconfigure
377 int64_t current_input_length;
378 // Number of frames to skip.
379 int64_t frame_step = 1;
383 // Number of frames since start of rendering
385 framerate_counter = 0;
386 framerate_timer.update();
388 start_lock->unlock();
392 !renderengine->video->interrupt &&
395 // Perform the most time consuming part of frame decompression now.
396 // Want the condition before, since only 1 frame is rendered
397 // and the number of frames skipped after this frame varies.
398 current_input_length = 1;
400 reconfigure = vconsole->test_reconfigure(current_position,
401 current_input_length,
404 if(reconfigure) restart_playback();
407 process_buffer(current_position);
410 if(renderengine->command->single_frame())
417 // Perform synchronization
420 // Determine the delay until the frame needs to be shown.
421 current_sample = (int64_t)(renderengine->sync_position() *
422 renderengine->command->get_speed());
423 // latest sample at which the frame can be shown.
424 end_sample = Units::tosamples(session_frame,
425 renderengine->edl->session->sample_rate,
426 renderengine->edl->session->frame_rate);
427 // earliest sample by which the frame needs to be shown.
428 start_sample = Units::tosamples(session_frame - 1,
429 renderengine->edl->session->sample_rate,
430 renderengine->edl->session->frame_rate);
433 if(first_frame || end_sample < current_sample)
436 // Frame rendered late or this is the first frame. Flash it now.
440 if(renderengine->edl->session->video_every_frame)
442 // User wants every frame.
446 if(skip_countdown > 0)
448 // Maybe just a freak.
454 // Get the frames to skip.
455 delay_countdown = VRENDER_THRESHOLD;
457 frame_step += (int64_t)Units::toframes(current_sample,
458 renderengine->edl->session->sample_rate,
459 renderengine->edl->session->frame_rate);
460 frame_step -= (int64_t)Units::toframes(end_sample,
461 renderengine->edl->session->sample_rate,
462 renderengine->edl->session->frame_rate);
467 // Frame rendered early or just in time.
471 if(delay_countdown > 0)
473 // Maybe just a freak
478 skip_countdown = VRENDER_THRESHOLD;
479 if(start_sample > current_sample)
482 int64_t delay_time = (int64_t)((float)(start_sample - current_sample) *
484 renderengine->edl->session->sample_rate);
486 timer.delay(delay_time);
491 // Came after the earliest sample so keep going
502 // Trigger audio to start
505 renderengine->first_frame_lock->unlock();
507 renderengine->reset_sync_position();
510 session_frame += frame_step;
512 // advance position in project
513 current_input_length = frame_step;
516 // Subtract frame_step in a loop to allow looped playback to drain
517 while(frame_step && current_input_length && !last_playback)
519 // set last_playback if necessary and trim current_input_length to range
520 get_boundaries(current_input_length);
522 advance_position(current_input_length);
523 frame_step -= current_input_length;
524 current_input_length = frame_step;
528 if(renderengine->command->realtime &&
529 renderengine->playback_engine &&
530 renderengine->command->command != CURRENT_FRAME)
532 renderengine->playback_engine->update_tracking(fromunits(current_position));
535 // Calculate the framerate counter
537 if(framerate_counter >= renderengine->edl->session->frame_rate &&
538 renderengine->command->realtime)
540 renderengine->update_framerate((float)framerate_counter /
541 ((float)framerate_timer.get_difference() / 1000));
542 framerate_counter = 0;
543 framerate_timer.update();
548 // In case we were interrupted before the first loop
549 renderengine->first_frame_lock->unlock();
576 VRender::VRender(MWindow *mwindow, RenderEngine *renderengine)
577 : CommonRender(mwindow, renderengine)
580 vmodule_render_fragment = 0;
583 asynchronous = 0; // render 1 frame at a time
584 framerate_counter = 0;
586 render_strategy = -1;
589 int VRender::init_device_buffers()
591 // allocate output buffer if there is a video device
592 if(renderengine->video)
595 render_strategy = -1;
599 int VRender::get_datatype()
605 int VRender::start_playback()
607 // start reading input and sending to vrenderthread
608 // use a thread only if there's a video device
609 if(renderengine->command->realtime)
615 int VRender::wait_for_startup()
625 int64_t VRender::tounits(double position, int round)
628 return Units::round(position * renderengine->edl->session->frame_rate);
630 return Units::to_int64(position * renderengine->edl->session->frame_rate);
633 double VRender::fromunits(int64_t position)
635 return (double)position / renderengine->edl->session->frame_rate;