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 "channeldb.h"
28 #include "condition.h"
30 #include "edlsession.h"
33 #include "playbackengine.h"
34 #include "preferences.h"
35 #include "preferencesthread.h"
36 #include "renderengine.h"
37 #include "mainsession.h"
39 #include "transportque.h"
40 #include "videodevice.h"
42 #include "workarounds.h"
46 RenderEngine::RenderEngine(PlaybackEngine *playback_engine,
47 Preferences *preferences,
53 this->playback_engine = playback_engine;
54 this->output = output;
55 this->channeldb = channeldb;
56 this->is_nested = is_nested;
59 config = new PlaybackConfig;
65 this->preferences = new Preferences;
66 this->command = new TransportCommand;
67 this->preferences->copy_from(preferences);
72 if(playback_engine && playback_engine->mwindow)
73 mwindow = playback_engine->mwindow;
77 input_lock = new Condition(1, "RenderEngine::input_lock");
78 start_lock = new Condition(1, "RenderEngine::start_lock");
79 output_lock = new Condition(1, "RenderEngine::output_lock");
80 interrupt_lock = new Mutex("RenderEngine::interrupt_lock");
81 first_frame_lock = new Condition(1, "RenderEngine::first_frame_lock");
84 RenderEngine::~RenderEngine()
89 if(arender) delete arender;
90 if(vrender) delete vrender;
94 delete interrupt_lock;
95 delete first_frame_lock;
97 edl->Garbage::remove_user();
100 EDL* RenderEngine::get_edl()
102 // return command->get_edl();
106 int RenderEngine::arm_command(TransportCommand *command)
109 // Prevent this renderengine from accepting another command until finished.
110 // Since the renderengine is often deleted after the input_lock command it must
111 // be locked here as well as in the calling routine.
112 if(debug) printf("RenderEngine::arm_command %d\n", __LINE__);
115 input_lock->lock("RenderEngine::arm_command");
120 edl->create_objects();
121 edl->copy_all(command->get_edl());
123 this->command->copy_from(command);
125 // Fix background rendering asset to use current dimensions and ignore
127 preferences->brender_asset->frame_rate = command->get_edl()->session->frame_rate;
128 preferences->brender_asset->width = command->get_edl()->session->output_w;
129 preferences->brender_asset->height = command->get_edl()->session->output_h;
130 preferences->brender_asset->use_header = 0;
131 preferences->brender_asset->layers = 1;
132 preferences->brender_asset->video_data = 1;
137 // Retool configuration for this node
138 this->config->copy_from(command->get_edl()->session->playback_config);
139 VideoOutConfig *vconfig = this->config->vconfig;
140 AudioOutConfig *aconfig = this->config->aconfig;
141 if(command->realtime)
143 if(command->single_frame() && vconfig->driver != PLAYBACK_X11_GL)
145 vconfig->driver = PLAYBACK_X11;
150 vconfig->driver = PLAYBACK_X11;
159 fragment_len = aconfig->fragment_size;
160 // Larger of audio_module_fragment and fragment length adjusted for speed
161 // Extra memory must be allocated for rendering slow motion.
162 float speed = command->get_speed();
163 adjusted_fragment_len = speed >= 1.0 ?
164 (int64_t)(aconfig->fragment_size * speed + 0.5) :
165 (int64_t)(aconfig->fragment_size / speed + 0.5) ;
166 if(adjusted_fragment_len < aconfig->fragment_size)
167 adjusted_fragment_len = aconfig->fragment_size;
170 // Set lock so audio doesn't start until video has started.
173 while(first_frame_lock->get_value() > 0)
174 first_frame_lock->lock("RenderEngine::arm_command");
177 // Set lock so audio doesn't wait for video which is never to come.
179 while(first_frame_lock->get_value() <= 0)
180 first_frame_lock->unlock();
184 create_render_threads();
185 arm_render_threads();
186 if(debug) printf("RenderEngine::arm_command %d\n", __LINE__);
191 void RenderEngine::get_duty()
196 //printf("RenderEngine::get_duty %d\n", __LINE__);
197 if(!command->single_frame() &&
198 get_edl()->tracks->playable_audio_tracks() &&
199 get_edl()->session->audio_channels)
204 //printf("RenderEngine::get_duty %d\n", __LINE__);
205 if(get_edl()->tracks->playable_video_tracks())
207 //printf("RenderEngine::get_duty %d\n", __LINE__);
212 void RenderEngine::create_render_threads()
214 if(do_video && !vrender)
216 vrender = new VRender(this);
219 if(do_audio && !arender)
221 arender = new ARender(this);
226 int RenderEngine::get_output_w()
228 return get_edl()->session->output_w;
231 int RenderEngine::get_output_h()
233 return get_edl()->session->output_h;
236 int RenderEngine::brender_available(int position, int direction)
240 int64_t corrected_position = position;
241 if(direction == PLAY_REVERSE)
242 corrected_position--;
243 return playback_engine->brender_available(corrected_position);
249 Channel* RenderEngine::get_current_channel()
253 switch(config->vconfig->driver)
256 if(config->vconfig->buz_out_channel >= 0 &&
257 config->vconfig->buz_out_channel < channeldb->size())
259 return channeldb->get(config->vconfig->buz_out_channel);
262 case VIDEO4LINUX2JPEG:
263 case VIDEO4LINUX2MPEG:
270 CICache* RenderEngine::get_acache()
273 return playback_engine->audio_cache;
278 CICache* RenderEngine::get_vcache()
281 return playback_engine->video_cache;
286 void RenderEngine::set_acache(CICache *cache)
288 this->audio_cache = cache;
291 void RenderEngine::set_vcache(CICache *cache)
293 this->video_cache = cache;
297 double RenderEngine::get_tracking_position()
300 return playback_engine->get_tracking_position();
305 int RenderEngine::open_output()
307 if(command->realtime && !is_nested)
312 audio = new AudioDevice(mwindow);
317 video = new VideoDevice(mwindow);
320 // Initialize sharing
324 if(do_audio && do_video)
326 video->set_adevice(audio);
327 audio->set_vdevice(video);
332 // Retool playback configuration
335 if(audio->open_output(config->aconfig,
336 get_edl()->session->sample_rate,
337 adjusted_fragment_len,
338 get_edl()->session->audio_channels,
339 get_edl()->session->real_time_playback))
343 audio->set_software_positioning(
344 get_edl()->session->playback_software_position);
345 audio->start_playback();
351 video->open_output(config->vconfig,
352 get_edl()->session->frame_rate,
356 command->single_frame());
357 Channel *channel = get_current_channel();
358 if(channel) video->set_channel(channel);
359 video->set_quality(80);
360 video->set_cpus(preferences->processors);
367 void RenderEngine::reset_sync_position()
372 int64_t RenderEngine::sync_position()
375 // No danger of race conditions because the output devices are closed after all
379 return audio->current_position();
384 int64_t result = timer.get_scaled_difference(
385 get_edl()->session->sample_rate);
392 int RenderEngine::start_command()
394 if(command->realtime && !is_nested)
396 interrupt_lock->lock("RenderEngine::start_command");
397 start_lock->lock("RenderEngine::start_command 1");
399 start_lock->lock("RenderEngine::start_command 2");
400 start_lock->unlock();
405 void RenderEngine::arm_render_threads()
409 arender->arm_command();
414 vrender->arm_command();
419 void RenderEngine::start_render_threads()
421 // Synchronization timer. Gets reset once again after the first video frame.
426 arender->start_command();
431 vrender->start_command();
435 void RenderEngine::update_framerate(float framerate)
437 playback_engine->mwindow->session->actual_frame_rate = framerate;
438 playback_engine->mwindow->preferences_thread->update_framerate();
441 void RenderEngine::wait_render_threads()
445 arender->Thread::join();
450 vrender->Thread::join();
454 void RenderEngine::interrupt_playback()
456 interrupt_lock->lock("RenderEngine::interrupt_playback");
458 if(do_audio && arender)
460 arender->interrupt_playback();
463 if(do_video && vrender)
465 vrender->interrupt_playback();
467 interrupt_lock->unlock();
470 int RenderEngine::close_output()
472 // Nested engines share devices
495 void RenderEngine::get_output_levels(double *levels, int64_t position)
499 int history_entry = arender->get_history_number(arender->level_samples,
501 for(int i = 0; i < MAXCHANNELS; i++)
503 if(arender->audio_out[i])
504 levels[i] = arender->level_history[i][history_entry];
509 void RenderEngine::get_module_levels(ArrayList<double> *module_levels, int64_t position)
513 for(int i = 0; i < arender->total_modules; i++)
515 //printf("RenderEngine::get_module_levels %p %p\n", ((AModule*)arender->modules[i]), ((AModule*)arender->modules[i])->level_samples);
516 int history_entry = arender->get_history_number(((AModule*)arender->modules[i])->level_samples, position);
518 module_levels->append(((AModule*)arender->modules[i])->level_history[history_entry]);
527 void RenderEngine::run()
529 start_render_threads();
530 start_lock->unlock();
531 interrupt_lock->unlock();
533 wait_render_threads();
535 interrupt_lock->lock("RenderEngine::run");
540 playback_engine->tracking_position = playback_engine->get_tracking_position();
545 // Fix the tracking position
548 if(command->command == CURRENT_FRAME)
550 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
551 playback_engine->tracking_position = command->playbackstart;
555 // Make sure transport doesn't issue a pause command next
556 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
560 playback_engine->tracking_position =
561 (double)arender->current_position /
562 command->get_edl()->session->sample_rate;
566 playback_engine->tracking_position =
567 (double)vrender->current_position /
568 command->get_edl()->session->frame_rate;
572 if(!interrupted) playback_engine->command->command = STOP;
573 playback_engine->stop_tracking();
576 playback_engine->is_playing_back = 0;
579 input_lock->unlock();
580 interrupt_lock->unlock();