r602: Fix baver's code... don't insert timecode when show_tc is not set
[cinelerra_cv/mob.git] / cinelerra / renderengine.C
blob553ead5f6404b0e526543f17dd19454ed07c6791
1 #include "amodule.h"
2 #include "arender.h"
3 #include "asset.h"
4 #include "audiodevice.h"
5 #include "channeldb.h"
6 #include "condition.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "mutex.h"
10 #include "mwindow.h"
11 #include "playbackengine.h"
12 #include "preferences.h"
13 #include "preferencesthread.h"
14 #include "renderengine.h"
15 #include "mainsession.h"
16 #include "tracks.h"
17 #include "transportque.h"
18 #include "videodevice.h"
19 #include "vrender.h"
20 #include "workarounds.h"
24 RenderEngine::RenderEngine(PlaybackEngine *playback_engine,
25         Preferences *preferences, 
26         TransportCommand *command,
27         Canvas *output,
28         ArrayList<PluginServer*> *plugindb,
29         ChannelDB *channeldb)
30  : Thread(1, 0, 0)
32         this->playback_engine = playback_engine;
33         this->output = output;
34         this->plugindb = plugindb;
35         this->channeldb = channeldb;
36         audio = 0;
37         video = 0;
38         config = new PlaybackConfig;
39         arender = 0;
40         vrender = 0;
41         do_audio = 0;
42         do_video = 0;
43         interrupted = 0;
44         actual_frame_rate = 0;
45         this->preferences = new Preferences;
46         this->command = new TransportCommand;
47         this->preferences->copy_from(preferences);
48         this->command->copy_from(command);
49         edl = new EDL;
50         edl->create_objects();
51 // EDL only changed in construction.
52 // The EDL contained in later commands is ignored.
53         edl->copy_all(command->get_edl());
54         audio_cache = 0;
55         video_cache = 0;
56         if(playback_engine && playback_engine->mwindow)
57                 mwindow = playback_engine->mwindow;
58         else
59                 mwindow = 0;
60         show_tc = 0;
63         input_lock = new Condition(1, "RenderEngine::input_lock");
64         start_lock = new Condition(1, "RenderEngine::start_lock");
65         output_lock = new Condition(1, "RenderEngine::output_lock");
66         interrupt_lock = new Mutex("RenderEngine::interrupt_lock");
67         first_frame_lock = new Condition(1, "RenderEngine::first_frame_lock");
68         reset_parameters();
71 RenderEngine::~RenderEngine()
73         close_output();
74         delete command;
75         delete preferences;
76         if(arender) delete arender;
77         if(vrender) delete vrender;
78         delete edl;
79         delete input_lock;
80         delete start_lock;
81         delete output_lock;
82         delete interrupt_lock;
83         delete first_frame_lock;
84         delete config;
87 int RenderEngine::arm_command(TransportCommand *command,
88         int &current_vchannel, 
89         int &current_achannel)
91 // Prevent this renderengine from accepting another command until finished.
92 // Since the renderengine is often deleted after the input_lock command it must
93 // be locked here as well as in the calling routine.
96         input_lock->lock("RenderEngine::arm_command");
99         this->command->copy_from(command);
101 // Fix background rendering asset to use current dimensions and ignore
102 // headers.
103         preferences->brender_asset->frame_rate = command->get_edl()->session->frame_rate;
104         preferences->brender_asset->width = command->get_edl()->session->output_w;
105         preferences->brender_asset->height = command->get_edl()->session->output_h;
106         preferences->brender_asset->use_header = 0;
107         preferences->brender_asset->layers = 1;
108         preferences->brender_asset->video_data = 1;
110         done = 0;
111         interrupted = 0;
113 // Retool configuration for this node
114         this->config->copy_from(command->get_edl()->session->playback_config);
115         VideoOutConfig *vconfig = this->config->vconfig;
116         AudioOutConfig *aconfig = this->config->aconfig;
117         if(command->realtime)
118         {
119                 int device_channels = 0;
120                 int edl_channels = 0;
121                 if(command->single_frame())
122                 {
123                         vconfig->driver = PLAYBACK_X11;
124                         device_channels = 1;
125                         edl_channels = command->get_edl()->session->video_channels;
126                 }
127                 else
128                 {
129                         device_channels = 1;
130                         edl_channels = command->get_edl()->session->video_channels;
131                 }
133                 for(int i = 0; i < MAX_CHANNELS; i++)
134                 {
135                         vconfig->do_channel[i] = 
136                                 ((i == current_vchannel) && 
137                                         device_channels &&
138                                         edl_channels);
140 // GCC 3.2 optimization error causes do_channel[0] to always be 0 unless
141 // we do this.
142 Workarounds::clamp(vconfig->do_channel[i], 0, 1);
144                         if(vconfig->do_channel[i])
145                         {
146                                 current_vchannel++;
147                                 device_channels--;
148                                 edl_channels--;
149                         }
150                 }
152                 device_channels = aconfig->total_output_channels();
153                 edl_channels = command->get_edl()->session->audio_channels;
155                 for(int i = 0; i < MAX_CHANNELS; i++)
156                 {
158                         aconfig->do_channel[i] = 
159                                 (i == current_achannel && 
160                                         device_channels &&
161                                         edl_channels);
162                         if(aconfig->do_channel[i])
163                         {
164                                 current_achannel++;
165                                 device_channels--;
166                                 edl_channels--;
167                         }
168                 }
170         }
171         else
172         {
173                 vconfig->driver = PLAYBACK_X11;
174                 for(int i = 0; i < MAX_CHANNELS; i++)
175                 {
176                         vconfig->do_channel[i] = (i < command->get_edl()->session->video_channels);
177                         vconfig->do_channel[i] = (i < command->get_edl()->session->video_channels);
178                         aconfig->do_channel[i] = (i < command->get_edl()->session->audio_channels);
179                 }
180         }
184         get_duty();
186         if(do_audio)
187         {
188                 fragment_len = aconfig->fragment_size;
189 // Larger of audio_module_fragment and fragment length adjusted for speed
190 // Extra memory must be allocated for rendering slow motion.
191                 adjusted_fragment_len = (int64_t)((float)aconfig->fragment_size / 
192                         command->get_speed() + 0.5);
193                 if(adjusted_fragment_len < aconfig->fragment_size)
194                         adjusted_fragment_len = aconfig->fragment_size;
195         }
197 // Set lock so audio doesn't start until video has started.
198         if(do_video)
199         {
200                 while(first_frame_lock->get_value() > 0) 
201                         first_frame_lock->lock("RenderEngine::arm_command");
202         }
203         else
204 // Set lock so audio doesn't wait for video which is never to come.
205         {
206                 while(first_frame_lock->get_value() <= 0)
207                         first_frame_lock->unlock();
208         }
210         open_output();
211         create_render_threads();
212         arm_render_threads();
214         return 0;
217 void RenderEngine::get_duty()
219         do_audio = 0;
220         do_video = 0;
222 //edl->dump();
223 //printf("RenderEngine::get_duty 1 %d %d\n", edl->tracks->playable_audio_tracks(), config->vconfig->total_playable_channels());
224         if(!command->single_frame() &&
225                 edl->tracks->playable_audio_tracks() &&
226                 config->aconfig->total_playable_channels())
227         {
228                 do_audio = 1;
229         }
231 //printf("RenderEngine::get_duty 2 %d %d\n", edl->tracks->playable_video_tracks(), config->vconfig->total_playable_channels());
232         if(edl->tracks->playable_video_tracks() &&
233                 config->vconfig->total_playable_channels())
234         {
235                 do_video = 1;
236         }
239 void RenderEngine::create_render_threads()
241         if(do_video && !vrender)
242         {
243                 vrender = new VRender(this);
244         }
246         if(do_audio && !arender)
247         {
248                 arender = new ARender(this);
249         }
253 int RenderEngine::get_output_w()
255         return edl->calculate_output_w(1);
258 int RenderEngine::get_output_h()
260         return edl->calculate_output_h(1);
263 int RenderEngine::brender_available(int position, int direction)
265         if(playback_engine)
266         {
267                 int64_t corrected_position = position;
268                 if(direction == PLAY_REVERSE)
269                         corrected_position--;
270                 return playback_engine->brender_available(corrected_position);
271         }
272         else
273                 return 0;
276 Channel* RenderEngine::get_current_channel()
278         if(channeldb)
279         {
280                 switch(config->vconfig->driver)
281                 {
282                         case PLAYBACK_BUZ:
283                                 if(config->vconfig->buz_out_channel >= 0 && 
284                                         config->vconfig->buz_out_channel < channeldb->size())
285                                 {
286                                         return channeldb->get(config->vconfig->buz_out_channel);
287                                 }
288                                 break;
289                         case VIDEO4LINUX2JPEG:
290                                 
291                                 break;
292                 }
293         }
294         return 0;
297 CICache* RenderEngine::get_acache()
299         if(playback_engine)
300                 return playback_engine->audio_cache;
301         else
302                 return audio_cache;
305 CICache* RenderEngine::get_vcache()
307         if(playback_engine)
308                 return playback_engine->video_cache;
309         else
310                 return video_cache;
313 void RenderEngine::set_acache(CICache *cache)
315         this->audio_cache = cache;
318 void RenderEngine::set_vcache(CICache *cache)
320         this->video_cache = cache;
324 double RenderEngine::get_tracking_position()
326         if(playback_engine) 
327                 return playback_engine->get_tracking_position();
328         else
329                 return 0;
332 int RenderEngine::open_output()
334         if(command->realtime)
335         {
336 // Allocate devices
337                 if(do_audio)
338                 {
339                         audio = new AudioDevice;
340                 }
342                 if(do_video)
343                 {
344                         video = new VideoDevice;
345                 }
347 // Initialize sharing
350 // Start playback
351                 if(do_audio && do_video)
352                 {
353                         video->set_adevice(audio);
354                         audio->set_vdevice(video);
355                 }
359 // Retool playback configuration
360                 if(do_audio)
361                 {
362                         audio->open_output(config->aconfig, 
363                                 edl->session->sample_rate, 
364                                 adjusted_fragment_len,
365                                 edl->session->real_time_playback);
366                         audio->set_software_positioning(edl->session->playback_software_position);
367                         audio->start_playback();
368                 }
370                 if(do_video)
371                 {
372                         video->open_output(config->vconfig, 
373                                 edl->session->frame_rate,
374                                 get_output_w(),
375                                 get_output_h(),
376                                 output,
377                                 command->single_frame());
378                         Channel *channel = get_current_channel();
379                         if(channel) video->set_channel(channel);
380                         video->set_quality(80);
381                         video->set_cpus(preferences->processors);
382                 }
383         }
385         return 0;
388 int64_t RenderEngine::session_position()
390         if(do_audio)
391         {
392                 return audio->current_position();
393         }
395         if(do_video)
396         {
397                 return (int64_t)((double)vrender->session_frame / 
398                                 edl->session->frame_rate * 
399                                 edl->session->sample_rate /
400                                 command->get_speed() + 0.5);
401         }
404 void RenderEngine::reset_sync_position()
406         timer.update();
409 int64_t RenderEngine::sync_position()
411 // Use audio device
412 // No danger of race conditions because the output devices are closed after all
413 // threads join.
414         if(do_audio)
415         {
416                 return audio->current_position();
417         }
419         if(do_video)
420         {
421                 int64_t result = timer.get_scaled_difference(
422                         edl->session->sample_rate);
423                 return result;
424         }
427 PluginServer* RenderEngine::scan_plugindb(char *title, 
428         int data_type)
430         for(int i = 0; i < plugindb->total; i++)
431         {
432                 PluginServer *server = plugindb->values[i];
433                 if(!strcasecmp(server->title, title) &&
434                         ((data_type == TRACK_AUDIO && server->audio) ||
435                         (data_type == TRACK_VIDEO && server->video)))
436                         return plugindb->values[i];
437         }
438         return 0;
441 int RenderEngine::start_command()
443         if(command->realtime)
444         {
445                 interrupt_lock->lock("RenderEngine::start_command");
446                 start_lock->lock("RenderEngine::start_command 1");
447                 Thread::start();
448                 start_lock->lock("RenderEngine::start_command 2");
449                 start_lock->unlock();
450         }
451         return 0;
454 void RenderEngine::arm_render_threads()
456         if(do_audio)
457         {
458                 arender->arm_command();
459         }
461         if(do_video)
462         {
463                 vrender->arm_command();
464         }
468 void RenderEngine::start_render_threads()
470 // Synchronization timer.  Gets reset once again after the first video frame.
471         timer.update();
473         if(do_audio)
474         {
475                 arender->start_command();
476         }
478         if(do_video)
479         {
480                 vrender->start_command();
481         }
484 void RenderEngine::update_framerate(float framerate)
486         playback_engine->mwindow->edl->session->actual_frame_rate = framerate;
487         playback_engine->mwindow->preferences_thread->update_framerate();
490 void RenderEngine::wait_render_threads()
492         if(do_audio)
493         {
494                 arender->Thread::join();
495         }
497         if(do_video)
498         {
499                 vrender->Thread::join();
500         }
503 void RenderEngine::interrupt_playback()
505         interrupt_lock->lock("RenderEngine::interrupt_playback");
506         interrupted = 1;
507         if(audio)
508         {
509                 audio->interrupt_playback();
510         }
511         if(video)
512         {
513 //printf("RenderEngine::interrupt_playback 3 %p\n", this);
514                 video->interrupt_playback();
515 //printf("RenderEngine::interrupt_playback 4 %p\n", this);
516         }
517         interrupt_lock->unlock();
520 int RenderEngine::close_output()
522 //printf("RenderEngine::close_output 1\n");
523         if(audio)
524         {
525 //printf("RenderEngine::close_output 2\n");
526                 audio->close_all();
527                 delete audio;
528                 audio = 0;
529         }
533         if(video)
534         {
535 //printf("RenderEngine::close_output 1\n");
536                 video->close_all();
537 //printf("RenderEngine::close_output 2\n");
538                 delete video;
539 //printf("RenderEngine::close_output 3\n");
540                 video = 0;
541         }
542 //printf("RenderEngine::close_output 4\n");
543         return 0;
546 void RenderEngine::get_output_levels(double *levels, int64_t position)
548         if(do_audio)
549         {
550                 int history_entry = arender->get_history_number(arender->level_samples, position);
551 //printf("RenderEngine::get_output_levels %d\n", history_entry);
552                 for(int i = 0; i < MAXCHANNELS; i++)
553                 {
554                         if(arender->audio_out[i])
555                                 levels[i] = arender->level_history[i][history_entry];
556                 }
557         }
560 void RenderEngine::get_module_levels(ArrayList<double> *module_levels, int64_t position)
562         if(do_audio)
563         {
564                 for(int i = 0; i < arender->total_modules; i++)
565                 {
566 //printf("RenderEngine::get_module_levels %p %p\n", ((AModule*)arender->modules[i]), ((AModule*)arender->modules[i])->level_samples);
567                         int history_entry = arender->get_history_number(((AModule*)arender->modules[i])->level_samples, position);
569                         module_levels->append(((AModule*)arender->modules[i])->level_history[history_entry]);
570                 }
571         }
578 void RenderEngine::run()
580         start_render_threads();
581         start_lock->unlock();
582         interrupt_lock->unlock();
584         wait_render_threads();
586         interrupt_lock->lock("RenderEngine::run");
589         if(interrupted)
590         {
591                 playback_engine->tracking_position = playback_engine->get_tracking_position();
592         }
594         close_output();
596 // Fix the tracking position
597         if(playback_engine)
598         {
599                 if(command->command == CURRENT_FRAME)
600                 {
601 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
602                         playback_engine->tracking_position = command->playbackstart;
603                 }
604                 else
605                 {
606 // Make sure transport doesn't issue a pause command next
607 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
608                         if(!interrupted)
609                         {
610                                 if(do_audio)
611                                         playback_engine->tracking_position = 
612                                                 (double)arender->current_position / 
613                                                         command->get_edl()->session->sample_rate;
614                                 else
615                                 if(do_video)
616                                 {
617                                         playback_engine->tracking_position = 
618                                                 (double)vrender->current_position / 
619                                                         command->get_edl()->session->frame_rate;
620                                 }
621                         }
623                         if(!interrupted) playback_engine->command->command = STOP;
624                         playback_engine->stop_tracking();
626                 }
627                 playback_engine->is_playing_back = 0;
628         }
630         input_lock->unlock();
631         interrupt_lock->unlock();
658 int RenderEngine::reset_parameters()
660         start_position = 0;
661         follow_loop = 0;
662         end_position = 0;
663         infinite = 0;
664         start_position = 0;
665         audio_channels = 0;
666         do_audio = 0;
667         do_video = 0;
668         done = 0;
671 int RenderEngine::arm_playback_audio(int64_t input_length, 
672                         int64_t amodule_render_fragment, 
673                         int64_t playback_buffer, 
674                         int64_t output_length, 
675                         int audio_channels)
677         this->audio_channels = audio_channels;
679         do_audio = 1;
681         arender = new ARender(this);
682         arender->arm_playback(current_sample, 
683                                                         input_length, 
684                                                         amodule_render_fragment, 
685                                                         playback_buffer, 
686                                                         output_length);
689 int RenderEngine::arm_playback_video(int every_frame, 
690                         int64_t read_length, 
691                         int64_t output_length,
692                         int track_w,
693                         int track_h,
694                         int output_w,
695                         int output_h)
697         do_video = 1;
698         this->every_frame = every_frame;
700         vrender = new VRender(this);
701 //      vrender->arm_playback(current_sample, 
702 //                                                      read_length, 
703 //                                                      output_length, 
704 //                                                      output_length, 
705 //                                                      track_w,
706 //                                                      track_h,
707 //                                                      output_w,
708 //                                                      output_h);
711 int RenderEngine::start_video()
713 // start video for realtime
714         if(video) video->start_playback();
715         vrender->start_playback();
719 int64_t RenderEngine::get_correction_factor(int reset)
721         if(!every_frame)
722         {
723                 int64_t x;
724 //              x = playbackengine->correction_factor;
725 //              if(reset) playbackengine->correction_factor = 0;
726                 return x;
727         }
728         else
729                 return 0;