Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

renderengine.C

Go to the documentation of this file.
00001 #include "amodule.h"
00002 #include "arender.h"
00003 #include "asset.h"
00004 #include "audiodevice.h"
00005 #include "channeldb.h"
00006 #include "condition.h"
00007 #include "edl.h"
00008 #include "edlsession.h"
00009 #include "mutex.h"
00010 #include "mwindow.h"
00011 #include "playbackengine.h"
00012 #include "preferences.h"
00013 #include "preferencesthread.h"
00014 #include "renderengine.h"
00015 #include "mainsession.h"
00016 #include "tracks.h"
00017 #include "transportque.h"
00018 #include "videodevice.h"
00019 #include "vrender.h"
00020 #include "workarounds.h"
00021 
00022 
00023 
00024 RenderEngine::RenderEngine(PlaybackEngine *playback_engine,
00025         Preferences *preferences, 
00026         TransportCommand *command,
00027         Canvas *output,
00028         ArrayList<PluginServer*> *plugindb,
00029         ChannelDB *channeldb)
00030  : Thread(1, 0, 0)
00031 {
00032         this->playback_engine = playback_engine;
00033         this->output = output;
00034         this->plugindb = plugindb;
00035         this->channeldb = channeldb;
00036         audio = 0;
00037         video = 0;
00038         config = new PlaybackConfig;
00039         arender = 0;
00040         vrender = 0;
00041         do_audio = 0;
00042         do_video = 0;
00043         interrupted = 0;
00044         actual_frame_rate = 0;
00045         this->preferences = new Preferences;
00046         this->command = new TransportCommand;
00047         this->preferences->copy_from(preferences);
00048         this->command->copy_from(command);
00049         edl = new EDL;
00050         edl->create_objects();
00051 // EDL only changed in construction.
00052 // The EDL contained in later commands is ignored.
00053         edl->copy_all(command->get_edl());
00054         audio_cache = 0;
00055         video_cache = 0;
00056         if(playback_engine && playback_engine->mwindow)
00057                 mwindow = playback_engine->mwindow;
00058         else
00059                 mwindow = 0;
00060         show_tc = 0;
00061 
00062 
00063         input_lock = new Condition(1, "RenderEngine::input_lock");
00064         start_lock = new Condition(1, "RenderEngine::start_lock");
00065         output_lock = new Condition(1, "RenderEngine::output_lock");
00066         interrupt_lock = new Mutex("RenderEngine::interrupt_lock");
00067         first_frame_lock = new Condition(1, "RenderEngine::first_frame_lock");
00068         reset_parameters();
00069 }
00070 
00071 RenderEngine::~RenderEngine()
00072 {
00073         close_output();
00074         delete command;
00075         delete preferences;
00076         if(arender) delete arender;
00077         if(vrender) delete vrender;
00078         delete edl;
00079         delete input_lock;
00080         delete start_lock;
00081         delete output_lock;
00082         delete interrupt_lock;
00083         delete first_frame_lock;
00084         delete config;
00085 }
00086 
00087 int RenderEngine::arm_command(TransportCommand *command,
00088         int &current_vchannel, 
00089         int &current_achannel)
00090 {
00091 // Prevent this renderengine from accepting another command until finished.
00092 // Since the renderengine is often deleted after the input_lock command it must
00093 // be locked here as well as in the calling routine.
00094 
00095 
00096         input_lock->lock("RenderEngine::arm_command");
00097 
00098 
00099         this->command->copy_from(command);
00100 
00101 // Fix background rendering asset to use current dimensions and ignore
00102 // headers.
00103         preferences->brender_asset->frame_rate = command->get_edl()->session->frame_rate;
00104         preferences->brender_asset->width = command->get_edl()->session->output_w;
00105         preferences->brender_asset->height = command->get_edl()->session->output_h;
00106         preferences->brender_asset->use_header = 0;
00107         preferences->brender_asset->layers = 1;
00108         preferences->brender_asset->video_data = 1;
00109 
00110         done = 0;
00111         interrupted = 0;
00112 
00113 // Retool configuration for this node
00114         this->config->copy_from(command->get_edl()->session->playback_config);
00115         VideoOutConfig *vconfig = this->config->vconfig;
00116         AudioOutConfig *aconfig = this->config->aconfig;
00117         if(command->realtime)
00118         {
00119                 int device_channels = 0;
00120                 int edl_channels = 0;
00121                 if(command->single_frame())
00122                 {
00123                         vconfig->driver = PLAYBACK_X11;
00124                         device_channels = 1;
00125                         edl_channels = command->get_edl()->session->video_channels;
00126                 }
00127                 else
00128                 {
00129                         device_channels = 1;
00130                         edl_channels = command->get_edl()->session->video_channels;
00131                 }
00132 
00133                 for(int i = 0; i < MAX_CHANNELS; i++)
00134                 {
00135                         vconfig->do_channel[i] = 
00136                                 ((i == current_vchannel) && 
00137                                         device_channels &&
00138                                         edl_channels);
00139 
00140 // GCC 3.2 optimization error causes do_channel[0] to always be 0 unless
00141 // we do this.
00142 Workarounds::clamp(vconfig->do_channel[i], 0, 1);
00143 
00144                         if(vconfig->do_channel[i])
00145                         {
00146                                 current_vchannel++;
00147                                 device_channels--;
00148                                 edl_channels--;
00149                         }
00150                 }
00151 
00152                 device_channels = aconfig->total_output_channels();
00153                 edl_channels = command->get_edl()->session->audio_channels;
00154 
00155                 for(int i = 0; i < MAX_CHANNELS; i++)
00156                 {
00157 
00158                         aconfig->do_channel[i] = 
00159                                 (i == current_achannel && 
00160                                         device_channels &&
00161                                         edl_channels);
00162                         if(aconfig->do_channel[i])
00163                         {
00164                                 current_achannel++;
00165                                 device_channels--;
00166                                 edl_channels--;
00167                         }
00168                 }
00169 
00170         }
00171         else
00172         {
00173                 vconfig->driver = PLAYBACK_X11;
00174                 for(int i = 0; i < MAX_CHANNELS; i++)
00175                 {
00176                         vconfig->do_channel[i] = (i < command->get_edl()->session->video_channels);
00177                         vconfig->do_channel[i] = (i < command->get_edl()->session->video_channels);
00178                         aconfig->do_channel[i] = (i < command->get_edl()->session->audio_channels);
00179                 }
00180         }
00181 
00182 
00183 
00184         get_duty();
00185 
00186         if(do_audio)
00187         {
00188                 fragment_len = aconfig->fragment_size;
00189 // Larger of audio_module_fragment and fragment length adjusted for speed
00190 // Extra memory must be allocated for rendering slow motion.
00191                 adjusted_fragment_len = (int64_t)((float)aconfig->fragment_size / 
00192                         command->get_speed() + 0.5);
00193                 if(adjusted_fragment_len < aconfig->fragment_size)
00194                         adjusted_fragment_len = aconfig->fragment_size;
00195         }
00196 
00197 // Set lock so audio doesn't start until video has started.
00198         if(do_video)
00199         {
00200                 while(first_frame_lock->get_value() > 0) 
00201                         first_frame_lock->lock("RenderEngine::arm_command");
00202         }
00203         else
00204 // Set lock so audio doesn't wait for video which is never to come.
00205         {
00206                 while(first_frame_lock->get_value() <= 0)
00207                         first_frame_lock->unlock();
00208         }
00209 
00210         open_output();
00211         create_render_threads();
00212         arm_render_threads();
00213 
00214         return 0;
00215 }
00216 
00217 void RenderEngine::get_duty()
00218 {
00219         do_audio = 0;
00220         do_video = 0;
00221 
00222 //edl->dump();
00223 //printf("RenderEngine::get_duty 1 %d %d\n", edl->tracks->playable_audio_tracks(), config->vconfig->total_playable_channels());
00224         if(!command->single_frame() &&
00225                 edl->tracks->playable_audio_tracks() &&
00226                 config->aconfig->total_playable_channels())
00227         {
00228                 do_audio = 1;
00229         }
00230 
00231 //printf("RenderEngine::get_duty 2 %d %d\n", edl->tracks->playable_video_tracks(), config->vconfig->total_playable_channels());
00232         if(edl->tracks->playable_video_tracks() &&
00233                 config->vconfig->total_playable_channels())
00234         {
00235                 do_video = 1;
00236         }
00237 }
00238 
00239 void RenderEngine::create_render_threads()
00240 {
00241         if(do_video && !vrender)
00242         {
00243                 vrender = new VRender(this);
00244         }
00245 
00246         if(do_audio && !arender)
00247         {
00248                 arender = new ARender(this);
00249         }
00250 }
00251 
00252 
00253 int RenderEngine::get_output_w()
00254 {
00255         return edl->session->output_w;
00256 }
00257 
00258 int RenderEngine::get_output_h()
00259 {
00260         return edl->session->output_h;
00261 }
00262 
00263 int RenderEngine::brender_available(int position, int direction)
00264 {
00265         if(playback_engine)
00266         {
00267                 int64_t corrected_position = position;
00268                 if(direction == PLAY_REVERSE)
00269                         corrected_position--;
00270                 return playback_engine->brender_available(corrected_position);
00271         }
00272         else
00273                 return 0;
00274 }
00275 
00276 Channel* RenderEngine::get_current_channel()
00277 {
00278         if(channeldb)
00279         {
00280                 switch(config->vconfig->driver)
00281                 {
00282                         case PLAYBACK_BUZ:
00283                                 if(config->vconfig->buz_out_channel >= 0 && 
00284                                         config->vconfig->buz_out_channel < channeldb->size())
00285                                 {
00286                                         return channeldb->get(config->vconfig->buz_out_channel);
00287                                 }
00288                                 break;
00289                         case VIDEO4LINUX2JPEG:
00290                                 
00291                                 break;
00292                 }
00293         }
00294         return 0;
00295 }
00296 
00297 CICache* RenderEngine::get_acache()
00298 {
00299         if(playback_engine)
00300                 return playback_engine->audio_cache;
00301         else
00302                 return audio_cache;
00303 }
00304 
00305 CICache* RenderEngine::get_vcache()
00306 {
00307         if(playback_engine)
00308                 return playback_engine->video_cache;
00309         else
00310                 return video_cache;
00311 }
00312 
00313 void RenderEngine::set_acache(CICache *cache)
00314 {
00315         this->audio_cache = cache;
00316 }
00317 
00318 void RenderEngine::set_vcache(CICache *cache)
00319 {
00320         this->video_cache = cache;
00321 }
00322 
00323 
00324 double RenderEngine::get_tracking_position()
00325 {
00326         if(playback_engine) 
00327                 return playback_engine->get_tracking_position();
00328         else
00329                 return 0;
00330 }
00331 
00332 int RenderEngine::open_output()
00333 {
00334         if(command->realtime)
00335         {
00336 // Allocate devices
00337                 if(do_audio)
00338                 {
00339                         audio = new AudioDevice;
00340                 }
00341 
00342                 if(do_video)
00343                 {
00344                         video = new VideoDevice;
00345                 }
00346 
00347 // Initialize sharing
00348 
00349 
00350 // Start playback
00351                 if(do_audio && do_video)
00352                 {
00353                         video->set_adevice(audio);
00354                         audio->set_vdevice(video);
00355                 }
00356 
00357 
00358 
00359 // Retool playback configuration
00360                 if(do_audio)
00361                 {
00362                         audio->open_output(config->aconfig, 
00363                                 edl->session->sample_rate, 
00364                                 adjusted_fragment_len,
00365                                 edl->session->real_time_playback);
00366                         audio->set_software_positioning(edl->session->playback_software_position);
00367                         audio->start_playback();
00368                 }
00369 
00370                 if(do_video)
00371                 {
00372                         video->open_output(config->vconfig, 
00373                                 edl->session->frame_rate,
00374                                 get_output_w(),
00375                                 get_output_h(),
00376                                 output,
00377                                 command->single_frame());
00378                         Channel *channel = get_current_channel();
00379                         if(channel) video->set_channel(channel);
00380                         video->set_quality(80);
00381                         video->set_cpus(preferences->processors);
00382                 }
00383         }
00384 
00385         return 0;
00386 }
00387 
00388 int64_t RenderEngine::session_position()
00389 {
00390         if(do_audio)
00391         {
00392                 return audio->current_position();
00393         }
00394 
00395         if(do_video)
00396         {
00397                 return (int64_t)((double)vrender->session_frame / 
00398                                 edl->session->frame_rate * 
00399                                 edl->session->sample_rate /
00400                                 command->get_speed() + 0.5);
00401         }
00402 }
00403 
00404 void RenderEngine::reset_sync_position()
00405 {
00406         timer.update();
00407 }
00408 
00409 int64_t RenderEngine::sync_position()
00410 {
00411 // Use audio device
00412 // No danger of race conditions because the output devices are closed after all
00413 // threads join.
00414         if(do_audio)
00415         {
00416                 return audio->current_position();
00417         }
00418 
00419         if(do_video)
00420         {
00421                 int64_t result = timer.get_scaled_difference(
00422                         edl->session->sample_rate);
00423                 return result;
00424         }
00425 }
00426 
00427 PluginServer* RenderEngine::scan_plugindb(char *title, 
00428         int data_type)
00429 {
00430         for(int i = 0; i < plugindb->total; i++)
00431         {
00432                 PluginServer *server = plugindb->values[i];
00433                 if(!strcasecmp(server->title, title) &&
00434                         ((data_type == TRACK_AUDIO && server->audio) ||
00435                         (data_type == TRACK_VIDEO && server->video)))
00436                         return plugindb->values[i];
00437         }
00438         return 0;
00439 }
00440 
00441 int RenderEngine::start_command()
00442 {
00443         if(command->realtime)
00444         {
00445                 interrupt_lock->lock("RenderEngine::start_command");
00446                 start_lock->lock("RenderEngine::start_command 1");
00447                 Thread::start();
00448                 start_lock->lock("RenderEngine::start_command 2");
00449                 start_lock->unlock();
00450         }
00451         return 0;
00452 }
00453 
00454 void RenderEngine::arm_render_threads()
00455 {
00456         if(do_audio)
00457         {
00458                 arender->arm_command();
00459         }
00460 
00461         if(do_video)
00462         {
00463                 vrender->arm_command();
00464         }
00465 }
00466 
00467 
00468 void RenderEngine::start_render_threads()
00469 {
00470 // Synchronization timer.  Gets reset once again after the first video frame.
00471         timer.update();
00472 
00473         if(do_audio)
00474         {
00475                 arender->start_command();
00476         }
00477 
00478         if(do_video)
00479         {
00480                 vrender->start_command();
00481         }
00482 }
00483 
00484 void RenderEngine::update_framerate(float framerate)
00485 {
00486         playback_engine->mwindow->edl->session->actual_frame_rate = framerate;
00487         playback_engine->mwindow->preferences_thread->update_framerate();
00488 }
00489 
00490 void RenderEngine::wait_render_threads()
00491 {
00492         if(do_audio)
00493         {
00494                 arender->Thread::join();
00495         }
00496 
00497         if(do_video)
00498         {
00499                 vrender->Thread::join();
00500         }
00501 }
00502 
00503 void RenderEngine::interrupt_playback()
00504 {
00505         interrupt_lock->lock("RenderEngine::interrupt_playback");
00506         interrupted = 1;
00507         if(audio)
00508         {
00509                 audio->interrupt_playback();
00510         }
00511         if(video)
00512         {
00513 //printf("RenderEngine::interrupt_playback 3 %p\n", this);
00514                 video->interrupt_playback();
00515 //printf("RenderEngine::interrupt_playback 4 %p\n", this);
00516         }
00517         interrupt_lock->unlock();
00518 }
00519 
00520 int RenderEngine::close_output()
00521 {
00522         if(audio)
00523         {
00524                 audio->close_all();
00525                 delete audio;
00526                 audio = 0;
00527         }
00528 
00529 
00530 
00531         if(video)
00532         {
00533                 video->close_all();
00534                 delete video;
00535                 video = 0;
00536         }
00537         return 0;
00538 }
00539 
00540 void RenderEngine::get_output_levels(double *levels, int64_t position)
00541 {
00542         if(do_audio)
00543         {
00544                 int history_entry = arender->get_history_number(arender->level_samples, 
00545                         position);
00546                 for(int i = 0; i < MAXCHANNELS; i++)
00547                 {
00548                         if(arender->audio_out[i])
00549                                 levels[i] = arender->level_history[i][history_entry];
00550                 }
00551         }
00552 }
00553 
00554 void RenderEngine::get_module_levels(ArrayList<double> *module_levels, int64_t position)
00555 {
00556         if(do_audio)
00557         {
00558                 for(int i = 0; i < arender->total_modules; i++)
00559                 {
00560 //printf("RenderEngine::get_module_levels %p %p\n", ((AModule*)arender->modules[i]), ((AModule*)arender->modules[i])->level_samples);
00561                         int history_entry = arender->get_history_number(((AModule*)arender->modules[i])->level_samples, position);
00562 
00563                         module_levels->append(((AModule*)arender->modules[i])->level_history[history_entry]);
00564                 }
00565         }
00566 }
00567 
00568 
00569 
00570 
00571 
00572 void RenderEngine::run()
00573 {
00574         start_render_threads();
00575         start_lock->unlock();
00576         interrupt_lock->unlock();
00577 
00578         wait_render_threads();
00579 
00580         interrupt_lock->lock("RenderEngine::run");
00581 
00582 
00583         if(interrupted)
00584         {
00585                 playback_engine->tracking_position = playback_engine->get_tracking_position();
00586         }
00587 
00588         close_output();
00589 
00590 // Fix the tracking position
00591         if(playback_engine)
00592         {
00593                 if(command->command == CURRENT_FRAME)
00594                 {
00595 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
00596                         playback_engine->tracking_position = command->playbackstart;
00597                 }
00598                 else
00599                 {
00600 // Make sure transport doesn't issue a pause command next
00601 //printf("RenderEngine::run 4.1 %d\n", playback_engine->tracking_position);
00602                         if(!interrupted)
00603                         {
00604                                 if(do_audio)
00605                                         playback_engine->tracking_position = 
00606                                                 (double)arender->current_position / 
00607                                                         command->get_edl()->session->sample_rate;
00608                                 else
00609                                 if(do_video)
00610                                 {
00611                                         playback_engine->tracking_position = 
00612                                                 (double)vrender->current_position / 
00613                                                         command->get_edl()->session->frame_rate;
00614                                 }
00615                         }
00616 
00617                         if(!interrupted) playback_engine->command->command = STOP;
00618                         playback_engine->stop_tracking();
00619 
00620                 }
00621                 playback_engine->is_playing_back = 0;
00622         }
00623 
00624         input_lock->unlock();
00625         interrupt_lock->unlock();
00626 }
00627 
00628 
00629 
00630 
00631 
00632 
00633 
00634 
00635 
00636 
00637 
00638 
00639 
00640 
00641 
00642 
00643 
00644 
00645 
00646 
00647 
00648 
00649 
00650 
00651 
00652 int RenderEngine::reset_parameters()
00653 {
00654         start_position = 0;
00655         follow_loop = 0;
00656         end_position = 0;
00657         infinite = 0;
00658         start_position = 0;
00659         audio_channels = 0;
00660         do_audio = 0;
00661         do_video = 0;
00662         done = 0;
00663 }
00664 
00665 int RenderEngine::arm_playback_audio(int64_t input_length, 
00666                         int64_t amodule_render_fragment, 
00667                         int64_t playback_buffer, 
00668                         int64_t output_length, 
00669                         int audio_channels)
00670 {
00671         this->audio_channels = audio_channels;
00672 
00673         do_audio = 1;
00674 
00675         arender = new ARender(this);
00676         arender->arm_playback(current_sample, 
00677                                                         input_length, 
00678                                                         amodule_render_fragment, 
00679                                                         playback_buffer, 
00680                                                         output_length);
00681 }
00682 
00683 int RenderEngine::arm_playback_video(int every_frame, 
00684                         int64_t read_length, 
00685                         int64_t output_length,
00686                         int track_w,
00687                         int track_h,
00688                         int output_w,
00689                         int output_h)
00690 {
00691         do_video = 1;
00692         this->every_frame = every_frame;
00693 
00694         vrender = new VRender(this);
00695 //      vrender->arm_playback(current_sample, 
00696 //                                                      read_length, 
00697 //                                                      output_length, 
00698 //                                                      output_length, 
00699 //                                                      track_w,
00700 //                                                      track_h,
00701 //                                                      output_w,
00702 //                                                      output_h);
00703 }
00704 
00705 int RenderEngine::start_video()
00706 {
00707 // start video for realtime
00708         if(video) video->start_playback();
00709         vrender->start_playback();
00710 }
00711 
00712 
00713 int64_t RenderEngine::get_correction_factor(int reset)
00714 {
00715         if(!every_frame)
00716         {
00717                 int64_t x;
00718 //              x = playbackengine->correction_factor;
00719 //              if(reset) playbackengine->correction_factor = 0;
00720                 return x;
00721         }
00722         else
00723                 return 0;
00724 }
00725 

Generated on Sun Jan 8 13:39:00 2006 for Cinelerra-svn by  doxygen 1.4.4