4 * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
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.
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.
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
25 #include "audiodevice.h"
26 #include "bcsignals.h"
27 #include "condition.h"
29 #include "edlsession.h"
32 #include "playbackengine.h"
33 #include "preferences.h"
34 #include "preferencesthread.h"
35 #include "renderengine.h"
36 #include "mainsession.h"
38 #include "transportque.h"
39 #include "videodevice.h"
41 #include "workarounds.h"
45 RenderEngine::RenderEngine(PlaybackEngine *playback_engine,
46 Preferences *preferences,
51 this->playback_engine = playback_engine;
52 this->output = output;
53 this->is_nested = is_nested;
56 config = new PlaybackConfig;
62 this->preferences = new Preferences;
63 this->command = new TransportCommand;
64 this->preferences->copy_from(preferences);
69 mwindow = !playback_engine ? 0 : playback_engine->mwindow;
71 input_lock = new Condition(1, "RenderEngine::input_lock");
72 start_lock = new Condition(1, "RenderEngine::start_lock");
73 output_lock = new Condition(1, "RenderEngine::output_lock");
74 render_active = new Condition(1,"RenderEngine::render_active");
75 interrupt_lock = new Mutex("RenderEngine::interrupt_lock");
76 first_frame_lock = new Condition(1, "RenderEngine::first_frame_lock");
79 RenderEngine::~RenderEngine()
84 if(arender) delete arender;
85 if(vrender) delete vrender;
90 delete interrupt_lock;
91 delete first_frame_lock;
93 if( edl ) edl->Garbage::remove_user();
96 EDL* RenderEngine::get_edl()
98 // return command->get_edl();
102 int RenderEngine::arm_command(TransportCommand *command)
105 // Prevent this renderengine from accepting another command until finished.
106 // Since the renderengine is often deleted after the input_lock command it must
107 // be locked here as well as in the calling routine.
108 if(debug) printf("RenderEngine::arm_command %d\n", __LINE__);
111 input_lock->lock("RenderEngine::arm_command");
116 edl->create_objects();
117 edl->copy_all(command->get_edl());
119 this->command->copy_from(command);
121 // Fix background rendering asset to use current dimensions and ignore
123 preferences->brender_asset->frame_rate = command->get_edl()->session->frame_rate;
124 preferences->brender_asset->width = command->get_edl()->session->output_w;
125 preferences->brender_asset->height = command->get_edl()->session->output_h;
126 preferences->brender_asset->use_header = 0;
127 preferences->brender_asset->layers = 1;
128 preferences->brender_asset->video_data = 1;
133 // Retool configuration for this node
134 this->config->copy_from(command->get_edl()->session->playback_config);
135 VideoOutConfig *vconfig = this->config->vconfig;
136 AudioOutConfig *aconfig = this->config->aconfig;
137 if(command->realtime)
139 if(command->single_frame() && vconfig->driver != PLAYBACK_X11_GL)
141 vconfig->driver = PLAYBACK_X11;
146 vconfig->driver = PLAYBACK_X11;
155 fragment_len = aconfig->fragment_size;
156 // Larger of audio_module_fragment and fragment length adjusted for speed
157 // Extra memory must be allocated for rendering slow motion.
158 float speed = command->get_speed();
159 adjusted_fragment_len = speed >= 1.0 ?
160 (int64_t)(aconfig->fragment_size * speed + 0.5) :
161 (int64_t)(aconfig->fragment_size / speed + 0.5) ;
162 if(adjusted_fragment_len < aconfig->fragment_size)
163 adjusted_fragment_len = aconfig->fragment_size;
166 // Set lock so audio doesn't start until video has started.
169 while(first_frame_lock->get_value() > 0)
170 first_frame_lock->lock("RenderEngine::arm_command");
173 // Set lock so audio doesn't wait for video which is never to come.
175 while(first_frame_lock->get_value() <= 0)
176 first_frame_lock->unlock();
180 create_render_threads();
181 arm_render_threads();
182 if(debug) printf("RenderEngine::arm_command %d\n", __LINE__);
187 void RenderEngine::get_duty()
192 //printf("RenderEngine::get_duty %d\n", __LINE__);
193 if( get_edl()->tracks->playable_audio_tracks() &&
194 get_edl()->session->audio_channels )
196 do_audio = !command->single_frame() ? 1 : 0;
197 if( command->audio_toggle ) do_audio = !do_audio;
200 //printf("RenderEngine::get_duty %d\n", __LINE__);
201 if(get_edl()->tracks->playable_video_tracks())
203 //printf("RenderEngine::get_duty %d\n", __LINE__);
208 void RenderEngine::create_render_threads()
210 if(do_video && !vrender)
212 vrender = new VRender(this);
215 if(do_audio && !arender)
217 arender = new ARender(this);
222 int RenderEngine::get_output_w()
224 return get_edl()->session->output_w;
227 int RenderEngine::get_output_h()
229 return get_edl()->session->output_h;
232 int RenderEngine::brender_available(int position, int direction)
236 int64_t corrected_position = position;
237 if(direction == PLAY_REVERSE)
238 corrected_position--;
239 return playback_engine->brender_available(corrected_position);
246 CICache* RenderEngine::get_acache()
249 return playback_engine->audio_cache;
254 CICache* RenderEngine::get_vcache()
257 return playback_engine->video_cache;
262 void RenderEngine::set_acache(CICache *cache)
264 this->audio_cache = cache;
267 void RenderEngine::set_vcache(CICache *cache)
269 this->video_cache = cache;
273 double RenderEngine::get_tracking_position()
276 return playback_engine->get_tracking_position();
281 int RenderEngine::open_output()
283 if(command->realtime && !is_nested)
288 audio = new AudioDevice(mwindow);
293 video = new VideoDevice(mwindow);
296 // Initialize sharing
300 if(do_audio && do_video)
302 video->set_adevice(audio);
303 audio->set_vdevice(video);
308 // Retool playback configuration
311 if(audio->open_output(config->aconfig,
312 get_edl()->session->sample_rate,
313 adjusted_fragment_len,
314 get_edl()->session->audio_channels,
315 get_edl()->session->real_time_playback))
319 audio->set_software_positioning(
320 get_edl()->session->playback_software_position);
321 audio->start_playback();
327 video->open_output(config->vconfig,
328 get_edl()->session->frame_rate,
332 command->single_frame());
333 video->set_quality(80);
334 video->set_cpus(preferences->processors);
341 void RenderEngine::reset_sync_position()
346 int64_t RenderEngine::sync_position()
349 // No danger of race conditions because the output devices are closed after all
353 return audio->current_position();
358 int64_t result = timer.get_scaled_difference(
359 get_edl()->session->sample_rate);
366 int RenderEngine::start_command()
368 if(command->realtime && !is_nested)
370 interrupt_lock->lock("RenderEngine::start_command");
371 start_lock->lock("RenderEngine::start_command 1");
373 start_lock->lock("RenderEngine::start_command 2");
374 start_lock->unlock();
379 void RenderEngine::arm_render_threads()
383 arender->arm_command();
388 vrender->arm_command();
393 void RenderEngine::start_render_threads()
395 // Synchronization timer. Gets reset once again after the first video frame.
400 arender->start_command();
405 vrender->start_command();
409 void RenderEngine::update_framerate(float framerate)
411 playback_engine->mwindow->session->actual_frame_rate = framerate;
412 playback_engine->mwindow->preferences_thread->update_framerate();
415 void RenderEngine::wait_render_threads()
419 arender->Thread::join();
424 vrender->Thread::join();
428 void RenderEngine::interrupt_playback()
430 interrupt_lock->lock("RenderEngine::interrupt_playback");
432 if(do_audio && arender)
434 arender->interrupt_playback();
437 if(do_video && vrender)
439 vrender->interrupt_playback();
441 interrupt_lock->unlock();
444 int RenderEngine::close_output()
446 // Nested engines share devices
469 void RenderEngine::get_output_levels(double *levels, int64_t position)
473 int history_entry = arender->get_history_number(arender->level_samples,
475 for(int i = 0; i < MAXCHANNELS; i++)
477 if(arender->audio_out[i])
478 levels[i] = arender->level_history[i][history_entry];
483 void RenderEngine::get_module_levels(ArrayList<double> *module_levels, int64_t position)
487 for(int i = 0; i < arender->total_modules; i++)
489 //printf("RenderEngine::get_module_levels %p %p\n", ((AModule*)arender->modules[i]), ((AModule*)arender->modules[i])->level_samples);
490 int history_entry = arender->get_history_number(((AModule*)arender->modules[i])->level_samples, position);
492 module_levels->append(((AModule*)arender->modules[i])->level_history[history_entry]);
501 void RenderEngine::run()
503 render_active->lock("RenderEngine::run");
504 start_render_threads();
505 start_lock->unlock();
506 interrupt_lock->unlock();
508 wait_render_threads();
510 interrupt_lock->lock("RenderEngine::run");
515 playback_engine->tracking_position = playback_engine->get_tracking_position();
520 // Fix the tracking position
523 if(command->command == CURRENT_FRAME)
525 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
526 playback_engine->tracking_position = command->playbackstart;
530 // Make sure transport doesn't issue a pause command next
531 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
535 playback_engine->tracking_position =
536 (double)arender->current_position /
537 command->get_edl()->session->sample_rate;
541 playback_engine->tracking_position =
542 (double)vrender->current_position /
543 command->get_edl()->session->frame_rate;
547 if( playback_engine->is_playing_back && command->displacement ) {
548 double position = playback_engine->tracking_position -
549 1./command->get_edl()->session->frame_rate;
550 playback_engine->tracking_position = position >= 0 ? position : 0;
553 if(!interrupted) playback_engine->command->command = STOP;
554 playback_engine->stop_tracking();
557 playback_engine->is_playing_back = 0;
560 input_lock->unlock();
561 interrupt_lock->unlock();
562 render_active->unlock();
565 void RenderEngine::wait_done()
567 render_active->lock("RenderEngine::wait_done");
568 render_active->unlock();