4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "bcsignals.h"
27 #include "condition.h"
29 #include "edlsession.h"
32 #include "filethread.h"
37 #include "mwindowgui.h"
38 #include "preferences.h"
40 #include "recordaudio.h"
41 #include "recordgui.h"
42 #include "recordvideo.h"
43 #include "recordmonitor.h"
46 #include "videodevice.h"
51 RecordVideo::RecordVideo(MWindow *mwindow, Record *record)
54 this->mwindow = mwindow;
55 this->record = record;
56 this->gui = record->record_gui;
57 trigger_lock = new Condition(0, "RecordVideo::trigger_lock");
58 pause_record_lock = new Condition(0, "RecordVideo::pause_record_lock");
59 record_paused_lock = new Condition(0, "RecordVideo::record_paused_lock");
66 RecordVideo::~RecordVideo()
71 delete pause_record_lock;
72 delete record_paused_lock;
75 void RecordVideo::reset_parameters()
80 buffer_frames = mwindow->edl->session->video_write_length;
84 trigger_lock->reset();
85 pause_record_lock->reset();
86 record_paused_lock->reset();
89 void RecordVideo::arm_recording()
96 void RecordVideo::start_recording()
98 trigger_lock->unlock();
101 void RecordVideo::stop_recording()
104 // Device won't exist if interrupting a cron job
106 if( record->vdevice ) {
107 // Interrupt IEEE1394 crashes
108 record->vdevice->interrupt_crash();
109 // Interrupt video4linux crashes
110 if( record->vdevice->get_failed() )
114 // Joined in RecordThread
118 VFrame *RecordVideo::get_buffer()
121 record->file_lock->lock();
122 writing_file = record->writing_file > 0 && record->do_video ? 1 : 0;
125 frame_ptr = record->file->get_video_buffer();
128 result = frame_ptr[0][buffer_position];
131 record->file_lock->unlock();
133 if( !buffer_frame ) {
134 if( !record->fixed_compression ) {
135 Asset *asset = record->default_asset;
136 int w = asset->width, h = asset->height;
137 int cmodel = record->vdevice->get_best_colormodel(asset);
138 buffer_frame = new VFrame(w, h, cmodel);
141 buffer_frame = new VFrame;
144 result = buffer_frame;
149 void RecordVideo::delete_buffer()
151 RecordMonitorThread *thr = !record->record_monitor ?
152 0 : record->record_monitor->thread;
153 if( thr && thr->running() ) thr->lock_input();
159 if( thr && thr->running() ) thr->unlock_input();
162 void RecordVideo::config_update()
164 VideoDevice *vdevice = record->vdevice;
165 vdevice->config_update();
166 int width = vdevice->get_iwidth();
167 int height = vdevice->get_iheight();
168 double frame_rate = vdevice->get_irate();
169 float awidth, aheight;
170 MWindow::create_aspect_ratio(awidth, aheight, width, height);
171 EDLSession *session = record->edl->session;
172 SESSION->aspect_w = session->aspect_w = awidth;
173 SESSION->aspect_h = session->aspect_h = aheight;
174 SESSION->output_w = session->output_w = width;
175 SESSION->output_h = session->output_h = height;
176 Asset *rf_asset = SESSION->recording_format;
177 Asset *df_asset = record->default_asset;
178 rf_asset->width = df_asset->width = width;
179 rf_asset->height = df_asset->height = height;
180 rf_asset->frame_rate = df_asset->frame_rate = frame_rate;
183 void RecordVideo::run()
185 // Number of frames for user to know about.
189 trigger_lock->lock("RecordVideo::run");
191 while( !done && !write_result ) {
192 if( recording_paused ) {
193 pause_record_lock->unlock();
194 record_paused_lock->lock();
197 VideoDevice *vdevice = record->vdevice;
198 VFrame *capture_frame = get_buffer();
199 vdevice->set_field_order(record->reverse_interlace);
200 record->set_do_cursor();
202 grab_result = read_buffer(capture_frame);
204 if( vdevice->config_updated() ) {
209 record->record_monitor->reconfig();
216 decompress_buffer(capture_frame);
219 if( record->monitor_video && capture_frame->get_data() )
220 if( !writing_file || !record->is_behind() )
221 record->record_monitor->update(capture_frame);
222 if( writing_file && record->fill_underrun_frames ) {
223 VFrame *last_frame = capture_frame;
224 int fill = record->dropped;
225 while( --fill >= 0 ) {
226 capture_frame = get_buffer();
227 capture_frame->copy_from(last_frame);
228 last_frame = capture_frame;
233 record->written_frames += record->dropped;
234 if( record->single_frame ) {
235 record->single_frame = 0;
236 record->stop_writing_file();
239 if( !done ) done = write_result;
241 record->check_batch_complete();
248 //TRACE("RecordVideo::run 2");
250 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
251 mwindow->gui->get_abs_cursor_x(1),
252 mwindow->gui->get_abs_cursor_y(1));
253 error_box.create_objects(_("No space left on disk."));
254 error_box.run_window();
259 int RecordVideo::read_buffer(VFrame *frame)
261 return record->vdevice->read_buffer(frame);
264 void RecordVideo::decompress_buffer(VFrame *frame)
266 if( !strcmp(record->default_asset->vcodec, CODEC_TAG_MJPEG) &&
267 record->vdevice->is_compressed(0, 1)) {
268 unsigned char *data = frame->get_data();
269 int64_t size = frame->get_compressed_size();
270 //int64_t allocation = frame->get_compressed_allocated();
272 int64_t field2_offset = mjpeg_get_field2(data, size);
273 frame->set_compressed_size(size);
274 frame->set_field2_offset(field2_offset);
279 int RecordVideo::flush_buffer()
281 record->file_lock->lock();
282 if( writing_file && frame_ptr ) {
283 int result = record->file->write_video_buffer(buffer_position);
284 if( result ) write_result = 1;
287 record->file_lock->unlock();
292 int RecordVideo::write_buffer()
294 ++record->written_frames;
295 if( ++buffer_position >= buffer_frames )
302 void RecordVideo::pause_recording()
304 recording_paused = 1;
305 pause_record_lock->lock();
308 void RecordVideo::resume_recording()
310 recording_paused = 0;
311 record_paused_lock->unlock();