r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / recordthread.C
blob61578508dd7b0c4448e4c80f74aaae4624d6ca64
1 #include "assets.h"
2 #include "audiodevice.h"
3 #include "batch.h"
4 #include "drivesync.h"
5 #include "edl.h"
6 #include "edlsession.h"
7 #include "file.h"
8 #include "mwindow.h"
9 #include "record.h"
10 #include "recordaudio.h"
11 #include "recordgui.h"
12 #include "recordthread.h"
13 #include "recordvideo.h"
14 #include "timer.h"
15 #include "videodevice.h"
18 RecordThread::RecordThread(MWindow *mwindow, Record *record)
19  : Thread()
21         this->mwindow = mwindow;
22         this->record = record;
23         quit_when_completed = 0;
24         record_timer = new Timer;
25         record_audio = 0;
26         record_video = 0;
29 RecordThread::~RecordThread()
31         delete record_timer;
34 int RecordThread::create_objects()
36         if(record->default_asset->audio_data) 
37                 record_audio = new RecordAudio(mwindow, 
38                         record, 
39                         this);
41         if(record->default_asset->video_data) 
42                 record_video = new RecordVideo(mwindow, 
43                         record, 
44                         this);
45         engine_done = 0;
46         return 0;
49 int RecordThread::start_recording(int monitor, int context)
51 //printf("RecordThread::start_recording 1\n");
52         engine_done = 0;
53         this->monitor = monitor;
54         this->context = context;
55         resume_monitor = !monitor;
56         loop_lock.lock();
57 // Startup lock isn't 
58         startup_lock.lock();
59         completion_lock.lock();
62         set_synchronous(0);
63         Thread::start();
64         startup_lock.lock();
65         startup_lock.unlock();
66 //printf("RecordThread::start_recording 10\n");
67         return 0;
70 int RecordThread::stop_recording(int resume_monitor)
72 // Stop RecordThread while waiting for batch
73         state_lock.lock();
74         engine_done = 1;
76         this->resume_monitor = resume_monitor;
77 // In the monitor engine, stops the engine.
78 // In the recording engine, causes the monitor engine not to be restarted.
79 // Video thread stops the audio thread itself
80 // printf("RecordThread::stop_recording 1\n");
81         if(record_video)
82         {
83                 record_video->batch_done = 1;
84                 state_lock.unlock();
85                 record_video->stop_recording();
86         }
87         else
88         if(record_audio && context != CONTEXT_SINGLEFRAME) 
89         {
90 //printf("RecordThread::stop_recording 3\n");
91                 record_audio->batch_done = 1;
92                 state_lock.unlock();
93 //printf("RecordThread::stop_recording 4\n");
94                 record_audio->stop_recording();
95 //printf("RecordThread::stop_recording 5\n");
96         }
99 //printf("RecordThread::stop_recording 6\n");
100         completion_lock.lock();
101         completion_lock.unlock();
102 //printf("RecordThread::stop_recording 100\n");
103         return 0;
106 int RecordThread::pause_recording()
108 // Stop the thread before finishing the loop
109 //printf("RecordThread::pause_recording 1\n");
110         pause_lock.lock();
111 //printf("RecordThread::pause_recording 1\n");
113         state_lock.lock();
114         if(record->default_asset->video_data)
115         {
116                 record_video->batch_done = 1;
117         }
118         else
119         {
120                 record_audio->batch_done = 1;
121         }
122         state_lock.unlock();
123 //printf("RecordThread::pause_recording 1\n");
124 // Stop the recordings
125         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
126                 record_audio->stop_recording();
127         if(record->default_asset->video_data)
128                 record_video->stop_recording();
129 //printf("RecordThread::pause_recording 1\n");
131 // Wait for thread to stop before closing devices
132         loop_lock.lock();
133         loop_lock.unlock();
134 //printf("RecordThread::pause_recording 1\n");
138         record->close_input_devices();
139 //printf("RecordThread::pause_recording 2\n");
140         record->capture_state = IS_DONE;
141         return 0;
144 int RecordThread::resume_recording()
146 //printf("RecordThread::resume_recording 1\n");
147         if(record_video)
148         {
149                 record_video->batch_done = 0;
150         }
151         else
152         {
153                 record_audio->batch_done = 0;
154         }
155         loop_lock.lock();
156         pause_lock.unlock();
157 //printf("RecordThread::resume_recording 2\n");
158         return 0;
161 int64_t RecordThread::sync_position()
163         if(record->default_asset->audio_data)
164                 return record_audio->sync_position();
165         else
166                 return (int64_t)((float)record_timer->get_difference() / 
167                         1000 * 
168                         record->default_asset->sample_rate + 0.5);
171 void RecordThread::do_cron()
173         do{
174                 double position = record->current_display_position();
175                 int day;
176                 double seconds;
177                 
179 // Batch already started
180                 if(position > 0)
181                 {
182                         break;
183                 }
184                 else
185 // Delay until start of batch
186                 {
187                         record->get_current_time(seconds, day);
189 // Wildcard
190                         if(record->get_current_batch()->start_day == 7)
191                                 day = record->get_current_batch()->start_day;
192 // Start recording
193                         if(record->get_current_batch()->start_day == day &&
194                                 record->get_current_batch()->start_time >= last_seconds &&
195                                 record->get_current_batch()->start_time <= seconds)
196                         {
197                                 break;
198                         }
200 //                      record->record_gui->lock_window();
201 //                      record->record_gui->flash_batch();
202 //                      record->record_gui->unlock_window();
203                 }
205                 last_seconds = seconds;
206                 last_day = day;
207                 if(!engine_done) usleep(BATCH_DELAY);
208                 if(!engine_done)
209                 {
210                         record->record_gui->lock_window();
211                         record->record_gui->flash_batch();
212                         record->record_gui->unlock_window();
213                 }
214         }while(!engine_done);
219 void RecordThread::run()
221         int rewinding_loop = 0;
222         startup_lock.unlock();
223         record->get_current_time(last_seconds, last_day);
224         
226         do
227         {
228 // Prepare next batch
229                 if(context == CONTEXT_BATCH &&
230                         !rewinding_loop)
231                 {
232                         do_cron();
233                 }
235                 state_lock.lock();
236 // Test for stopped while waiting
237                 if(!engine_done)
238                 {
239                         
240                         rewinding_loop = 0;
241 //printf("RecordThread::run 6\n");
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                                 record->delete_output_file();
249                                 record->open_input_devices(0, context);
250                         }
251 //printf("RecordThread::run 7 %d\n", monitor);
253 // Switch interactive recording to batch recording
254 // to get delay before next batch
255                         if(!monitor && context == CONTEXT_INTERACTIVE)
256                                 context = CONTEXT_BATCH;
258                         if(!monitor)
259                         {
260 // This draws to RecordGUI, incidentally
261                                 record->open_output_file();
262                                 if(mwindow->edl->session->record_sync_drives)
263                                 {
264                                         drivesync = new DriveSync;
265                                         drivesync->start();
266                                 }
267                                 else
268                                         drivesync = 0;
270                                 record->get_current_batch()->recorded = 1;
272 // Open file threads here to keep loop synchronized
273                                 if(record->default_asset->audio_data && 
274                                         context != CONTEXT_SINGLEFRAME)
275                                 {
276                                         int64_t buffer_size, fragment_size;
277                                         record->get_audio_write_length(buffer_size, fragment_size);
278                                         record->file->start_audio_thread(buffer_size, RING_BUFFERS);
279                                 }
281                                 if(record->default_asset->video_data)
282                                         record->file->start_video_thread(mwindow->edl->session->video_write_length,
283                                                 record->vdevice->get_best_colormodel(record->default_asset),
284                                                 RING_BUFFERS,
285                                                 record->vdevice->is_compressed());
286                         }
287 //printf("RecordThread::run 8\n");
289 // Reset synchronization  counters
290                         record->get_current_batch()->session_samples = 0;
291                         record->get_current_batch()->session_frames = 0;
292                         record_timer->update();
294 // Do initialization
295                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
296                                 record_audio->arm_recording();
297                         if(record->default_asset->video_data)
298                                 record_video->arm_recording();
299 //printf("RecordThread::run 9\n");
300                         state_lock.unlock();
302 // Trigger loops
304                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
305                                 record_audio->start_recording();
306                         if(record->default_asset->video_data)
307                                 record_video->start_recording();
309 //printf("RecordThread::run 10\n");
311                         if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
312                                 record_audio->join();
313 //printf("RecordThread::run 10\n");
314                         if(record->default_asset->video_data)
315                                 record_video->join();
316 //printf("RecordThread::run 11\n");
318 // Stop file threads here to keep loop synchronized
319                         if(!monitor)
320                         {
321                                 if(drivesync) drivesync->done = 1;
322                                 if(record->default_asset->audio_data && context != CONTEXT_SINGLEFRAME)
323                                         record->file->stop_audio_thread();
324                                 if(record->default_asset->video_data)
325                                         record->file->stop_video_thread();
327 // Update asset info
328                                 record->get_current_batch()->get_current_asset()->audio_length = 
329                                         record->get_current_batch()->total_samples;
330                                 record->get_current_batch()->get_current_asset()->video_length = 
331                                         record->get_current_batch()->total_frames;
333 // Reset the loop flag and rewind files for the next loop
334                                 if(!engine_done)
335                                 {
336 // Rewind loop if in loop mode
337                                         if(record->get_current_batch()->record_mode == RECORD_LOOP)
338                                         {
339 // Don't close devices when rewinding a loop
340                                                 record->rewind_file();
341                                                 record->get_current_batch()->session_samples = 0;
342                                                 record->get_current_batch()->session_frames = 0;
343                                                 rewinding_loop = 1;
344                                         }
345                                         else
346 // Advance batch if not terminated by user and not single frame and continue loop
347                                         if(record->get_next_batch() >= 0 && context != CONTEXT_SINGLEFRAME)
348                                         {
349                                                 record->activate_batch(record->get_next_batch(), 0);
350                                                 record->close_input_devices();
351                                         }
352                                         else
353 // End loop
354                                         {
355                                                 engine_done = 1;
356                                         }
357                                 }
359                                 if(drivesync) delete drivesync;
360                         }
361 //printf("RecordThread::run 12\n");
362                 }
363                 else
364                 {
365                         state_lock.unlock();
366                 }
368 // Wait for thread to stop before closing devices
369                 loop_lock.unlock();
370                 if(monitor)
371                 {
372 // Pause until monitor is resumed
373                         pause_lock.lock();
374                         pause_lock.unlock();
375                 }
376         }while(!engine_done);
378 //printf("RecordThread::run 13\n");
379         record->close_input_devices();
381 // Resume monitoring only if not a monitor ourselves
382         if(!monitor)
383         {
384                 record->stop_duplex();
385                 if(resume_monitor) record->resume_monitor();
386         }
387         else
388         {
389                 record->capture_state = IS_DONE;
390         }
391         completion_lock.unlock();