Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / recordvideo.C
blob8f62754027137f24d1bb14bf68c40a4cf3c1a552
1 #include "asset.h"
2 #include "batch.h"
3 #include "bcsignals.h"
4 #include "clip.h"
5 #include "condition.h"
6 #include "edl.h"
7 #include "edlsession.h"
8 #include "errorbox.h"
9 #include "file.h"
10 #include "filethread.h"
11 #include "language.h"
12 #include "mutex.h"
13 #include "mwindow.h"
14 #include "mwindowgui.h"
15 #include "preferences.h"
16 #include "quicktime.h"
17 #include "record.h"
18 #include "recordaudio.h"
19 #include "recordgui.h"
20 #include "recordthread.h"
21 #include "recordvideo.h"
22 #include "recordmonitor.h"
23 #include "units.h"
24 #include "vframe.h"
25 #include "videodevice.h"
27 #include <unistd.h>
30 RecordVideo::RecordVideo(MWindow *mwindow,
31         Record *record, 
32         RecordThread *record_thread)
33  : Thread(1, 0, 0)
35         reset_parameters();
36         this->mwindow = mwindow;
37         this->record = record;
38         this->record_thread = record_thread; 
39         this->gui = record->record_gui;
40         unhang_lock = new Mutex("RecordVideo::unhang_lock");
41         trigger_lock = new Condition(1, "RecordVideo::trigger_lock");
42         capture_frame = 0;
43         frame_ptr = 0;
46 RecordVideo::~RecordVideo()
48         delete unhang_lock;
49         delete trigger_lock;
50 // These objects are shared with the file if recording.
51         if(record_thread->monitor)
52         {
53                 if(frame_ptr)
54                 {
55                         if(frame_ptr[0]) delete [] frame_ptr[0];
56                         delete [] frame_ptr;
57                 }
58                 delete capture_frame;
59         }
62 void RecordVideo::reset_parameters()
64         write_result = 0;
65         grab_result = 0;
66         total_dropped_frames = 0;
67         dropped_frames = 0;
68         last_dropped_frames = 0;
69         record_start = 0;
70         buffer_position = 0;
71         batch_done = 0;
74 int RecordVideo::arm_recording()
76         reset_parameters();
77 // Resume next file in a series by incrementing existing counters
78         if(record_thread->monitor)
79                 buffer_size = 1;
80         else
81                 buffer_size = mwindow->edl->session->video_write_length;
83         trigger_lock->lock("RecordVideo::arm_recording");
84         Thread::start();
86         return 0;
89 void RecordVideo::start_recording()
91         trigger_lock->unlock();
94 int RecordVideo::stop_recording()
96 // Device won't exist if interrupting a cron job
97         if(record->vdevice)
98         {
99 // Interrupt IEEE1394 crashes
100                 record->vdevice->interrupt_crash();
102 // Interrupt video4linux crashes
103                 if(record->vdevice->get_failed())
104                 {
105                         Thread::end();
106                         Thread::join();
108                         cleanup_recording();
109                 }
110         }
111 // Joined in RecordThread
112         return 0;
116 int RecordVideo::cleanup_recording()
118         if(!record_thread->monitor)
119         {
120 // write last buffer
121                 write_buffer(1);
122 // stop file I/O
123         }
124         else
125         {
126 // RecordMonitorThread still needs capture_frame if uncompressed.
127 //              delete [] frame_ptr[0];
128 //              delete [] frame_ptr;
129 //              delete capture_frame;
130         }
131         return 0;
134 void RecordVideo::get_capture_frame()
136         if(!capture_frame)
137         {
138                 if(record->fixed_compression)
139                 {
140                         capture_frame = new VFrame;
141                 }
142                 else
143                 {
144                         capture_frame = new VFrame(0, 
145                                 record->default_asset->width, 
146                                 record->default_asset->height, 
147                                 record->vdevice->get_best_colormodel(record->default_asset));
148 //printf("RecordVideo::get_capture_frame %d %d\n", capture_frame->get_w(), capture_frame->get_h());
149                 }
150                 frame_ptr = new VFrame**[1];
151                 frame_ptr[0] = new VFrame*[1];
152                 frame_ptr[0][0] = capture_frame;
153         }
157 void RecordVideo::run()
159         write_result = 0;
160         grab_result = 0;
162 // Thread out the I/O
163         if(!record_thread->monitor)
164         {
165                 record_start = record->file->get_video_position(record->default_asset->frame_rate);
166                 frame_ptr = record->file->get_video_buffer();
167         }
168         else
169         {
170                 get_capture_frame();
171         }
173 // Number of frames for user to know about.
174         gui->total_dropped_frames = 0;
175         gui->update_dropped_frames(0);
178 // Wait for trigger
179         trigger_lock->lock("RecordVideo::run");
180         trigger_lock->unlock();
182         while(!batch_done && 
183                 !write_result)
184         {
185 // Synchronize with audio or timer
186                 dropped_frames = 0;
187                 next_sample = (int64_t)((float)record->get_current_batch()->session_frames / 
188                         record->default_asset->frame_rate * 
189                         record->default_asset->sample_rate);
190                 current_sample = record->sync_position();
193                 if(current_sample < next_sample && current_sample > 0)
194                 {
195 // Too early.
196                         delay = (int64_t)((float)(next_sample - current_sample) / 
197                                 record->default_asset->sample_rate * 
198                                 1000);
199 // Sanity check and delay.
200 // In 2.6.7 this doesn't work.  For some reason, probably buffer overflowing,
201 // it causes the driver to hang up momentarily so we try to only delay
202 // when really really far ahead.
203                         if(delay < 2000 && delay > 0) 
204                         {
205                                 delayer.delay(delay);
206                         }
207                         gui->update_dropped_frames(0);
208                         last_dropped_frames = 0;
209                 }
210                 else
211                 if(current_sample > 0 && !record_thread->monitor)
212                 {
213 // Too late.
214                         dropped_frames = (int64_t)((float)(current_sample - next_sample) / 
215                                 record->default_asset->sample_rate * 
216                                 record->default_asset->frame_rate);
217                         if(dropped_frames != last_dropped_frames)
218                         {
219                                 gui->update_dropped_frames(dropped_frames);
220                                 last_dropped_frames = dropped_frames;
221                         }
222                         last_dropped_frames = dropped_frames;
223                 }
227 // Capture a frame
228                 if(!batch_done)
229                 {
230 // Grab frame for recording
231                         if(!record_thread->monitor)
232                         {
233                                 capture_frame = frame_ptr[0][buffer_position];
234                                 record->vdevice->set_field_order(record->reverse_interlace);
235                                 read_buffer();
236                                 record->get_current_batch()->current_frame++;
237                                 record->get_current_batch()->total_frames = 
238                                         MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
239                                 record->get_current_batch()->session_frames++;
240                                 if(!grab_result) buffer_position++;
242 // Update the position indicator
243                                 gui->update_position(record->current_display_position());
244                         }
245                         else
246 // Grab frame for monitoring
247                         if(record->monitor_video)
248                         {
249                                 record->vdevice->set_field_order(record->reverse_interlace);
250                                 record->get_current_batch()->session_frames++;
252                                 read_buffer();
253                         }
254                         else
255 // Brief pause to keep CPU from burning up
256                         {
257                                 Timer::delay(250);
258                         }
259                 }
261 // Monitor the frame if monitoring
262 // printf("RecordVideo::run %p %d %d %d\n", 
263 // capture_frame->get_data(), 
264 // record->monitor_video, 
265 // batch_done, 
266 // grab_result);
267                 if(capture_frame->get_data() && 
268                         record->monitor_video && 
269                         !batch_done && 
270                         !grab_result)
271                 {
272                         record->record_monitor->update(capture_frame);
273                 }
275 // Duplicate a frame if behind
276                 if(!record_thread->monitor && 
277                         record->fill_frames && 
278                         !batch_done && 
279                         dropped_frames > 1)
280                 {
281                         VFrame *last_frame = capture_frame;
282 // Write frame 1
283                         if(buffer_position >= buffer_size) write_buffer(0);
284 // Copy to frame 2
285                         capture_frame = frame_ptr[0][buffer_position];
286                         capture_frame->copy_from(last_frame);
287                         record->get_current_batch()->current_frame++;
288                         record->get_current_batch()->total_frames = 
289                                 MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
290                         record->get_current_batch()->session_frames++;
291                         buffer_position++;
292                 }
294 // Compress a batch of frames or write the second frame if filling
295                 if(!record_thread->monitor && buffer_position >= buffer_size)
296                 {
297                         write_buffer(0);
298                 }
300                 if(!record_thread->monitor && 
301                         !batch_done &&
302                         !write_result)
303                 {
304 // Handle recording contexts
305                         if(record_thread->context == CONTEXT_SINGLEFRAME)
306                         {
307                                 batch_done = 1;
308                         }
309                         else
310 // Handle recording modes delegated to the thread
311                         switch(record->get_current_batch()->record_mode)
312                         {
313                                 case RECORD_TIMED:
314                                         if(record->current_display_position() > *record->current_duration())
315                                                 batch_done = 1;
316                                         break;
317                                 case RECORD_LOOP:
318                                         if(record->current_display_position() > *record->current_duration())
319                                                 batch_done = 1;
320                                         break;
321                                 case RECORD_SCENETOSCENE:
322                                         break;
323                         }
324                 }
326                 if(write_result)
327                 {
328                         batch_done = 1;
329                 }
330         }
332 //TRACE("RecordVideo::run 1");
333 // Update dependant threads
334         if(record->default_asset->audio_data)
335         {
336                 record_thread->record_audio->batch_done = 1;
337 // Interrupt driver for IEEE1394
338                 record_thread->record_audio->stop_recording();
339         }
341 //TRACE("RecordVideo::run 2");
343         if(write_result)
344         {
345                 if(!record_thread->monitor)
346                 {
347                         ErrorBox error_box(PROGRAM_NAME ": Error",
348                                 mwindow->gui->get_abs_cursor_x(1),
349                                 mwindow->gui->get_abs_cursor_y(1));
350                         error_box.create_objects(_("No space left on disk."));
351                         error_box.run_window();
352                         batch_done = 1;
353                 }
354         }
356         cleanup_recording();
357 SET_TRACE
360 void RecordVideo::read_buffer()
362         grab_result = record->vdevice->read_buffer(capture_frame);
365 // Get field offset for monitor
366         if(!strncmp(record->default_asset->vcodec, QUICKTIME_MJPA, 4) &&
367                 record->vdevice->is_compressed(0, 1))
368         {
369                 unsigned char *data = capture_frame->get_data();
370                 int64_t size = capture_frame->get_compressed_size();
371                 int64_t allocation = capture_frame->get_compressed_allocated();
373                 if(data)
374                 {
375                         int64_t field2_offset = mjpeg_get_field2(data, size);
376                         capture_frame->set_compressed_size(size);
377                         capture_frame->set_field2_offset(field2_offset);
378                 }
379         }
382 void RecordVideo::write_buffer(int skip_new)
384         write_result = record->file->write_video_buffer(buffer_position);
385         buffer_position = 0;
386         if(!skip_new && !write_result) 
387                 frame_ptr = record->file->get_video_buffer();
390 void RecordVideo::rewind_file()
392         write_buffer(1);
393         record->file->stop_video_thread();
394         record->file->set_video_position(0, record->default_asset->frame_rate);
395         record->file->start_video_thread(buffer_size,
396                 record->vdevice->get_best_colormodel(record->default_asset),
397                 2,
398                 record->vdevice->is_compressed(1, 0));
399         frame_ptr = record->file->get_video_buffer();
400         record->get_current_batch()->current_frame = 0;
401         record->get_current_batch()->current_sample = 0;
402         record->get_current_batch()->session_frames = 0;
403         record->get_current_batch()->session_samples = 0;
404         gui->update_position(0);
407 int RecordVideo::unhang_thread()
409 printf("RecordVideo::unhang_thread\n");
410         Thread::end();
414 //      Local Variables:
415 //      mode: C++
416 //      c-file-style: "linux"
417 //      End: