r807: Minor fix...
[cinelerra_cv/mob.git] / cinelerra / vrender.C
blobd659a2d6c15cd489813ce83bb812e7f56e74fa43
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         Edit *playable_edit = 0;
105         int colormodel;
106         int use_vconsole = 1;
107         int use_brender = 0;
108         int result = 0;
109 SET_TRACE
111 // Determine the rendering strategy for this frame.
112         use_vconsole = get_use_vconsole(playable_edit, 
113                 input_position,
114                 use_brender);
116 SET_TRACE
117 // Negotiate color model
118         colormodel = get_colormodel(playable_edit, use_vconsole, use_brender);
119 SET_TRACE
121 // Get output buffer from device
122         if(renderengine->command->realtime)
123                 renderengine->video->new_output_buffers(video_out, colormodel);
124 SET_TRACE
125 // Read directly from file to video_out
126         if(!use_vconsole)
127         {
129                 if(use_brender)
130                 {
131                         Asset *asset = renderengine->preferences->brender_asset;
132                         File *file = renderengine->get_vcache()->check_out(asset);
133                         if(file)
134                         {
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);
148                         }
149                 }
150                 else
151                 if(playable_edit)
152                 {
153                         result = ((VEdit*)playable_edit)->read_frame(video_out[0], 
154                                 current_position, 
155                                 renderengine->command->get_direction(),
156                                 renderengine->get_vcache(),
157                                 1,
158                                 renderengine->command->single_frame());
159                                                 /* Insert timecode */
160                         if(renderengine->show_tc)
161                                 insert_timecode(playable_edit,
162                                         input_position,
163                                         video_out[0]);
164                 }
165         }
166         else
167 // Read into virtual console
168         {
170 // process this buffer now in the virtual console
171 SET_TRACE
172                 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position);
173 SET_TRACE
174         }
177         return result;
180 // Determine if virtual console is needed
181 int VRender::get_use_vconsole(Edit* &playable_edit, 
182         int64_t position,
183         int &use_brender)
185         Track *playable_track;
188 // Background rendering completed
189         if((use_brender = renderengine->brender_available(position, 
190                 renderengine->command->get_direction())) != 0) 
191                 return 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(),
203                 1))
204                 return 1;
206         playable_edit = playable_track->edits->editof(position, 
207                 renderengine->command->get_direction(),
208                 1);
209 // No edit at current location
210         if(!playable_edit) return 1;
212 // Edit is silence
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)
218                 return 1;
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)
226                 return 1;
228 // If we get here the frame is going to be directly copied.  Whether it is
229 // decompressed in hardware depends on the colormodel.
230         return 0;
234 int VRender::insert_timecode(Edit* &playable_edit,
235                         int64_t position,
236                         VFrame *output)
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,
242                                                                 output->get_w(),
243                                                                 MIN(output->get_h(), 50),
244                                                                 output->get_color_model(),
245                                                                 output->get_bytes_per_line());
246         char etc[12];
247         char srctc[12];
248         int src_position = 0;
250 TRACE("VRender::insert_timecode 10")
252         /* Edited TC */
253         Units::totext(etc,
254                 (renderengine->vrender->current_position +
255                         session->get_frame_offset()) / session->frame_rate,
256                 session->time_format,
257                 session->sample_rate,
258                 session->frame_rate,
259                 session->frames_per_foot);
261 TRACE("VRender::insert_timecode 20")
263         if(playable_edit)
264         {
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")
271                 Units::totext(srctc,
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);
277         }
278         else
279         {
280 TRACE("VRender::insert_timecode 50")
281                 Units::totext(srctc,
282                         0.0,
283 //                      (renderengine->vrender->current_position - position) / session->frame_rate,
284                         session->time_format,
285                         session->sample_rate,
286                         session->frame_rate,
287                         session->frames_per_foot);
288         }
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 */
296         
297         
300         vrender->overlayer->overlay(output, 
301                 input,
302                 input->x, 
303                 input->y, 
304                 input->width, 
305                 input->height,
306                 output->x, 
307                 output->y, 
308                 output->width, 
309                 output->height, 
310                 1,
311                 TRANSFER_REPLACE, 
312                 renderengine->edl->session->interpolation_type);
314         delete(input);
315 UNTRACE
319 int VRender::get_colormodel(Edit* &playable_edit, 
320         int use_vconsole,
321         int use_brender)
323 SET_TRACE
324         int colormodel = renderengine->edl->session->color_model;
326 SET_TRACE
327         if(!use_vconsole && !renderengine->command->single_frame())
328         {
329 // Get best colormodel supported by the file
330 SET_TRACE
331                 int driver = renderengine->config->vconfig->driver;
332 SET_TRACE
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 SET_TRACE
346                 file = renderengine->get_vcache()->check_out(asset);
347 SET_TRACE
349                 if(file)
350                 {
351                         colormodel = file->get_best_colormodel(driver);
352                         renderengine->get_vcache()->check_in(asset);
353                 }
354 SET_TRACE
355         }
356         return colormodel;
365 void VRender::run()
367         int reconfigure;
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;
383         first_frame = 1;
385 // Number of frames since start of rendering
386         session_frame = 0;
387         framerate_counter = 0;
388         framerate_timer.update();
390         start_lock->unlock();
393         while(!done && 
394                 !renderengine->video->interrupt && 
395                 !last_playback)
396         {
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,
405                         last_playback);
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())
415                 {
416 //TRACE("VRender::run 2");
417                         flash_output();
418 //TRACE("VRender::run 3");
419                         frame_step = 1;
420                         done = 1;
421                 }
422                 else
423 // Perform synchronization
424                 {
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)
440                         {
441 // Frame rendered late or this is the first frame.  Flash it now.
442                                 flash_output();
444                                 if(renderengine->edl->session->video_every_frame)
445                                 {
446 // User wants every frame.
447                                         frame_step = 1;
448                                 }
449                                 else
450                                 if(skip_countdown > 0)
451                                 {
452 // Maybe just a freak.
453                                         frame_step = 1;
454                                         skip_countdown--;
455                                 }
456                                 else
457                                 {
458 // Get the frames to skip.
459                                         delay_countdown = VRENDER_THRESHOLD;
460                                         frame_step = 1;
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);
467                                 }
468 //TRACE("VRender::run 3");
469 //printf("VRender:run 11 frame_step %d\n", frame_step);
470                         }
471                         else
472                         {
473 // Frame rendered early or just in time.
474                                 frame_step = 1;
475 //TRACE("VRender::run 4");
477                                 if(delay_countdown > 0)
478                                 {
479 // Maybe just a freak
480                                         delay_countdown--;
481                                 }
482                                 else
483                                 {
484                                         skip_countdown = VRENDER_THRESHOLD;
485                                         if(start_sample > current_sample)
486                                         {
487                                                 int64_t delay_time = (int64_t)((float)(start_sample - current_sample) * 
488                                                         1000 / 
489                                                         renderengine->edl->session->sample_rate);
490                                                 timer.delay(delay_time);
491 //printf("VRender:run 10 %lld\n", delay_time);
492                                         }
493                                         else
494                                         {
495 // Came after the earliest sample so keep going
496                                         }
497                                 }
499 //TRACE("VRender::run 5");
500 // Flash frame now.
501                                 flash_output();
502 //TRACE("VRender::run 6");
503                         }
504                 }
506 // Trigger audio to start
507                 if(first_frame)
508                 {
509                         renderengine->first_frame_lock->unlock();
510                         first_frame = 0;
511                         renderengine->reset_sync_position();
512                 }
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)
523                 {
524 // set last_playback if necessary and trim current_input_length to range
525                         get_boundaries(current_input_length);
526 // advance 1 frame
527                         advance_position(current_input_length);
528                         frame_step -= current_input_length;
529                         current_input_length = frame_step;
530                 }
531 TRACE("VRender::run 6");
533 // Update tracking.
534                 if(renderengine->command->realtime &&
535                         renderengine->playback_engine &&
536                         renderengine->command->command != CURRENT_FRAME)
537                 {
538                         renderengine->playback_engine->update_tracking(fromunits(current_position));
539                 }
541 TRACE("VRender::run 7");
542 // Calculate the framerate counter
543                 framerate_counter++;
544                 if(framerate_counter >= renderengine->edl->session->frame_rate && 
545                         renderengine->command->realtime)
546                 {
547                         renderengine->update_framerate((float)framerate_counter / 
548                                 ((float)framerate_timer.get_difference() / 1000));
549                         framerate_counter = 0;
550                         framerate_timer.update();
551                 }
552 TRACE("VRender::run 8");
553         }
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)
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] = 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] = 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;