r851: Merge 2.1:
[cinelerra_cv/ct.git] / cinelerra / vrender.C
blobc47c240930b6258209fd8d3242389c238368b287
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         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, 
94                 render_len,
95                 last_playback);
97         if(reconfigure) restart_playback();
98         return process_buffer(input_position);
102 int VRender::process_buffer(int64_t input_position)
104 SET_TRACE
105         Edit *playable_edit = 0;
106         int colormodel;
107         int use_vconsole = 1;
108         int use_brender = 0;
109         int result = 0;
110 SET_TRACE
112 // Determine the rendering strategy for this frame.
113         use_vconsole = get_use_vconsole(playable_edit, 
114                 input_position,
115                 use_brender);
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", 
126 // use_vconsole, 
127 // colormodel,
128 // video_out);
129 // Read directly from file to video_out
130         if(!use_vconsole)
131         {
133                 if(use_brender)
134                 {
135 SET_TRACE
136                         Asset *asset = renderengine->preferences->brender_asset;
137                         File *file = renderengine->get_vcache()->check_out(asset);
138                         if(file)
139                         {
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);
153                         }
154 SET_TRACE
155                 }
156                 else
157                 if(playable_edit)
158                 {
159                         result = ((VEdit*)playable_edit)->read_frame(video_out[0], 
160                                 current_position, 
161                                 renderengine->command->get_direction(),
162                                 renderengine->get_vcache(),
163                                 1,
164                                 renderengine->command->single_frame());
165                                                 /* Insert timecode */
166                         if(renderengine->show_tc)
167                                 insert_timecode(playable_edit,
168                                         input_position,
169                                         video_out[0]);
170                 }
171         }
172         else
173 // Read into virtual console
174         {
176 // process this buffer now in the virtual console
177                 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position);
178         }
181         return result;
184 // Determine if virtual console is needed
185 int VRender::get_use_vconsole(Edit* &playable_edit, 
186         int64_t position,
187         int &use_brender)
189         Track *playable_track;
192 // Background rendering completed
193         if((use_brender = renderengine->brender_available(position, 
194                 renderengine->command->get_direction())) != 0) 
195                 return 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(),
207                 1))
208                 return 1;
210         playable_edit = playable_track->edits->editof(position, 
211                 renderengine->command->get_direction(),
212                 1);
213 // No edit at current location
214         if(!playable_edit) return 1;
216 // Edit is silence
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)
222                 return 1;
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)
230                 return 1;
232 // If we get here the frame is going to be directly copied.  Whether it is
233 // decompressed in hardware depends on the colormodel.
234         return 0;
238 int VRender::insert_timecode(Edit* &playable_edit,
239                         int64_t position,
240                         VFrame *output)
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,
246                                                                 output->get_w(),
247                                                                 MIN(output->get_h(), 50),
248                                                                 output->get_color_model(),
249                                                                 output->get_bytes_per_line());
250         char etc[12];
251         char srctc[12];
252         int src_position = 0;
254 TRACE("VRender::insert_timecode 10")
256         /* Edited TC */
257         Units::totext(etc,
258                 (renderengine->vrender->current_position +
259                         session->get_frame_offset()) / session->frame_rate,
260                 session->time_format,
261                 session->sample_rate,
262                 session->frame_rate,
263                 session->frames_per_foot);
265 TRACE("VRender::insert_timecode 20")
267         if(playable_edit)
268         {
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")
275                 Units::totext(srctc,
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);
281         }
282         else
283         {
284 TRACE("VRender::insert_timecode 50")
285                 Units::totext(srctc,
286                         0.0,
287 //                      (renderengine->vrender->current_position - position) / session->frame_rate,
288                         session->time_format,
289                         session->sample_rate,
290                         session->frame_rate,
291                         session->frames_per_foot);
292         }
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 */
300         
301         
304         vrender->overlayer->overlay(output, 
305                 input,
306                 input->x, 
307                 input->y, 
308                 input->width, 
309                 input->height,
310                 output->x, 
311                 output->y, 
312                 output->width, 
313                 output->height, 
314                 1,
315                 TRANSFER_REPLACE, 
316                 renderengine->edl->session->interpolation_type);
318         delete(input);
319 UNTRACE
323 int VRender::get_colormodel(Edit* &playable_edit, 
324         int use_vconsole,
325         int use_brender)
327         int colormodel = renderengine->edl->session->color_model;
329         if(!use_vconsole && !renderengine->command->single_frame())
330         {
331 // Get best colormodel supported by the file
332                 int driver = renderengine->config->vconfig->driver;
333                 File *file;
334                 Asset *asset;
336                 if(use_brender)
337                 {
338                         asset = renderengine->preferences->brender_asset;
339                 }
340                 else
341                 {
342                         asset = playable_edit->asset;
343                 }
345                 file = renderengine->get_vcache()->check_out(asset);
347                 if(file)
348                 {
349                         colormodel = file->get_best_colormodel(driver);
350                         renderengine->get_vcache()->check_in(asset);
351                 }
352         }
354         return colormodel;
363 void VRender::run()
365         int reconfigure;
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;
381         first_frame = 1;
383 // Number of frames since start of rendering
384         session_frame = 0;
385         framerate_counter = 0;
386         framerate_timer.update();
388         start_lock->unlock();
391         while(!done && 
392                 !renderengine->video->interrupt && 
393                 !last_playback)
394         {
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,
402                         last_playback);
404                 if(reconfigure) restart_playback();
406 SET_TRACE
407                 process_buffer(current_position);
408 SET_TRACE
410                 if(renderengine->command->single_frame())
411                 {
412                         flash_output();
413                         frame_step = 1;
414                         done = 1;
415                 }
416                 else
417 // Perform synchronization
418                 {
419 SET_TRACE
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);
431 SET_TRACE
433                         if(first_frame || end_sample < current_sample)
434                         {
435 SET_TRACE
436 // Frame rendered late or this is the first frame.  Flash it now.
437                                 flash_output();
438 SET_TRACE
440                                 if(renderengine->edl->session->video_every_frame)
441                                 {
442 // User wants every frame.
443                                         frame_step = 1;
444                                 }
445                                 else
446                                 if(skip_countdown > 0)
447                                 {
448 // Maybe just a freak.
449                                         frame_step = 1;
450                                         skip_countdown--;
451                                 }
452                                 else
453                                 {
454 // Get the frames to skip.
455                                         delay_countdown = VRENDER_THRESHOLD;
456                                         frame_step = 1;
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);
463                                 }
464                         }
465                         else
466                         {
467 // Frame rendered early or just in time.
468                                 frame_step = 1;
469 SET_TRACE
471                                 if(delay_countdown > 0)
472                                 {
473 // Maybe just a freak
474                                         delay_countdown--;
475                                 }
476                                 else
477                                 {
478                                         skip_countdown = VRENDER_THRESHOLD;
479                                         if(start_sample > current_sample)
480                                         {
481 SET_TRACE
482                                                 int64_t delay_time = (int64_t)((float)(start_sample - current_sample) * 
483                                                         1000 / 
484                                                         renderengine->edl->session->sample_rate);
485 SET_TRACE
486                                                 timer.delay(delay_time);
487 SET_TRACE
488                                         }
489                                         else
490                                         {
491 // Came after the earliest sample so keep going
492                                         }
493                                 }
495 // Flash frame now.
496 SET_TRACE
497                                 flash_output();
498 SET_TRACE
499                         }
500                 }
502 // Trigger audio to start
503                 if(first_frame)
504                 {
505                         renderengine->first_frame_lock->unlock();
506                         first_frame = 0;
507                         renderengine->reset_sync_position();
508                 }
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)
518                 {
519 // set last_playback if necessary and trim current_input_length to range
520                         get_boundaries(current_input_length);
521 // advance 1 frame
522                         advance_position(current_input_length);
523                         frame_step -= current_input_length;
524                         current_input_length = frame_step;
525                 }
527 // Update tracking.
528                 if(renderengine->command->realtime &&
529                         renderengine->playback_engine &&
530                         renderengine->command->command != CURRENT_FRAME)
531                 {
532                         renderengine->playback_engine->update_tracking(fromunits(current_position));
533                 }
535 // Calculate the framerate counter
536                 framerate_counter++;
537                 if(framerate_counter >= renderengine->edl->session->frame_rate && 
538                         renderengine->command->realtime)
539                 {
540                         renderengine->update_framerate((float)framerate_counter / 
541                                 ((float)framerate_timer.get_difference() / 1000));
542                         framerate_counter = 0;
543                         framerate_timer.update();
544                 }
545         }
547 SET_TRACE
548 // In case we were interrupted before the first loop
549         renderengine->first_frame_lock->unlock();
550         stop_plugins();
576 VRender::VRender(MWindow *mwindow, RenderEngine *renderengine)
577  : CommonRender(mwindow, renderengine)
579         input_length = 0;
580         vmodule_render_fragment = 0;
581         playback_buffer = 0;
582         session_frame = 0;
583         asynchronous = 0;     // render 1 frame at a time
584         framerate_counter = 0;
585         video_out[0] = 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)
593         {
594                 video_out[0] = 0;
595                 render_strategy = -1;
596         }
599 int VRender::get_datatype()
601         return TRACK_VIDEO;
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)
610         {
611                 start();
612         }
615 int VRender::wait_for_startup()
625 int64_t VRender::tounits(double position, int round)
627         if(round)
628                 return Units::round(position * renderengine->edl->session->frame_rate);
629         else
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;