r956: README.BUILD - add more library recommendations
[cinelerra_cv/ct.git] / cinelerra / vrender.C
bloba0b3d1f855437ba0b723692aa2d4816aaad7ba8b
1 #include "asset.h"
2 #include "bcsignals.h"
3 #include "cache.h"
4 #include "clip.h"
5 #include "condition.h"
6 #include "datatype.h"
7 #include "edits.h"
8 #include "edl.h"
9 #include "edlsession.h"
10 #include "file.h"
11 #include "interlacemodes.h"
12 #include "localsession.h"
13 #include "mainsession.h"
14 #include "mwindow.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"
22 #include "tracks.h"
23 #include "transportque.h"
24 #include "units.h"
25 #include "vedit.h"
26 #include "vframe.h"
27 #include "videoconfig.h"
28 #include "videodevice.h"
29 #include "virtualconsole.h"
30 #include "virtualvconsole.h"
31 #include "vmodule.h"
32 #include "vrender.h"
33 #include "vtrack.h"
39 VRender::VRender(RenderEngine *renderengine)
40  : CommonRender(renderengine)
42         data_type = TRACK_VIDEO;
43         transition_temp = 0;
44         overlayer = new OverlayFrame(renderengine->preferences->processors);
45         input_temp = 0;
48 VRender::~VRender()
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, 
78         int last_buffer)
80 // process buffer for non realtime
81         int i, j;
82         int64_t render_len = 1;
83         int reconfigure = 0;
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, 
93                 render_len,
94                 last_playback);
96         if(reconfigure) restart_playback();
97         return process_buffer(input_position);
101 int VRender::process_buffer(int64_t input_position)
103 SET_TRACE
104         Edit *playable_edit = 0;
105         int colormodel;
106         int use_vconsole = 1;
107         int use_brender = 0;
108         int result = 0;
109         int use_cache = renderengine->command->single_frame();
110         int use_asynchronous = 
111                 renderengine->command->realtime && 
112                 renderengine->edl->session->video_asynchronous;
113 SET_TRACE
115 // Determine the rendering strategy for this frame.
116         use_vconsole = get_use_vconsole(playable_edit, 
117                 input_position,
118                 use_brender);
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", 
129 // use_vconsole, 
130 // colormodel,
131 // video_out);
132 // Read directly from file to video_out
133         if(!use_vconsole)
134         {
136                 if(use_brender)
137                 {
138 SET_TRACE
139                         Asset *asset = renderengine->preferences->brender_asset;
140                         File *file = renderengine->get_vcache()->check_out(asset,
141                                 renderengine->edl);
142                         if(file)
143                         {
144                                 int64_t corrected_position = current_position;
145                                 if(renderengine->command->get_direction() == PLAY_REVERSE)
146                                         corrected_position--;
148 // Cache single frames only
149                                 if(use_asynchronous)
150                                         file->start_video_decode_thread();
151                                 else
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);
159                         }
160 SET_TRACE
161                 }
162                 else
163                 if(playable_edit)
164                 {
165                         result = ((VEdit*)playable_edit)->read_frame(video_out, 
166                                 current_position, 
167                                 renderengine->command->get_direction(),
168                                 renderengine->get_vcache(),
169                                 1,
170                                 use_cache,
171                                 use_asynchronous);
172 /* Insert timecode */
173                         if(renderengine->show_tc)
174                                 insert_timecode(playable_edit,
175                                         input_position,
176                                         video_out);
177                 }
178         }
179         else
180 // Read into virtual console
181         {
183 // process this buffer now in the virtual console
184                 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position);
185         }
188         return result;
191 // Determine if virtual console is needed
192 int VRender::get_use_vconsole(Edit* &playable_edit, 
193         int64_t position,
194         int &use_brender)
196         Track *playable_track;
199 // Background rendering completed
200         if((use_brender = renderengine->brender_available(position, 
201                 renderengine->command->get_direction())) != 0) 
202                 return 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(),
214                 1))
215                 return 1;
217         playable_edit = playable_track->edits->editof(position, 
218                 renderengine->command->get_direction(),
219                 1);
220 // No edit at current location
221         if(!playable_edit) return 1;
223 // Edit is silence
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)
229                 return 1;
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)
237                 return 1;
239 // If we get here the frame is going to be directly copied.  Whether it is
240 // decompressed in hardware depends on the colormodel.
241         return 0;
245 int VRender::insert_timecode(Edit* &playable_edit,
246                         int64_t position,
247                         VFrame *output)
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,
253                                                                 output->get_w(),
254                                                                 MIN(output->get_h(), 50),
255                                                                 output->get_color_model(),
256                                                                 output->get_bytes_per_line());
257         char etc[12];
258         char srctc[12];
259         int src_position = 0;
261 TRACE("VRender::insert_timecode 10")
263         /* Edited TC */
264         Units::totext(etc,
265                 (renderengine->vrender->current_position +
266                         session->get_frame_offset()) / session->frame_rate,
267                 session->time_format,
268                 session->sample_rate,
269                 session->frame_rate,
270                 session->frames_per_foot);
272 TRACE("VRender::insert_timecode 20")
274         if(playable_edit)
275         {
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")
282                 Units::totext(srctc,
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);
288         }
289         else
290         {
291 TRACE("VRender::insert_timecode 50")
292                 Units::totext(srctc,
293                         0.0,
294 //                      (renderengine->vrender->current_position - position) / session->frame_rate,
295                         session->time_format,
296                         session->sample_rate,
297                         session->frame_rate,
298                         session->frames_per_foot);
299         }
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 */
307         
308         
311         vrender->overlayer->overlay(output, 
312                 input,
313                 input->x, 
314                 input->y, 
315                 input->width, 
316                 input->height,
317                 output->x, 
318                 output->y, 
319                 output->width, 
320                 output->height, 
321                 1,
322                 TRANSFER_REPLACE, 
323                 renderengine->edl->session->interpolation_type);
325         delete(input);
326 UNTRACE
330 int VRender::get_colormodel(Edit* &playable_edit, 
331         int use_vconsole,
332         int use_brender)
334         int colormodel = renderengine->edl->session->color_model;
336         if(!use_vconsole && !renderengine->command->single_frame())
337         {
338 // Get best colormodel supported by the file
339                 int driver = renderengine->config->vconfig->driver;
340                 File *file;
341                 Asset *asset;
343                 if(use_brender)
344                 {
345                         asset = renderengine->preferences->brender_asset;
346                 }
347                 else
348                 {
349                         asset = playable_edit->asset;
350                 }
352                 file = renderengine->get_vcache()->check_out(asset,
353                         renderengine->edl);
355                 if(file)
356                 {
357                         colormodel = file->get_best_colormodel(driver);
358                         renderengine->get_vcache()->check_in(asset);
359                 }
360         }
362         return colormodel;
371 void VRender::run()
373         int reconfigure;
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;
389         first_frame = 1;
391 // Number of frames since start of rendering
392         session_frame = 0;
393         framerate_counter = 0;
394         framerate_timer.update();
396         start_lock->unlock();
399         while(!done && 
400                 !renderengine->video->interrupt && 
401                 !last_playback)
402         {
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,
410                         last_playback);
412                 if(reconfigure) restart_playback();
414 SET_TRACE
415                 process_buffer(current_position);
416 SET_TRACE
418                 if(renderengine->command->single_frame())
419                 {
420                         flash_output();
421                         frame_step = 1;
422                         done = 1;
423                 }
424                 else
425 // Perform synchronization
426                 {
427 SET_TRACE
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);
439 SET_TRACE
441                         if(first_frame || end_sample < current_sample)
442                         {
443 SET_TRACE
444 // Frame rendered late or this is the first frame.  Flash it now.
445                                 flash_output();
446 SET_TRACE
448                                 if(renderengine->edl->session->video_every_frame)
449                                 {
450 // User wants every frame.
451                                         frame_step = 1;
452                                 }
453                                 else
454                                 if(skip_countdown > 0)
455                                 {
456 // Maybe just a freak.
457                                         frame_step = 1;
458                                         skip_countdown--;
459                                 }
460                                 else
461                                 {
462 // Get the frames to skip.
463                                         delay_countdown = VRENDER_THRESHOLD;
464                                         frame_step = 1;
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);
471                                 }
472                         }
473                         else
474                         {
475 // Frame rendered early or just in time.
476                                 frame_step = 1;
477 SET_TRACE
479                                 if(delay_countdown > 0)
480                                 {
481 // Maybe just a freak
482                                         delay_countdown--;
483                                 }
484                                 else
485                                 {
486                                         skip_countdown = VRENDER_THRESHOLD;
487                                         if(start_sample > current_sample)
488                                         {
489 SET_TRACE
490                                                 int64_t delay_time = (int64_t)((float)(start_sample - current_sample) * 
491                                                         1000 / 
492                                                         renderengine->edl->session->sample_rate);
493 SET_TRACE
494                                                 timer.delay(delay_time);
495 SET_TRACE
496                                         }
497                                         else
498                                         {
499 // Came after the earliest sample so keep going
500                                         }
501                                 }
503 // Flash frame now.
504 SET_TRACE
505                                 flash_output();
506 SET_TRACE
507                         }
508                 }
510 // Trigger audio to start
511                 if(first_frame)
512                 {
513                         renderengine->first_frame_lock->unlock();
514                         first_frame = 0;
515                         renderengine->reset_sync_position();
516                 }
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)
526                 {
527 // set last_playback if necessary and trim current_input_length to range
528                         get_boundaries(current_input_length);
529 // advance 1 frame
530                         advance_position(current_input_length);
531                         frame_step -= current_input_length;
532                         current_input_length = frame_step;
533                 }
535 // Update tracking.
536                 if(renderengine->command->realtime &&
537                         renderengine->playback_engine &&
538                         renderengine->command->command != CURRENT_FRAME)
539                 {
540                         renderengine->playback_engine->update_tracking(fromunits(current_position));
541                 }
543 // Calculate the framerate counter
544                 framerate_counter++;
545                 if(framerate_counter >= renderengine->edl->session->frame_rate && 
546                         renderengine->command->realtime)
547                 {
548                         renderengine->update_framerate((float)framerate_counter / 
549                                 ((float)framerate_timer.get_difference() / 1000));
550                         framerate_counter = 0;
551                         framerate_timer.update();
552                 }
553         }
555 SET_TRACE
556 // In case we were interrupted before the first loop
557         renderengine->first_frame_lock->unlock();
558         stop_plugins();
584 VRender::VRender(MWindow *mwindow, RenderEngine *renderengine)
585  : CommonRender(mwindow, renderengine)
587         input_length = 0;
588         vmodule_render_fragment = 0;
589         playback_buffer = 0;
590         session_frame = 0;
591         asynchronous = 0;     // render 1 frame at a time
592         framerate_counter = 0;
593         video_out = 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)
601         {
602                 video_out = 0;
603                 render_strategy = -1;
604         }
607 int VRender::get_datatype()
609         return TRACK_VIDEO;
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)
618         {
619                 start();
620         }
623 int VRender::wait_for_startup()
633 int64_t VRender::tounits(double position, int round)
635         if(round)
636                 return Units::round(position * renderengine->edl->session->frame_rate);
637         else
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;