prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / videodevice.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2013 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "asset.h"
23 #include "assets.h"
24 #include "bccapture.h"
25 #include "bcsignals.h"
26 #include "channel.h"
27 #include "channeldb.h"
28 #include "chantables.h"
29 #include "edl.h"
30 #include "edlsession.h"
31 #include "file.inc"
32 #include "../hvirtual_config.h"
33 #include "libdv.h"
34 #include "libmjpeg.h"
35 #include "mainmenu.h"
36 #include "mutex.h"
37 #include "mwindow.h"
38 #include "mwindowgui.h"
39 #include "picture.h"
40 #include "playbackconfig.h"
41 #include "playbackengine.h"
42 #include "preferences.h"
43 #include "recordconfig.h"
44 #include "recordgui.h"
45 #include "recordmonitor.h"
46 #include "record.h"
47 #include "vdevice1394.h"
48 #include "vdevicebuz.h"
49 #include "vdevicedvb.h"
50 #include "vdevicev4l.h"
51 #include "vdevicev4l2.h"
52 #include "vdevicev4l2jpeg.h"
53 #include "vdevicev4l2mpeg.h"
54 #include "vdevicex11.h"
55 #include "videoconfig.h"
56 #include "videodevice.h"
57 #include "videowindow.h"
58 #include "videowindowgui.h"
59 #include "vframe.h"
60
61 #include <unistd.h>
62 #include <fcntl.h>
63
64 KeepaliveThread::KeepaliveThread(VideoDevice *device)
65  : Thread(1, 0, 0)
66 {
67         still_alive = 1;
68         failed = 0;
69         interrupted = 0;
70         set_synchronous(1);
71         this->device = device;
72         capturing = 0;
73         startup_lock = new Mutex("KeepaliveThread::startup_lock");
74 }
75
76 KeepaliveThread::~KeepaliveThread()
77 {
78         delete startup_lock;
79 }
80
81 int KeepaliveThread::start_keepalive()
82 {
83         startup_lock->lock("KeepaliveThread::start_keepalive 1");
84         start();
85         startup_lock->lock("KeepaliveThread::start_keepalive 2");
86         startup_lock->unlock();
87         return 0;
88 }
89
90 void KeepaliveThread::run()
91 {
92         startup_lock->unlock();
93         while(!interrupted)
94         {
95                 still_alive = 0;
96 // Give the capture a moment
97 // Should fix the delay in case users want slower frame rates.
98                 timer.delay((long)(KEEPALIVE_DELAY * 1000));
99
100 // See if a capture happened
101                 if(still_alive == 0 && capturing)
102                 {
103 //                      printf("KeepaliveThread::run: device crashed\n");
104                         failed++;
105                 }
106                 else
107                         failed = 0;
108         }
109 }
110
111 int KeepaliveThread::reset_keepalive()
112 {
113         still_alive = 1;
114         return 0;
115 }
116
117 int KeepaliveThread::get_failed()
118 {
119         if(failed) return 1; else return 0;
120 }
121
122 int KeepaliveThread::stop()
123 {
124         interrupted = 1;
125
126 // Force an immediate exit even if capture_frame worked.
127         Thread::cancel();
128         Thread::join();
129         return 0;
130 }
131
132
133
134
135
136
137
138 VideoDevice::VideoDevice(MWindow *mwindow)
139 {
140         this->mwindow = mwindow;
141         in_config = new VideoInConfig;
142         out_config = new VideoOutConfig;
143         channel = new Channel;
144         picture = new PictureConfig();
145         sharing_lock = new Mutex("VideoDevice::sharing_lock");
146         channel_lock = new Mutex("VideoDevice::channel_lock");
147         picture_lock = new Mutex("VideoDevice::picture_lock");
148         initialize();
149 }
150
151
152 VideoDevice::~VideoDevice()
153 {
154         input_sources.remove_all_objects();
155         delete in_config;
156         delete out_config;
157         delete channel;
158         delete picture;
159         delete sharing_lock;
160         delete channel_lock;
161         delete picture_lock;
162 }
163
164 int VideoDevice::initialize()
165 {
166         sharing = 0;
167         done_sharing = 0;
168         sharing_lock->reset();
169         orate = irate = 0;
170         out_w = out_h = 0;
171         r = w = 0;
172         is_playing_back = is_recording = 0;
173         input_x = 0;
174         input_y = 0;
175         input_z = 1;
176         frame_resized = 0;
177         frame_rate = 0;
178         timestamp = -1.;
179         capturing = 0;
180         keepalive = 0;
181         swap_bytes = 0;
182         in_config_updated = 0;
183         input_base = 0;
184         output_base = 0;
185         output_format = 0;
186         interrupt = 0;
187         adevice = 0;
188         quality = 80;
189         cpus = 1;
190         single_frame = 0;
191         channel_changed = 0;
192         picture_changed = 0;
193         return 0;
194 }
195
196 int VideoDevice::open_input(VideoInConfig *config, 
197         int input_x, 
198         int input_y, 
199         float input_z,
200         double frame_rate)
201 {
202         int result = 0;
203
204         *this->in_config = *config;
205
206         r = 1;
207         this->input_z = -1;   // Force initialization.
208         this->frame_rate = frame_rate;
209         if( input_base ) return 1; // device already open
210
211         switch(in_config->driver) {
212                 case VIDEO4LINUX:
213                         keepalive = new KeepaliveThread(this);
214                         keepalive->start_keepalive();
215                         break;
216
217
218 #ifdef HAVE_VIDEO4LINUX2
219
220                 case VIDEO4LINUX2:
221                 case VIDEO4LINUX2JPEG:
222                 case VIDEO4LINUX2MPEG:
223                 case CAPTURE_JPEG_WEBCAM:
224                 case CAPTURE_YUYV_WEBCAM:
225                         break;
226
227 #endif
228
229                 case SCREENCAPTURE:
230                         this->input_x = input_x;
231                         this->input_y = input_y;
232                         break;
233                 case CAPTURE_LML:
234                 case CAPTURE_BUZ:
235 //printf("VideoDevice 1\n");
236                         keepalive = new KeepaliveThread(this);
237                         keepalive->start_keepalive();
238                         break;
239 #ifdef HAVE_FIREWIRE
240                 case CAPTURE_FIREWIRE:
241                 case CAPTURE_IEC61883:
242                         break;
243 #endif
244
245 #ifdef HAVE_DVB
246                 case CAPTURE_DVB:
247                         break;
248 #endif
249
250                 default:
251                         return 1;
252         }
253
254         new_device_base();
255         if( !input_base ) return 1;
256         result = input_base->open_input();
257         if(!result) capturing = 1;
258         in_config_updated = 0;
259         return 0;
260 }
261
262 VDeviceBase* VideoDevice::new_device_base()
263 {
264         switch(in_config->driver) {
265 #ifdef HAVE_VIDEO4LINUX
266         case VIDEO4LINUX:
267                 return input_base = new VDeviceV4L(this);
268 #endif
269
270 #ifdef HAVE_VIDEO4LINUX2
271         case VIDEO4LINUX2:
272         case CAPTURE_JPEG_WEBCAM:
273         case CAPTURE_YUYV_WEBCAM:
274                 return input_base = new VDeviceV4L2(this);
275         case VIDEO4LINUX2JPEG:
276                 return input_base = new VDeviceV4L2JPEG(this);
277         case VIDEO4LINUX2MPEG:
278                 return input_base = new VDeviceV4L2MPEG(this);
279 #endif
280
281         case SCREENCAPTURE:
282                 return input_base = new VDeviceX11(this, 0);
283
284 #ifdef HAVE_VIDEO4LINUX
285         case CAPTURE_BUZ:
286                 return input_base = new VDeviceBUZ(this);
287         case CAPTURE_LML:
288                 return input_base = new VDeviceLML(this);
289 #endif
290
291 #ifdef HAVE_FIREWIRE
292         case CAPTURE_FIREWIRE:
293         case CAPTURE_IEC61883:
294                 return input_base = new VDevice1394(this);
295 #endif
296
297 #ifdef HAVE_DVB
298         case CAPTURE_DVB:
299                 return input_base = new VDeviceDVB(this);
300 #endif
301         }
302         return 0;
303 }
304
305 static char* get_channeldb_path(VideoInConfig *vconfig_in)
306 {
307         char *path = 0;
308         switch(vconfig_in->driver)
309         {
310                 case VIDEO4LINUX:
311                         path = (char*)"channels_v4l";
312                         break;
313                 case VIDEO4LINUX2:
314                 case CAPTURE_JPEG_WEBCAM:
315                 case CAPTURE_YUYV_WEBCAM:
316                         path = (char*)"channels_v4l2";
317                         break;
318                 case VIDEO4LINUX2JPEG:
319                         path = (char*)"channels_v4l2jpeg";
320                         break;
321                 case VIDEO4LINUX2MPEG:
322                         path = (char*)"channels_v4l2mpeg";
323                         break;
324                 case CAPTURE_BUZ:
325                         path = (char*)"channels_buz";
326                         break;
327                 case CAPTURE_DVB:
328                         path = (char*)"channels_dvb";
329                         break;
330         }
331         return path;
332 }
333
334 void VideoDevice::load_channeldb(ChannelDB *channeldb, VideoInConfig *vconfig_in)
335 {
336         channeldb->load(get_channeldb_path(vconfig_in));
337 }
338
339 void VideoDevice::save_channeldb(ChannelDB *channeldb, VideoInConfig *vconfig_in)
340 {
341         channeldb->save(get_channeldb_path(vconfig_in));
342 }
343
344
345 VDeviceBase* VideoDevice::get_input_base()
346 {
347         return input_base;
348 }
349
350 VDeviceBase* VideoDevice::get_output_base()
351 {
352         return output_base;
353 }
354
355 DeviceMPEGInput *VideoDevice::mpeg_device()
356 {
357         return !input_base ? 0 : input_base->mpeg_device();
358 }
359
360 int VideoDevice::is_compressed(int driver, int use_file, int use_fixed)
361 {
362 // FileMOV needs to have write_frames called so the start codes get scanned.
363         return ((driver == CAPTURE_BUZ && use_fixed) ||
364                 (driver == VIDEO4LINUX2JPEG && use_fixed) || 
365                 (driver == CAPTURE_JPEG_WEBCAM && use_fixed) || 
366                 driver == CAPTURE_LML || 
367                 driver == CAPTURE_FIREWIRE ||
368                 driver == CAPTURE_IEC61883);
369 }
370
371 int VideoDevice::is_compressed(int use_file, int use_fixed)
372 {
373         return is_compressed(in_config->driver, use_file, use_fixed);
374 }
375
376
377 void VideoDevice::fix_asset(Asset *asset, int driver)
378 {
379 // Fix asset using legacy routine
380         const char *vcodec = 0;
381         switch(driver) {
382         case CAPTURE_IEC61883:
383         case CAPTURE_FIREWIRE:
384                 vcodec = CODEC_TAG_DVSD;
385                 break;
386
387         case CAPTURE_BUZ:
388         case CAPTURE_LML:
389         case VIDEO4LINUX2JPEG:
390                 vcodec = CODEC_TAG_MJPEG;
391                 break;
392
393         case CAPTURE_JPEG_WEBCAM:
394                 vcodec = CODEC_TAG_JPEG;
395                 break;
396         }
397         if( vcodec ) {
398                 asset->format = FILE_FFMPEG;
399                 strcpy(asset->vcodec, vcodec);
400                 return;
401         }
402
403 // Fix asset using inherited routine
404         new_device_base();
405
406         if(input_base) input_base->fix_asset(asset);
407         delete input_base;
408         input_base = 0;
409 }
410
411
412 const char* VideoDevice::drivertostr(int driver)
413 {
414         switch(driver) {
415         case PLAYBACK_X11:     return PLAYBACK_X11_TITLE;
416         case PLAYBACK_X11_XV:  return PLAYBACK_X11_XV_TITLE;
417         case PLAYBACK_X11_GL:  return PLAYBACK_X11_GL_TITLE;
418         case PLAYBACK_BUZ:     return PLAYBACK_BUZ_TITLE;
419         case VIDEO4LINUX:      return VIDEO4LINUX_TITLE;
420         case VIDEO4LINUX2:     return VIDEO4LINUX2_TITLE;
421         case VIDEO4LINUX2JPEG: return VIDEO4LINUX2JPEG_TITLE;
422         case VIDEO4LINUX2MPEG: return VIDEO4LINUX2MPEG_TITLE;
423         case CAPTURE_JPEG_WEBCAM: return CAPTURE_JPEG_WEBCAM_TITLE;
424         case CAPTURE_YUYV_WEBCAM: return CAPTURE_YUYV_WEBCAM_TITLE;
425         case SCREENCAPTURE:    return SCREENCAPTURE_TITLE;
426         case CAPTURE_BUZ:      return CAPTURE_BUZ_TITLE;
427         case CAPTURE_LML:      return CAPTURE_LML_TITLE;
428         case CAPTURE_DVB:      return CAPTURE_DVB_TITLE;
429         case CAPTURE_FIREWIRE: return CAPTURE_FIREWIRE_TITLE;
430         case CAPTURE_IEC61883: return CAPTURE_IEC61883_TITLE;
431         }
432         return "";
433 }
434
435 int VideoDevice::get_best_colormodel(Asset *asset)
436 {
437         return input_base ? input_base->get_best_colormodel(asset) : BC_RGB888;
438 }
439
440 int VideoDevice::drop_frames(int frames)
441 {
442         return input_base ? input_base->drop_frames(frames) : 1;
443 }
444
445 double VideoDevice::device_timestamp()
446 {
447         return input_base ? input_base->device_timestamp() : -1.;
448 }
449
450 double VideoDevice::get_timestamp()
451 {
452         return timestamp;
453 }
454
455 int VideoDevice::close_all()
456 {
457         if(w) {
458                 if( output_base ) {
459                         output_base->close_all();
460                         delete output_base;
461                         output_base = 0;
462                 }
463         }
464
465         if(r && capturing) {
466                 capturing = 0;
467                 if(input_base) {
468                         input_base->close_all();
469                         delete input_base;
470                         input_base = 0;
471                 }
472                 if(keepalive) {
473                         keepalive->stop();
474                         delete keepalive;
475                 }
476         }
477
478         input_sources.remove_all_objects();
479         initialize();
480         return 0;
481 }
482
483
484 int VideoDevice::set_adevice(AudioDevice *adev)
485 {
486         adevice = adev;
487         return 0;
488 }
489
490
491 ArrayList<Channel*>* VideoDevice::get_inputs()
492 {
493         return &input_sources;
494 }
495
496 Channel* VideoDevice::new_input_source(char *device_name)
497 {
498         for( int i=0; i<input_sources.total; ++i ) {
499                 if(!strcmp(input_sources.values[i]->device_name, device_name))
500                         return input_sources.values[i];
501         }
502         Channel *item = new Channel;
503         strcpy(item->device_name, device_name);
504         input_sources.append(item);
505         return item;
506 }
507
508 int VideoDevice::get_failed()
509 {
510         return keepalive ? keepalive->get_failed() : 0;
511 }
512
513 int VideoDevice::interrupt_crash()
514 {
515         return input_base ? input_base->interrupt_crash() : 0;
516 }
517
518 int VideoDevice::set_translation(int in_x, int in_y)
519 {
520         input_x = in_x;
521         input_y = in_y;
522         return 0;
523 }
524
525 int VideoDevice::set_field_order(int odd_field_first)
526 {
527         this->odd_field_first = odd_field_first;
528         return 0;
529 }
530
531 int VideoDevice::set_channel(Channel *channel)
532 {
533         int result = 0;
534         if( channel ) {
535                 channel_lock->lock("VideoDevice::set_channel");
536                 this->channel->copy_settings(channel);
537                 channel_changed = 1;
538                 channel_lock->unlock();
539                 result = input_base ? input_base->set_channel(channel) :
540                          output_base ? output_base->set_channel(channel) :
541                          1;
542         }
543         return result;
544 }
545
546 int VideoDevice::set_captioning(int mode)
547 {
548         if( input_base )
549                 input_base->set_captioning(mode);
550         return 0;
551 }
552
553 void VideoDevice::set_quality(int quality)
554 {
555         this->quality = quality;
556 }
557
558 void VideoDevice::set_cpus(int cpus)
559 {
560         this->cpus = cpus;
561 }
562
563 int VideoDevice::set_picture(PictureConfig *picture)
564 {
565         if( picture ) {
566                 picture_lock->lock("VideoDevice::set_picture");
567                 this->picture->copy_settings(picture);
568                 picture_changed = 1;
569                 picture_lock->unlock();
570
571                 if(input_base) return input_base->set_picture(picture);
572         }
573         return 0;
574 }
575
576 int VideoDevice::update_translation()
577 {
578         float frame_in_capture_x1f, frame_in_capture_x2f, frame_in_capture_y1f, frame_in_capture_y2f;
579         float capture_in_frame_x1f, capture_in_frame_x2f, capture_in_frame_y1f, capture_in_frame_y2f;
580         //int z_changed = 0;
581
582         if(frame_resized) {
583                 input_x = new_input_x;
584                 input_y = new_input_y;
585                 if( in_config->driver == VIDEO4LINUX ||
586                         in_config->driver == VIDEO4LINUX2 ) {
587                         if(input_z != new_input_z) {
588                                 input_z = new_input_z;
589                                 //z_changed = 1;
590
591                                 capture_w = (int)((float)in_config->w * input_z + 0.5);
592                                 capture_h = (int)((float)in_config->h * input_z + 0.5);
593
594 // Need to align to multiple of 4
595                                 capture_w &= ~3;
596                                 capture_h &= ~3;
597                         }
598
599                         frame_in_capture_x1f = (float)input_x * input_z + capture_w / 2 - in_config->w / 2;
600                         frame_in_capture_x2f = (float)input_x * input_z  + capture_w / 2 + in_config->w / 2;
601                         frame_in_capture_y1f = (float)input_y * input_z  + capture_h / 2 - in_config->h / 2;
602                         frame_in_capture_y2f = (float)input_y * input_z  + capture_h / 2 + in_config->h / 2;
603
604                         capture_in_frame_x1f = 0;
605                         capture_in_frame_y1f = 0;
606                         capture_in_frame_x2f = in_config->w;
607                         capture_in_frame_y2f = in_config->h;
608
609                         if(frame_in_capture_x1f < 0) { capture_in_frame_x1f -= frame_in_capture_x1f; frame_in_capture_x1f = 0; }
610                         if(frame_in_capture_y1f < 0) { capture_in_frame_y1f -= frame_in_capture_y1f; frame_in_capture_y1f = 0; }
611                         if(frame_in_capture_x2f > capture_w) { capture_in_frame_x2f -= frame_in_capture_x2f - capture_w; frame_in_capture_x2f = capture_w; }
612                         if(frame_in_capture_y2f > capture_h) { capture_in_frame_y2f -= frame_in_capture_y2f - capture_h; frame_in_capture_y2f = capture_h; }
613
614                         frame_in_capture_x1 = (int)frame_in_capture_x1f;
615                         frame_in_capture_y1 = (int)frame_in_capture_y1f;
616                         frame_in_capture_x2 = (int)frame_in_capture_x2f;
617                         frame_in_capture_y2 = (int)frame_in_capture_y2f;
618
619                         capture_in_frame_x1 = (int)capture_in_frame_x1f;
620                         capture_in_frame_y1 = (int)capture_in_frame_y1f;
621                         capture_in_frame_x2 = (int)capture_in_frame_x2f;
622                         capture_in_frame_y2 = (int)capture_in_frame_y2f;
623
624                         frame_resized = 0;
625                 }
626         }
627         return 0;
628 }
629
630 int VideoDevice::set_latency_counter(int value)
631 {
632         latency_counter = value;
633         return 0;
634 }
635
636 int VideoDevice::has_signal()
637 {
638         return input_base ? input_base->has_signal() : 0;
639 }
640
641 int VideoDevice::create_channeldb(ArrayList<Channel*> *channeldb)
642 {
643         return input_base ? input_base->create_channeldb(channeldb) : 1;
644 }
645
646
647 int VideoDevice::read_buffer(VFrame *frame)
648 {
649         int result = 0;
650         if(!capturing) return 0;
651
652 //printf("VideoDevice::read_buffer %p %p\n", frame, input_base);
653         if(input_base) {
654 // Reset the keepalive thread
655                 if(keepalive) keepalive->capturing = 1;
656                 result = input_base->read_buffer(frame);
657                 timestamp = frame->get_timestamp();
658                 if( timestamp < 0 ) {
659                         struct timeval tv;  gettimeofday(&tv, 0);
660                         timestamp = tv.tv_sec + tv.tv_usec / 1000000.0;
661                 }
662                 if(keepalive) {
663                         keepalive->capturing = 0;
664                         keepalive->reset_keepalive();
665                 }
666                 return result;
667         }
668
669         return 0;
670 }
671
672
673 // ================================= OUTPUT ==========================================
674
675
676 int VideoDevice::open_output(VideoOutConfig *config, float rate, 
677         int out_w, int out_h, Canvas *output, int single_frame)
678 {
679         w = 1;
680 //printf("VideoDevice::open_output 1 %d\n", out_config->driver);
681         *this->out_config = *config;
682 //printf("VideoDevice::open_output 1 %d\n", out_config->driver);
683         this->out_w = out_w;
684         this->out_h = out_h;
685         this->orate = rate;
686         this->single_frame = single_frame;
687
688 //printf("VideoDevice::open_output 1 %d\n", out_config->driver);
689         switch(out_config->driver) {
690 #ifdef HAVE_VIDEO4LINUX
691         case PLAYBACK_BUZ:
692                 output_base = new VDeviceBUZ(this);
693                 break;
694         case PLAYBACK_LML:
695                 output_base = new VDeviceLML(this);
696                 break;
697 #endif
698         case PLAYBACK_X11:
699         case PLAYBACK_X11_XV:
700         case PLAYBACK_X11_GL:
701                 output_base = new VDeviceX11(this, output);
702                 break;
703
704         case PLAYBACK_DV1394:
705         case PLAYBACK_FIREWIRE:
706         case PLAYBACK_IEC61883:
707                 output_base = new VDevice1394(this);
708                 break;
709         }
710 //printf("VideoDevice::open_output 2 %d\n", out_config->driver);
711
712         if(output_base->open_output()) {
713                 delete output_base;
714                 output_base = 0;
715         }
716 //printf("VideoDevice::open_output 3 %d\n", out_config->driver);
717         return output_base ? 0 : 1;
718 }
719
720
721
722 int VideoDevice::start_playback()
723 {
724 // arm buffer before doing this
725         is_playing_back = 1;
726         interrupt = 0;
727         return output_base ? output_base->start_playback() : 1;
728 }
729
730 int VideoDevice::stop_playback()
731 {
732         if( output_base ) output_base->stop_playback();
733         is_playing_back = 0;
734         interrupt = 0;
735         return 0;
736 }
737
738 void VideoDevice::goose_input()
739 {
740         if(input_base) input_base->goose_input();
741 }
742
743 void VideoDevice::new_output_buffer(VFrame **output, int colormodel)
744 {
745         if(!output_base) return;
746         output_base->new_output_buffer(output, colormodel);
747 }
748
749
750 int VideoDevice::interrupt_playback()
751 {
752         interrupt = 1;
753         return 0;
754 }
755
756 int VideoDevice::write_buffer(VFrame *output, EDL *edl)
757 {
758         return output_base ? output_base->write_buffer(output, edl) : 1;
759 }
760
761 int VideoDevice::output_visible()
762 {
763         return output_base ? output_base->output_visible() : 0;
764 }
765
766 BC_Bitmap* VideoDevice::get_bitmap()
767 {
768         return output_base ? output_base->get_bitmap() : 0;
769 }
770
771
772 int VideoDevice::set_cloexec_flag(int desc, int value)
773 {
774         int oldflags = fcntl(desc, F_GETFD, 0);
775         if( oldflags < 0 ) return oldflags;
776         if( value != 0 ) 
777                 oldflags |= FD_CLOEXEC;
778         else
779                 oldflags &= ~FD_CLOEXEC;
780         return fcntl(desc, F_SETFD, oldflags);
781 }
782
783
784 void VideoDevice::auto_update(double rate, int width, int height)
785 {
786         if( !in_config || !in_config->follow_video ) return;
787         capture_w = width;
788         capture_h = height;
789         frame_rate = rate;
790         in_config_updated = 1;
791 }
792
793 int VideoDevice::config_updated()
794 {
795         if( !in_config || !in_config->follow_video ) return 0;
796         return in_config_updated;
797 }
798
799 void VideoDevice::config_update()
800 {
801         in_config_updated = 0;
802         VideoInConfig *vconfig_in = mwindow->edl->session->vconfig_in;
803         vconfig_in->w = capture_w;
804         vconfig_in->h = capture_h;
805         vconfig_in->in_framerate = frame_rate;
806 }
807
808
809 int VideoDevice::start_toc(const char *path, const char *toc_path)
810 {
811         return input_base ? input_base->start_toc(path, toc_path) : -1;
812 }
813
814 int VideoDevice::start_record(int fd, int bsz)
815 {
816         return input_base ? input_base->start_record(fd, bsz) : -1;
817 }
818
819 int VideoDevice::stop_record()
820 {
821         return input_base ? input_base->stop_record() : -1;
822 }
823
824
825 int VideoDevice::total_video_streams()
826 {
827         return input_base ? input_base->total_video_streams() : 0;
828 }
829
830
831 // skimming
832 int VideoDevice::get_video_pid(int track)
833 {
834         return !input_base ? -1 : input_base->get_video_pid(track);
835
836 }
837
838 int VideoDevice::get_video_info(int track, int &pid,
839                 double &framerate, int &width, int &height, char *title)
840 {
841         return !input_base ? 1 : input_base->
842                 get_video_info(track, pid, framerate, width, height, title);
843 }
844
845 int VideoDevice::get_thumbnail(int stream, int64_t &position,
846                 unsigned char *&thumbnail, int &ww, int &hh)
847 {
848         return !input_base ? 1 :
849                 input_base->get_thumbnail(stream, position, thumbnail, ww, hh);
850 }
851
852 int VideoDevice::set_skimming(int track, int skim, skim_fn fn, void *vp)
853 {
854         return !input_base ? 1 :
855                 input_base->set_skimming(track, skim, fn, vp);
856 }
857