prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / vrender.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include "asset.h"
23 #include "bcsignals.h"
24 #include "cache.h"
25 #include "condition.h"
26 #include "datatype.h"
27 #include "edits.h"
28 #include "edl.h"
29 #include "edlsession.h"
30 #include "file.h"
31 #include "format.inc"
32 #include "localsession.h"
33 #include "mainsession.h"
34 #include "mwindow.h"
35 #include "overlayframe.h"
36 #include "playabletracks.h"
37 #include "playbackengine.h"
38 #include "preferences.h"
39 #include "preferencesthread.h"
40 #include "renderengine.h"
41 #include "strategies.inc"
42 #include "tracks.h"
43 #include "transportque.h"
44 #include "units.h"
45 #include "vedit.h"
46 #include "vframe.h"
47 #include "videoconfig.h"
48 #include "videodevice.h"
49 #include "virtualconsole.h"
50 #include "virtualvconsole.h"
51 #include "vmodule.h"
52 #include "vrender.h"
53 #include "vtrack.h"
54
55
56
57
58
59 VRender::VRender(RenderEngine *renderengine)
60  : CommonRender(renderengine)
61 {
62         data_type = TRACK_VIDEO;
63         transition_temp = 0;
64         overlayer = new OverlayFrame(renderengine->preferences->processors);
65         input_temp = 0;
66         vmodule_render_fragment = 0;
67         playback_buffer = 0;
68         session_frame = 0;
69         asynchronous = 0;     // render 1 frame at a time
70         framerate_counter = 0;
71         video_out = 0;
72         render_strategy = -1;
73 }
74
75 VRender::~VRender()
76 {
77         if(input_temp) delete input_temp;
78         if(transition_temp) delete transition_temp;
79         if(overlayer) delete overlayer;
80 }
81
82
83 VirtualConsole* VRender::new_vconsole_object() 
84 {
85         return new VirtualVConsole(renderengine, this);
86 }
87
88 int VRender::get_total_tracks()
89 {
90         return renderengine->get_edl()->tracks->total_video_tracks();
91 }
92
93 Module* VRender::new_module(Track *track)
94 {
95         return new VModule(renderengine, this, 0, track);
96 }
97
98 int VRender::flash_output()
99 {
100         if(video_out)
101                 return renderengine->video->write_buffer(video_out, renderengine->get_edl());
102         else
103                 return 0;
104 }
105
106 int VRender::process_buffer(VFrame *video_out, 
107         int64_t input_position,
108         int use_opengl)
109 {
110 // process buffer for non realtime
111         int64_t render_len = 1;
112         int reconfigure = 0;
113
114
115         this->video_out = video_out;
116
117         current_position = input_position;
118
119         reconfigure = vconsole->test_reconfigure(input_position, 
120                 render_len);
121
122         if(reconfigure) restart_playback();
123         return process_buffer(input_position, use_opengl);
124 }
125
126
127 int VRender::process_buffer(int64_t input_position,
128         int use_opengl)
129 {
130         VEdit *playable_edit = 0;
131         int colormodel;
132         int use_vconsole = 1;
133         int use_brender = 0;
134         int result = 0;
135         int use_cache = renderengine->command->single_frame();
136         int use_asynchronous = 
137                 renderengine->command->realtime && 
138                 renderengine->get_edl()->session->video_every_frame &&
139                 renderengine->get_edl()->session->video_asynchronous;
140         const int debug = 0;
141
142 // Determine the rendering strategy for this frame.
143         use_vconsole = get_use_vconsole(&playable_edit, 
144                 input_position,
145                 use_brender);
146         if(debug) printf("VRender::process_buffer %d use_vconsole=%d\n", __LINE__, use_vconsole);
147
148 // Negotiate color model
149         colormodel = get_colormodel(playable_edit, use_vconsole, use_brender);
150         if(debug) printf("VRender::process_buffer %d\n", __LINE__);
151
152
153
154
155 // Get output buffer from device
156         if(renderengine->command->realtime &&
157                 !renderengine->is_nested)
158         {
159                 renderengine->video->new_output_buffer(&video_out, colormodel);
160         }
161
162         if(debug) printf("VRender::process_buffer %d video_out=%p\n", __LINE__, video_out);
163
164 // printf("VRender::process_buffer use_vconsole=%d colormodel=%d video_out=%p\n", 
165 // use_vconsole, 
166 // colormodel,
167 // video_out);
168 // Read directly from file to video_out
169         if(!use_vconsole)
170         {
171
172                 if(use_brender)
173                 {
174                         Asset *asset = renderengine->preferences->brender_asset;
175                         File *file = renderengine->get_vcache()->check_out(asset,
176                                 renderengine->get_edl());
177
178                         if(file)
179                         {
180                                 int64_t corrected_position = current_position;
181                                 if(renderengine->command->get_direction() == PLAY_REVERSE)
182                                         corrected_position--;
183
184 // Cache single frames only
185                                 if(use_asynchronous)
186                                         file->start_video_decode_thread();
187                                 else
188                                         file->stop_video_thread();
189                                 if(use_cache) file->set_cache_frames(1);
190                                 int64_t normalized_position = (int64_t)(corrected_position *
191                                         asset->frame_rate /
192                                         renderengine->get_edl()->session->frame_rate);
193
194                                 file->set_video_position(normalized_position,
195                                         0);
196                                 file->read_frame(video_out);
197
198
199                                 if(use_cache) file->set_cache_frames(0);
200                                 renderengine->get_vcache()->check_in(asset);
201                         }
202
203                 }
204                 else
205                 if(playable_edit)
206                 {
207                         if(debug) printf("VRender::process_buffer %d\n", __LINE__);
208                         result = ((VEdit*)playable_edit)->read_frame(video_out, 
209                                 current_position, 
210                                 renderengine->command->get_direction(),
211                                 renderengine->get_vcache(),
212                                 1,
213                                 use_cache,
214                                 use_asynchronous);
215                         if(debug) printf("VRender::process_buffer %d\n", __LINE__);
216                 }
217
218
219
220                 video_out->set_opengl_state(VFrame::RAM);
221         }
222         else
223 // Read into virtual console
224         {
225
226 // process this buffer now in the virtual console
227                 result = ((VirtualVConsole*)vconsole)->process_buffer(input_position,
228                         use_opengl);
229         }
230
231         return result;
232 }
233
234 // Determine if virtual console is needed
235 int VRender::get_use_vconsole(VEdit* *playable_edit, 
236         int64_t position, int &use_brender)
237 {
238         *playable_edit = 0;
239
240 // Background rendering completed
241         if((use_brender = renderengine->brender_available(position, 
242                 renderengine->command->get_direction())) != 0) 
243                 return 0;
244
245 // Descend into EDL nest
246         return renderengine->get_edl()->get_use_vconsole(playable_edit,
247                 position, 
248                 renderengine->command->get_direction(),
249                 vconsole->playable_tracks);
250 }
251
252 int VRender::get_colormodel(VEdit *playable_edit, 
253         int use_vconsole, int use_brender)
254 {
255         int colormodel = renderengine->get_edl()->session->color_model;
256
257         if(!use_vconsole && !renderengine->command->single_frame())
258         {
259 // Get best colormodel supported by the file
260                 int driver = renderengine->config->vconfig->driver;
261                 File *file;
262                 Asset *asset;
263
264                 if(use_brender)
265                 {
266                         asset = renderengine->preferences->brender_asset;
267                 }
268                 else
269                 {
270                         int64_t source_position = 0;
271                         asset = playable_edit->get_nested_asset(&source_position,
272                                 current_position,
273                                 renderengine->command->get_direction());
274                 }
275
276                 if(asset)
277                 {
278                         file = renderengine->get_vcache()->check_out(asset,
279                                 renderengine->get_edl());
280
281                         if(file)
282                         {
283                                 colormodel = file->get_best_colormodel(driver);
284                                 renderengine->get_vcache()->check_in(asset);
285                         }
286                 }
287         }
288
289         return colormodel;
290 }
291
292
293
294
295
296
297
298 void VRender::run()
299 {
300         int reconfigure;
301         const int debug = 0;
302
303 // Want to know how many samples rendering each frame takes.
304 // Then use this number to predict the next frame that should be rendered.
305 // Be suspicious of frames that render late so have a countdown
306 // before we start dropping.
307         int64_t current_sample, start_sample, end_sample; // Absolute counts.
308         int64_t skip_countdown = VRENDER_THRESHOLD;    // frames remaining until drop
309         int64_t delay_countdown = VRENDER_THRESHOLD;  // Frames remaining until delay
310 // Number of frames before next reconfigure
311         int64_t current_input_length;
312 // Number of frames to skip.
313         int64_t frame_step = 1;
314         int use_opengl = (renderengine->video && 
315                 renderengine->video->out_config->driver == PLAYBACK_X11_GL);
316
317         first_frame = 1;
318
319 // Number of frames since start of rendering
320         session_frame = 0;
321         framerate_counter = 0;
322         framerate_timer.update();
323
324         start_lock->unlock();
325         if(debug) printf("VRender::run %d\n", __LINE__);
326
327
328         while(!done && !interrupt )
329         {
330 // Perform the most time consuming part of frame decompression now.
331 // Want the condition before, since only 1 frame is rendered 
332 // and the number of frames skipped after this frame varies.
333                 current_input_length = 1;
334
335                 reconfigure = vconsole->test_reconfigure(current_position, 
336                         current_input_length);
337
338
339                 if(debug) printf("VRender::run %d\n", __LINE__);
340                 if(reconfigure) restart_playback();
341
342                 if(debug) printf("VRender::run %d\n", __LINE__);
343                 process_buffer(current_position, use_opengl);
344
345
346                 if(debug) printf("VRender::run %d\n", __LINE__);
347
348                 if(renderengine->command->single_frame())
349                 {
350                         if(debug) printf("VRender::run %d\n", __LINE__);
351                         flash_output();
352                         frame_step = 1;
353                         done = 1;
354                 }
355                 else
356 // Perform synchronization
357                 {
358 // Determine the delay until the frame needs to be shown.
359                         current_sample = (int64_t)(renderengine->sync_position() * 
360                                 renderengine->command->get_speed());
361 // latest sample at which the frame can be shown.
362                         end_sample = Units::tosamples(session_frame, 
363                                 renderengine->get_edl()->session->sample_rate, 
364                                 renderengine->get_edl()->session->frame_rate);
365 // earliest sample by which the frame needs to be shown.
366                         start_sample = Units::tosamples(session_frame - 1, 
367                                 renderengine->get_edl()->session->sample_rate, 
368                                 renderengine->get_edl()->session->frame_rate);
369
370                         if(first_frame || end_sample < current_sample)
371                         {
372 // Frame rendered late or this is the first frame.  Flash it now.
373 //printf("VRender::run %d\n", __LINE__);
374                                 flash_output();
375
376                                 if(renderengine->get_edl()->session->video_every_frame)
377                                 {
378 // User wants every frame.
379                                         frame_step = 1;
380                                 }
381                                 else
382                                 if(skip_countdown > 0)
383                                 {
384 // Maybe just a freak.
385                                         frame_step = 1;
386                                         skip_countdown--;
387                                 }
388                                 else
389                                 {
390 // Get the frames to skip.
391                                         delay_countdown = VRENDER_THRESHOLD;
392                                         frame_step = 1;
393                                         frame_step += (int64_t)Units::toframes(current_sample, 
394                                                         renderengine->get_edl()->session->sample_rate, 
395                                                         renderengine->get_edl()->session->frame_rate);
396                                         frame_step -= (int64_t)Units::toframes(end_sample, 
397                                                                 renderengine->get_edl()->session->sample_rate, 
398                                                                 renderengine->get_edl()->session->frame_rate);
399                                 }
400                         }
401                         else
402                         {
403 // Frame rendered early or just in time.
404                                 frame_step = 1;
405
406                                 if(delay_countdown > 0)
407                                 {
408 // Maybe just a freak
409                                         delay_countdown--;
410                                 }
411                                 else
412                                 {
413                                         skip_countdown = VRENDER_THRESHOLD;
414                                         if(start_sample > current_sample)
415                                         {
416                                                 int64_t delay_time = (int64_t)((float)(start_sample - current_sample) * 
417                                                         1000 / renderengine->get_edl()->session->sample_rate);
418                                                 if( delay_time > 1000 ) delay_time = 1000;
419                                                 timer.delay(delay_time);
420                                         }
421                                         else
422                                         {
423 // Came after the earliest sample so keep going
424                                         }
425                                 }
426
427 // Flash frame now.
428 //printf("VRender::run %d " _LD "\n", __LINE__, current_input_length);
429                                 flash_output();
430                         }
431                 }
432                 if(debug) printf("VRender::run %d\n", __LINE__);
433
434 // Trigger audio to start
435                 if(first_frame)
436                 {
437                         renderengine->first_frame_lock->unlock();
438                         first_frame = 0;
439                         renderengine->reset_sync_position();
440                 }
441                 if(debug) printf("VRender::run %d\n", __LINE__);
442
443                 session_frame += frame_step;
444
445 // advance position in project
446                 current_input_length = frame_step;
447
448
449 // Subtract frame_step in a loop to allow looped playback to drain
450 // printf("VRender::run %d %d %d %d\n", 
451 // __LINE__,
452 // done,
453 // frame_step, 
454 // current_input_length);
455                 while(frame_step && current_input_length)
456                 {
457 // trim current_input_length to range
458                         get_boundaries(current_input_length);
459 // advance 1 frame
460                         advance_position(current_input_length);
461                         frame_step -= current_input_length;
462                         current_input_length = frame_step;
463                         if(done) break;
464 // printf("VRender::run %d %d %d %d\n", 
465 // __LINE__,
466 // done,
467 // frame_step, 
468 // current_input_length);
469                 }
470
471                 if(debug) printf("VRender::run %d current_position=" _LD " done=%d\n", 
472                         __LINE__, current_position, done);
473
474 // Update tracking.
475                 if(renderengine->command->realtime &&
476                         renderengine->playback_engine &&
477                         renderengine->command->command != CURRENT_FRAME)
478                 {
479                         renderengine->playback_engine->update_tracking(fromunits(current_position));
480                 }
481                 if(debug) printf("VRender::run %d\n", __LINE__);
482
483 // Calculate the framerate counter
484                 framerate_counter++;
485                 if(framerate_counter >= renderengine->get_edl()->session->frame_rate && 
486                         renderengine->command->realtime)
487                 {
488                         renderengine->update_framerate((float)framerate_counter / 
489                                 ((float)framerate_timer.get_difference() / 1000));
490                         framerate_counter = 0;
491                         framerate_timer.update();
492                 }
493                 if(debug) printf("VRender::run %d done=%d\n", __LINE__, done);
494                 if( !interrupt )
495                         interrupt = renderengine->video->interrupt;
496         }
497
498
499 // In case we were interrupted before the first loop
500         renderengine->first_frame_lock->unlock();
501         stop_plugins();
502         if(debug) printf("VRender::run %d done=%d\n", __LINE__, done);
503 }
504
505 int VRender::start_playback()
506 {
507 // start reading input and sending to vrenderthread
508 // use a thread only if there's a video device
509         if(renderengine->command->realtime)
510         {
511                 start();
512         }
513         return 0;
514 }
515
516 int64_t VRender::tounits(double position, int round)
517 {
518         if(round)
519                 return Units::round(position * renderengine->get_edl()->session->frame_rate);
520         else
521                 return Units::to_int64(position * renderengine->get_edl()->session->frame_rate);
522 }
523
524 double VRender::fromunits(int64_t position)
525 {
526         return (double)position / renderengine->get_edl()->session->frame_rate;
527 }
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547