4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "bcsignals.h"
26 #include "condition.h"
28 #include "edlsession.h"
31 #include "filethread.h"
36 #include "mwindowgui.h"
37 #include "preferences.h"
39 #include "recordaudio.h"
40 #include "recordgui.h"
41 #include "recordvideo.h"
42 #include "recordmonitor.h"
45 #include "videodevice.h"
50 RecordVideo::RecordVideo(MWindow *mwindow, Record *record)
53 this->mwindow = mwindow;
54 this->record = record;
55 this->gui = record->record_gui;
56 trigger_lock = new Condition(0, "RecordVideo::trigger_lock");
57 pause_record_lock = new Condition(0, "RecordVideo::pause_record_lock");
58 record_paused_lock = new Condition(0, "RecordVideo::record_paused_lock");
65 RecordVideo::~RecordVideo()
70 delete pause_record_lock;
71 delete record_paused_lock;
74 void RecordVideo::reset_parameters()
79 buffer_frames = mwindow->edl->session->video_write_length;
83 trigger_lock->reset();
84 pause_record_lock->reset();
85 record_paused_lock->reset();
88 void RecordVideo::arm_recording()
95 void RecordVideo::start_recording()
97 trigger_lock->unlock();
100 void RecordVideo::stop_recording()
103 // Device won't exist if interrupting a cron job
105 if( record->vdevice ) {
106 // Interrupt IEEE1394 crashes
107 record->vdevice->interrupt_crash();
108 // Interrupt video4linux crashes
109 if( record->vdevice->get_failed() )
113 // Joined in RecordThread
117 VFrame *RecordVideo::get_buffer()
120 record->file_lock->lock();
121 writing_file = record->writing_file > 0 && record->do_video ? 1 : 0;
124 frame_ptr = record->file->get_video_buffer();
127 result = frame_ptr[0][buffer_position];
130 record->file_lock->unlock();
132 if( !buffer_frame ) {
133 if( !record->fixed_compression ) {
134 Asset *asset = record->default_asset;
135 int w = asset->width, h = asset->height;
136 int cmodel = record->vdevice->get_best_colormodel(asset);
137 buffer_frame = new VFrame(w, h, cmodel);
140 buffer_frame = new VFrame;
143 result = buffer_frame;
148 void RecordVideo::delete_buffer()
150 RecordMonitorThread *thr = !record->record_monitor ?
151 0 : record->record_monitor->thread;
152 if( thr && thr->running() ) thr->lock_input();
158 if( thr && thr->running() ) thr->unlock_input();
161 void RecordVideo::config_update()
163 VideoDevice *vdevice = record->vdevice;
164 vdevice->config_update();
165 int width = vdevice->get_iwidth();
166 int height = vdevice->get_iheight();
167 double frame_rate = vdevice->get_irate();
168 float awidth, aheight;
169 MWindow::create_aspect_ratio(awidth, aheight, width, height);
170 EDLSession *session = record->edl->session;
171 SESSION->aspect_w = session->aspect_w = awidth;
172 SESSION->aspect_h = session->aspect_h = aheight;
173 SESSION->output_w = session->output_w = width;
174 SESSION->output_h = session->output_h = height;
175 Asset *rf_asset = SESSION->recording_format;
176 Asset *df_asset = record->default_asset;
177 rf_asset->width = df_asset->width = width;
178 rf_asset->height = df_asset->height = height;
179 rf_asset->frame_rate = df_asset->frame_rate = frame_rate;
182 void RecordVideo::run()
184 // Number of frames for user to know about.
188 trigger_lock->lock("RecordVideo::run");
190 while( !done && !write_result ) {
191 if( recording_paused ) {
192 pause_record_lock->unlock();
193 record_paused_lock->lock();
196 VideoDevice *vdevice = record->vdevice;
197 VFrame *capture_frame = get_buffer();
198 vdevice->set_field_order(record->reverse_interlace);
200 grab_result = read_buffer(capture_frame);
202 if( vdevice->config_updated() ) {
207 record->record_monitor->reconfig();
214 decompress_buffer(capture_frame);
217 if( record->monitor_video && capture_frame->get_data() )
218 if( !writing_file || !record->is_behind() )
219 record->record_monitor->update(capture_frame);
220 if( writing_file && record->fill_underrun_frames ) {
221 VFrame *last_frame = capture_frame;
222 int fill = record->dropped;
223 while( --fill >= 0 ) {
224 capture_frame = get_buffer();
225 capture_frame->copy_from(last_frame);
226 last_frame = capture_frame;
231 record->written_frames += record->dropped;
232 if( record->single_frame ) {
233 record->single_frame = 0;
234 record->stop_writing_file();
237 if( !done ) done = write_result;
239 record->check_batch_complete();
246 //TRACE("RecordVideo::run 2");
248 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
249 mwindow->gui->get_abs_cursor_x(1),
250 mwindow->gui->get_abs_cursor_y(1));
251 error_box.create_objects(_("No space left on disk."));
252 error_box.run_window();
257 int RecordVideo::read_buffer(VFrame *frame)
259 return record->vdevice->read_buffer(frame);
262 void RecordVideo::decompress_buffer(VFrame *frame)
264 if( !strcmp(record->default_asset->vcodec, CODEC_TAG_MJPEG) &&
265 record->vdevice->is_compressed(0, 1)) {
266 unsigned char *data = frame->get_data();
267 int64_t size = frame->get_compressed_size();
268 //int64_t allocation = frame->get_compressed_allocated();
270 int64_t field2_offset = mjpeg_get_field2(data, size);
271 frame->set_compressed_size(size);
272 frame->set_field2_offset(field2_offset);
277 int RecordVideo::flush_buffer()
279 record->file_lock->lock();
280 if( writing_file && frame_ptr ) {
281 int result = record->file->write_video_buffer(buffer_position);
282 if( result ) write_result = 1;
285 record->file_lock->unlock();
290 int RecordVideo::write_buffer()
292 ++record->written_frames;
293 if( ++buffer_position >= buffer_frames )
300 void RecordVideo::pause_recording()
302 recording_paused = 1;
303 pause_record_lock->lock();
306 void RecordVideo::resume_recording()
308 recording_paused = 0;
309 record_paused_lock->unlock();