r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / recordvideo.C
blobc57f14f114ff1b53ec41d2d40ee3a04986294ba2
1 #include "assets.h"
2 #include "batch.h"
3 #include "clip.h"
4 #include "edl.h"
5 #include "edlsession.h"
6 #include "errorbox.h"
7 #include "file.h"
8 #include "filethread.h"
9 #include "mwindow.h"
10 #include "mwindowgui.h"
11 #include "preferences.h"
12 #include "quicktime.h"
13 #include "record.h"
14 #include "recordaudio.h"
15 #include "recordgui.h"
16 #include "recordthread.h"
17 #include "recordvideo.h"
18 #include "recordmonitor.h"
19 #include "units.h"
20 #include "vframe.h"
21 #include "videodevice.h"
23 #include <unistd.h>
25 #include <libintl.h>
26 #define _(String) gettext(String)
27 #define gettext_noop(String) String
28 #define N_(String) gettext_noop (String)
30 RecordVideo::RecordVideo(MWindow *mwindow,
31         Record *record, 
32         RecordThread *record_thread)
33  : Thread()
35         reset_parameters();
36         this->mwindow = mwindow;
37         this->record = record;
38         this->record_thread = record_thread; 
39         this->gui = record->record_gui;
42 RecordVideo::~RecordVideo()
46 void RecordVideo::reset_parameters()
48         write_result = 0;
49         grab_result = 0;
50         total_dropped_frames = 0;
51         dropped_frames = 0;
52         last_dropped_frames = 0;
53         record_start = 0;
54         buffer_position = 0;
55         batch_done = 0;
58 int RecordVideo::arm_recording()
60         reset_parameters();
61 // Resume next file in a series by incrementing existing counters
62         if(record_thread->monitor)
63                 buffer_size = 1;
64         else
65                 buffer_size = mwindow->edl->session->video_write_length;
67         set_synchronous(1);
68         trigger_lock.lock();
69         Thread::start();
71         return 0;
74 void RecordVideo::start_recording()
76         trigger_lock.unlock();
79 int RecordVideo::stop_recording()
81 // Device won't exist if interrupting a cron job
82         if(record->vdevice)
83         {
84 //printf("RecordVideo::stop_recording 1 %p\n", record->vdevice);
85 // Interrupt IEEE1394 crashes
86                 record->vdevice->interrupt_crash();
87 //printf("RecordVideo::stop_recording 1\n");
89 // Interrupt video4linux crashes
90                 if(record->vdevice->get_failed())
91                 {
92 //printf("RecordVideo::stop_recording 2\n");
93                         Thread::end();
94                         Thread::join();
95 //printf("RecordVideo::stop_recording 3\n");
97                         cleanup_recording();
98 //printf("RecordVideo::stop_recording 4\n");
99                 }
100         }
101 //printf("RecordVideo::stop_recording 5\n");
102         return 0;
106 int RecordVideo::cleanup_recording()
108         if(!record_thread->monitor)
109         {
110 //printf("RecordVideo::cleanup_recording 1\n");
111 // write last buffer
112                 write_buffer(1);
113 // stop file I/O
114 //printf("RecordVideo::cleanup_recording 2\n");
115         }
116         else
117         {
118                 delete [] frame_ptr[0];
119                 delete [] frame_ptr;
120                 delete capture_frame;
121         }
122         return 0;
125 void RecordVideo::get_capture_frame()
127         if(record->fixed_compression)
128         {
129                 capture_frame = new VFrame;
130         }
131         else
132         {
133                 capture_frame = new VFrame(0, 
134                         record->default_asset->width, 
135                         record->default_asset->height, 
136                         record->vdevice->get_best_colormodel(record->default_asset));
137 //printf("RecordVideo::get_capture_frame %d %d\n", capture_frame->get_w(), capture_frame->get_h());
138         }
139         frame_ptr = new VFrame**[1];
140         frame_ptr[0] = new VFrame*[1];
141         frame_ptr[0][0] = capture_frame;
145 void RecordVideo::run()
147         write_result = 0;
148         grab_result = 0;
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 //printf("RecordVideo::run 4\n");
223                                 capture_frame = frame_ptr[0][buffer_position];
224 //printf("RecordVideo::run 5 %d\n", capture_frame->get_color_model());
225                                 record->vdevice->set_field_order(record->reverse_interlace);
226 //printf("RecordVideo::run 6\n");
227                                 read_buffer();
228 //printf("RecordVideo::run 7\n");
229                                 record->get_current_batch()->current_frame++;
230                                 record->get_current_batch()->total_frames = 
231                                         MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
232                                 record->get_current_batch()->session_frames++;
233 //printf("RecordVideo::run 4\n");
234                                 if(!grab_result) buffer_position++;
235 //printf("RecordVideo::run 5 %ld\n", record_thread->session_frames);
237 // Update the position indicator
238                                 gui->update_position(record->current_display_position(),
239                                         record->current_display_length());
240                         }
241                         else
242 // Grab frame for monitoring
243                         if(record->monitor_video)
244                         {
245                                 record->vdevice->set_field_order(record->reverse_interlace);
246                                 record->get_current_batch()->session_frames++;
248 //printf("RecordVideo::run 4\n");
249                                 read_buffer();
250 //printf("RecordVideo::run 5\n");
251                         }
252                         else
253 // Brief pause to keep CPU from burning up
254                         {
255                                 Timer timer;
256                                 timer.delay(250);
257                         }
258                 }
260 //printf("RecordVideo::run 10\n");
261 // Monitor the frame if monitoring
262                 if(capture_frame->get_data() && 
263                         record->monitor_video && 
264                         !batch_done && 
265                         !grab_result)
266                         record->record_monitor->update(capture_frame);
267 // printf("RecordVideo::run 11 %d %d %d %d\n", record_thread->monitor,
268 //                      record->fill_frames, 
269 //                      batch_done,  
270 //                      dropped_frames);
272 // Duplicate a frame if behind
273                 if(!record_thread->monitor && 
274                         record->fill_frames && 
275                         !batch_done && 
276                         dropped_frames > 1)
277                 {
278                         VFrame *last_frame = capture_frame;
279 // Write frame 1
280                         if(buffer_position >= buffer_size) write_buffer(0);
281 // Copy to frame 2
282                         capture_frame = frame_ptr[0][buffer_position];
283                         capture_frame->copy_from(last_frame);
284                         record->get_current_batch()->current_frame++;
285                         record->get_current_batch()->total_frames = 
286                                 MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
287                         record->get_current_batch()->session_frames++;
288                         buffer_position++;
289                 }
291 // Compress a batch of frames or write the second frame if filling
292                 if(!record_thread->monitor && buffer_position >= buffer_size)
293                 {
294                         write_buffer(0);
295                 }
296 //printf("RecordVideo::run 12\n");
297 //printf("RecordVideo::run 12 %d %f %f\n", record->get_current_batch()->record_mode, record->current_display_position(), *record->current_duration());
299                 if(!record_thread->monitor && 
300                         !batch_done &&
301                         !write_result)
302                 {
303 // Handle recording contexts
304                         if(record_thread->context == CONTEXT_SINGLEFRAME)
305                         {
306                                 batch_done = 1;
307                         }
308                         else
309 // Handle recording modes delegated to the thread
310                         switch(record->get_current_batch()->record_mode)
311                         {
312                                 case RECORD_TIMED:
313                                         if(record->current_display_position() > *record->current_duration())
314                                                 batch_done = 1;
315                                         break;
316                                 case RECORD_LOOP:
317                                         if(record->current_display_position() > *record->current_duration())
318                                                 batch_done = 1;
319                                         break;
320                                 case RECORD_SCENETOSCENE:
321                                         break;
322                         }
323                 }
324 //printf("RecordVideo::run 13 %d\n", write_result);
326                 if(write_result)
327                 {
328                         batch_done = 1;
329                 }
330         }
331 //printf("RecordVideo::run 14 %d\n", write_result);
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         }
340 //printf("RecordVideo::run 15 %d\n", write_result);
342         if(write_result)
343         {
344                 if(!record_thread->monitor)
345                 {
346                         ErrorBox error_box(PROGRAM_NAME ": Error",
347                                 mwindow->gui->get_abs_cursor_x(),
348                                 mwindow->gui->get_abs_cursor_y());
349                         error_box.create_objects(_("No space left on disk."));
350                         error_box.run_window();
351                         batch_done = 1;
352                 }
353         }
355         cleanup_recording();
356 //printf("RecordVideo::run 16 %p %d\n", this, write_result);
359 void RecordVideo::read_buffer()
361 //printf("RecordVideo::read_buffer 1\n");
363         grab_result = record->vdevice->read_buffer(capture_frame);
365 //printf("RecordVideo::read_buffer 10\n");
367         if(!strncmp(record->default_asset->vcodec, QUICKTIME_MJPA, 4) &&
368                 record->vdevice->is_compressed())
369         {
370                 unsigned char *data = capture_frame->get_data();
371                 int64_t size = capture_frame->get_compressed_size();
372                 int64_t allocation = capture_frame->get_compressed_allocated();
374 //printf("RecordVideo::read_buffer 20 %d\n", size);
375                 if(data)
376                 {
377                         int64_t field2_offset = mjpeg_get_field2(data, size);
378 // Markers are added in the file in direct copy more.
379 //                      mjpeg_insert_quicktime_markers(&data, 
380 //                              &size, 
381 //                              &allocation,
382 //                              2,
383 //                              &field2_offset);
384                         capture_frame->set_compressed_size(size);
385                         capture_frame->set_field2_offset(field2_offset);
386                 }
387 //printf("RecordVideo::read_buffer 30\n");
388         }
389 //printf("RecordVideo::read_buffer 100\n");
392 void RecordVideo::write_buffer(int skip_new)
394         write_result = record->file->write_video_buffer(buffer_position);
395         buffer_position = 0;
396         if(!skip_new && !write_result) 
397                 frame_ptr = record->file->get_video_buffer();
400 void RecordVideo::rewind_file()
402         write_buffer(1);
403         record->file->stop_video_thread();
404         record->file->set_video_position(0, record->default_asset->frame_rate);
405         record->file->start_video_thread(buffer_size,
406                 record->vdevice->get_best_colormodel(record->default_asset),
407                 2,
408                 record->vdevice->is_compressed());
409         frame_ptr = record->file->get_video_buffer();
410         record->get_current_batch()->current_frame = 0;
411         record->get_current_batch()->current_sample = 0;
412         record->get_current_batch()->session_frames = 0;
413         record->get_current_batch()->session_samples = 0;
414         gui->update_position(0, record->current_display_length());
417 int RecordVideo::unhang_thread()
419 printf("RecordVideo::unhang_thread\n");
420         Thread::end();