r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / vrender.C
blob97c092adae52e0ac0e43fb0a7508c9128e7ef14e
1 #include "assets.h"
2 #include "cache.h"
3 #include "virtualconsole.h"
4 #include "datatype.h"
5 #include "edits.h"
6 #include "edl.h"
7 #include "edlsession.h"
8 #include "file.h"
9 #include "localsession.h"
10 #include "mwindow.h"
11 #include "playbackengine.h"
12 #include "playabletracks.h"
13 #include "preferences.h"
14 #include "preferencesthread.h"
15 #include "renderengine.h"
16 #include "mainsession.h"
17 #include "strategies.inc"
18 #include "units.h"
19 #include "tracks.h"
20 #include "transportque.h"
21 #include "vrender.h"
22 #include "vedit.h"
23 #include "vframe.h"
24 #include "videoconfig.h"
25 #include "videodevice.h"
26 #include "virtualvconsole.h"
27 #include "vmodule.h"
28 #include "vtrack.h"
34 VRender::VRender(RenderEngine *renderengine)
35  : CommonRender(renderengine)
37         data_type = TRACK_VIDEO;
40 VRender::~VRender()
45 VirtualConsole* VRender::new_vconsole_object() 
47         return new VirtualVConsole(renderengine, this);
50 int VRender::get_total_tracks()
52         return renderengine->edl->tracks->total_video_tracks();
55 Module* VRender::new_module(Track *track)
57 //printf("VRender::new_module\n");
58         return new VModule(renderengine, this, 0, track);
61 int VRender::flash_output()
63 //printf("VRender::flash_output 1\n");
64         return renderengine->video->write_buffer(video_out, renderengine->edl);
67 int VRender::process_buffer(VFrame **video_out, 
68         int64_t input_position, 
69         int last_buffer)
71 // process buffer for non realtime
72         int i, j;
73         int64_t render_len = 1;
74         int reconfigure = 0;
77 //printf("VRender::process_buffer 1\n");
78         for(i = 0; i < MAX_CHANNELS; i++)
79                 this->video_out[i] = video_out[i];
80         this->last_playback = last_buffer;
82         current_position = input_position;
83 //printf("VRender::process_buffer 2\n");
85 // test for automation configuration and shorten the fragment len if necessary
86         reconfigure = vconsole->test_reconfigure(input_position, 
87                 render_len,
88                 last_playback);
89 //printf("VRender::process_buffer 3\n");
91         if(reconfigure) restart_playback();
92 //printf("VRender::process_buffer 4\n");
93         return process_buffer(input_position);
97 int VRender::process_buffer(int64_t input_position)
99         Edit *playable_edit = 0;
100         int colormodel;
101         int use_vconsole = 1;
102         int use_brender = 0;
103         int result = 0;
104 //printf("VRender::process_buffer 1 %d\n", input_position);
106 // Determine the rendering strategy for this frame.
107         use_vconsole = get_use_vconsole(playable_edit, 
108                 input_position,
109                 use_brender);
111 // printf("VRender::process_buffer 1 %d %d %d\n", 
112 // input_position, 
113 // use_vconsole, 
114 // use_brender);
116 // Negotiate color model
117         colormodel = get_colormodel(playable_edit, use_vconsole, use_brender);
119 //printf("VRender::process_buffer 2 %p %d %d\n", renderengine->video, use_vconsole, colormodel);
120 // Get output buffer from device
121         if(renderengine->command->realtime)
122                 renderengine->video->new_output_buffers(video_out, colormodel);
124 //printf("VRender::process_buffer 3 %d %d\n", current_position, use_vconsole);
125 // Read directly from file to video_out
126         if(!use_vconsole)
127         {
129 //printf("VRender::process_buffer 4 %d %p %p %p\n", 
130 //current_position, renderengine->get_vcache(), playable_edit, video_out[0]);    
131                 if(use_brender)
132                 {
133 //printf("VRender::process_buffer 4.1\n");
134                         Asset *asset = renderengine->preferences->brender_asset;
135                         File *file = renderengine->get_vcache()->check_out(asset);
136                         if(file)
137                         {
138                                 int64_t corrected_position = current_position;
139                                 if(renderengine->command->get_direction() == PLAY_REVERSE)
140                                         corrected_position--;
142                                 file->set_video_position(corrected_position, 
143                                         renderengine->edl->session->frame_rate);
144                                 file->read_frame(video_out[0]);
145                                 renderengine->get_vcache()->check_in(asset);
146                         }
147                 }
148                 else
149                 if(playable_edit)
150                 {
151 //printf("VRender::process_buffer 4.2\n");
152                         result = ((VEdit*)playable_edit)->read_frame(video_out[0], 
153                                 current_position, 
154                                 renderengine->command->get_direction(),
155                                 renderengine->get_vcache());
156 //printf("VRender::process_buffer 4.3\n");
157                 }
159 //printf("VRender::process_buffer 5\n");
160 //for(int j = video_out[0]->get_w() * 3 * 5; j < video_out[0]->get_w() * 3 * 10; j += 2)
161 //      ((u_int16_t*)video_out[0]->get_rows()[0])[j] = 0xffff;
162         }
163         else
164 // Read into virtual console
165         {
167 //printf("VRender::process_buffer 6 %d\n", input_position);
168 // process this buffer now in the virtual console
169                 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position);
171 //printf("VRender::process_buffer 7\n");
172         }
175 //printf("VRender::process_buffer 8\n");
176         return result;
179 // Determine if virtual console is needed
180 int VRender::get_use_vconsole(Edit* &playable_edit, 
181         int64_t position,
182         int &use_brender)
184         Track *playable_track;
187 // Background rendering completed
188         if((use_brender = renderengine->brender_available(position, 
189                 renderengine->command->get_direction())) != 0) 
190                 return 0;
194 //printf("VRender::get_use_vconsole 1\n");
195 // Total number of playable tracks is 1
196         if(vconsole->total_tracks != 1) return 1;
198         playable_track = vconsole->playable_tracks->values[0];
199 //printf("VRender::get_use_vconsole 2\n");
201 // Test mutual conditions between render.C and this.
202         if(!playable_track->direct_copy_possible(position, renderengine->command->get_direction()))
203                 return 1;
205 //printf("VRender::get_use_vconsole 3\n");
206         playable_edit = playable_track->edits->editof(position, renderengine->command->get_direction());
207 // No edit at current location
208         if(!playable_edit) return 1;
210 // Edit is silence
211         if(!playable_edit->asset) return 1;
212 //printf("VRender::get_use_vconsole 4\n");
214 // Asset and output device must have the same dimensions
215         if(playable_edit->asset->width != renderengine->edl->session->output_w ||
216                 playable_edit->asset->height != renderengine->edl->session->output_h)
217                 return 1;
218 //printf("VRender::get_use_vconsole 5\n");
220 // If we get here the frame is going to be directly copied.  Whether it is
221 // decompressed in hardware depends on the colormodel.
222         return 0;
225 int VRender::get_colormodel(Edit* &playable_edit, 
226         int use_vconsole,
227         int use_brender)
229         int colormodel = renderengine->edl->session->color_model;
231 //printf("VRender::get_colormodel 1\n");
232         if(!use_vconsole && !renderengine->command->single_frame())
233         {
234 // Get best colormodel supported by the file
235                 int driver = renderengine->config->vconfig->driver;
236                 File *file;
237                 Asset *asset;
239                 if(use_brender)
240                 {
241                         asset = renderengine->preferences->brender_asset;
242                 }
243                 else
244                 {
245                         asset = playable_edit->asset;
246                 }
248 //printf("VRender::get_colormodel 1\n");
249                 file = renderengine->get_vcache()->check_out(asset);
250 //printf("VRender::get_colormodel 10\n");
252                 if(file)
253                 {
254 //printf("VRender::get_colormodel 20n");
255                         colormodel = file->get_best_colormodel(driver);
256 //printf("VRender::get_colormodel 30\n");
257                         renderengine->get_vcache()->check_in(asset);
258 //printf("VRender::get_colormodel 40\n");
259                 }
260         }
261 //printf("VRender::get_colormodel 100\n");
262         return colormodel;
271 void VRender::run()
273         int reconfigure;
274 //printf("VRender:run 1\n");
276 // Want to know how many samples rendering each frame takes.
277 // Then use this number to predict the next frame that should be rendered.
278 // Be suspicious of frames that render late so have a countdown
279 // before we start dropping.
280         int64_t current_sample, start_sample, end_sample; // Absolute counts.
281         int64_t next_frame;  // Actual position.
282         int64_t last_delay = 0;  // delay used before last frame
283         int64_t skip_countdown = VRENDER_THRESHOLD;    // frames remaining until drop
284         int64_t delay_countdown = VRENDER_THRESHOLD;  // Frames remaining until delay
285 // Number of frames before next reconfigure
286         int64_t current_input_length;
287 // Number of frames to skip.
288         int64_t frame_step = 1;
290 // Number of frames since start of rendering
291         session_frame = 0;
292         framerate_counter = 0;
293         framerate_timer.update();
295         start_lock.unlock();
298 //printf("VRender:run 2 %d %d %d\n", done, renderengine->video->interrupt, last_playback);
299         while(!done && 
300                 !renderengine->video->interrupt && 
301                 !last_playback)
302         {
303 // Perform the most time consuming part of frame decompression now.
304 // Want the condition before, since only 1 frame is rendered 
305 // and the number of frames skipped after this frame varies.
306                 current_input_length = 1;    // 1 frame
308 //printf("VRender:run 3 %d\n", current_position);
309                 reconfigure = vconsole->test_reconfigure(current_position, 
310                         current_input_length,
311                         last_playback);
313 //printf("VRender:run 4 %d %d\n", current_position, reconfigure);
314                 if(reconfigure) restart_playback();
315 //printf("VRender:run 5 %p\n", renderengine);
317                 process_buffer(current_position);
318 //printf("VRender:run 6 %p %p\n", renderengine, renderengine->video);
320                 if(renderengine->command->single_frame())
321                 {
322 //printf("VRender:run 7 %d\n", current_position);
323                         flash_output();
324                         frame_step = 1;
325                         done = 1;
326 //printf("VRender:run 8 %d\n", current_position);
327                 }
328                 else
329 // Perform synchronization
330                 {
331 // Determine the delay until the frame needs to be shown.
332 //printf("VRender:run 9\n");
333                         current_sample = (int64_t)(renderengine->sync_position() * 
334                                 renderengine->command->get_speed());
335 // latest sample at which the frame can be shown.
336                         end_sample = Units::tosamples(session_frame, 
337                                 renderengine->edl->session->sample_rate, 
338                                 renderengine->edl->session->frame_rate);
339 // earliest sample by which the frame needs to be shown.
340                         start_sample = Units::tosamples(session_frame - 1, 
341                                 renderengine->edl->session->sample_rate, 
342                                 renderengine->edl->session->frame_rate);
343 //printf("VRender:run 9 current sample %d end sample %d start sample %d\n", current_sample, end_sample, start_sample);
344 //printf("VRender:run 10 everyframe %d\n", renderengine->edl->session->video_every_frame);
346 // Straight from XMovie
347                         if(end_sample < current_sample)
348                         {
349 // Frame rendered late.  Flash it now.
350                                 flash_output();
352                                 if(renderengine->edl->session->video_every_frame)
353                                 {
354 // User wants every frame.
355                                         frame_step = 1;
356                                 }
357                                 else
358                                 if(skip_countdown > 0)
359                                 {
360 // Maybe just a freak.
361                                         frame_step = 1;
362                                         skip_countdown--;
363                                 }
364                                 else
365                                 {
366 // Get the frames to skip.
367                                         delay_countdown = VRENDER_THRESHOLD;
368                                         frame_step = 1;
369                                         frame_step += (int64_t)Units::toframes(current_sample, 
370                                                         renderengine->edl->session->sample_rate, 
371                                                         renderengine->edl->session->frame_rate);
372                                         frame_step -= (int64_t)Units::toframes(end_sample, 
373                                                                 renderengine->edl->session->sample_rate, 
374                                                                 renderengine->edl->session->frame_rate);
375                                 }
376 //printf("VRender:run 11 frame_step %d\n", frame_step);
377                         }
378                         else
379                         {
380 // Frame rendered early or just in time.
381                                 frame_step = 1;
383                                 if(delay_countdown > 0)
384                                 {
385 // Maybe just a freak
386                                         delay_countdown--;
387                                 }
388                                 else
389                                 {
390                                         skip_countdown = VRENDER_THRESHOLD;
391                                         if(start_sample > current_sample)
392                                         {
393 // Came before the earliest sample so delay
394                                                 timer.delay((int64_t)((float)(start_sample - current_sample) * 
395                                                         1000 / 
396                                                         renderengine->edl->session->sample_rate));
397                                         }
398                                         else
399                                         {
400 // Came after the earliest sample so keep going
401                                         }
402                                 }
404 // Flash frame now.
405                                 flash_output();
406                         }
407 //printf("VRender:run 11\n");
408                 }
410 //printf("VRender:run 12 %d\n", current_position);
412                 session_frame += frame_step;
413 //printf("VRender:run 13 %d %d\n", frame_step, last_playback);
415 // advance position in project
416                 current_input_length = frame_step;
417 // Subtract frame_step in a loop to allow looped playback to drain
418                 while(frame_step && current_input_length && !last_playback)
419                 {
420 // set last_playback if necessary and trim current_input_length to range
421 //printf("VRender:run 14 %d %d\n", current_input_length, renderengine->edl->local_session->loop_playback);
422                         get_boundaries(current_input_length);
423 //printf("VRender:run 15 %d %d %d\n", frame_step, current_input_length, last_playback);
424 // advance 1 frame
425 //sleep(1);
426                         advance_position(current_input_length);
427 //printf("VRender:run 16 %d %d\n", frame_step, last_playback);
428                         frame_step -= current_input_length;
429                         current_input_length = frame_step;
430                 }
432 // Update tracking.
433                 if(renderengine->command->realtime &&
434                         renderengine->playback_engine &&
435                         renderengine->command->command != CURRENT_FRAME)
436                 {
437 //printf("VRender:run 17 %d\n", current_position);
438                         renderengine->playback_engine->update_tracking(fromunits(current_position));
439                 }
441 // Calculate the framerate counter
442                 framerate_counter++;
443                 if(framerate_counter >= renderengine->edl->session->frame_rate && 
444                         renderengine->command->realtime)
445                 {
446 //printf("VRender::run 1\n");
447                         renderengine->update_framerate((float)framerate_counter / 
448                                 ((float)framerate_timer.get_difference() / 1000));
449 //printf("VRender::run 2\n");
450                         framerate_counter = 0;
451                         framerate_timer.update();
452                 }
453 //printf("VRender:run 13\n");
454         }
456 //printf("VRender:run 14\n");
482 VRender::VRender(MWindow *mwindow, RenderEngine *renderengine)
483  : CommonRender(mwindow, renderengine)
485         input_length = 0;
486         vmodule_render_fragment = 0;
487         playback_buffer = 0;
488         session_frame = 0;
489         asynchronous = 0;     // render 1 frame at a time
490         framerate_counter = 0;
491         video_out[0] = 0;
492         render_strategy = -1;
495 int VRender::init_device_buffers()
497 // allocate output buffer if there is a video device
498         if(renderengine->video)
499         {
500                 video_out[0] = 0;
501                 render_strategy = -1;
502         }
505 int VRender::get_datatype()
507         return TRACK_VIDEO;
511 int VRender::start_playback()
513 // start reading input and sending to vrenderthread
514 // use a thread only if there's a video device
515         if(renderengine->command->realtime)
516         {
517                 start();
518         }
521 int VRender::wait_for_startup()
531 int64_t VRender::tounits(double position, int round)
533         if(round)
534                 return Units::round(position * renderengine->edl->session->frame_rate);
535         else
536                 return Units::to_int64(position * renderengine->edl->session->frame_rate);
539 double VRender::fromunits(int64_t position)
541         return (double)position / renderengine->edl->session->frame_rate;