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)
104 Edit *playable_edit = 0;
106 int use_vconsole = 1;
111 // Determine the rendering strategy for this frame.
112 use_vconsole = get_use_vconsole(playable_edit,
117 // Negotiate color model
118 colormodel = get_colormodel(playable_edit, use_vconsole, use_brender);
121 // Get output buffer from device
122 if(renderengine->command->realtime)
123 renderengine->video->new_output_buffers(video_out, colormodel);
125 // Read directly from file to video_out
131 Asset *asset = renderengine->preferences->brender_asset;
132 File *file = renderengine->get_vcache()->check_out(asset);
135 int64_t corrected_position = current_position;
136 if(renderengine->command->get_direction() == PLAY_REVERSE)
137 corrected_position--;
139 // Cache single frames only
140 if(renderengine->command->single_frame())
141 file->set_cache_frames(1);
142 file->set_video_position(corrected_position,
143 renderengine->edl->session->frame_rate);
144 file->read_frame(video_out[0]);
145 if(renderengine->command->single_frame())
146 file->set_cache_frames(0);
147 renderengine->get_vcache()->check_in(asset);
153 result = ((VEdit*)playable_edit)->read_frame(video_out[0],
155 renderengine->command->get_direction(),
156 renderengine->get_vcache(),
158 renderengine->command->single_frame());
159 /* Insert timecode */
160 if(renderengine->show_tc)
161 insert_timecode(playable_edit,
167 // Read into virtual console
170 // process this buffer now in the virtual console
172 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position);
180 // Determine if virtual console is needed
181 int VRender::get_use_vconsole(Edit* &playable_edit,
185 Track *playable_track;
188 // Background rendering completed
189 if((use_brender = renderengine->brender_available(position,
190 renderengine->command->get_direction())) != 0)
195 // Total number of playable tracks is 1
196 if(vconsole->total_entry_nodes != 1) return 1;
198 playable_track = vconsole->playable_tracks->values[0];
200 // Test mutual conditions between render.C and this.
201 if(!playable_track->direct_copy_possible(position,
202 renderengine->command->get_direction(),
206 playable_edit = playable_track->edits->editof(position,
207 renderengine->command->get_direction(),
209 // No edit at current location
210 if(!playable_edit) return 1;
213 if(!playable_edit->asset) return 1;
215 // Asset and output device must have the same dimensions
216 if(playable_edit->asset->width != renderengine->edl->session->output_w ||
217 playable_edit->asset->height != renderengine->edl->session->output_h)
220 // Asset and output device must have same resulting de-interlacing method
221 if (ilaceautofixmethod2(renderengine->edl->session->interlace_mode,
222 playable_edit->asset->interlace_autofixoption,
223 playable_edit->asset->interlace_mode,
224 playable_edit->asset->interlace_fixmethod)
225 != BC_ILACE_FIXMETHOD_NONE)
228 // If we get here the frame is going to be directly copied. Whether it is
229 // decompressed in hardware depends on the colormodel.
234 int VRender::insert_timecode(Edit* &playable_edit,
238 EDLSession *session = renderengine->edl->session;
239 /* Create a vframe with TC and SRC timecode in white
240 * with a black border */
241 VFrame *input = new VFrame(0,
243 MIN(output->get_h(), 50),
244 output->get_color_model(),
245 output->get_bytes_per_line());
248 int src_position = 0;
250 TRACE("VRender::insert_timecode 10")
254 (renderengine->vrender->current_position +
255 session->get_frame_offset()) / session->frame_rate,
256 session->time_format,
257 session->sample_rate,
259 session->frames_per_foot);
261 TRACE("VRender::insert_timecode 20")
265 TRACE("VRender::insert_timecode 30")
266 src_position = renderengine->vrender->current_position -
267 playable_edit->startproject +
268 playable_edit->startsource +
269 playable_edit->asset->tcstart;
270 TRACE("VRender::insert_timecode 40")
272 src_position / playable_edit->asset->frame_rate,
273 session->time_format,
274 session->sample_rate,
275 playable_edit->asset->frame_rate,
276 session->frames_per_foot);
280 TRACE("VRender::insert_timecode 50")
283 // (renderengine->vrender->current_position - position) / session->frame_rate,
284 session->time_format,
285 session->sample_rate,
287 session->frames_per_foot);
289 TRACE("VRender::insert_timecode 60")
291 //printf("re position %i position %i\n",
292 // renderengine->vrender->current_position, position);
293 //printf("SRC %s TC %s\n", srctc, etc);
295 /* Insert the timecode data onto the input frame */
300 vrender->overlayer->overlay(output,
312 renderengine->edl->session->interpolation_type);
319 int VRender::get_colormodel(Edit* &playable_edit,
324 int colormodel = renderengine->edl->session->color_model;
327 if(!use_vconsole && !renderengine->command->single_frame())
329 // Get best colormodel supported by the file
331 int driver = renderengine->config->vconfig->driver;
338 asset = renderengine->preferences->brender_asset;
342 asset = playable_edit->asset;
346 file = renderengine->get_vcache()->check_out(asset);
351 colormodel = file->get_best_colormodel(driver);
352 renderengine->get_vcache()->check_in(asset);
369 // Want to know how many samples rendering each frame takes.
370 // Then use this number to predict the next frame that should be rendered.
371 // Be suspicious of frames that render late so have a countdown
372 // before we start dropping.
373 int64_t current_sample, start_sample, end_sample; // Absolute counts.
374 int64_t next_frame; // Actual position.
375 int64_t last_delay = 0; // delay used before last frame
376 int64_t skip_countdown = VRENDER_THRESHOLD; // frames remaining until drop
377 int64_t delay_countdown = VRENDER_THRESHOLD; // Frames remaining until delay
378 // Number of frames before next reconfigure
379 int64_t current_input_length;
380 // Number of frames to skip.
381 int64_t frame_step = 1;
385 // Number of frames since start of rendering
387 framerate_counter = 0;
388 framerate_timer.update();
390 start_lock->unlock();
394 !renderengine->video->interrupt &&
397 TRACE("VRender::run 0");
398 // Perform the most time consuming part of frame decompression now.
399 // Want the condition before, since only 1 frame is rendered
400 // and the number of frames skipped after this frame varies.
401 current_input_length = 1;
403 reconfigure = vconsole->test_reconfigure(current_position,
404 current_input_length,
406 TRACE("VRender::run 0.1");
408 if(reconfigure) restart_playback();
409 TRACE("VRender::run 0.2");
411 process_buffer(current_position);
413 TRACE("VRender::run 0.3");
414 if(renderengine->command->single_frame())
416 //TRACE("VRender::run 2");
418 //TRACE("VRender::run 3");
423 // Perform synchronization
425 TRACE("VRender::run 0.4");
426 // Determine the delay until the frame needs to be shown.
427 current_sample = (int64_t)(renderengine->sync_position() *
428 renderengine->command->get_speed());
429 TRACE("VRender::run 0.5");
430 // latest sample at which the frame can be shown.
431 end_sample = Units::tosamples(session_frame,
432 renderengine->edl->session->sample_rate,
433 renderengine->edl->session->frame_rate);
434 // earliest sample by which the frame needs to be shown.
435 start_sample = Units::tosamples(session_frame - 1,
436 renderengine->edl->session->sample_rate,
437 renderengine->edl->session->frame_rate);
439 if(first_frame || end_sample < current_sample)
441 // Frame rendered late or this is the first frame. Flash it now.
444 if(renderengine->edl->session->video_every_frame)
446 // User wants every frame.
450 if(skip_countdown > 0)
452 // Maybe just a freak.
458 // Get the frames to skip.
459 delay_countdown = VRENDER_THRESHOLD;
461 frame_step += (int64_t)Units::toframes(current_sample,
462 renderengine->edl->session->sample_rate,
463 renderengine->edl->session->frame_rate);
464 frame_step -= (int64_t)Units::toframes(end_sample,
465 renderengine->edl->session->sample_rate,
466 renderengine->edl->session->frame_rate);
468 //TRACE("VRender::run 3");
469 //printf("VRender:run 11 frame_step %d\n", frame_step);
473 // Frame rendered early or just in time.
475 //TRACE("VRender::run 4");
477 if(delay_countdown > 0)
479 // Maybe just a freak
484 skip_countdown = VRENDER_THRESHOLD;
485 if(start_sample > current_sample)
487 int64_t delay_time = (int64_t)((float)(start_sample - current_sample) *
489 renderengine->edl->session->sample_rate);
490 timer.delay(delay_time);
491 //printf("VRender:run 10 %lld\n", delay_time);
495 // Came after the earliest sample so keep going
499 //TRACE("VRender::run 5");
502 //TRACE("VRender::run 6");
506 // Trigger audio to start
509 renderengine->first_frame_lock->unlock();
511 renderengine->reset_sync_position();
513 //TRACE("VRender::run 5");
515 session_frame += frame_step;
517 // advance position in project
518 current_input_length = frame_step;
521 // Subtract frame_step in a loop to allow looped playback to drain
522 while(frame_step && current_input_length && !last_playback)
524 // set last_playback if necessary and trim current_input_length to range
525 get_boundaries(current_input_length);
527 advance_position(current_input_length);
528 frame_step -= current_input_length;
529 current_input_length = frame_step;
531 TRACE("VRender::run 6");
534 if(renderengine->command->realtime &&
535 renderengine->playback_engine &&
536 renderengine->command->command != CURRENT_FRAME)
538 renderengine->playback_engine->update_tracking(fromunits(current_position));
541 TRACE("VRender::run 7");
542 // Calculate the framerate counter
544 if(framerate_counter >= renderengine->edl->session->frame_rate &&
545 renderengine->command->realtime)
547 renderengine->update_framerate((float)framerate_counter /
548 ((float)framerate_timer.get_difference() / 1000));
549 framerate_counter = 0;
550 framerate_timer.update();
552 TRACE("VRender::run 8");
554 TRACE("VRender::run 10");
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;