00001 #include "asset.h"
00002 #include "batch.h"
00003 #include "bcsignals.h"
00004 #include "clip.h"
00005 #include "condition.h"
00006 #include "edl.h"
00007 #include "edlsession.h"
00008 #include "errorbox.h"
00009 #include "file.h"
00010 #include "filethread.h"
00011 #include "language.h"
00012 #include "mutex.h"
00013 #include "mwindow.h"
00014 #include "mwindowgui.h"
00015 #include "preferences.h"
00016 #include "quicktime.h"
00017 #include "record.h"
00018 #include "recordaudio.h"
00019 #include "recordgui.h"
00020 #include "recordthread.h"
00021 #include "recordvideo.h"
00022 #include "recordmonitor.h"
00023 #include "units.h"
00024 #include "vframe.h"
00025 #include "videodevice.h"
00026
00027 #include <unistd.h>
00028
00029
00030 RecordVideo::RecordVideo(MWindow *mwindow,
00031 Record *record,
00032 RecordThread *record_thread)
00033 : Thread(1, 0, 0)
00034 {
00035 reset_parameters();
00036 this->mwindow = mwindow;
00037 this->record = record;
00038 this->record_thread = record_thread;
00039 this->gui = record->record_gui;
00040 unhang_lock = new Mutex("RecordVideo::unhang_lock");
00041 trigger_lock = new Condition(1, "RecordVideo::trigger_lock");
00042 }
00043
00044 RecordVideo::~RecordVideo()
00045 {
00046 delete unhang_lock;
00047 delete trigger_lock;
00048 }
00049
00050 void RecordVideo::reset_parameters()
00051 {
00052 write_result = 0;
00053 grab_result = 0;
00054 total_dropped_frames = 0;
00055 dropped_frames = 0;
00056 last_dropped_frames = 0;
00057 record_start = 0;
00058 buffer_position = 0;
00059 batch_done = 0;
00060 }
00061
00062 int RecordVideo::arm_recording()
00063 {
00064 reset_parameters();
00065
00066 if(record_thread->monitor)
00067 buffer_size = 1;
00068 else
00069 buffer_size = mwindow->edl->session->video_write_length;
00070
00071 trigger_lock->lock("RecordVideo::arm_recording");
00072 Thread::start();
00073
00074 return 0;
00075 }
00076
00077 void RecordVideo::start_recording()
00078 {
00079 trigger_lock->unlock();
00080 }
00081
00082 int RecordVideo::stop_recording()
00083 {
00084
00085 if(record->vdevice)
00086 {
00087
00088 record->vdevice->interrupt_crash();
00089
00090
00091 if(record->vdevice->get_failed())
00092 {
00093 Thread::end();
00094 Thread::join();
00095
00096 cleanup_recording();
00097 }
00098 }
00099 return 0;
00100 }
00101
00102
00103 int RecordVideo::cleanup_recording()
00104 {
00105 if(!record_thread->monitor)
00106 {
00107
00108
00109 write_buffer(1);
00110
00111
00112 }
00113 else
00114 {
00115 delete [] frame_ptr[0];
00116 delete [] frame_ptr;
00117 delete capture_frame;
00118 }
00119 return 0;
00120 }
00121
00122 void RecordVideo::get_capture_frame()
00123 {
00124 if(record->fixed_compression)
00125 {
00126 capture_frame = new VFrame;
00127 }
00128 else
00129 {
00130 capture_frame = new VFrame(0,
00131 record->default_asset->width,
00132 record->default_asset->height,
00133 record->vdevice->get_best_colormodel(record->default_asset));
00134
00135 }
00136 frame_ptr = new VFrame**[1];
00137 frame_ptr[0] = new VFrame*[1];
00138 frame_ptr[0][0] = capture_frame;
00139 }
00140
00141
00142 void RecordVideo::run()
00143 {
00144 write_result = 0;
00145 grab_result = 0;
00146
00147
00148 if(!record_thread->monitor)
00149 {
00150 record_start = record->file->get_video_position(record->default_asset->frame_rate);
00151 frame_ptr = record->file->get_video_buffer();
00152 }
00153 else
00154 {
00155 get_capture_frame();
00156 }
00157
00158
00159 gui->total_dropped_frames = 0;
00160 gui->update_dropped_frames(0);
00161
00162
00163
00164 trigger_lock->lock("RecordVideo::run");
00165 trigger_lock->unlock();
00166
00167 while(!batch_done &&
00168 !write_result)
00169 {
00170
00171 dropped_frames = 0;
00172 next_sample = (int64_t)((float)record->get_current_batch()->session_frames /
00173 record->default_asset->frame_rate *
00174 record->default_asset->sample_rate);
00175 current_sample = record->sync_position();
00176
00177
00178 if(current_sample < next_sample && current_sample > 0)
00179 {
00180
00181 delay = (int64_t)((float)(next_sample - current_sample) /
00182 record->default_asset->sample_rate *
00183 1000);
00184
00185
00186
00187
00188 if(delay < 2000 && delay > 0) delayer.delay(delay);
00189 gui->update_dropped_frames(0);
00190 last_dropped_frames = 0;
00191 }
00192 else
00193 if(current_sample > 0 && !record_thread->monitor)
00194 {
00195
00196 dropped_frames = (int64_t)((float)(current_sample - next_sample) /
00197 record->default_asset->sample_rate *
00198 record->default_asset->frame_rate);
00199 if(dropped_frames != last_dropped_frames)
00200 {
00201 gui->update_dropped_frames(dropped_frames);
00202 last_dropped_frames = dropped_frames;
00203 }
00204 last_dropped_frames = dropped_frames;
00205 }
00206
00207
00208
00209
00210 if(!batch_done)
00211 {
00212
00213 if(!record_thread->monitor)
00214 {
00215 capture_frame = frame_ptr[0][buffer_position];
00216 record->vdevice->set_field_order(record->reverse_interlace);
00217 read_buffer();
00218 record->get_current_batch()->current_frame++;
00219 record->get_current_batch()->total_frames =
00220 MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
00221 record->get_current_batch()->session_frames++;
00222 if(!grab_result) buffer_position++;
00223
00224
00225 gui->update_position(record->current_display_position());
00226 }
00227 else
00228
00229 if(record->monitor_video)
00230 {
00231 record->vdevice->set_field_order(record->reverse_interlace);
00232 record->get_current_batch()->session_frames++;
00233
00234 read_buffer();
00235 }
00236 else
00237
00238 {
00239 Timer::delay(250);
00240 }
00241 }
00242
00243
00244
00245
00246
00247
00248
00249 if(capture_frame->get_data() &&
00250 record->monitor_video &&
00251 !batch_done &&
00252 !grab_result)
00253 {
00254 record->record_monitor->update(capture_frame);
00255 }
00256
00257
00258 if(!record_thread->monitor &&
00259 record->fill_frames &&
00260 !batch_done &&
00261 dropped_frames > 1)
00262 {
00263 VFrame *last_frame = capture_frame;
00264
00265 if(buffer_position >= buffer_size) write_buffer(0);
00266
00267 capture_frame = frame_ptr[0][buffer_position];
00268 capture_frame->copy_from(last_frame);
00269 record->get_current_batch()->current_frame++;
00270 record->get_current_batch()->total_frames =
00271 MAX(record->get_current_batch()->current_frame, record->get_current_batch()->total_frames);
00272 record->get_current_batch()->session_frames++;
00273 buffer_position++;
00274 }
00275
00276
00277 if(!record_thread->monitor && buffer_position >= buffer_size)
00278 {
00279 write_buffer(0);
00280 }
00281
00282 if(!record_thread->monitor &&
00283 !batch_done &&
00284 !write_result)
00285 {
00286
00287 if(record_thread->context == CONTEXT_SINGLEFRAME)
00288 {
00289 batch_done = 1;
00290 }
00291 else
00292
00293 switch(record->get_current_batch()->record_mode)
00294 {
00295 case RECORD_TIMED:
00296 if(record->current_display_position() > *record->current_duration())
00297 batch_done = 1;
00298 break;
00299 case RECORD_LOOP:
00300 if(record->current_display_position() > *record->current_duration())
00301 batch_done = 1;
00302 break;
00303 case RECORD_SCENETOSCENE:
00304 break;
00305 }
00306 }
00307
00308 if(write_result)
00309 {
00310 batch_done = 1;
00311 }
00312 }
00313
00314
00315
00316 if(record->default_asset->audio_data)
00317 {
00318 record_thread->record_audio->batch_done = 1;
00319
00320 record_thread->record_audio->stop_recording();
00321 }
00322
00323
00324
00325 if(write_result)
00326 {
00327 if(!record_thread->monitor)
00328 {
00329 ErrorBox error_box(PROGRAM_NAME ": Error",
00330 mwindow->gui->get_abs_cursor_x(1),
00331 mwindow->gui->get_abs_cursor_y(1));
00332 error_box.create_objects(_("No space left on disk."));
00333 error_box.run_window();
00334 batch_done = 1;
00335 }
00336 }
00337
00338 cleanup_recording();
00339
00340 }
00341
00342 void RecordVideo::read_buffer()
00343 {
00344 grab_result = record->vdevice->read_buffer(capture_frame);
00345
00346
00347
00348 if(!strncmp(record->default_asset->vcodec, QUICKTIME_MJPA, 4) &&
00349 record->vdevice->is_compressed(0, 1))
00350 {
00351 unsigned char *data = capture_frame->get_data();
00352 int64_t size = capture_frame->get_compressed_size();
00353 int64_t allocation = capture_frame->get_compressed_allocated();
00354
00355 if(data)
00356 {
00357 int64_t field2_offset = mjpeg_get_field2(data, size);
00358 capture_frame->set_compressed_size(size);
00359 capture_frame->set_field2_offset(field2_offset);
00360 }
00361 }
00362 }
00363
00364 void RecordVideo::write_buffer(int skip_new)
00365 {
00366 write_result = record->file->write_video_buffer(buffer_position);
00367 buffer_position = 0;
00368 if(!skip_new && !write_result)
00369 frame_ptr = record->file->get_video_buffer();
00370 }
00371
00372 void RecordVideo::rewind_file()
00373 {
00374 write_buffer(1);
00375 record->file->stop_video_thread();
00376 record->file->set_video_position(0, record->default_asset->frame_rate);
00377 record->file->start_video_thread(buffer_size,
00378 record->vdevice->get_best_colormodel(record->default_asset),
00379 2,
00380 record->vdevice->is_compressed(1, 0));
00381 frame_ptr = record->file->get_video_buffer();
00382 record->get_current_batch()->current_frame = 0;
00383 record->get_current_batch()->current_sample = 0;
00384 record->get_current_batch()->session_frames = 0;
00385 record->get_current_batch()->session_samples = 0;
00386 gui->update_position(0);
00387 }
00388
00389 int RecordVideo::unhang_thread()
00390 {
00391 printf("RecordVideo::unhang_thread\n");
00392 Thread::end();
00393 }
00394