Panda3D

recorderController.cxx

00001 // Filename: recorderController.cxx
00002 // Created by:  drose (24Jan04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "recorderController.h"
00016 #include "recorderFrame.h"
00017 #include "bamReader.h"
00018 #include "bamWriter.h"
00019 #include "config_recorder.h"
00020 #include "bam.h"
00021 #include "clockObject.h"
00022 
00023 TypeHandle RecorderController::_type_handle;
00024 RecorderController::RecorderFactory *RecorderController::_factory = NULL;
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: RecorderController::Constructor
00028 //       Access: Published
00029 //  Description:
00030 ////////////////////////////////////////////////////////////////////
00031 RecorderController::
00032 RecorderController() {
00033   _clock_offset = 0.0;
00034   _frame_offset = 0;
00035   _writer = (BamWriter *)NULL;
00036   _reader = (BamReader *)NULL;
00037   _frame_tie = true;
00038   _user_table = new RecorderTable;
00039   _user_table_modified = false;
00040   _file_table = NULL;
00041   _active_table = NULL;
00042   _eof = false;
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: RecorderController::Destructor
00047 //       Access: Published
00048 //  Description:
00049 ////////////////////////////////////////////////////////////////////
00050 RecorderController::
00051 ~RecorderController() {
00052   close();
00053   delete _user_table;
00054 }
00055 
00056 ////////////////////////////////////////////////////////////////////
00057 //     Function: RecorderController::begin_record
00058 //       Access: Published
00059 //  Description: Begins recording data to the indicated filename.  All
00060 //               of the recorders in use should already have been
00061 //               added.
00062 ////////////////////////////////////////////////////////////////////
00063 bool RecorderController::
00064 begin_record(const Filename &filename) {
00065   close();
00066   _filename = filename;
00067   ClockObject *global_clock = ClockObject::get_global_clock();
00068   _clock_offset = global_clock->get_frame_time();
00069   _frame_offset = global_clock->get_frame_count();
00070 
00071   time(&_header._start_time);
00072 
00073   if (!_dout.open(_filename)) {
00074     recorder_cat.error() << "Unable to open " << _filename << "\n";
00075     return false;
00076   }
00077 
00078   if (!_dout.write_header(_bam_header)) {
00079     recorder_cat.error() << "Unable to write to " << _filename << "\n";
00080     return false;
00081   }
00082 
00083   _writer = new BamWriter(&_dout);
00084 
00085   if (!_writer->init()) {
00086     close();
00087     return false;
00088   }
00089 
00090   // Write out the header information.
00091   _writer->write_object(&_header);
00092 
00093   _user_table_modified = true;
00094 
00095   // Tell all of our recorders that they're live now.
00096   RecorderTable::Recorders::iterator ri;
00097   for (ri = _user_table->_recorders.begin(); 
00098        ri != _user_table->_recorders.end(); 
00099        ++ri) {
00100     RecorderBase *recorder = (*ri).second;
00101     recorder->_flags |= RecorderBase::F_recording;
00102   }
00103 
00104   recorder_cat.info() 
00105     << "Recording session to " << _filename << "\n";
00106     
00107   return true;
00108 }
00109 
00110 ////////////////////////////////////////////////////////////////////
00111 //     Function: RecorderController::begin_playback
00112 //       Access: Published
00113 //  Description: Begins playing back data from the indicated filename.
00114 //               All of the recorders in use should already have been
00115 //               added, although this may define additional recorders
00116 //               if they are present in the file (these new recorders
00117 //               will not be used).  This may also undefine recorders
00118 //               that were previously added but are not present in the
00119 //               file.
00120 ////////////////////////////////////////////////////////////////////
00121 bool RecorderController::
00122 begin_playback(const Filename &filename) {
00123   close();
00124   _filename = filename;
00125   ClockObject *global_clock = ClockObject::get_global_clock();
00126   _clock_offset = global_clock->get_frame_time();
00127   _frame_offset = global_clock->get_frame_count();
00128 
00129   if (!_din.open(_filename)) {
00130     recorder_cat.error() << "Unable to open " << _filename << "\n";
00131     return false;
00132   }
00133 
00134   string head;
00135   if (!_din.read_header(head, _bam_header.size()) || head != _bam_header) {
00136     recorder_cat.error() << "Unable to read " << _filename << "\n";
00137     return false;
00138   }
00139 
00140   _reader = new BamReader(&_din);
00141   if (!_reader->init()) {
00142     close();
00143     return false;
00144   }
00145 
00146   _user_table_modified = true;
00147   _active_table = new RecorderTable;
00148   _eof = false;
00149 
00150   // Start out by reading the RecorderHeader.
00151   TypedWritable *object = _reader->read_object();
00152 
00153   if (object == (TypedWritable *)NULL || 
00154       !object->is_of_type(RecorderHeader::get_class_type())) {
00155     recorder_cat.error()
00156       << _filename << " does not contain a recorded session.\n";
00157     close();
00158     return false;
00159   }
00160 
00161   if (!_reader->resolve()) {
00162     recorder_cat.warning()
00163       << "Unable to resolve header data.\n";
00164   }
00165 
00166   RecorderHeader *new_header = DCAST(RecorderHeader, object);
00167   _header = (*new_header);
00168   delete new_header;
00169 
00170   // Now read the first frame.
00171   _next_frame = read_frame();
00172   if (_next_frame == (RecorderFrame *)NULL) {
00173     recorder_cat.error()
00174       << _filename << " does not contain any frames.\n";
00175     close();
00176     return false;
00177   }
00178 
00179   recorder_cat.info() 
00180     << "Playing back session from " << _filename << "\n";
00181 
00182   return true;
00183 }
00184 
00185 ////////////////////////////////////////////////////////////////////
00186 //     Function: RecorderController::close
00187 //       Access: Published
00188 //  Description: Finishes recording data to the indicated filename.
00189 ////////////////////////////////////////////////////////////////////
00190 void RecorderController::
00191 close() {
00192   if (_writer != (BamWriter *)NULL) {
00193     delete _writer;
00194     _writer = NULL;
00195 
00196     // Tell all of our recorders that they're no longer recording.
00197     RecorderTable::Recorders::iterator ri;
00198     for (ri = _user_table->_recorders.begin(); 
00199          ri != _user_table->_recorders.end(); 
00200          ++ri) {
00201       RecorderBase *recorder = (*ri).second;
00202       recorder->_flags &= ~RecorderBase::F_recording;
00203     }
00204   }
00205   if (_reader != (BamReader *)NULL) {
00206     delete _reader;
00207     _reader = NULL;
00208 
00209     // Tell all of our recorders that they're no longer playing.
00210     RecorderTable::Recorders::iterator ri;
00211     for (ri = _active_table->_recorders.begin(); 
00212          ri != _active_table->_recorders.end(); 
00213          ++ri) {
00214       RecorderBase *recorder = (*ri).second;
00215       recorder->_flags &= ~RecorderBase::F_playing;
00216     }
00217   }
00218   _dout.close();
00219   _din.close();
00220 
00221   if (_file_table != (RecorderTable *)NULL) {
00222     delete _file_table;
00223     _file_table = (RecorderTable *)NULL;
00224   }
00225 
00226   if (_active_table != (RecorderTable *)NULL) {
00227     delete _active_table;
00228     _active_table = (RecorderTable *)NULL;
00229   }
00230 }
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: RecorderController::record_frame
00234 //       Access: Published
00235 //  Description: Gets the next frame of data from all of the active
00236 //               recorders and adds it to the output file.
00237 ////////////////////////////////////////////////////////////////////
00238 void RecorderController::
00239 record_frame() {
00240   if (is_recording()) {
00241     ClockObject *global_clock = ClockObject::get_global_clock();
00242     double now = global_clock->get_frame_time() - _clock_offset;
00243     int frame = global_clock->get_frame_count() - _frame_offset;
00244 
00245     RecorderFrame data(now, frame, _user_table_modified, _user_table);
00246     _user_table_modified = false;
00247     
00248     _writer->write_object(&data);
00249   }
00250 }
00251 
00252 ////////////////////////////////////////////////////////////////////
00253 //     Function: RecorderController::play_frame
00254 //       Access: Published
00255 //  Description: Gets the next frame of data from all of the active
00256 //               recorders and adds it to the output file.
00257 ////////////////////////////////////////////////////////////////////
00258 void RecorderController::
00259 play_frame() {
00260   if (is_playing()) {
00261     if (_eof) {
00262       close();
00263       return;
00264     }
00265 
00266     ClockObject *global_clock = ClockObject::get_global_clock();
00267     double now = global_clock->get_frame_time() - _clock_offset;
00268     int frame = global_clock->get_frame_count() - _frame_offset;
00269 
00270     while (_next_frame != (RecorderFrame *)NULL) {
00271       if (_frame_tie) {
00272         if (frame < _next_frame->_frame) {
00273           // We haven't reached the next frame yet.
00274           return;
00275         }
00276 
00277         // Insist that the clock runs at the same rate as it did in
00278         // the previous session.
00279         //global_clock->set_frame_time(_next_frame->_timestamp + _clock_offset);
00280         //global_clock->set_real_time(_next_frame->_timestamp + _clock_offset);
00281 
00282         // Hmm, that's crummy.  Just keep the clock offset up-to-date.
00283         _clock_offset = global_clock->get_frame_time() - _next_frame->_timestamp;
00284 
00285       } else {
00286         if (now < _next_frame->_timestamp) {
00287           // We haven't reached the next frame yet.
00288           return;
00289         }
00290 
00291         // Keep our frame_offset up-to-date.
00292         _frame_offset = global_clock->get_frame_count() - _next_frame->_frame;
00293       }
00294 
00295       if (_next_frame->_table_changed && _file_table != _next_frame->_table) {
00296         delete _file_table;
00297         _file_table = _next_frame->_table;
00298       }
00299 
00300       if (_next_frame->_table_changed || _user_table_modified) {
00301         // We're about to change the active table.  Temporarily
00302         // disable the playing flag on the currently-active recorders.
00303         RecorderTable::Recorders::iterator ri;
00304         for (ri = _active_table->_recorders.begin(); 
00305              ri != _active_table->_recorders.end(); 
00306              ++ri) {
00307           RecorderBase *recorder = (*ri).second;
00308           recorder->_flags &= ~RecorderBase::F_playing;
00309         }
00310 
00311         delete _active_table;
00312         _active_table = new RecorderTable(*_file_table);
00313         _active_table->merge_from(*_user_table);
00314         _user_table_modified = false;
00315         
00316         // Now reenable the playing flag on the newly-active
00317         // recorders.
00318         for (ri = _active_table->_recorders.begin(); 
00319              ri != _active_table->_recorders.end(); 
00320              ++ri) {
00321           RecorderBase *recorder = (*ri).second;
00322           recorder->_flags |= RecorderBase::F_playing;
00323         }
00324       }
00325 
00326       _next_frame->_table = _active_table;
00327       _next_frame->play_frame(_reader);
00328 
00329       delete _next_frame;
00330       _next_frame = read_frame();
00331     }
00332 
00333     if (_reader->is_eof()) {
00334       recorder_cat.info()
00335         << "End of recorded session.\n";
00336     } else {
00337       recorder_cat.error()
00338         << "Unable to read datagram from recorded session.\n";
00339     }
00340     _eof = true;
00341   }
00342 }
00343 
00344 
00345 ////////////////////////////////////////////////////////////////////
00346 //     Function: RecorderController::read_frame
00347 //       Access: Private
00348 //  Description: Loads the next frame data from the playback session
00349 //               file.  Returns the frame data pointer on success, or
00350 //               NULL on failure.
00351 ////////////////////////////////////////////////////////////////////
00352 RecorderFrame *RecorderController::
00353 read_frame() {
00354   TypedWritable *object = _reader->read_object();
00355 
00356   if (object == (TypedWritable *)NULL || 
00357       !object->is_of_type(RecorderFrame::get_class_type())) {
00358     return NULL;
00359   }
00360 
00361   if (!_reader->resolve()) {
00362     recorder_cat.warning()
00363       << "Unable to resolve frame data.\n";
00364   }
00365 
00366   return DCAST(RecorderFrame, object);
00367 }
 All Classes Functions Variables Enumerations