Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

recordvideo.C

Go to the documentation of this file.
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 // Resume next file in a series by incrementing existing counters
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 // Device won't exist if interrupting a cron job
00085         if(record->vdevice)
00086         {
00087 // Interrupt IEEE1394 crashes
00088                 record->vdevice->interrupt_crash();
00089 
00090 // Interrupt video4linux crashes
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 //printf("RecordVideo::cleanup_recording 1\n");
00108 // write last buffer
00109                 write_buffer(1);
00110 // stop file I/O
00111 //printf("RecordVideo::cleanup_recording 2\n");
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 //printf("RecordVideo::get_capture_frame %d %d\n", capture_frame->get_w(), capture_frame->get_h());
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 // Thread out the I/O
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 // Number of frames for user to know about.
00159         gui->total_dropped_frames = 0;
00160         gui->update_dropped_frames(0);
00161 
00162 
00163 // Wait for trigger
00164         trigger_lock->lock("RecordVideo::run");
00165         trigger_lock->unlock();
00166 
00167         while(!batch_done && 
00168                 !write_result)
00169         {
00170 // Synchronize with audio or timer
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 // Too early.
00181                         delay = (int64_t)((float)(next_sample - current_sample) / 
00182                                 record->default_asset->sample_rate * 
00183                                 1000);
00184 // Sanity check and delay.
00185 // In 2.6.7 this doesn't work.  For some reason, probably buffer overflowing,
00186 // it causes the driver to hang up momentarily so we try to only delay
00187 // when really really far ahead.
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 // Too late.
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 // Capture a frame
00210                 if(!batch_done)
00211                 {
00212 // Grab frame for recording
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 // Update the position indicator
00225                                 gui->update_position(record->current_display_position());
00226                         }
00227                         else
00228 // Grab frame for monitoring
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 // Brief pause to keep CPU from burning up
00238                         {
00239                                 Timer::delay(250);
00240                         }
00241                 }
00242 
00243 // Monitor the frame if monitoring
00244 // printf("RecordVideo::run %p %d %d %d\n", 
00245 // capture_frame->get_data(), 
00246 // record->monitor_video, 
00247 // batch_done, 
00248 // grab_result);
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 // Duplicate a frame if behind
00258                 if(!record_thread->monitor && 
00259                         record->fill_frames && 
00260                         !batch_done && 
00261                         dropped_frames > 1)
00262                 {
00263                         VFrame *last_frame = capture_frame;
00264 // Write frame 1
00265                         if(buffer_position >= buffer_size) write_buffer(0);
00266 // Copy to frame 2
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 // Compress a batch of frames or write the second frame if filling
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 // Handle recording contexts
00287                         if(record_thread->context == CONTEXT_SINGLEFRAME)
00288                         {
00289                                 batch_done = 1;
00290                         }
00291                         else
00292 // Handle recording modes delegated to the thread
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 //TRACE("RecordVideo::run 1");
00315 // Update dependant threads
00316         if(record->default_asset->audio_data)
00317         {
00318                 record_thread->record_audio->batch_done = 1;
00319 // Interrupt driver for IEEE1394
00320                 record_thread->record_audio->stop_recording();
00321         }
00322 
00323 //TRACE("RecordVideo::run 2");
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 //TRACE("RecordVideo::run 100");
00340 }
00341 
00342 void RecordVideo::read_buffer()
00343 {
00344         grab_result = record->vdevice->read_buffer(capture_frame);
00345 
00346 
00347 // Get field offset for monitor
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 

Generated on Sun Jan 8 13:38:59 2006 for Cinelerra-svn by  doxygen 1.4.4