license header for review
[cinelerra_cv/ct.git] / cinelerra / recordthread.C
blobf41ed38902dcbb1ce092c5018bd2f367fada628b
1 #include "asset.h"
2 #include "audiodevice.h"
3 #include "batch.h"
4 #include "bcsignals.h"
5 #include "condition.h"
6 #include "drivesync.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "file.h"
10 #include "mutex.h"
11 #include "mwindow.h"
12 #include "record.h"
13 #include "recordaudio.h"
14 #include "recordgui.h"
15 #include "recordthread.h"
16 #include "recordvideo.h"
17 #include "bctimer.h"
18 #include "videodevice.h"
22 #define RING_BUFFERS 2
25 RecordThread::RecordThread(MWindow *mwindow, Record *record)
26  : Thread(1, 0, 0)
28         this->mwindow = mwindow;
29         this->record = record;
30         quit_when_completed = 0;
31         record_timer = new Timer;
32         record_audio = 0;
33         record_video = 0;
34         pause_lock = new Condition(1, "RecordThread::pause_lock");
35         startup_lock = new Condition(1, "RecordThread::startup_lock");
36         loop_lock = new Condition(1, "RecordThread::loop_lock");
37         state_lock = new Mutex("RecordThread::state_lock");
40 RecordThread::~RecordThread()
42 SET_TRACE
43         delete record_audio;
44 SET_TRACE
45         delete record_video;
46 SET_TRACE
47         delete record_timer;
48 SET_TRACE
49         delete pause_lock;
50 SET_TRACE
51         delete startup_lock;
52 SET_TRACE
53         delete loop_lock;
54 SET_TRACE
55         delete state_lock;
56 SET_TRACE
59 int RecordThread::create_objects()
61         if(record->default_asset->audio_data) 
62                 record_audio = new RecordAudio(mwindow, 
63                         record, 
64                         this);
66         if(record->default_asset->video_data) 
67                 record_video = new RecordVideo(mwindow, 
68                         record, 
69                         this);
70         engine_done = 0;
71         return 0;
74 int RecordThread::start_recording(int monitor, int context)
76         engine_done = 0;
77         this->monitor = monitor;
78         this->context = context;
79         resume_monitor = !monitor;
80         loop_lock->lock("RecordThread::start_recording");
81 // Startup lock isn't 
82         startup_lock->lock("RecordThread::start_recording");
85         Thread::start();
86         startup_lock->lock("RecordThread::start_recording");
87         startup_lock->unlock();
88         return 0;
91 int RecordThread::stop_recording(int resume_monitor)
93 SET_TRACE
94 // Stop RecordThread while waiting for batch
95         state_lock->lock("RecordThread::stop_recording");
97         engine_done = 1;
98         if(monitor)
99         {
100                 pause_lock->unlock();
101         }
103 SET_TRACE
104         this->resume_monitor = resume_monitor;
105 // In the monitor engine, stops the engine.
106 // In the recording engine, causes the monitor engine not to be restarted.
107 // Video thread stops the audio thread itself
108 // printf("RecordThread::stop_recording 1\n");
109 SET_TRACE
110         if(record_video)
111         {
112                 record_video->batch_done = 1;
113                 state_lock->unlock();
114                 record_video->stop_recording();
115         }
116         else
117         if(record_audio && context != CONTEXT_SINGLEFRAME) 
118         {
119                 record_audio->batch_done = 1;
120                 state_lock->unlock();
121                 record_audio->stop_recording();
122         }
124 SET_TRACE
125         Thread::join();
126 SET_TRACE
127         return 0;
130 int RecordThread::pause_recording()
132 // Stop the thread before finishing the loop
133         pause_lock->lock("RecordThread::pause_recording");
135         state_lock->lock("RecordThread::pause_recording");
136         if(record->default_asset->video_data)
137         {
138                 record_video->batch_done = 1;
139         }
140         else if (record->default_asset->audio_data)
141         {
142                 record_audio->batch_done = 1;
143         }
144         state_lock->unlock();
145 // Stop the recordings
146         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
147                 record_audio->stop_recording();
148         if(record->default_asset->video_data)
149                 record_video->stop_recording();
151 // Wait for thread to stop before closing devices
152         loop_lock->lock("RecordThread::pause_recording");
153         loop_lock->unlock();
157         record->close_input_devices(monitor);
158 //printf("RecordThread::pause_recording 2\n");
159         record->capture_state = IS_DONE;
160         return 0;
163 int RecordThread::resume_recording()
165 //printf("RecordThread::resume_recording 1\n");
166         if(record_video)
167         {
168                 record_video->batch_done = 0;
169         }
170         else if (record_audio)
171         {
172                 record_audio->batch_done = 0;
173         }
174         loop_lock->lock("RecordThread::resume_recording");
175         pause_lock->unlock();
176 //printf("RecordThread::resume_recording 2\n");
177         return 0;
180 int64_t RecordThread::sync_position()
182         if(record->default_asset->audio_data)
183                 return record_audio->sync_position();
184         else
185                 return (int64_t)((float)record_timer->get_difference() / 
186                         1000 * 
187                         record->default_asset->sample_rate + 0.5);
190 void RecordThread::do_cron()
192         do{
193                 double position = record->current_display_position();
194                 int day;
195                 double seconds;
196                 
198 // Batch already started
199                 if(position > 0)
200                 {
201                         break;
202                 }
203                 else
204 // Delay until start of batch
205                 {
206                         record->get_current_time(seconds, day);
208 // Wildcard
209                         if(record->get_current_batch()->start_day == 7)
210                                 day = record->get_current_batch()->start_day;
211 // Start recording
212                         if(record->get_current_batch()->start_day == day &&
213                                 record->get_current_batch()->start_time >= last_seconds &&
214                                 record->get_current_batch()->start_time <= seconds)
215                         {
216                                 break;
217                         }
219 //                      record->record_gui->lock_window();
220 //                      record->record_gui->flash_batch();
221 //                      record->record_gui->unlock_window();
222                 }
224                 last_seconds = seconds;
225                 last_day = day;
226                 if(!engine_done) usleep(BATCH_DELAY);
227                 if(!engine_done)
228                 {
229                         record->record_gui->lock_window("RecordThread::do_cron");
230                         record->record_gui->flash_batch();
231                         record->record_gui->unlock_window();
232                 }
233         }while(!engine_done);
238 void RecordThread::run()
240         int rewinding_loop = 0;
241         startup_lock->unlock();
242         record->get_current_time(last_seconds, last_day);
245         do
246         {
247 // Prepare next batch
248                 if(context == CONTEXT_BATCH &&
249                         !rewinding_loop)
250                 {
251                         do_cron();
252                 }
254                 state_lock->lock("RecordThread::run");
255 // Test for stopped while waiting
256                 if(!engine_done)
257                 {
258                         
259                         rewinding_loop = 0;
261 // Batch context needs to open the device here.  Interactive and singleframe
262 // contexts need to open in Record::start_recording to allow full duplex.
263                         if(context == CONTEXT_BATCH)
264                         {
265 // Delete output file before opening the devices to avoid buffer overflow.
266 TRACE("RecordThread::run 1");
267                                 record->delete_output_file();
268 TRACE("RecordThread::run 2");
269                                 record->open_input_devices(0, context);
270 TRACE("RecordThread::run 3");
271                         }
273 // Switch interactive recording to batch recording
274 // to get delay before next batch
275                         if(!monitor && context == CONTEXT_INTERACTIVE)
276                                 context = CONTEXT_BATCH;
278                         if(!monitor)
279                         {
280 // This draws to RecordGUI, incidentally
281 TRACE("RecordThread::run 4");
282                                 record->open_output_file();
283 TRACE("RecordThread::run 5");
284                                 if(mwindow->edl->session->record_sync_drives)
285                                 {
286                                         drivesync = new DriveSync;
287                                         drivesync->start();
288                                 }
289                                 else
290                                         drivesync = 0;
292                                 record->get_current_batch()->recorded = 1;
293 TRACE("RecordThread::run 6");
295 // Open file threads here to keep loop synchronized
296                                 if(record->default_asset->audio_data && 
297                                         context != CONTEXT_SINGLEFRAME)
298                                 {
299                                         int buffer_size, fragment_size;
300                                         record->get_audio_write_length(buffer_size, 
301                                                 fragment_size);
302                                         record->file->start_audio_thread(buffer_size, RING_BUFFERS);
303                                 }
304 TRACE("RecordThread::run 7");
306                                 if(record->default_asset->video_data)
307                                         record->file->start_video_thread(mwindow->edl->session->video_write_length,
308                                                 record->vdevice->get_best_colormodel(record->default_asset),
309                                                 RING_BUFFERS,
310                                                 record->vdevice->is_compressed(1, 0));
311 TRACE("RecordThread::run 8");
312                         }
314 // Reset synchronization  counters
315                         record->get_current_batch()->session_samples = 0;
316                         record->get_current_batch()->session_frames = 0;
317                         record_timer->update();
319 // Do initialization
320 TRACE("RecordThread::run 9");
321                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
322                                 record_audio->arm_recording();
323 TRACE("RecordThread::run 10");
324                         if(record->default_asset->video_data)
325                                 record_video->arm_recording();
326 TRACE("RecordThread::run 11");
327                         state_lock->unlock();
329 // Trigger loops
331                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
332                                 record_audio->start_recording();
333 TRACE("RecordThread::run 12");
334                         if(record->default_asset->video_data)
335                                 record_video->start_recording();
336 TRACE("RecordThread::run 13");
339                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
340                                 record_audio->Thread::join();
341 TRACE("RecordThread::run 14");
342                         if(record->default_asset->video_data)
343                                 record_video->Thread::join();
344 TRACE("RecordThread::run 15");
346 // Stop file threads here to keep loop synchronized
347                         if(!monitor)
348                         {
349                                 if(drivesync) drivesync->done = 1;
350 TRACE("RecordThread::run 16");
351                                 if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
352                                         record->file->stop_audio_thread();
353 TRACE("RecordThread::run 17");
354                                 if(record->default_asset->video_data)
355                                         record->file->stop_video_thread();
356 TRACE("RecordThread::run 18");
358 // Update asset info
359                                 record->get_current_batch()->get_current_asset()->audio_length = 
360                                         record->get_current_batch()->total_samples;
361                                 record->get_current_batch()->get_current_asset()->video_length = 
362                                         record->get_current_batch()->total_frames;
364 // Reset the loop flag and rewind files for the next loop
365                                 if(!engine_done)
366                                 {
367 // Rewind loop if in loop mode
368                                         if(record->get_current_batch()->record_mode == RECORD_LOOP)
369                                         {
370 // Don't close devices when rewinding a loop
371                                                 record->rewind_file();
372                                                 record->get_current_batch()->session_samples = 0;
373                                                 record->get_current_batch()->session_frames = 0;
374                                                 rewinding_loop = 1;
375                                         }
376                                         else
377 // Advance batch if not terminated by user and not single frame and continue loop
378                                         if(record->get_next_batch() >= 0 && context != CONTEXT_SINGLEFRAME)
379                                         {
380                                                 record->activate_batch(record->get_next_batch(), 0);
381                                                 record->close_input_devices(monitor);
382                                         }
383                                         else
384 // End loop
385                                         {
386                                                 engine_done = 1;
387                                         }
388                                 }
389 TRACE("RecordThread::run 20");
391                                 if(drivesync) delete drivesync;
392                         }
393 SET_TRACE
394                 }
395                 else
396                 {
397                         state_lock->unlock();
398                 }
400 SET_TRACE
401 // Wait for thread to stop before closing devices
402                 loop_lock->unlock();
403                 if(monitor)
404                 {
405 // Pause until monitor is resumed
406                         pause_lock->lock("RecordThread::run");
407                         pause_lock->unlock();
408                 }
409 SET_TRACE
410         }while(!engine_done);
412 SET_TRACE
413         record->close_input_devices(monitor);
414 SET_TRACE
416 // Resume monitoring only if not a monitor ourselves
417         if(!monitor)
418         {
419                 record->stop_duplex();
420                 if(resume_monitor) record->resume_monitor();
421         }
422         else
423         {
424                 record->capture_state = IS_DONE;
425         }
426 SET_TRACE
430 //      Local Variables:
431 //      mode: C++
432 //      c-file-style: "linux"
433 //      End: