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