r846: Merge 2.1:
[cinelerra_cv.git] / cinelerra / renderengine.C
blobbfa569d8b6cbfbae6c8cdf0388f614874fb6d456
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                 int device_channels = 0;
121                 int edl_channels = 0;
122                 if(command->single_frame())
123                 {
124                         vconfig->driver = PLAYBACK_X11;
125                         device_channels = 1;
126                         edl_channels = command->get_edl()->session->video_channels;
127                 }
128                 else
129                 {
130                         device_channels = 1;
131                         edl_channels = command->get_edl()->session->video_channels;
132                 }
134                 for(int i = 0; i < MAX_CHANNELS; i++)
135                 {
136                         vconfig->do_channel[i] = 
137                                 ((i == current_vchannel) && 
138                                         device_channels &&
139                                         edl_channels);
141 // GCC 3.2 optimization error causes do_channel[0] to always be 0 unless
142 // we do this.
143 Workarounds::clamp(vconfig->do_channel[i], 0, 1);
145                         if(vconfig->do_channel[i])
146                         {
147                                 current_vchannel++;
148                                 device_channels--;
149                                 edl_channels--;
150                         }
151                 }
153                 device_channels = aconfig->total_output_channels();
154                 edl_channels = command->get_edl()->session->audio_channels;
156                 for(int i = 0; i < MAX_CHANNELS; i++)
157                 {
159                         aconfig->do_channel[i] = 
160                                 (i == current_achannel && 
161                                         device_channels &&
162                                         edl_channels);
163                         if(aconfig->do_channel[i])
164                         {
165                                 current_achannel++;
166                                 device_channels--;
167                                 edl_channels--;
168                         }
169                 }
171         }
172         else
173         {
174                 vconfig->driver = PLAYBACK_X11;
175                 for(int i = 0; i < MAX_CHANNELS; i++)
176                 {
177                         vconfig->do_channel[i] = (i < command->get_edl()->session->video_channels);
178                         vconfig->do_channel[i] = (i < command->get_edl()->session->video_channels);
179                         aconfig->do_channel[i] = (i < command->get_edl()->session->audio_channels);
180                 }
181         }
185         get_duty();
187         if(do_audio)
188         {
189                 fragment_len = aconfig->fragment_size;
190 // Larger of audio_module_fragment and fragment length adjusted for speed
191 // Extra memory must be allocated for rendering slow motion.
192                 adjusted_fragment_len = (int64_t)((float)aconfig->fragment_size / 
193                         command->get_speed() + 0.5);
194                 if(adjusted_fragment_len < aconfig->fragment_size)
195                         adjusted_fragment_len = aconfig->fragment_size;
196         }
198 // Set lock so audio doesn't start until video has started.
199         if(do_video)
200         {
201                 while(first_frame_lock->get_value() > 0) 
202                         first_frame_lock->lock("RenderEngine::arm_command");
203         }
204         else
205 // Set lock so audio doesn't wait for video which is never to come.
206         {
207                 while(first_frame_lock->get_value() <= 0)
208                         first_frame_lock->unlock();
209         }
211         open_output();
212         create_render_threads();
213         arm_render_threads();
215         return 0;
218 void RenderEngine::get_duty()
220         do_audio = 0;
221         do_video = 0;
223 //edl->dump();
224         if(!command->single_frame() &&
225                 edl->tracks->playable_audio_tracks() &&
226                 config->aconfig->total_playable_channels())
227         {
228                 do_audio = 1;
229         }
231         if(edl->tracks->playable_video_tracks() &&
232                 config->vconfig->total_playable_channels())
233         {
234                 do_video = 1;
235         }
238 void RenderEngine::create_render_threads()
240         if(do_video && !vrender)
241         {
242                 vrender = new VRender(this);
243         }
245         if(do_audio && !arender)
246         {
247                 arender = new ARender(this);
248         }
252 int RenderEngine::get_output_w()
254         return edl->session->output_w;
257 int RenderEngine::get_output_h()
259         return edl->session->output_h;
262 int RenderEngine::brender_available(int position, int direction)
264         if(playback_engine)
265         {
266                 int64_t corrected_position = position;
267                 if(direction == PLAY_REVERSE)
268                         corrected_position--;
269                 return playback_engine->brender_available(corrected_position);
270         }
271         else
272                 return 0;
275 Channel* RenderEngine::get_current_channel()
277         if(channeldb)
278         {
279                 switch(config->vconfig->driver)
280                 {
281                         case PLAYBACK_BUZ:
282                                 if(config->vconfig->buz_out_channel >= 0 && 
283                                         config->vconfig->buz_out_channel < channeldb->size())
284                                 {
285                                         return channeldb->get(config->vconfig->buz_out_channel);
286                                 }
287                                 break;
288                         case VIDEO4LINUX2JPEG:
289                                 
290                                 break;
291                 }
292         }
293         return 0;
296 CICache* RenderEngine::get_acache()
298         if(playback_engine)
299                 return playback_engine->audio_cache;
300         else
301                 return audio_cache;
304 CICache* RenderEngine::get_vcache()
306         if(playback_engine)
307                 return playback_engine->video_cache;
308         else
309                 return video_cache;
312 void RenderEngine::set_acache(CICache *cache)
314         this->audio_cache = cache;
317 void RenderEngine::set_vcache(CICache *cache)
319         this->video_cache = cache;
323 double RenderEngine::get_tracking_position()
325         if(playback_engine) 
326                 return playback_engine->get_tracking_position();
327         else
328                 return 0;
331 int RenderEngine::open_output()
333         if(command->realtime)
334         {
335 // Allocate devices
336                 if(do_audio)
337                 {
338                         audio = new AudioDevice;
339                         if (audio->open_output(config->aconfig, 
340                                 edl->session->sample_rate, 
341                                 adjusted_fragment_len,
342                                 edl->session->real_time_playback))
343                         {
344                                 do_audio = 0;
345                                 delete audio;
346                                 audio = 0;
347                         }
348                 }
350                 if(do_video)
351                 {
352                         video = new VideoDevice;
353                 }
355 // Initialize sharing
358 // Start playback
359                 if(do_audio && do_video)
360                 {
361                         video->set_adevice(audio);
362                         audio->set_vdevice(video);
363                 }
367 // Retool playback configuration
368                 if(do_audio)
369                 {       
370                         audio->set_software_positioning(edl->session->playback_software_position);
371                         audio->start_playback();
372                 }
374                 if(do_video)
375                 {
376                         video->open_output(config->vconfig, 
377                                 edl->session->frame_rate,
378                                 get_output_w(),
379                                 get_output_h(),
380                                 output,
381                                 command->single_frame());
382                         Channel *channel = get_current_channel();
383                         if(channel) video->set_channel(channel);
384                         video->set_quality(80);
385                         video->set_cpus(preferences->processors);
386                 }
387         }
389         return 0;
392 int64_t RenderEngine::session_position()
394         if(do_audio)
395         {
396                 return audio->current_position();
397         }
399         if(do_video)
400         {
401                 return (int64_t)((double)vrender->session_frame / 
402                                 edl->session->frame_rate * 
403                                 edl->session->sample_rate /
404                                 command->get_speed() + 0.5);
405         }
408 void RenderEngine::reset_sync_position()
410         timer.update();
413 int64_t RenderEngine::sync_position()
415 // Use audio device
416 // No danger of race conditions because the output devices are closed after all
417 // threads join.
418         if(do_audio)
419         {
420                 return audio->current_position();
421         }
423         if(do_video)
424         {
425                 int64_t result = timer.get_scaled_difference(
426                         edl->session->sample_rate);
427                 return result;
428         }
431 PluginServer* RenderEngine::scan_plugindb(char *title, 
432         int data_type)
434         for(int i = 0; i < plugindb->total; i++)
435         {
436                 PluginServer *server = plugindb->values[i];
437                 if(!strcasecmp(server->title, title) &&
438                         ((data_type == TRACK_AUDIO && server->audio) ||
439                         (data_type == TRACK_VIDEO && server->video)))
440                         return plugindb->values[i];
441         }
442         return 0;
445 int RenderEngine::start_command()
447         if(command->realtime)
448         {
449                 interrupt_lock->lock("RenderEngine::start_command");
450                 start_lock->lock("RenderEngine::start_command 1");
451                 Thread::start();
452                 start_lock->lock("RenderEngine::start_command 2");
453                 start_lock->unlock();
454         }
455         return 0;
458 void RenderEngine::arm_render_threads()
460         if(do_audio)
461         {
462                 arender->arm_command();
463         }
465         if(do_video)
466         {
467                 vrender->arm_command();
468         }
472 void RenderEngine::start_render_threads()
474 // Synchronization timer.  Gets reset once again after the first video frame.
475         timer.update();
477         if(do_audio)
478         {
479                 arender->start_command();
480         }
482         if(do_video)
483         {
484                 vrender->start_command();
485         }
488 void RenderEngine::update_framerate(float framerate)
490         playback_engine->mwindow->edl->session->actual_frame_rate = framerate;
491         playback_engine->mwindow->preferences_thread->update_framerate();
494 void RenderEngine::wait_render_threads()
496         if(do_audio)
497         {
498                 arender->Thread::join();
499         }
501         if(do_video)
502         {
503                 vrender->Thread::join();
504         }
507 void RenderEngine::interrupt_playback()
509         interrupt_lock->lock("RenderEngine::interrupt_playback");
510         interrupted = 1;
511         if(audio)
512         {
513                 audio->interrupt_playback();
514         }
515         if(video)
516         {
517 //printf("RenderEngine::interrupt_playback 3 %p\n", this);
518                 video->interrupt_playback();
519 //printf("RenderEngine::interrupt_playback 4 %p\n", this);
520         }
521         interrupt_lock->unlock();
524 int RenderEngine::close_output()
526         if(audio)
527         {
528                 audio->close_all();
529                 delete audio;
530                 audio = 0;
531         }
535         if(video)
536         {
537                 video->close_all();
538                 delete video;
539                 video = 0;
540         }
541         return 0;
544 void RenderEngine::get_output_levels(double *levels, int64_t position)
546         if(do_audio)
547         {
548                 int history_entry = arender->get_history_number(arender->level_samples, 
549                         position);
550                 for(int i = 0; i < MAXCHANNELS; i++)
551                 {
552                         if(arender->audio_out[i])
553                                 levels[i] = arender->level_history[i][history_entry];
554                 }
555         }
558 void RenderEngine::get_module_levels(ArrayList<double> *module_levels, int64_t position)
560         if(do_audio)
561         {
562                 for(int i = 0; i < arender->total_modules; i++)
563                 {
564 //printf("RenderEngine::get_module_levels %p %p\n", ((AModule*)arender->modules[i]), ((AModule*)arender->modules[i])->level_samples);
565                         int history_entry = arender->get_history_number(((AModule*)arender->modules[i])->level_samples, position);
567                         module_levels->append(((AModule*)arender->modules[i])->level_history[history_entry]);
568                 }
569         }
576 void RenderEngine::run()
578         start_render_threads();
579         start_lock->unlock();
580         interrupt_lock->unlock();
582         wait_render_threads();
584         interrupt_lock->lock("RenderEngine::run");
587         if(interrupted)
588         {
589                 playback_engine->tracking_position = playback_engine->get_tracking_position();
590         }
592         close_output();
594 // Fix the tracking position
595         if(playback_engine)
596         {
597                 if(command->command == CURRENT_FRAME)
598                 {
599 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
600                         playback_engine->tracking_position = command->playbackstart;
601                 }
602                 else
603                 {
604 // Make sure transport doesn't issue a pause command next
605 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
606                         if(!interrupted)
607                         {
608                                 if(do_audio)
609                                         playback_engine->tracking_position = 
610                                                 (double)arender->current_position / 
611                                                         command->get_edl()->session->sample_rate;
612                                 else
613                                 if(do_video)
614                                 {
615                                         playback_engine->tracking_position = 
616                                                 (double)vrender->current_position / 
617                                                         command->get_edl()->session->frame_rate;
618                                 }
619                         }
621                         if(!interrupted) playback_engine->command->command = STOP;
622                         playback_engine->stop_tracking();
624                 }
625                 playback_engine->is_playing_back = 0;
626         }
628         input_lock->unlock();
629         interrupt_lock->unlock();
656 int RenderEngine::reset_parameters()
658         start_position = 0;
659         follow_loop = 0;
660         end_position = 0;
661         infinite = 0;
662         start_position = 0;
663         audio_channels = 0;
664         do_audio = 0;
665         do_video = 0;
666         done = 0;
669 int RenderEngine::arm_playback_audio(int64_t input_length, 
670                         int64_t amodule_render_fragment, 
671                         int64_t playback_buffer, 
672                         int64_t output_length, 
673                         int audio_channels)
675         this->audio_channels = audio_channels;
677         do_audio = 1;
679         arender = new ARender(this);
680         arender->arm_playback(current_sample, 
681                                                         input_length, 
682                                                         amodule_render_fragment, 
683                                                         playback_buffer, 
684                                                         output_length);
687 int RenderEngine::arm_playback_video(int every_frame, 
688                         int64_t read_length, 
689                         int64_t output_length,
690                         int track_w,
691                         int track_h,
692                         int output_w,
693                         int output_h)
695         do_video = 1;
696         this->every_frame = every_frame;
698         vrender = new VRender(this);
699 //      vrender->arm_playback(current_sample, 
700 //                                                      read_length, 
701 //                                                      output_length, 
702 //                                                      output_length, 
703 //                                                      track_w,
704 //                                                      track_h,
705 //                                                      output_w,
706 //                                                      output_h);
709 int RenderEngine::start_video()
711 // start video for realtime
712         if(video) video->start_playback();
713         vrender->start_playback();
717 int64_t RenderEngine::get_correction_factor(int reset)
719         if(!every_frame)
720         {
721                 int64_t x;
722 //              x = playbackengine->correction_factor;
723 //              if(reset) playbackengine->correction_factor = 0;
724                 return x;
725         }
726         else
727                 return 0;