r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / cinelerra / renderengine.C
bloba73f73c80915e52f4be9efb15bca565abce3389a
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;
61         input_lock = new Condition(1, "RenderEngine::input_lock");
62         start_lock = new Condition(1, "RenderEngine::start_lock");
63         output_lock = new Condition(1, "RenderEngine::output_lock");
64         interrupt_lock = new Mutex("RenderEngine::interrupt_lock");
65         first_frame_lock = new Condition(1, "RenderEngine::first_frame_lock");
68 RenderEngine::~RenderEngine()
70         close_output();
71         delete command;
72         delete preferences;
73         if(arender) delete arender;
74         if(vrender) delete vrender;
75         delete edl;
76         delete input_lock;
77         delete start_lock;
78         delete output_lock;
79         delete interrupt_lock;
80         delete first_frame_lock;
81         delete config;
84 int RenderEngine::arm_command(TransportCommand *command,
85         int &current_vchannel, 
86         int &current_achannel)
88 // Prevent this renderengine from accepting another command until finished.
89 // Since the renderengine is often deleted after the input_lock command it must
90 // be locked here as well as in the calling routine.
93         input_lock->lock("RenderEngine::arm_command");
96         this->command->copy_from(command);
98 // Fix background rendering asset to use current dimensions and ignore
99 // headers.
100         preferences->brender_asset->frame_rate = command->get_edl()->session->frame_rate;
101         preferences->brender_asset->width = command->get_edl()->session->output_w;
102         preferences->brender_asset->height = command->get_edl()->session->output_h;
103         preferences->brender_asset->use_header = 0;
104         preferences->brender_asset->layers = 1;
105         preferences->brender_asset->video_data = 1;
107         done = 0;
108         interrupted = 0;
110 // Retool configuration for this node
111         this->config->copy_from(command->get_edl()->session->playback_config);
112         VideoOutConfig *vconfig = this->config->vconfig;
113         AudioOutConfig *aconfig = this->config->aconfig;
114         if(command->realtime)
115         {
116                 int device_channels = 0;
117                 int edl_channels = 0;
118                 if(command->single_frame())
119                 {
120                         vconfig->driver = PLAYBACK_X11;
121                         device_channels = 1;
122                         edl_channels = command->get_edl()->session->video_channels;
123                 }
124                 else
125                 {
126                         device_channels = 1;
127                         edl_channels = command->get_edl()->session->video_channels;
128                 }
130                 for(int i = 0; i < MAX_CHANNELS; i++)
131                 {
132                         vconfig->do_channel[i] = 
133                                 ((i == current_vchannel) && 
134                                         device_channels &&
135                                         edl_channels);
137 // GCC 3.2 optimization error causes do_channel[0] to always be 0 unless
138 // we do this.
139 Workarounds::clamp(vconfig->do_channel[i], 0, 1);
141                         if(vconfig->do_channel[i])
142                         {
143                                 current_vchannel++;
144                                 device_channels--;
145                                 edl_channels--;
146                         }
147                 }
149                 device_channels = aconfig->total_output_channels();
150                 edl_channels = command->get_edl()->session->audio_channels;
152                 for(int i = 0; i < MAX_CHANNELS; i++)
153                 {
155                         aconfig->do_channel[i] = 
156                                 (i == current_achannel && 
157                                         device_channels &&
158                                         edl_channels);
159                         if(aconfig->do_channel[i])
160                         {
161                                 current_achannel++;
162                                 device_channels--;
163                                 edl_channels--;
164                         }
165                 }
167         }
168         else
169         {
170                 vconfig->driver = PLAYBACK_X11;
171                 for(int i = 0; i < MAX_CHANNELS; i++)
172                 {
173                         vconfig->do_channel[i] = (i < command->get_edl()->session->video_channels);
174                         vconfig->do_channel[i] = (i < command->get_edl()->session->video_channels);
175                         aconfig->do_channel[i] = (i < command->get_edl()->session->audio_channels);
176                 }
177         }
181         get_duty();
183         if(do_audio)
184         {
185                 fragment_len = aconfig->fragment_size;
186 // Larger of audio_module_fragment and fragment length adjusted for speed
187 // Extra memory must be allocated for rendering slow motion.
188                 adjusted_fragment_len = (int64_t)((float)aconfig->fragment_size / 
189                         command->get_speed() + 0.5);
190                 if(adjusted_fragment_len < aconfig->fragment_size)
191                         adjusted_fragment_len = aconfig->fragment_size;
192         }
194 // Set lock so audio doesn't start until video has started.
195         if(do_video)
196         {
197                 while(first_frame_lock->get_value() > 0) 
198                         first_frame_lock->lock("RenderEngine::arm_command");
199         }
200         else
201 // Set lock so audio doesn't wait for video which is never to come.
202         {
203                 while(first_frame_lock->get_value() <= 0)
204                         first_frame_lock->unlock();
205         }
207         open_output();
208         create_render_threads();
209         arm_render_threads();
211         return 0;
214 void RenderEngine::get_duty()
216         do_audio = 0;
217         do_video = 0;
219 //edl->dump();
220 //printf("RenderEngine::get_duty 1 %d %d\n", edl->tracks->playable_audio_tracks(), config->vconfig->total_playable_channels());
221         if(!command->single_frame() &&
222                 edl->tracks->playable_audio_tracks() &&
223                 config->aconfig->total_playable_channels())
224         {
225                 do_audio = 1;
226         }
228 //printf("RenderEngine::get_duty 2 %d %d\n", edl->tracks->playable_video_tracks(), config->vconfig->total_playable_channels());
229         if(edl->tracks->playable_video_tracks() &&
230                 config->vconfig->total_playable_channels())
231         {
232                 do_video = 1;
233         }
236 void RenderEngine::create_render_threads()
238         if(do_video && !vrender)
239         {
240                 vrender = new VRender(this);
241         }
243         if(do_audio && !arender)
244         {
245                 arender = new ARender(this);
246         }
250 int RenderEngine::get_output_w()
252         return edl->calculate_output_w(1);
255 int RenderEngine::get_output_h()
257         return edl->calculate_output_h(1);
260 int RenderEngine::brender_available(int position, int direction)
262         if(playback_engine)
263         {
264                 int64_t corrected_position = position;
265                 if(direction == PLAY_REVERSE)
266                         corrected_position--;
267                 return playback_engine->brender_available(corrected_position);
268         }
269         else
270                 return 0;
273 Channel* RenderEngine::get_current_channel()
275         if(channeldb)
276         {
277                 switch(config->vconfig->driver)
278                 {
279                         case PLAYBACK_BUZ:
280                                 if(config->vconfig->buz_out_channel >= 0 && 
281                                         config->vconfig->buz_out_channel < channeldb->size())
282                                 {
283                                         return channeldb->get(config->vconfig->buz_out_channel);
284                                 }
285                                 break;
286                         case VIDEO4LINUX2JPEG:
287                                 
288                                 break;
289                 }
290         }
291         return 0;
294 CICache* RenderEngine::get_acache()
296         if(playback_engine)
297                 return playback_engine->audio_cache;
298         else
299                 return audio_cache;
302 CICache* RenderEngine::get_vcache()
304         if(playback_engine)
305                 return playback_engine->video_cache;
306         else
307                 return video_cache;
310 void RenderEngine::set_acache(CICache *cache)
312         this->audio_cache = cache;
315 void RenderEngine::set_vcache(CICache *cache)
317         this->video_cache = cache;
321 double RenderEngine::get_tracking_position()
323         if(playback_engine) 
324                 return playback_engine->get_tracking_position();
325         else
326                 return 0;
329 int RenderEngine::open_output()
331 //printf("RenderEngine::open_output 1\n");
332         if(command->realtime)
333         {
334 // Allocate devices
335                 if(do_audio)
336                 {
337                         audio = new AudioDevice;
338                 }
340                 if(do_video)
341                 {
342                         video = new VideoDevice;
343                 }
345 // Initialize sharing
348 // Start playback
349                 if(do_audio && do_video)
350                 {
351                         video->set_adevice(audio);
352                         audio->set_vdevice(video);
353                 }
357 // Retool playback configuration
358                 if(do_audio)
359                 {
360                         audio->open_output(config->aconfig, 
361                                 edl->session->sample_rate, 
362                                 adjusted_fragment_len,
363                                 edl->session->real_time_playback);
364                         audio->set_software_positioning(edl->session->playback_software_position);
365                         audio->start_playback();
366                 }
368                 if(do_video)
369                 {
370                         video->open_output(config->vconfig, 
371                                 edl->session->frame_rate,
372                                 get_output_w(),
373                                 get_output_h(),
374                                 output,
375                                 command->single_frame());
376                         Channel *channel = get_current_channel();
377                         if(channel) video->set_channel(channel);
378                         video->set_quality(80);
379                         video->set_cpus(preferences->processors);
380                 }
381         }
383         return 0;
386 int64_t RenderEngine::session_position()
388         if(do_audio)
389         {
390                 return audio->current_position();
391         }
393         if(do_video)
394         {
395                 return (int64_t)((double)vrender->session_frame / 
396                                 edl->session->frame_rate * 
397                                 edl->session->sample_rate /
398                                 command->get_speed() + 0.5);
399         }
402 void RenderEngine::reset_sync_position()
404         timer.update();
407 int64_t RenderEngine::sync_position()
409 // Use audio device
410 // No danger of race conditions because the output devices are closed after all
411 // threads join.
412         if(do_audio)
413         {
414                 return audio->current_position();
415         }
417         if(do_video)
418         {
419                 int64_t result = timer.get_scaled_difference(
420                         edl->session->sample_rate);
421                 return result;
422         }
425 PluginServer* RenderEngine::scan_plugindb(char *title, 
426         int data_type)
428         for(int i = 0; i < plugindb->total; i++)
429         {
430                 PluginServer *server = plugindb->values[i];
431                 if(!strcasecmp(server->title, title) &&
432                         ((data_type == TRACK_AUDIO && server->audio) ||
433                         (data_type == TRACK_VIDEO && server->video)))
434                         return plugindb->values[i];
435         }
436         return 0;
439 int RenderEngine::start_command()
441         if(command->realtime)
442         {
443                 interrupt_lock->lock("RenderEngine::start_command");
444                 start_lock->lock("RenderEngine::start_command 1");
445                 Thread::start();
446                 start_lock->lock("RenderEngine::start_command 2");
447                 start_lock->unlock();
448         }
449         return 0;
452 void RenderEngine::arm_render_threads()
454         if(do_audio)
455         {
456                 arender->arm_command();
457         }
459         if(do_video)
460         {
461                 vrender->arm_command();
462         }
466 void RenderEngine::start_render_threads()
468 // Synchronization timer.  Gets reset once again after the first video frame.
469         timer.update();
471         if(do_audio)
472         {
473                 arender->start_command();
474         }
476         if(do_video)
477         {
478                 vrender->start_command();
479         }
482 void RenderEngine::update_framerate(float framerate)
484         playback_engine->mwindow->edl->session->actual_frame_rate = framerate;
485         playback_engine->mwindow->preferences_thread->update_framerate();
488 void RenderEngine::wait_render_threads()
490         if(do_audio)
491         {
492                 arender->Thread::join();
493         }
494         if(do_video)
495         {
496                 vrender->Thread::join();
497         }
500 void RenderEngine::interrupt_playback()
502         interrupt_lock->lock("RenderEngine::interrupt_playback");
503         interrupted = 1;
504         if(audio)
505         {
506                 audio->interrupt_playback();
507         }
508         if(video)
509         {
510 //printf("RenderEngine::interrupt_playback 3 %p\n", this);
511                 video->interrupt_playback();
512 //printf("RenderEngine::interrupt_playback 4 %p\n", this);
513         }
514         interrupt_lock->unlock();
517 int RenderEngine::close_output()
519 //printf("RenderEngine::close_output 1\n");
520         if(audio)
521         {
522 //printf("RenderEngine::close_output 2\n");
523                 audio->close_all();
524                 delete audio;
525                 audio = 0;
526         }
530         if(video)
531         {
532 //printf("RenderEngine::close_output 1\n");
533                 video->close_all();
534 //printf("RenderEngine::close_output 2\n");
535                 delete video;
536 //printf("RenderEngine::close_output 3\n");
537                 video = 0;
538         }
539 //printf("RenderEngine::close_output 4\n");
540         return 0;
543 void RenderEngine::get_output_levels(double *levels, int64_t position)
545         if(do_audio)
546         {
547                 int history_entry = arender->get_history_number(arender->level_samples, position);
548 //printf("RenderEngine::get_output_levels %d\n", history_entry);
549                 for(int i = 0; i < MAXCHANNELS; i++)
550                 {
551                         if(arender->audio_out[i])
552                                 levels[i] = arender->level_history[i][history_entry];
553                 }
554         }
557 void RenderEngine::get_module_levels(ArrayList<double> *module_levels, int64_t position)
559         if(do_audio)
560         {
561                 for(int i = 0; i < arender->total_modules; i++)
562                 {
563 //printf("RenderEngine::get_module_levels %p %p\n", ((AModule*)arender->modules[i]), ((AModule*)arender->modules[i])->level_samples);
564                         int history_entry = arender->get_history_number(((AModule*)arender->modules[i])->level_samples, position);
566                         module_levels->append(((AModule*)arender->modules[i])->level_history[history_entry]);
567                 }
568         }
575 void RenderEngine::run()
577         start_render_threads();
578         start_lock->unlock();
579         interrupt_lock->unlock();
581         wait_render_threads();
583         interrupt_lock->lock("RenderEngine::run");
586         if(interrupted)
587         {
588                 playback_engine->tracking_position = playback_engine->get_tracking_position();
589         }
591         close_output();
593 // Fix the tracking position
594         if(playback_engine)
595         {
596                 if(command->command == CURRENT_FRAME)
597                 {
598 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
599                         playback_engine->tracking_position = command->playbackstart;
600                 }
601                 else
602                 {
603 // Make sure transport doesn't issue a pause command next
604 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
605                         if(!interrupted)
606                         {
607                                 if(do_audio)
608                                         playback_engine->tracking_position = 
609                                                 (double)arender->current_position / 
610                                                         command->get_edl()->session->sample_rate;
611                                 else
612                                 if(do_video)
613                                 {
614                                         playback_engine->tracking_position = 
615                                                 (double)vrender->current_position / 
616                                                         command->get_edl()->session->frame_rate;
617                                 }
618                         }
620                         if(!interrupted) playback_engine->command->command = STOP;
621                         playback_engine->stop_tracking();
623                 }
624                 playback_engine->is_playing_back = 0;
625         }
627         input_lock->unlock();
628         interrupt_lock->unlock();
655 int RenderEngine::reset_parameters()
657         start_position = 0;
658         follow_loop = 0;
659         end_position = 0;
660         infinite = 0;
661         reverse = 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_common(int64_t start_sample, 
670                         int64_t end_sample,
671                         int64_t current_sample,
672                         int reverse, 
673                         float speed, 
674                         int follow_loop,
675                         int infinite)
677         this->follow_loop = follow_loop;
678         this->start_position = start_sample;
679         this->end_position = end_sample;
680         this->reverse = reverse;
681         this->infinite = infinite;
682         this->current_sample = current_sample;
683         if(infinite) this->follow_loop = 0;
686 int RenderEngine::arm_playback_audio(int64_t input_length, 
687                         int64_t amodule_render_fragment, 
688                         int64_t playback_buffer, 
689                         int64_t output_length, 
690                         int audio_channels)
692         this->audio_channels = audio_channels;
694         do_audio = 1;
696         arender = new ARender(this);
697         arender->arm_playback(current_sample, 
698                                                         input_length, 
699                                                         amodule_render_fragment, 
700                                                         playback_buffer, 
701                                                         output_length);
704 int RenderEngine::arm_playback_video(int every_frame, 
705                         int64_t read_length, 
706                         int64_t output_length,
707                         int track_w,
708                         int track_h,
709                         int output_w,
710                         int output_h)
712         do_video = 1;
713         this->every_frame = every_frame;
715         vrender = new VRender(this);
716 //      vrender->arm_playback(current_sample, 
717 //                                                      read_length, 
718 //                                                      output_length, 
719 //                                                      output_length, 
720 //                                                      track_w,
721 //                                                      track_h,
722 //                                                      output_w,
723 //                                                      output_h);
726 int RenderEngine::start_video()
728 // start video for realtime
729         if(video) video->start_playback();
730         vrender->start_playback();
734 int64_t RenderEngine::get_correction_factor(int reset)
736         if(!every_frame)
737         {
738                 int64_t x;
739 //              x = playbackengine->correction_factor;
740 //              if(reset) playbackengine->correction_factor = 0;
741                 return x;
742         }
743         else
744                 return 0;