r136: This commit was manufactured by cvs2svn to create tag 'hv_1_1_8'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / vrender.C
blobe700253f4038aab52de562df758df86b52fd83af
1 #include "asset.h"
2 #include "cache.h"
3 #include "condition.h"
4 #include "virtualconsole.h"
5 #include "datatype.h"
6 #include "edits.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "file.h"
10 #include "localsession.h"
11 #include "mwindow.h"
12 #include "playbackengine.h"
13 #include "playabletracks.h"
14 #include "preferences.h"
15 #include "preferencesthread.h"
16 #include "renderengine.h"
17 #include "mainsession.h"
18 #include "strategies.inc"
19 #include "units.h"
20 #include "tracks.h"
21 #include "transportque.h"
22 #include "vrender.h"
23 #include "vedit.h"
24 #include "vframe.h"
25 #include "videoconfig.h"
26 #include "videodevice.h"
27 #include "virtualvconsole.h"
28 #include "vmodule.h"
29 #include "vtrack.h"
35 VRender::VRender(RenderEngine *renderengine)
36  : CommonRender(renderengine)
38         data_type = TRACK_VIDEO;
41 VRender::~VRender()
46 VirtualConsole* VRender::new_vconsole_object() 
48         return new VirtualVConsole(renderengine, this);
51 int VRender::get_total_tracks()
53         return renderengine->edl->tracks->total_video_tracks();
56 Module* VRender::new_module(Track *track)
58         return new VModule(renderengine, this, 0, track);
61 int VRender::flash_output()
63         return renderengine->video->write_buffer(video_out, renderengine->edl);
66 int VRender::process_buffer(VFrame **video_out, 
67         int64_t input_position, 
68         int last_buffer)
70 // process buffer for non realtime
71         int i, j;
72         int64_t render_len = 1;
73         int reconfigure = 0;
76         for(i = 0; i < MAX_CHANNELS; i++)
77                 this->video_out[i] = video_out[i];
78         this->last_playback = last_buffer;
80         current_position = input_position;
82 // test for automation configuration and shorten the fragment len if necessary
83         reconfigure = vconsole->test_reconfigure(input_position, 
84                 render_len,
85                 last_playback);
87         if(reconfigure) restart_playback();
88         return process_buffer(input_position);
92 int VRender::process_buffer(int64_t input_position)
94         Edit *playable_edit = 0;
95         int colormodel;
96         int use_vconsole = 1;
97         int use_brender = 0;
98         int result = 0;
100 // Determine the rendering strategy for this frame.
101         use_vconsole = get_use_vconsole(playable_edit, 
102                 input_position,
103                 use_brender);
106 // Negotiate color model
107         colormodel = get_colormodel(playable_edit, use_vconsole, use_brender);
109 // Get output buffer from device
110         if(renderengine->command->realtime)
111                 renderengine->video->new_output_buffers(video_out, colormodel);
113 // Read directly from file to video_out
114         if(!use_vconsole)
115         {
117                 if(use_brender)
118                 {
119                         Asset *asset = renderengine->preferences->brender_asset;
120                         File *file = renderengine->get_vcache()->check_out(asset);
121                         if(file)
122                         {
123                                 int64_t corrected_position = current_position;
124                                 if(renderengine->command->get_direction() == PLAY_REVERSE)
125                                         corrected_position--;
127                                 file->set_video_position(corrected_position, 
128                                         renderengine->edl->session->frame_rate);
129                                 file->read_frame(video_out[0]);
130                                 renderengine->get_vcache()->check_in(asset);
131                         }
132                 }
133                 else
134                 if(playable_edit)
135                 {
136 //printf("VRender::process_buffer 1 %d\n", current_position);
137                         result = ((VEdit*)playable_edit)->read_frame(video_out[0], 
138                                 current_position, 
139                                 renderengine->command->get_direction(),
140                                 renderengine->get_vcache(),
141                                 1);
142                 }
143         }
144         else
145 // Read into virtual console
146         {
148 // process this buffer now in the virtual console
149                 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position);
151         }
154         return result;
157 // Determine if virtual console is needed
158 int VRender::get_use_vconsole(Edit* &playable_edit, 
159         int64_t position,
160         int &use_brender)
162         Track *playable_track;
165 // Background rendering completed
166         if((use_brender = renderengine->brender_available(position, 
167                 renderengine->command->get_direction())) != 0) 
168                 return 0;
172 // Total number of playable tracks is 1
173         if(vconsole->total_tracks != 1) return 1;
175         playable_track = vconsole->playable_tracks->values[0];
177 // Test mutual conditions between render.C and this.
178         if(!playable_track->direct_copy_possible(position, 
179                 renderengine->command->get_direction(),
180                 1))
181                 return 1;
183         playable_edit = playable_track->edits->editof(position, 
184                 renderengine->command->get_direction(),
185                 1);
186 // No edit at current location
187         if(!playable_edit) return 1;
189 // Edit is silence
190         if(!playable_edit->asset) return 1;
192 // Asset and output device must have the same dimensions
193         if(playable_edit->asset->width != renderengine->edl->session->output_w ||
194                 playable_edit->asset->height != renderengine->edl->session->output_h)
195                 return 1;
197 // If we get here the frame is going to be directly copied.  Whether it is
198 // decompressed in hardware depends on the colormodel.
199         return 0;
202 int VRender::get_colormodel(Edit* &playable_edit, 
203         int use_vconsole,
204         int use_brender)
206         int colormodel = renderengine->edl->session->color_model;
208 //printf("VRender::get_colormodel 1\n");
209         if(!use_vconsole && !renderengine->command->single_frame())
210         {
211 // Get best colormodel supported by the file
212                 int driver = renderengine->config->vconfig->driver;
213                 File *file;
214                 Asset *asset;
216                 if(use_brender)
217                 {
218                         asset = renderengine->preferences->brender_asset;
219                 }
220                 else
221                 {
222                         asset = playable_edit->asset;
223                 }
225 //printf("VRender::get_colormodel 1\n");
226                 file = renderengine->get_vcache()->check_out(asset);
227 //printf("VRender::get_colormodel 10\n");
229                 if(file)
230                 {
231 //printf("VRender::get_colormodel 20n");
232                         colormodel = file->get_best_colormodel(driver);
233 //printf("VRender::get_colormodel 30\n");
234                         renderengine->get_vcache()->check_in(asset);
235 //printf("VRender::get_colormodel 40\n");
236                 }
237         }
238 //printf("VRender::get_colormodel 100\n");
239         return colormodel;
248 void VRender::run()
250         int reconfigure;
252 // Want to know how many samples rendering each frame takes.
253 // Then use this number to predict the next frame that should be rendered.
254 // Be suspicious of frames that render late so have a countdown
255 // before we start dropping.
256         int64_t current_sample, start_sample, end_sample; // Absolute counts.
257         int64_t next_frame;  // Actual position.
258         int64_t last_delay = 0;  // delay used before last frame
259         int64_t skip_countdown = VRENDER_THRESHOLD;    // frames remaining until drop
260         int64_t delay_countdown = VRENDER_THRESHOLD;  // Frames remaining until delay
261 // Number of frames before next reconfigure
262         int64_t current_input_length;
263 // Number of frames to skip.
264         int64_t frame_step = 1;
266 // Number of frames since start of rendering
267         session_frame = 0;
268         framerate_counter = 0;
269         framerate_timer.update();
271         start_lock->unlock();
274         while(!done && 
275                 !renderengine->video->interrupt && 
276                 !last_playback)
277         {
278 // Perform the most time consuming part of frame decompression now.
279 // Want the condition before, since only 1 frame is rendered 
280 // and the number of frames skipped after this frame varies.
281                 current_input_length = 1;
283                 reconfigure = vconsole->test_reconfigure(current_position, 
284                         current_input_length,
285                         last_playback);
287                 if(reconfigure) restart_playback();
289                 process_buffer(current_position);
291                 if(renderengine->command->single_frame())
292                 {
293                         flash_output();
294                         frame_step = 1;
295                         done = 1;
296                 }
297                 else
298 // Perform synchronization
299                 {
300 // Determine the delay until the frame needs to be shown.
301                         current_sample = (int64_t)(renderengine->sync_position() * 
302                                 renderengine->command->get_speed());
303 // latest sample at which the frame can be shown.
304                         end_sample = Units::tosamples(session_frame, 
305                                 renderengine->edl->session->sample_rate, 
306                                 renderengine->edl->session->frame_rate);
307 // earliest sample by which the frame needs to be shown.
308                         start_sample = Units::tosamples(session_frame - 1, 
309                                 renderengine->edl->session->sample_rate, 
310                                 renderengine->edl->session->frame_rate);
311 // printf("VRender:run 9 currentsample=%lld endsample=%lld startsample=%lld samplerate=%lld framerate=%f\n", 
312 // current_sample, 
313 // end_sample, 
314 // start_sample, 
315 // renderengine->edl->session->sample_rate,
316 // renderengine->edl->session->frame_rate);
318 // Straight from XMovie
319                         if(end_sample < current_sample)
320                         {
321 // Frame rendered late.  Flash it now.
322                                 flash_output();
324                                 if(renderengine->edl->session->video_every_frame)
325                                 {
326 // User wants every frame.
327                                         frame_step = 1;
328                                 }
329                                 else
330                                 if(skip_countdown > 0)
331                                 {
332 // Maybe just a freak.
333                                         frame_step = 1;
334                                         skip_countdown--;
335                                 }
336                                 else
337                                 {
338 // Get the frames to skip.
339                                         delay_countdown = VRENDER_THRESHOLD;
340                                         frame_step = 1;
341                                         frame_step += (int64_t)Units::toframes(current_sample, 
342                                                         renderengine->edl->session->sample_rate, 
343                                                         renderengine->edl->session->frame_rate);
344                                         frame_step -= (int64_t)Units::toframes(end_sample, 
345                                                                 renderengine->edl->session->sample_rate, 
346                                                                 renderengine->edl->session->frame_rate);
347                                 }
348 //printf("VRender:run 11 frame_step %d\n", frame_step);
349                         }
350                         else
351                         {
352 // Frame rendered early or just in time.
353                                 frame_step = 1;
355                                 if(delay_countdown > 0)
356                                 {
357 // Maybe just a freak
358                                         delay_countdown--;
359                                 }
360                                 else
361                                 {
362                                         skip_countdown = VRENDER_THRESHOLD;
363                                         if(start_sample > current_sample)
364                                         {
365                                                 int64_t delay_time = (int64_t)((float)(start_sample - current_sample) * 
366                                                         1000 / 
367                                                         renderengine->edl->session->sample_rate);
368                                                 timer.delay(delay_time);
369 //printf("VRender:run 10 %lld\n", delay_time);
370                                         }
371                                         else
372                                         {
373 // Came after the earliest sample so keep going
374                                         }
375 //printf("VRender:run 20\n");
376                                 }
378 // Flash frame now.
379                                 flash_output();
380                         }
381 //printf("VRender:run 11\n");
382                 }
384 //printf("VRender:run 12 %d\n", current_position);
386                 session_frame += frame_step;
387 //printf("VRender:run 13 %d %d\n", frame_step, last_playback);
389 // advance position in project
390                 current_input_length = frame_step;
393 // Subtract frame_step in a loop to allow looped playback to drain
394                 while(frame_step && current_input_length && !last_playback)
395                 {
396 // set last_playback if necessary and trim current_input_length to range
397                         get_boundaries(current_input_length);
398 // advance 1 frame
399                         advance_position(current_input_length);
400                         frame_step -= current_input_length;
401                         current_input_length = frame_step;
402                 }
404 // Update tracking.
405                 if(renderengine->command->realtime &&
406                         renderengine->playback_engine &&
407                         renderengine->command->command != CURRENT_FRAME)
408                 {
409 //printf("VRender:run 17 %d\n", current_position);
410                         renderengine->playback_engine->update_tracking(fromunits(current_position));
411                 }
413 // Calculate the framerate counter
414                 framerate_counter++;
415                 if(framerate_counter >= renderengine->edl->session->frame_rate && 
416                         renderengine->command->realtime)
417                 {
418 //printf("VRender::run 1\n");
419                         renderengine->update_framerate((float)framerate_counter / 
420                                 ((float)framerate_timer.get_difference() / 1000));
421 //printf("VRender::run 2\n");
422                         framerate_counter = 0;
423                         framerate_timer.update();
424                 }
425 //printf("VRender:run 13\n");
426         }
428 //printf("VRender:run 14\n");
454 VRender::VRender(MWindow *mwindow, RenderEngine *renderengine)
455  : CommonRender(mwindow, renderengine)
457         input_length = 0;
458         vmodule_render_fragment = 0;
459         playback_buffer = 0;
460         session_frame = 0;
461         asynchronous = 0;     // render 1 frame at a time
462         framerate_counter = 0;
463         video_out[0] = 0;
464         render_strategy = -1;
467 int VRender::init_device_buffers()
469 // allocate output buffer if there is a video device
470         if(renderengine->video)
471         {
472                 video_out[0] = 0;
473                 render_strategy = -1;
474         }
477 int VRender::get_datatype()
479         return TRACK_VIDEO;
483 int VRender::start_playback()
485 // start reading input and sending to vrenderthread
486 // use a thread only if there's a video device
487         if(renderengine->command->realtime)
488         {
489                 start();
490         }
493 int VRender::wait_for_startup()
503 int64_t VRender::tounits(double position, int round)
505         if(round)
506                 return Units::round(position * renderengine->edl->session->frame_rate);
507         else
508                 return Units::to_int64(position * renderengine->edl->session->frame_rate);
511 double VRender::fromunits(int64_t position)
513         return (double)position / renderengine->edl->session->frame_rate;