r632: Boost up the requirement for mjpegtools to 1.6.3
[cinelerra_cv/mob.git] / cinelerra / recordthread.C
blob91244c6a4aa9ce721357f0f082bc4dbf18002439
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 TRACE("RecordThread::~RecordThread 1");
43         delete record_timer;
44         delete pause_lock;
45         delete startup_lock;
46         delete loop_lock;
47         delete state_lock;
48 TRACE("RecordThread::~RecordThread 10");
51 int RecordThread::create_objects()
53         if(record->default_asset->audio_data) 
54                 record_audio = new RecordAudio(mwindow, 
55                         record, 
56                         this);
58         if(record->default_asset->video_data) 
59                 record_video = new RecordVideo(mwindow, 
60                         record, 
61                         this);
62         engine_done = 0;
63         return 0;
66 int RecordThread::start_recording(int monitor, int context)
68         engine_done = 0;
69         this->monitor = monitor;
70         this->context = context;
71         resume_monitor = !monitor;
72         loop_lock->lock("RecordThread::start_recording");
73 // Startup lock isn't 
74         startup_lock->lock("RecordThread::start_recording");
77         Thread::start();
78         startup_lock->lock("RecordThread::start_recording");
79         startup_lock->unlock();
80         return 0;
83 int RecordThread::stop_recording(int resume_monitor)
85 // Stop RecordThread while waiting for batch
86         state_lock->lock("RecordThread::stop_recording");
87         engine_done = 1;
89         this->resume_monitor = resume_monitor;
90 // In the monitor engine, stops the engine.
91 // In the recording engine, causes the monitor engine not to be restarted.
92 // Video thread stops the audio thread itself
93 // printf("RecordThread::stop_recording 1\n");
94         if(record_video)
95         {
96                 record_video->batch_done = 1;
97                 state_lock->unlock();
98                 record_video->stop_recording();
99         }
100         else
101         if(record_audio && context != CONTEXT_SINGLEFRAME) 
102         {
103                 record_audio->batch_done = 1;
104                 state_lock->unlock();
105                 record_audio->stop_recording();
106         }
108         Thread::join();
109         return 0;
112 int RecordThread::pause_recording()
114 // Stop the thread before finishing the loop
115         pause_lock->lock("RecordThread::pause_recording");
117         state_lock->lock("RecordThread::pause_recording");
118         if(record->default_asset->video_data)
119         {
120                 record_video->batch_done = 1;
121         }
122         else
123         {
124                 record_audio->batch_done = 1;
125         }
126         state_lock->unlock();
127 // Stop the recordings
128         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
129                 record_audio->stop_recording();
130         if(record->default_asset->video_data)
131                 record_video->stop_recording();
133 // Wait for thread to stop before closing devices
134         loop_lock->lock("RecordThread::pause_recording");
135         loop_lock->unlock();
139         record->close_input_devices();
140 //printf("RecordThread::pause_recording 2\n");
141         record->capture_state = IS_DONE;
142         return 0;
145 int RecordThread::resume_recording()
147 //printf("RecordThread::resume_recording 1\n");
148         if(record_video)
149         {
150                 record_video->batch_done = 0;
151         }
152         else
153         {
154                 record_audio->batch_done = 0;
155         }
156         loop_lock->lock("RecordThread::resume_recording");
157         pause_lock->unlock();
158 //printf("RecordThread::resume_recording 2\n");
159         return 0;
162 int64_t RecordThread::sync_position()
164         if(record->default_asset->audio_data)
165                 return record_audio->sync_position();
166         else
167                 return (int64_t)((float)record_timer->get_difference() / 
168                         1000 * 
169                         record->default_asset->sample_rate + 0.5);
172 void RecordThread::do_cron()
174         do{
175                 double position = record->current_display_position();
176                 int day;
177                 double seconds;
178                 
180 // Batch already started
181                 if(position > 0)
182                 {
183                         break;
184                 }
185                 else
186 // Delay until start of batch
187                 {
188                         record->get_current_time(seconds, day);
190 // Wildcard
191                         if(record->get_current_batch()->start_day == 7)
192                                 day = record->get_current_batch()->start_day;
193 // Start recording
194                         if(record->get_current_batch()->start_day == day &&
195                                 record->get_current_batch()->start_time >= last_seconds &&
196                                 record->get_current_batch()->start_time <= seconds)
197                         {
198                                 break;
199                         }
201 //                      record->record_gui->lock_window();
202 //                      record->record_gui->flash_batch();
203 //                      record->record_gui->unlock_window();
204                 }
206                 last_seconds = seconds;
207                 last_day = day;
208                 if(!engine_done) usleep(BATCH_DELAY);
209                 if(!engine_done)
210                 {
211                         record->record_gui->lock_window("RecordThread::do_cron");
212                         record->record_gui->flash_batch();
213                         record->record_gui->unlock_window();
214                 }
215         }while(!engine_done);
220 void RecordThread::run()
222         int rewinding_loop = 0;
223         startup_lock->unlock();
224         record->get_current_time(last_seconds, last_day);
227         do
228         {
229 // Prepare next batch
230                 if(context == CONTEXT_BATCH &&
231                         !rewinding_loop)
232                 {
233                         do_cron();
234                 }
236                 state_lock->lock("RecordThread::run");
237 // Test for stopped while waiting
238                 if(!engine_done)
239                 {
240                         
241                         rewinding_loop = 0;
243 // Batch context needs to open the device here.  Interactive and singleframe
244 // contexts need to open in Record::start_recording to allow full duplex.
245                         if(context == CONTEXT_BATCH)
246                         {
247 // Delete output file before opening the devices to avoid buffer overflow.
248 TRACE("RecordThread::run 1");
249                                 record->delete_output_file();
250 TRACE("RecordThread::run 2");
251                                 record->open_input_devices(0, context);
252 TRACE("RecordThread::run 3");
253                         }
255 // Switch interactive recording to batch recording
256 // to get delay before next batch
257                         if(!monitor && context == CONTEXT_INTERACTIVE)
258                                 context = CONTEXT_BATCH;
260                         if(!monitor)
261                         {
262 // This draws to RecordGUI, incidentally
263 TRACE("RecordThread::run 4");
264                                 record->open_output_file();
265 TRACE("RecordThread::run 5");
266                                 if(mwindow->edl->session->record_sync_drives)
267                                 {
268                                         drivesync = new DriveSync;
269                                         drivesync->start();
270                                 }
271                                 else
272                                         drivesync = 0;
274                                 record->get_current_batch()->recorded = 1;
275 TRACE("RecordThread::run 6");
277 // Open file threads here to keep loop synchronized
278                                 if(record->default_asset->audio_data && 
279                                         context != CONTEXT_SINGLEFRAME)
280                                 {
281                                         int buffer_size, fragment_size;
282                                         record->get_audio_write_length(buffer_size, 
283                                                 fragment_size);
284                                         record->file->start_audio_thread(buffer_size, RING_BUFFERS);
285                                 }
286 TRACE("RecordThread::run 7");
288                                 if(record->default_asset->video_data)
289                                         record->file->start_video_thread(mwindow->edl->session->video_write_length,
290                                                 record->vdevice->get_best_colormodel(record->default_asset),
291                                                 RING_BUFFERS,
292                                                 record->vdevice->is_compressed(1, 0));
293 TRACE("RecordThread::run 8");
294                         }
296 // Reset synchronization  counters
297                         record->get_current_batch()->session_samples = 0;
298                         record->get_current_batch()->session_frames = 0;
299                         record_timer->update();
301 // Do initialization
302 TRACE("RecordThread::run 9");
303                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
304                                 record_audio->arm_recording();
305 TRACE("RecordThread::run 10");
306                         if(record->default_asset->video_data)
307                                 record_video->arm_recording();
308 TRACE("RecordThread::run 11");
309                         state_lock->unlock();
311 // Trigger loops
313                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
314                                 record_audio->start_recording();
315 TRACE("RecordThread::run 12");
316                         if(record->default_asset->video_data)
317                                 record_video->start_recording();
318 TRACE("RecordThread::run 13");
321                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
322                                 record_audio->Thread::join();
323 TRACE("RecordThread::run 14");
324                         if(record->default_asset->video_data)
325                                 record_video->Thread::join();
326 TRACE("RecordThread::run 15");
328 // Stop file threads here to keep loop synchronized
329                         if(!monitor)
330                         {
331                                 if(drivesync) drivesync->done = 1;
332 TRACE("RecordThread::run 16");
333                                 if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
334                                         record->file->stop_audio_thread();
335 TRACE("RecordThread::run 17");
336                                 if(record->default_asset->video_data)
337                                         record->file->stop_video_thread();
338 TRACE("RecordThread::run 18");
340 // Update asset info
341                                 record->get_current_batch()->get_current_asset()->audio_length = 
342                                         record->get_current_batch()->total_samples;
343                                 record->get_current_batch()->get_current_asset()->video_length = 
344                                         record->get_current_batch()->total_frames;
346 // Reset the loop flag and rewind files for the next loop
347                                 if(!engine_done)
348                                 {
349 // Rewind loop if in loop mode
350                                         if(record->get_current_batch()->record_mode == RECORD_LOOP)
351                                         {
352 // Don't close devices when rewinding a loop
353                                                 record->rewind_file();
354                                                 record->get_current_batch()->session_samples = 0;
355                                                 record->get_current_batch()->session_frames = 0;
356                                                 rewinding_loop = 1;
357                                         }
358                                         else
359 // Advance batch if not terminated by user and not single frame and continue loop
360                                         if(record->get_next_batch() >= 0 && context != CONTEXT_SINGLEFRAME)
361                                         {
362                                                 record->activate_batch(record->get_next_batch(), 0);
363                                                 record->close_input_devices();
364                                         }
365                                         else
366 // End loop
367                                         {
368                                                 engine_done = 1;
369                                         }
370                                 }
371 TRACE("RecordThread::run 20");
373                                 if(drivesync) delete drivesync;
374                         }
375                 }
376                 else
377                 {
378                         state_lock->unlock();
379                 }
381 // Wait for thread to stop before closing devices
382                 loop_lock->unlock();
383                 if(monitor)
384                 {
385 // Pause until monitor is resumed
386                         pause_lock->lock("RecordThread::run");
387                         pause_lock->unlock();
388                 }
389         }while(!engine_done);
391         record->close_input_devices();
393 // Resume monitoring only if not a monitor ourselves
394         if(!monitor)
395         {
396                 record->stop_duplex();
397                 if(resume_monitor) record->resume_monitor();
398         }
399         else
400         {
401                 record->capture_state = IS_DONE;
402         }