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

recordthread.C

Go to the documentation of this file.
00001 #include "asset.h"
00002 #include "audiodevice.h"
00003 #include "batch.h"
00004 #include "bcsignals.h"
00005 #include "condition.h"
00006 #include "drivesync.h"
00007 #include "edl.h"
00008 #include "edlsession.h"
00009 #include "file.h"
00010 #include "mutex.h"
00011 #include "mwindow.h"
00012 #include "record.h"
00013 #include "recordaudio.h"
00014 #include "recordgui.h"
00015 #include "recordthread.h"
00016 #include "recordvideo.h"
00017 #include "bctimer.h"
00018 #include "videodevice.h"
00019 
00020 
00021 
00022 #define RING_BUFFERS 2
00023 
00024 
00025 RecordThread::RecordThread(MWindow *mwindow, Record *record)
00026  : Thread(1, 0, 0)
00027 {
00028         this->mwindow = mwindow;
00029         this->record = record;
00030         quit_when_completed = 0;
00031         record_timer = new Timer;
00032         record_audio = 0;
00033         record_video = 0;
00034         pause_lock = new Condition(1, "RecordThread::pause_lock");
00035         startup_lock = new Condition(1, "RecordThread::startup_lock");
00036         loop_lock = new Condition(1, "RecordThread::loop_lock");
00037         state_lock = new Mutex("RecordThread::state_lock");
00038 }
00039 
00040 RecordThread::~RecordThread()
00041 {
00042 TRACE("RecordThread::~RecordThread 1");
00043         delete record_timer;
00044         delete pause_lock;
00045         delete startup_lock;
00046         delete loop_lock;
00047         delete state_lock;
00048 TRACE("RecordThread::~RecordThread 10");
00049 }
00050 
00051 int RecordThread::create_objects()
00052 {
00053         if(record->default_asset->audio_data) 
00054                 record_audio = new RecordAudio(mwindow, 
00055                         record, 
00056                         this);
00057 
00058         if(record->default_asset->video_data) 
00059                 record_video = new RecordVideo(mwindow, 
00060                         record, 
00061                         this);
00062         engine_done = 0;
00063         return 0;
00064 }
00065 
00066 int RecordThread::start_recording(int monitor, int context)
00067 {
00068         engine_done = 0;
00069         this->monitor = monitor;
00070         this->context = context;
00071         resume_monitor = !monitor;
00072         loop_lock->lock("RecordThread::start_recording");
00073 // Startup lock isn't 
00074         startup_lock->lock("RecordThread::start_recording");
00075 
00076 
00077         Thread::start();
00078         startup_lock->lock("RecordThread::start_recording");
00079         startup_lock->unlock();
00080         return 0;
00081 }
00082 
00083 int RecordThread::stop_recording(int resume_monitor)
00084 {
00085 // Stop RecordThread while waiting for batch
00086         state_lock->lock("RecordThread::stop_recording");
00087         engine_done = 1;
00088 
00089         this->resume_monitor = resume_monitor;
00090 // In the monitor engine, stops the engine.
00091 // In the recording engine, causes the monitor engine not to be restarted.
00092 // Video thread stops the audio thread itself
00093 // printf("RecordThread::stop_recording 1\n");
00094         if(record_video)
00095         {
00096                 record_video->batch_done = 1;
00097                 state_lock->unlock();
00098                 record_video->stop_recording();
00099         }
00100         else
00101         if(record_audio && context != CONTEXT_SINGLEFRAME) 
00102         {
00103                 record_audio->batch_done = 1;
00104                 state_lock->unlock();
00105                 record_audio->stop_recording();
00106         }
00107 
00108         Thread::join();
00109         return 0;
00110 }
00111 
00112 int RecordThread::pause_recording()
00113 {
00114 // Stop the thread before finishing the loop
00115         pause_lock->lock("RecordThread::pause_recording");
00116 
00117         state_lock->lock("RecordThread::pause_recording");
00118         if(record->default_asset->video_data)
00119         {
00120                 record_video->batch_done = 1;
00121         }
00122         else
00123         {
00124                 record_audio->batch_done = 1;
00125         }
00126         state_lock->unlock();
00127 // Stop the recordings
00128         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
00129                 record_audio->stop_recording();
00130         if(record->default_asset->video_data)
00131                 record_video->stop_recording();
00132 
00133 // Wait for thread to stop before closing devices
00134         loop_lock->lock("RecordThread::pause_recording");
00135         loop_lock->unlock();
00136 
00137 
00138 
00139         record->close_input_devices();
00140 //printf("RecordThread::pause_recording 2\n");
00141         record->capture_state = IS_DONE;
00142         return 0;
00143 }
00144 
00145 int RecordThread::resume_recording()
00146 {
00147 //printf("RecordThread::resume_recording 1\n");
00148         if(record_video)
00149         {
00150                 record_video->batch_done = 0;
00151         }
00152         else
00153         {
00154                 record_audio->batch_done = 0;
00155         }
00156         loop_lock->lock("RecordThread::resume_recording");
00157         pause_lock->unlock();
00158 //printf("RecordThread::resume_recording 2\n");
00159         return 0;
00160 }
00161 
00162 int64_t RecordThread::sync_position()
00163 {
00164         if(record->default_asset->audio_data)
00165                 return record_audio->sync_position();
00166         else
00167                 return (int64_t)((float)record_timer->get_difference() / 
00168                         1000 * 
00169                         record->default_asset->sample_rate + 0.5);
00170 }
00171 
00172 void RecordThread::do_cron()
00173 {
00174         do{
00175                 double position = record->current_display_position();
00176                 int day;
00177                 double seconds;
00178                 
00179 
00180 // Batch already started
00181                 if(position > 0)
00182                 {
00183                         break;
00184                 }
00185                 else
00186 // Delay until start of batch
00187                 {
00188                         record->get_current_time(seconds, day);
00189 
00190 // Wildcard
00191                         if(record->get_current_batch()->start_day == 7)
00192                                 day = record->get_current_batch()->start_day;
00193 // Start recording
00194                         if(record->get_current_batch()->start_day == day &&
00195                                 record->get_current_batch()->start_time >= last_seconds &&
00196                                 record->get_current_batch()->start_time <= seconds)
00197                         {
00198                                 break;
00199                         }
00200 
00201 //                      record->record_gui->lock_window();
00202 //                      record->record_gui->flash_batch();
00203 //                      record->record_gui->unlock_window();
00204                 }
00205 
00206                 last_seconds = seconds;
00207                 last_day = day;
00208                 if(!engine_done) usleep(BATCH_DELAY);
00209                 if(!engine_done)
00210                 {
00211                         record->record_gui->lock_window("RecordThread::do_cron");
00212                         record->record_gui->flash_batch();
00213                         record->record_gui->unlock_window();
00214                 }
00215         }while(!engine_done);
00216 }
00217 
00218 
00219 
00220 void RecordThread::run()
00221 {
00222         int rewinding_loop = 0;
00223         startup_lock->unlock();
00224         record->get_current_time(last_seconds, last_day);
00225 
00226 
00227         do
00228         {
00229 // Prepare next batch
00230                 if(context == CONTEXT_BATCH &&
00231                         !rewinding_loop)
00232                 {
00233                         do_cron();
00234                 }
00235 
00236                 state_lock->lock("RecordThread::run");
00237 // Test for stopped while waiting
00238                 if(!engine_done)
00239                 {
00240                         
00241                         rewinding_loop = 0;
00242 
00243 // Batch context needs to open the device here.  Interactive and singleframe
00244 // contexts need to open in Record::start_recording to allow full duplex.
00245                         if(context == CONTEXT_BATCH)
00246                         {
00247 // Delete output file before opening the devices to avoid buffer overflow.
00248 TRACE("RecordThread::run 1");
00249                                 record->delete_output_file();
00250 TRACE("RecordThread::run 2");
00251                                 record->open_input_devices(0, context);
00252 TRACE("RecordThread::run 3");
00253                         }
00254 
00255 // Switch interactive recording to batch recording
00256 // to get delay before next batch
00257                         if(!monitor && context == CONTEXT_INTERACTIVE)
00258                                 context = CONTEXT_BATCH;
00259 
00260                         if(!monitor)
00261                         {
00262 // This draws to RecordGUI, incidentally
00263 TRACE("RecordThread::run 4");
00264                                 record->open_output_file();
00265 TRACE("RecordThread::run 5");
00266                                 if(mwindow->edl->session->record_sync_drives)
00267                                 {
00268                                         drivesync = new DriveSync;
00269                                         drivesync->start();
00270                                 }
00271                                 else
00272                                         drivesync = 0;
00273 
00274                                 record->get_current_batch()->recorded = 1;
00275 TRACE("RecordThread::run 6");
00276 
00277 // Open file threads here to keep loop synchronized
00278                                 if(record->default_asset->audio_data && 
00279                                         context != CONTEXT_SINGLEFRAME)
00280                                 {
00281                                         int buffer_size, fragment_size;
00282                                         record->get_audio_write_length(buffer_size, 
00283                                                 fragment_size);
00284                                         record->file->start_audio_thread(buffer_size, RING_BUFFERS);
00285                                 }
00286 TRACE("RecordThread::run 7");
00287 
00288                                 if(record->default_asset->video_data)
00289                                         record->file->start_video_thread(mwindow->edl->session->video_write_length,
00290                                                 record->vdevice->get_best_colormodel(record->default_asset),
00291                                                 RING_BUFFERS,
00292                                                 record->vdevice->is_compressed(1, 0));
00293 TRACE("RecordThread::run 8");
00294                         }
00295 
00296 // Reset synchronization  counters
00297                         record->get_current_batch()->session_samples = 0;
00298                         record->get_current_batch()->session_frames = 0;
00299                         record_timer->update();
00300 
00301 // Do initialization
00302 TRACE("RecordThread::run 9");
00303                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
00304                                 record_audio->arm_recording();
00305 TRACE("RecordThread::run 10");
00306                         if(record->default_asset->video_data)
00307                                 record_video->arm_recording();
00308 TRACE("RecordThread::run 11");
00309                         state_lock->unlock();
00310 
00311 // Trigger loops
00312 
00313                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
00314                                 record_audio->start_recording();
00315 TRACE("RecordThread::run 12");
00316                         if(record->default_asset->video_data)
00317                                 record_video->start_recording();
00318 TRACE("RecordThread::run 13");
00319 
00320 
00321                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
00322                                 record_audio->Thread::join();
00323 TRACE("RecordThread::run 14");
00324                         if(record->default_asset->video_data)
00325                                 record_video->Thread::join();
00326 TRACE("RecordThread::run 15");
00327 
00328 // Stop file threads here to keep loop synchronized
00329                         if(!monitor)
00330                         {
00331                                 if(drivesync) drivesync->done = 1;
00332 TRACE("RecordThread::run 16");
00333                                 if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
00334                                         record->file->stop_audio_thread();
00335 TRACE("RecordThread::run 17");
00336                                 if(record->default_asset->video_data)
00337                                         record->file->stop_video_thread();
00338 TRACE("RecordThread::run 18");
00339 
00340 // Update asset info
00341                                 record->get_current_batch()->get_current_asset()->audio_length = 
00342                                         record->get_current_batch()->total_samples;
00343                                 record->get_current_batch()->get_current_asset()->video_length = 
00344                                         record->get_current_batch()->total_frames;
00345 
00346 // Reset the loop flag and rewind files for the next loop
00347                                 if(!engine_done)
00348                                 {
00349 // Rewind loop if in loop mode
00350                                         if(record->get_current_batch()->record_mode == RECORD_LOOP)
00351                                         {
00352 // Don't close devices when rewinding a loop
00353                                                 record->rewind_file();
00354                                                 record->get_current_batch()->session_samples = 0;
00355                                                 record->get_current_batch()->session_frames = 0;
00356                                                 rewinding_loop = 1;
00357                                         }
00358                                         else
00359 // Advance batch if not terminated by user and not single frame and continue loop
00360                                         if(record->get_next_batch() >= 0 && context != CONTEXT_SINGLEFRAME)
00361                                         {
00362                                                 record->activate_batch(record->get_next_batch(), 0);
00363                                                 record->close_input_devices();
00364                                         }
00365                                         else
00366 // End loop
00367                                         {
00368                                                 engine_done = 1;
00369                                         }
00370                                 }
00371 TRACE("RecordThread::run 20");
00372 
00373                                 if(drivesync) delete drivesync;
00374                         }
00375                 }
00376                 else
00377                 {
00378                         state_lock->unlock();
00379                 }
00380 
00381 // Wait for thread to stop before closing devices
00382                 loop_lock->unlock();
00383                 if(monitor)
00384                 {
00385 // Pause until monitor is resumed
00386                         pause_lock->lock("RecordThread::run");
00387                         pause_lock->unlock();
00388                 }
00389         }while(!engine_done);
00390 
00391         record->close_input_devices();
00392 
00393 // Resume monitoring only if not a monitor ourselves
00394         if(!monitor)
00395         {
00396                 record->stop_duplex();
00397                 if(resume_monitor) record->resume_monitor();
00398         }
00399         else
00400         {
00401                 record->capture_state = IS_DONE;
00402         }
00403 }
00404 

Generated on Sun Jan 8 13:38:59 2006 for Cinelerra-svn by  doxygen 1.4.4