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