r136: This commit was manufactured by cvs2svn to create tag 'hv_1_1_8'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / recordvideo.C
blob78852650c9e5a0493b23a15985b52157299283a0
1 #include "asset.h"
2 #include "batch.h"
3 #include "bcsignals.h"
4 #include "clip.h"
5 #include "edl.h"
6 #include "edlsession.h"
7 #include "errorbox.h"
8 #include "file.h"
9 #include "filethread.h"
10 #include "language.h"
11 #include "mwindow.h"
12 #include "mwindowgui.h"
13 #include "preferences.h"
14 #include "quicktime.h"
15 #include "record.h"
16 #include "recordaudio.h"
17 #include "recordgui.h"
18 #include "recordthread.h"
19 #include "recordvideo.h"
20 #include "recordmonitor.h"
21 #include "units.h"
22 #include "vframe.h"
23 #include "videodevice.h"
25 #include <unistd.h>
28 RecordVideo::RecordVideo(MWindow *mwindow,
29         Record *record, 
30         RecordThread *record_thread)
31  : Thread()
33         reset_parameters();
34         this->mwindow = mwindow;
35         this->record = record;
36         this->record_thread = record_thread; 
37         this->gui = record->record_gui;
40 RecordVideo::~RecordVideo()
44 void RecordVideo::reset_parameters()
46         write_result = 0;
47         grab_result = 0;
48         total_dropped_frames = 0;
49         dropped_frames = 0;
50         last_dropped_frames = 0;
51         record_start = 0;
52         buffer_position = 0;
53         batch_done = 0;
56 int RecordVideo::arm_recording()
58         reset_parameters();
59 // Resume next file in a series by incrementing existing counters
60         if(record_thread->monitor)
61                 buffer_size = 1;
62         else
63                 buffer_size = mwindow->edl->session->video_write_length;
65         set_synchronous(1);
66         trigger_lock.lock();
67         Thread::start();
69         return 0;
72 void RecordVideo::start_recording()
74         trigger_lock.unlock();
77 int RecordVideo::stop_recording()
79 // Device won't exist if interrupting a cron job
80         if(record->vdevice)
81         {
82 //printf("RecordVideo::stop_recording 1 %p\n", record->vdevice);
83 // Interrupt IEEE1394 crashes
84                 record->vdevice->interrupt_crash();
85 //printf("RecordVideo::stop_recording 1\n");
87 // Interrupt video4linux crashes
88                 if(record->vdevice->get_failed())
89                 {
90 //printf("RecordVideo::stop_recording 2\n");
91                         Thread::end();
92                         Thread::join();
93 //printf("RecordVideo::stop_recording 3\n");
95                         cleanup_recording();
96 //printf("RecordVideo::stop_recording 4\n");
97                 }
98         }
99 //printf("RecordVideo::stop_recording 5\n");
100         return 0;
104 int RecordVideo::cleanup_recording()
106         if(!record_thread->monitor)
107         {
108 //printf("RecordVideo::cleanup_recording 1\n");
109 // write last buffer
110                 write_buffer(1);
111 // stop file I/O
112 //printf("RecordVideo::cleanup_recording 2\n");
113         }
114         else
115         {
116                 delete [] frame_ptr[0];
117                 delete [] frame_ptr;
118                 delete capture_frame;
119         }
120         return 0;
123 void RecordVideo::get_capture_frame()
125         if(record->fixed_compression)
126         {
127                 capture_frame = new VFrame;
128         }
129         else
130         {
131                 capture_frame = new VFrame(0, 
132                         record->default_asset->width, 
133                         record->default_asset->height, 
134                         record->vdevice->get_best_colormodel(record->default_asset));
135 //printf("RecordVideo::get_capture_frame %d %d\n", capture_frame->get_w(), capture_frame->get_h());
136         }
137         frame_ptr = new VFrame**[1];
138         frame_ptr[0] = new VFrame*[1];
139         frame_ptr[0][0] = capture_frame;
143 void RecordVideo::run()
145         write_result = 0;
146         grab_result = 0;
148 //printf("RecordVideo::run 1 %d\n", getpid());
150 // Thread out the I/O
151         if(!record_thread->monitor)
152         {
153                 record_start = record->file->get_video_position(record->default_asset->frame_rate);
154                 frame_ptr = record->file->get_video_buffer();
155         }
156         else
157         {
158                 get_capture_frame();
159         }
161 // Number of frames for user to know about.
162         gui->total_dropped_frames = 0;
163         gui->update_dropped_frames(0);
166 // Wait for trigger
167         trigger_lock.lock();
168         trigger_lock.unlock();
170 //printf("RecordVideo::run 1 %d\n", record_thread->monitor);
172         while(!batch_done && 
173                 !write_result)
174         {
175 // Synchronize with audio or timer
176 //printf("RecordVideo::run 1 %d\n", batch_done);
177                 dropped_frames = 0;
178                 next_sample = (int64_t)((float)record->get_current_batch()->session_frames / 
179                         record->default_asset->frame_rate * 
180                         record->default_asset->sample_rate);
181 //printf("RecordVideo::run 1\n");
182                 current_sample = record->sync_position();
184 //printf("RecordVideo::run 2\n");
187                 if(current_sample < next_sample && current_sample > 0)
188                 {
189 // Too early.
190                         delay = (int64_t)((float)(next_sample - current_sample) / 
191                                 record->default_asset->sample_rate * 
192                                 1000  
193 //              / 2
194                                 );
195 // Sanity check and delay.
196                         if(delay < 2000 && delay > 0) delayer.delay(delay);
197                         gui->update_dropped_frames(0);
198                         last_dropped_frames = 0;
199                 }
200                 else
201                 if(current_sample > 0 && !record_thread->monitor)
202                 {
203 // Too late.
204                         dropped_frames = (int64_t)((float)(current_sample - next_sample) / 
205                                 record->default_asset->sample_rate * 
206                                 record->default_asset->frame_rate);
207                         if(dropped_frames != last_dropped_frames)
208                         {
209                                 gui->update_dropped_frames(dropped_frames);
210                                 last_dropped_frames = dropped_frames;
211                         }
212                         last_dropped_frames = dropped_frames;
213                 }
215 //printf("RecordVideo::run 3\n");
216 // Capture a frame
217                 if(!batch_done)
218                 {
219 // Grab frame for recording
220                         if(!record_thread->monitor)
221                         {
222                                 capture_frame = frame_ptr[0][buffer_position];
223                                 record->vdevice->set_field_order(record->reverse_interlace);
224                                 read_buffer();
225                                 record->get_current_batch()->current_frame++;
226                                 record->get_current_batch()->total_frames = 
227                                         MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
228                                 record->get_current_batch()->session_frames++;
229                                 if(!grab_result) buffer_position++;
231 // Update the position indicator
232                                 gui->update_position(record->current_display_position(),
233                                         record->current_display_length());
234                         }
235                         else
236 // Grab frame for monitoring
237                         if(record->monitor_video)
238                         {
239                                 record->vdevice->set_field_order(record->reverse_interlace);
240                                 record->get_current_batch()->session_frames++;
242                                 read_buffer();
243                         }
244                         else
245 // Brief pause to keep CPU from burning up
246                         {
247                                 Timer timer;
248                                 timer.delay(250);
249                         }
250                 }
252 // Monitor the frame if monitoring
253                 if(capture_frame->get_data() && 
254                         record->monitor_video && 
255                         !batch_done && 
256                         !grab_result)
257                         record->record_monitor->update(capture_frame);
259 // Duplicate a frame if behind
260                 if(!record_thread->monitor && 
261                         record->fill_frames && 
262                         !batch_done && 
263                         dropped_frames > 1)
264                 {
265                         VFrame *last_frame = capture_frame;
266 // Write frame 1
267                         if(buffer_position >= buffer_size) write_buffer(0);
268 // Copy to frame 2
269                         capture_frame = frame_ptr[0][buffer_position];
270                         capture_frame->copy_from(last_frame);
271                         record->get_current_batch()->current_frame++;
272                         record->get_current_batch()->total_frames = 
273                                 MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
274                         record->get_current_batch()->session_frames++;
275                         buffer_position++;
276                 }
278 // Compress a batch of frames or write the second frame if filling
279                 if(!record_thread->monitor && buffer_position >= buffer_size)
280                 {
281                         write_buffer(0);
282                 }
284                 if(!record_thread->monitor && 
285                         !batch_done &&
286                         !write_result)
287                 {
288 // Handle recording contexts
289                         if(record_thread->context == CONTEXT_SINGLEFRAME)
290                         {
291                                 batch_done = 1;
292                         }
293                         else
294 // Handle recording modes delegated to the thread
295                         switch(record->get_current_batch()->record_mode)
296                         {
297                                 case RECORD_TIMED:
298                                         if(record->current_display_position() > *record->current_duration())
299                                                 batch_done = 1;
300                                         break;
301                                 case RECORD_LOOP:
302                                         if(record->current_display_position() > *record->current_duration())
303                                                 batch_done = 1;
304                                         break;
305                                 case RECORD_SCENETOSCENE:
306                                         break;
307                         }
308                 }
310                 if(write_result)
311                 {
312                         batch_done = 1;
313                 }
314         }
316 TRACE("RecordVideo::run 1");
317 // Update dependant threads
318         if(record->default_asset->audio_data)
319         {
320                 record_thread->record_audio->batch_done = 1;
321 // Interrupt driver for IEEE1394
322                 record_thread->record_audio->stop_recording();
323         }
324 TRACE("RecordVideo::run 2");
326         if(write_result)
327         {
328                 if(!record_thread->monitor)
329                 {
330                         ErrorBox error_box(PROGRAM_NAME ": Error",
331                                 mwindow->gui->get_abs_cursor_x(),
332                                 mwindow->gui->get_abs_cursor_y());
333                         error_box.create_objects(_("No space left on disk."));
334                         error_box.run_window();
335                         batch_done = 1;
336                 }
337         }
339         cleanup_recording();
342 void RecordVideo::read_buffer()
345         grab_result = record->vdevice->read_buffer(capture_frame);
348         if(!strncmp(record->default_asset->vcodec, QUICKTIME_MJPA, 4) &&
349                 record->vdevice->is_compressed())
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());
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, record->current_display_length());
389 int RecordVideo::unhang_thread()
391 printf("RecordVideo::unhang_thread\n");
392         Thread::end();