Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / renderengine.C
blob06aaea1eac12a36fe2be068dbff651668c72dda0
1 #include "amodule.h"
2 #include "arender.h"
3 #include "asset.h"
4 #include "audiodevice.h"
5 #include "bcsignals.h"
6 #include "channeldb.h"
7 #include "condition.h"
8 #include "edl.h"
9 #include "edlsession.h"
10 #include "mutex.h"
11 #include "mwindow.h"
12 #include "playbackengine.h"
13 #include "preferences.h"
14 #include "preferencesthread.h"
15 #include "renderengine.h"
16 #include "mainsession.h"
17 #include "tracks.h"
18 #include "transportque.h"
19 #include "videodevice.h"
20 #include "vrender.h"
21 #include "workarounds.h"
25 RenderEngine::RenderEngine(PlaybackEngine *playback_engine,
26         Preferences *preferences, 
27         TransportCommand *command,
28         Canvas *output,
29         ArrayList<PluginServer*> *plugindb,
30         ChannelDB *channeldb)
31  : Thread(1, 0, 0)
33         this->playback_engine = playback_engine;
34         this->output = output;
35         this->plugindb = plugindb;
36         this->channeldb = channeldb;
37         audio = 0;
38         video = 0;
39         config = new PlaybackConfig;
40         arender = 0;
41         vrender = 0;
42         do_audio = 0;
43         do_video = 0;
44         interrupted = 0;
45         actual_frame_rate = 0;
46         this->preferences = new Preferences;
47         this->command = new TransportCommand;
48         this->preferences->copy_from(preferences);
49         this->command->copy_from(command);
50         edl = new EDL;
51         edl->create_objects();
52 // EDL only changed in construction.
53 // The EDL contained in later commands is ignored.
54         edl->copy_all(command->get_edl());
55         audio_cache = 0;
56         video_cache = 0;
57         if(playback_engine && playback_engine->mwindow)
58                 mwindow = playback_engine->mwindow;
59         else
60                 mwindow = 0;
61         show_tc = 0;
64         input_lock = new Condition(1, "RenderEngine::input_lock");
65         start_lock = new Condition(1, "RenderEngine::start_lock");
66         output_lock = new Condition(1, "RenderEngine::output_lock");
67         interrupt_lock = new Mutex("RenderEngine::interrupt_lock");
68         first_frame_lock = new Condition(1, "RenderEngine::first_frame_lock");
69         reset_parameters();
72 RenderEngine::~RenderEngine()
74         close_output();
75         delete command;
76         delete preferences;
77         if(arender) delete arender;
78         if(vrender) delete vrender;
79         delete edl;
80         delete input_lock;
81         delete start_lock;
82         delete output_lock;
83         delete interrupt_lock;
84         delete first_frame_lock;
85         delete config;
88 int RenderEngine::arm_command(TransportCommand *command,
89         int &current_vchannel, 
90         int &current_achannel)
92 // Prevent this renderengine from accepting another command until finished.
93 // Since the renderengine is often deleted after the input_lock command it must
94 // be locked here as well as in the calling routine.
97         input_lock->lock("RenderEngine::arm_command");
100         this->command->copy_from(command);
102 // Fix background rendering asset to use current dimensions and ignore
103 // headers.
104         preferences->brender_asset->frame_rate = command->get_edl()->session->frame_rate;
105         preferences->brender_asset->width = command->get_edl()->session->output_w;
106         preferences->brender_asset->height = command->get_edl()->session->output_h;
107         preferences->brender_asset->use_header = 0;
108         preferences->brender_asset->layers = 1;
109         preferences->brender_asset->video_data = 1;
111         done = 0;
112         interrupted = 0;
114 // Retool configuration for this node
115         this->config->copy_from(command->get_edl()->session->playback_config);
116         VideoOutConfig *vconfig = this->config->vconfig;
117         AudioOutConfig *aconfig = this->config->aconfig;
118         if(command->realtime)
119         {
120                 if(command->single_frame() && vconfig->driver != PLAYBACK_X11_GL)
121                 {
122                         vconfig->driver = PLAYBACK_X11;
123                 }
124         }
125         else
126         {
127                 vconfig->driver = PLAYBACK_X11;
128         }
132         get_duty();
134         if(do_audio)
135         {
136                 fragment_len = aconfig->fragment_size;
137 // Larger of audio_module_fragment and fragment length adjusted for speed
138 // Extra memory must be allocated for rendering slow motion.
139                 adjusted_fragment_len = (int64_t)((float)aconfig->fragment_size / 
140                         command->get_speed() + 0.5);
141                 if(adjusted_fragment_len < aconfig->fragment_size)
142                         adjusted_fragment_len = aconfig->fragment_size;
143         }
145 // Set lock so audio doesn't start until video has started.
146         if(do_video)
147         {
148                 while(first_frame_lock->get_value() > 0) 
149                         first_frame_lock->lock("RenderEngine::arm_command");
150         }
151         else
152 // Set lock so audio doesn't wait for video which is never to come.
153         {
154                 while(first_frame_lock->get_value() <= 0)
155                         first_frame_lock->unlock();
156         }
158         open_output();
159         create_render_threads();
160         arm_render_threads();
162         return 0;
165 void RenderEngine::get_duty()
167         do_audio = 0;
168         do_video = 0;
170 //edl->dump();
171         if(!command->single_frame() &&
172                 edl->tracks->playable_audio_tracks() &&
173                 edl->session->audio_channels)
174         {
175                 do_audio = 1;
176         }
178         if(edl->tracks->playable_video_tracks())
179         {
180                 do_video = 1;
181         }
184 void RenderEngine::create_render_threads()
186         if(do_video && !vrender)
187         {
188                 vrender = new VRender(this);
189         }
191         if(do_audio && !arender)
192         {
193                 arender = new ARender(this);
194         }
198 int RenderEngine::get_output_w()
200         return edl->session->output_w;
203 int RenderEngine::get_output_h()
205         return edl->session->output_h;
208 int RenderEngine::brender_available(int position, int direction)
210         if(playback_engine)
211         {
212                 int64_t corrected_position = position;
213                 if(direction == PLAY_REVERSE)
214                         corrected_position--;
215                 return playback_engine->brender_available(corrected_position);
216         }
217         else
218                 return 0;
221 Channel* RenderEngine::get_current_channel()
223         if(channeldb)
224         {
225                 switch(config->vconfig->driver)
226                 {
227                         case PLAYBACK_BUZ:
228                                 if(config->vconfig->buz_out_channel >= 0 && 
229                                         config->vconfig->buz_out_channel < channeldb->size())
230                                 {
231                                         return channeldb->get(config->vconfig->buz_out_channel);
232                                 }
233                                 break;
234                         case VIDEO4LINUX2JPEG:
235                                 
236                                 break;
237                 }
238         }
239         return 0;
242 CICache* RenderEngine::get_acache()
244         if(playback_engine)
245                 return playback_engine->audio_cache;
246         else
247                 return audio_cache;
250 CICache* RenderEngine::get_vcache()
252         if(playback_engine)
253                 return playback_engine->video_cache;
254         else
255                 return video_cache;
258 void RenderEngine::set_acache(CICache *cache)
260         this->audio_cache = cache;
263 void RenderEngine::set_vcache(CICache *cache)
265         this->video_cache = cache;
269 double RenderEngine::get_tracking_position()
271         if(playback_engine) 
272                 return playback_engine->get_tracking_position();
273         else
274                 return 0;
277 int RenderEngine::open_output()
279         if(command->realtime)
280         {
281 // Allocate devices
282                 if(do_audio)
283                 {
284                         audio = new AudioDevice;
285                         if (audio->open_output(config->aconfig, 
286                                 edl->session->sample_rate, 
287                                 adjusted_fragment_len,
288                                 edl->session->audio_channels,
289                                 edl->session->real_time_playback))
290                         {
291                                 do_audio = 0;
292                                 delete audio;
293                                 audio = 0;
294                         }
295                 }
297                 if(do_video)
298                 {
299                         video = new VideoDevice;
300                 }
302 // Initialize sharing
305 // Start playback
306                 if(do_audio && do_video)
307                 {
308                         video->set_adevice(audio);
309                         audio->set_vdevice(video);
310                 }
314 // Retool playback configuration
315                 if(do_audio)
316                 {       
317                         audio->set_software_positioning(edl->session->playback_software_position);
318                         audio->start_playback();
319                 }
321                 if(do_video)
322                 {
323                         video->open_output(config->vconfig, 
324                                 edl->session->frame_rate,
325                                 get_output_w(),
326                                 get_output_h(),
327                                 output,
328                                 command->single_frame());
329                         Channel *channel = get_current_channel();
330                         if(channel) video->set_channel(channel);
331                         video->set_quality(80);
332                         video->set_cpus(preferences->processors);
333                 }
334         }
336         return 0;
339 int64_t RenderEngine::session_position()
341         if(do_audio)
342         {
343                 return audio->current_position();
344         }
346         if(do_video)
347         {
348                 return (int64_t)((double)vrender->session_frame / 
349                                 edl->session->frame_rate * 
350                                 edl->session->sample_rate /
351                                 command->get_speed() + 0.5);
352         }
355 void RenderEngine::reset_sync_position()
357         timer.update();
360 int64_t RenderEngine::sync_position()
362 // Use audio device
363 // No danger of race conditions because the output devices are closed after all
364 // threads join.
365         if(do_audio)
366         {
367                 return audio->current_position();
368         }
370         if(do_video)
371         {
372                 int64_t result = timer.get_scaled_difference(
373                         edl->session->sample_rate);
374                 return result;
375         }
378 PluginServer* RenderEngine::scan_plugindb(char *title, 
379         int data_type)
381         for(int i = 0; i < plugindb->total; i++)
382         {
383                 PluginServer *server = plugindb->values[i];
384                 if(!strcasecmp(server->title, title) &&
385                         ((data_type == TRACK_AUDIO && server->audio) ||
386                         (data_type == TRACK_VIDEO && server->video)))
387                         return plugindb->values[i];
388         }
389         return 0;
392 int RenderEngine::start_command()
394         if(command->realtime)
395         {
396                 interrupt_lock->lock("RenderEngine::start_command");
397                 start_lock->lock("RenderEngine::start_command 1");
398                 Thread::start();
399                 start_lock->lock("RenderEngine::start_command 2");
400                 start_lock->unlock();
401         }
402         return 0;
405 void RenderEngine::arm_render_threads()
407         if(do_audio)
408         {
409                 arender->arm_command();
410         }
412         if(do_video)
413         {
414                 vrender->arm_command();
415         }
419 void RenderEngine::start_render_threads()
421 // Synchronization timer.  Gets reset once again after the first video frame.
422         timer.update();
424         if(do_audio)
425         {
426                 arender->start_command();
427         }
429         if(do_video)
430         {
431                 vrender->start_command();
432         }
435 void RenderEngine::update_framerate(float framerate)
437         playback_engine->mwindow->edl->session->actual_frame_rate = framerate;
438         playback_engine->mwindow->preferences_thread->update_framerate();
441 void RenderEngine::wait_render_threads()
443         if(do_audio)
444         {
445                 arender->Thread::join();
446         }
448         if(do_video)
449         {
450                 vrender->Thread::join();
451         }
454 void RenderEngine::interrupt_playback()
456         interrupt_lock->lock("RenderEngine::interrupt_playback");
457         interrupted = 1;
458         if(audio)
459         {
460                 audio->interrupt_playback();
461         }
462         if(video)
463         {
464 //printf("RenderEngine::interrupt_playback 3 %p\n", this);
465                 video->interrupt_playback();
466 //printf("RenderEngine::interrupt_playback 4 %p\n", this);
467         }
468         interrupt_lock->unlock();
471 int RenderEngine::close_output()
473         if(audio)
474         {
475                 audio->close_all();
476                 delete audio;
477                 audio = 0;
478         }
482         if(video)
483         {
484                 video->close_all();
485                 delete video;
486                 video = 0;
487         }
488         return 0;
491 void RenderEngine::get_output_levels(double *levels, int64_t position)
493         if(do_audio)
494         {
495                 int history_entry = arender->get_history_number(arender->level_samples, 
496                         position);
497                 for(int i = 0; i < MAXCHANNELS; i++)
498                 {
499                         if(arender->audio_out[i])
500                                 levels[i] = arender->level_history[i][history_entry];
501                 }
502         }
505 void RenderEngine::get_module_levels(ArrayList<double> *module_levels, int64_t position)
507         if(do_audio)
508         {
509                 for(int i = 0; i < arender->total_modules; i++)
510                 {
511 //printf("RenderEngine::get_module_levels %p %p\n", ((AModule*)arender->modules[i]), ((AModule*)arender->modules[i])->level_samples);
512                         int history_entry = arender->get_history_number(((AModule*)arender->modules[i])->level_samples, position);
514                         module_levels->append(((AModule*)arender->modules[i])->level_history[history_entry]);
515                 }
516         }
523 void RenderEngine::run()
525         start_render_threads();
526         start_lock->unlock();
527         interrupt_lock->unlock();
529         wait_render_threads();
531         interrupt_lock->lock("RenderEngine::run");
534         if(interrupted)
535         {
536                 playback_engine->tracking_position = playback_engine->get_tracking_position();
537         }
539         close_output();
541 // Fix the tracking position
542         if(playback_engine)
543         {
544                 if(command->command == CURRENT_FRAME)
545                 {
546 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
547                         playback_engine->tracking_position = command->playbackstart;
548                 }
549                 else
550                 {
551 // Make sure transport doesn't issue a pause command next
552 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
553                         if(!interrupted)
554                         {
555                                 if(do_audio)
556                                         playback_engine->tracking_position = 
557                                                 (double)arender->current_position / 
558                                                         command->get_edl()->session->sample_rate;
559                                 else
560                                 if(do_video)
561                                 {
562                                         playback_engine->tracking_position = 
563                                                 (double)vrender->current_position / 
564                                                         command->get_edl()->session->frame_rate;
565                                 }
566                         }
568                         if(!interrupted) playback_engine->command->command = STOP;
569                         playback_engine->stop_tracking();
571                 }
572                 playback_engine->is_playing_back = 0;
573         }
575         input_lock->unlock();
576         interrupt_lock->unlock();
603 int RenderEngine::reset_parameters()
605         start_position = 0;
606         follow_loop = 0;
607         end_position = 0;
608         infinite = 0;
609         start_position = 0;
610         do_audio = 0;
611         do_video = 0;
612         done = 0;
615 int RenderEngine::arm_playback_audio(int64_t input_length, 
616                         int64_t amodule_render_fragment, 
617                         int64_t playback_buffer, 
618                         int64_t output_length)
621         do_audio = 1;
623         arender = new ARender(this);
624         arender->arm_playback(current_sample, 
625                                                         input_length, 
626                                                         amodule_render_fragment, 
627                                                         playback_buffer, 
628                                                         output_length);
631 int RenderEngine::arm_playback_video(int every_frame, 
632                         int64_t read_length, 
633                         int64_t output_length,
634                         int track_w,
635                         int track_h,
636                         int output_w,
637                         int output_h)
639         do_video = 1;
640         this->every_frame = every_frame;
642         vrender = new VRender(this);
643 //      vrender->arm_playback(current_sample, 
644 //                                                      read_length, 
645 //                                                      output_length, 
646 //                                                      output_length, 
647 //                                                      track_w,
648 //                                                      track_h,
649 //                                                      output_w,
650 //                                                      output_h);
653 int RenderEngine::start_video()
655 // start video for realtime
656         if(video) video->start_playback();
657         vrender->start_playback();
661 int64_t RenderEngine::get_correction_factor(int reset)
663         if(!every_frame)
664         {
665                 int64_t x;
666 //              x = playbackengine->correction_factor;
667 //              if(reset) playbackengine->correction_factor = 0;
668                 return x;
669         }
670         else
671                 return 0;
675 //      Local Variables:
676 //      mode: C++
677 //      c-file-style: "linux"
678 //      End: