r602: Fix baver's code... don't insert timecode when show_tc is not set
[cinelerra_cv/mob.git] / cinelerra / recordvideo.C
blob97d630849f1e8dc4ec468de596b56dbcbd2974a8
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");
44 RecordVideo::~RecordVideo()
46         delete unhang_lock;
47         delete trigger_lock;
50 void RecordVideo::reset_parameters()
52         write_result = 0;
53         grab_result = 0;
54         total_dropped_frames = 0;
55         dropped_frames = 0;
56         last_dropped_frames = 0;
57         record_start = 0;
58         buffer_position = 0;
59         batch_done = 0;
62 int RecordVideo::arm_recording()
64         reset_parameters();
65 // Resume next file in a series by incrementing existing counters
66         if(record_thread->monitor)
67                 buffer_size = 1;
68         else
69                 buffer_size = mwindow->edl->session->video_write_length;
71         trigger_lock->lock("RecordVideo::arm_recording");
72         Thread::start();
74         return 0;
77 void RecordVideo::start_recording()
79         trigger_lock->unlock();
82 int RecordVideo::stop_recording()
84 // Device won't exist if interrupting a cron job
85         if(record->vdevice)
86         {
87 // Interrupt IEEE1394 crashes
88                 record->vdevice->interrupt_crash();
90 // Interrupt video4linux crashes
91                 if(record->vdevice->get_failed())
92                 {
93                         Thread::end();
94                         Thread::join();
96                         cleanup_recording();
97                 }
98         }
99         return 0;
103 int RecordVideo::cleanup_recording()
105         if(!record_thread->monitor)
106         {
107 //printf("RecordVideo::cleanup_recording 1\n");
108 // write last buffer
109                 write_buffer(1);
110 // stop file I/O
111 //printf("RecordVideo::cleanup_recording 2\n");
112         }
113         else
114         {
115                 delete [] frame_ptr[0];
116                 delete [] frame_ptr;
117                 delete capture_frame;
118         }
119         return 0;
122 void RecordVideo::get_capture_frame()
124         if(record->fixed_compression)
125         {
126                 capture_frame = new VFrame;
127         }
128         else
129         {
130                 capture_frame = new VFrame(0, 
131                         record->default_asset->width, 
132                         record->default_asset->height, 
133                         record->vdevice->get_best_colormodel(record->default_asset));
134 //printf("RecordVideo::get_capture_frame %d %d\n", capture_frame->get_w(), capture_frame->get_h());
135         }
136         frame_ptr = new VFrame**[1];
137         frame_ptr[0] = new VFrame*[1];
138         frame_ptr[0][0] = capture_frame;
142 void RecordVideo::run()
144         write_result = 0;
145         grab_result = 0;
147 // Thread out the I/O
148         if(!record_thread->monitor)
149         {
150                 record_start = record->file->get_video_position(record->default_asset->frame_rate);
151                 frame_ptr = record->file->get_video_buffer();
152         }
153         else
154         {
155                 get_capture_frame();
156         }
158 // Number of frames for user to know about.
159         gui->total_dropped_frames = 0;
160         gui->update_dropped_frames(0);
163 // Wait for trigger
164         trigger_lock->lock("RecordVideo::run");
165         trigger_lock->unlock();
167         while(!batch_done && 
168                 !write_result)
169         {
170 // Synchronize with audio or timer
171                 dropped_frames = 0;
172                 next_sample = (int64_t)((float)record->get_current_batch()->session_frames / 
173                         record->default_asset->frame_rate * 
174                         record->default_asset->sample_rate);
175                 current_sample = record->sync_position();
178                 if(current_sample < next_sample && current_sample > 0)
179                 {
180 // Too early.
181                         delay = (int64_t)((float)(next_sample - current_sample) / 
182                                 record->default_asset->sample_rate * 
183                                 1000);
184 // Sanity check and delay.
185 // In 2.6.7 this doesn't work.  For some reason, probably buffer overflowing,
186 // it causes the driver to hang up momentarily so we try to only delay
187 // when really really far ahead.
188                         if(delay < 2000 && delay > 0) delayer.delay(delay);
189                         gui->update_dropped_frames(0);
190                         last_dropped_frames = 0;
191                 }
192                 else
193                 if(current_sample > 0 && !record_thread->monitor)
194                 {
195 // Too late.
196                         dropped_frames = (int64_t)((float)(current_sample - next_sample) / 
197                                 record->default_asset->sample_rate * 
198                                 record->default_asset->frame_rate);
199                         if(dropped_frames != last_dropped_frames)
200                         {
201                                 gui->update_dropped_frames(dropped_frames);
202                                 last_dropped_frames = dropped_frames;
203                         }
204                         last_dropped_frames = dropped_frames;
205                 }
209 // Capture a frame
210                 if(!batch_done)
211                 {
212 // Grab frame for recording
213                         if(!record_thread->monitor)
214                         {
215                                 capture_frame = frame_ptr[0][buffer_position];
216                                 record->vdevice->set_field_order(record->reverse_interlace);
217                                 read_buffer();
218                                 record->get_current_batch()->current_frame++;
219                                 record->get_current_batch()->total_frames = 
220                                         MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
221                                 record->get_current_batch()->session_frames++;
222                                 if(!grab_result) buffer_position++;
224 // Update the position indicator
225                                 gui->update_position(record->current_display_position());
226                         }
227                         else
228 // Grab frame for monitoring
229                         if(record->monitor_video)
230                         {
231                                 record->vdevice->set_field_order(record->reverse_interlace);
232                                 record->get_current_batch()->session_frames++;
234                                 read_buffer();
235                         }
236                         else
237 // Brief pause to keep CPU from burning up
238                         {
239                                 Timer::delay(250);
240                         }
241                 }
243 // Monitor the frame if monitoring
244 // printf("RecordVideo::run %p %d %d %d\n", 
245 // capture_frame->get_data(), 
246 // record->monitor_video, 
247 // batch_done, 
248 // grab_result);
249                 if(capture_frame->get_data() && 
250                         record->monitor_video && 
251                         !batch_done && 
252                         !grab_result)
253                 {
254                         record->record_monitor->update(capture_frame);
255                 }
257 // Duplicate a frame if behind
258                 if(!record_thread->monitor && 
259                         record->fill_frames && 
260                         !batch_done && 
261                         dropped_frames > 1)
262                 {
263                         VFrame *last_frame = capture_frame;
264 // Write frame 1
265                         if(buffer_position >= buffer_size) write_buffer(0);
266 // Copy to frame 2
267                         capture_frame = frame_ptr[0][buffer_position];
268                         capture_frame->copy_from(last_frame);
269                         record->get_current_batch()->current_frame++;
270                         record->get_current_batch()->total_frames = 
271                                 MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
272                         record->get_current_batch()->session_frames++;
273                         buffer_position++;
274                 }
276 // Compress a batch of frames or write the second frame if filling
277                 if(!record_thread->monitor && buffer_position >= buffer_size)
278                 {
279                         write_buffer(0);
280                 }
282                 if(!record_thread->monitor && 
283                         !batch_done &&
284                         !write_result)
285                 {
286 // Handle recording contexts
287                         if(record_thread->context == CONTEXT_SINGLEFRAME)
288                         {
289                                 batch_done = 1;
290                         }
291                         else
292 // Handle recording modes delegated to the thread
293                         switch(record->get_current_batch()->record_mode)
294                         {
295                                 case RECORD_TIMED:
296                                         if(record->current_display_position() > *record->current_duration())
297                                                 batch_done = 1;
298                                         break;
299                                 case RECORD_LOOP:
300                                         if(record->current_display_position() > *record->current_duration())
301                                                 batch_done = 1;
302                                         break;
303                                 case RECORD_SCENETOSCENE:
304                                         break;
305                         }
306                 }
308                 if(write_result)
309                 {
310                         batch_done = 1;
311                 }
312         }
314 //TRACE("RecordVideo::run 1");
315 // Update dependant threads
316         if(record->default_asset->audio_data)
317         {
318                 record_thread->record_audio->batch_done = 1;
319 // Interrupt driver for IEEE1394
320                 record_thread->record_audio->stop_recording();
321         }
323 //TRACE("RecordVideo::run 2");
325         if(write_result)
326         {
327                 if(!record_thread->monitor)
328                 {
329                         ErrorBox error_box(PROGRAM_NAME ": Error",
330                                 mwindow->gui->get_abs_cursor_x(1),
331                                 mwindow->gui->get_abs_cursor_y(1));
332                         error_box.create_objects(_("No space left on disk."));
333                         error_box.run_window();
334                         batch_done = 1;
335                 }
336         }
338         cleanup_recording();
339 //TRACE("RecordVideo::run 100");
342 void RecordVideo::read_buffer()
344         grab_result = record->vdevice->read_buffer(capture_frame);
347 // Get field offset for monitor
348         if(!strncmp(record->default_asset->vcodec, QUICKTIME_MJPA, 4) &&
349                 record->vdevice->is_compressed(0, 1))
350         {
351                 unsigned char *data = capture_frame->get_data();
352                 int64_t size = capture_frame->get_compressed_size();
353                 int64_t allocation = capture_frame->get_compressed_allocated();
355                 if(data)
356                 {
357                         int64_t field2_offset = mjpeg_get_field2(data, size);
358                         capture_frame->set_compressed_size(size);
359                         capture_frame->set_field2_offset(field2_offset);
360                 }
361         }
364 void RecordVideo::write_buffer(int skip_new)
366         write_result = record->file->write_video_buffer(buffer_position);
367         buffer_position = 0;
368         if(!skip_new && !write_result) 
369                 frame_ptr = record->file->get_video_buffer();
372 void RecordVideo::rewind_file()
374         write_buffer(1);
375         record->file->stop_video_thread();
376         record->file->set_video_position(0, record->default_asset->frame_rate);
377         record->file->start_video_thread(buffer_size,
378                 record->vdevice->get_best_colormodel(record->default_asset),
379                 2,
380                 record->vdevice->is_compressed(1, 0));
381         frame_ptr = record->file->get_video_buffer();
382         record->get_current_batch()->current_frame = 0;
383         record->get_current_batch()->current_sample = 0;
384         record->get_current_batch()->session_frames = 0;
385         record->get_current_batch()->session_samples = 0;
386         gui->update_position(0);
389 int RecordVideo::unhang_thread()
391 printf("RecordVideo::unhang_thread\n");
392         Thread::end();