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