1 /*
2  * video4linux.cxx
3  *
4  * Classes to support streaming video input (grabbing) and output.
5  *
6  * Portable Windows Library
7  *
8  * Copyright (c) 1993-2000 Equivalence Pty. Ltd.
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Portable Windows Library.
21  *
22  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23  *
24  * Contributor(s): Derek Smithies (derek@indranet.co.nz)
25  *                 Mark Cooke (mpc@star.sr.bham.ac.uk)
26  *
27  * $Revision: 25888 $
28  * $Author: ededu $
29  * $Date: 2011-05-24 05:07:25 -0500 (Tue, 24 May 2011) $
30  */
31 
32 #pragma implementation "vidinput_v4l.h"
33 #include <ptlib.h>
34 #include <ptlib/pstring.h>
35 #include <ptlib/pluginmgr.h>
36 #include "vidinput_v4l.h"
37 #include <sys/utsname.h>
38 
39 PCREATE_VIDINPUT_PLUGIN(V4L);
40 
41 ///////////////////////////////////////////////////////////////////////////////
42 // Linux Video4Linux Driver Hints Tables.
43 //
44 // In an ideal API, we wouldn't need these hints on setup.  There are enough
45 // wrinkles it seems we have to provide a static list of hints for known
46 // issues.
47 
48 #define HINT_CSWIN_ZERO_FLAGS               0x0001
49 #define HINT_CSPICT_ALWAYS_WORKS            0x0002  /// ioctl return value indicates pict was set ok.
50 #define HINT_CGPICT_DOESNT_SET_PALETTE      0x0004
51 #define HINT_HAS_PREF_PALETTE               0x0008  /// use this palette with this camera.
52 #define HINT_ALWAYS_WORKS_320_240           0x0010  /// Camera always  opens OK at this size.
53 #define HINT_ALWAYS_WORKS_640_480           0x0020  /// Camera always  opens OK at this size.
54 #define HINT_ONLY_WORKS_PREF_PALETTE        0x0040  /// Camera always (and only) opens at pref palette.
55 #define HINT_CGWIN_FAILS                    0x0080  /// ioctl VIDIOCGWIN always fails.
56 #define HINT_FORCE_LARGE_SIZE               0x0100  /// driver does not work in small video size.
57 #define HINT_FORCE_DEPTH_16                 0x0200  /// CPiA cameras return a wrong value for the depth, and if you try to use that wrong value, it fails.
58 #define HINT_FORCE_DBLBUF                   0x0400  /// Force double buffering on quickcam express
59 
60 static struct {
61   const char     *name_regexp;        // String used to match the driver name
62   const char     *name;               // String used for ptrace output
63   const char     *version;             // Apply the hint if kernel
64                                 // version < given version,
65                                 // 0 means always apply
66   unsigned hints;               // Hint flags
67   int      pref_palette;        // Preferred palette.
68 } driver_hints[] = {
69 
70     /**Most of usb web cameras from the spca5xx driver
71      */
72 
73   { "^Broken sensor chipset that accept only 640x480$",
74     "Broken sensor chipset that accept only 640x480",
75     NULL,
76     HINT_ALWAYS_WORKS_640_480|
77     HINT_CGWIN_FAILS,
78     0},
79 
80      /**Philips usb web cameras
81        Native format is 420(P) so use it.
82      */
83 
84   { "^Philips [0-9]+ webcam$",
85     "Philips USB webcam",
86     NULL,
87     HINT_ALWAYS_WORKS_640_480,
88     VIDEO_PALETTE_YUV420P },
89 
90   /**Brooktree based capture boards.
91 
92      The current bttv driver doesn't fail CSPICT calls with unsupported
93      palettes.  It also doesn't return a useful value from CGPICT calls
94      to readback the palette. Not needed anymore from 2.4.23
95    */
96     { "^BT8(4|7)(8|9)",
97       "Brooktree BT848 and BT878 based capture boards",
98       "2.4.23",
99       HINT_CSWIN_ZERO_FLAGS |
100       HINT_CSPICT_ALWAYS_WORKS |
101       HINT_CGPICT_DOESNT_SET_PALETTE |
102       HINT_HAS_PREF_PALETTE,
103       VIDEO_PALETTE_YUV420P },
104 
105   /** Quickcam Communicate STX (spca5xx driver)
106       Actually, it's not true that it needs VIDEO_PALETTE_YUV420P.
107       But it wouldn't be reasonable to convert the pictures twice.
108    */
109   { "Logitech QuickCam Communicate S",
110     "Logitech Quickcam Communicate STX (spca5xx driver)",
111     NULL,
112     HINT_ALWAYS_WORKS_320_240 |
113     HINT_ALWAYS_WORKS_640_480 |
114     HINT_HAS_PREF_PALETTE,
115     VIDEO_PALETTE_YUV420P },
116 
117   /** Quickcam Express (qc-usb driver) */
118   { "Logitech [USB Camera|QuickCam USB]",
119     "Quickcam Express (qc-usb driver)",
120     NULL,
121     HINT_FORCE_DBLBUF,
122     0},
123 
124   /** Sony Vaio Motion Eye camera
125       Linux kernel 2.4.7 has meye.c driver module.
126    */
127   { "meye",
128     "Sony Vaio Motion Eye Camera",
129     NULL,
130     HINT_CGPICT_DOESNT_SET_PALETTE |
131     HINT_CSPICT_ALWAYS_WORKS       |
132     HINT_ALWAYS_WORKS_320_240      |
133     HINT_ALWAYS_WORKS_640_480      |
134     HINT_CGWIN_FAILS               |
135     HINT_ONLY_WORKS_PREF_PALETTE   |
136     HINT_HAS_PREF_PALETTE,
137     VIDEO_PALETTE_YUV422 },
138 
139   /** USB camera, which only works in large size.
140    */
141   { "Logitech USB Webcam",
142     "Logitech USB Webcam which works in large size only",
143     NULL,
144     HINT_FORCE_LARGE_SIZE,
145     VIDEO_PALETTE_YUV420P
146   },
147 
148   /** Creative VideoBlaster Webcam II USB
149    */
150   {"CPiA Camera",
151    "CPIA which works with cpia and cpia_usb driver modules",
152    NULL,
153    HINT_FORCE_DEPTH_16 |
154    HINT_ONLY_WORKS_PREF_PALETTE   |
155    HINT_HAS_PREF_PALETTE,
156    VIDEO_PALETTE_YUV422
157   },
158 
159  /** Intel PC Pro Camera
160 
161  */
162   { "SPCA50X USB Camera",
163     "Intel PC Pro Camera uses the spca50x driver",
164     NULL,
165     HINT_ONLY_WORKS_PREF_PALETTE        |
166     HINT_HAS_PREF_PALETTE,
167     VIDEO_PALETTE_RGB24
168   },
169 
170 
171   /** Default device with no special settings
172    */
173   { "",
174     "V4L Supported Device",
175     0,
176     0,
177     0 }
178 
179 };
180 
181 /*
182  * This is list of channel names that accept only fixed size resolution
183  * The spca5xx driver store in the channel name, the name of the bridge,
184  * not the sensor, so we use a second list to trim false positive.
185  */
186 static const char *bridges_with_640x480_fixed_width[] = {
187    "SPCA505",
188    "SPCA506",
189    "SPCA501",
190    "SPCA504",
191    "SPCA500", /* Only the LogitechClickSmart310 doesn't support the 640x480 */
192    "SPCA504B",
193    "SPCA504C",
194    "SPCA536",
195    "SN9C102", /* SENSOR_PAS106 and SENSOR_TAS5110 doesn't support the 640x480 */
196    "ZC301-2", /* SENSOR_PAS106 doesn't support the 640x480 */
197    "CX11646",
198    "SN9CXXX",
199    "MR97311",
200    "VC0321",
201 };
202 
203 static const char *sensors_with_352x288_fixed_width[] = {
204    "Philips SPC200NC ",	/* Using the SENSOR_PAS106 sensor */
205    "Philips SPC210NC (FB) ",
206    "Philips SPC300NC ",
207    "Creative NX",
208    "Creative Instant P0620",
209    "Creative Instant P0620D",
210    "Sonix sn9c10x + Pas106 sensor",
211    "Genius VideoCAM NB", /* Using the SENSOR_TAS5110 sensor */
212    "Sweex SIF webcam",
213    "Logitech ClickSmart 310", /* Using the SENSOR_HDCS1020 sensor */
214 };
215 
216 #if 0
217 /* TODO: We need to do the same hack */
218 static const char *bridges_with_352x288_fixed_width[] = {
219    "SPCA508", /* 352x288 */
220    "SPCA561", /* 352x288 */
221    "TV8532", /* 352x288 */
222    "ET61XX51", /* 320x240 */
223    //  "SPCA533", /* 464*480 */
224    //  "PAC207BCA", /* 320x240 only */
225 };
226 #endif
227 
228 #define HINT(h) ((driver_hints[hint_index].hints & h) ? PTrue : PFalse)
229 #define MAJOR(a) (int)((unsigned short) (a) >> 8)
230 #define MINOR(a) (int)((unsigned short) (a) & 0xFF)
231 // this is used to get more userfriendly names:
232 class V4LNames : public PObject
233 {
234    PCLASSINFO(V4LNames, PObject);
235 public:
V4LNames()236   V4LNames() {/* nothing */};
237 
238   void Update ();
239 
240   PString GetUserFriendly(PString devName);
241 
242   PString GetDeviceName(PString userName);
243 
244   PStringList GetInputDeviceNames();
245 
246 protected:
247   void AddUserDeviceName(PString userName, PString devName);
248 
249   PString BuildUserFriendly(PString devname);
250 
251   void PopulateDictionary();
252 
253   void ReadDeviceDirectory(PDirectory devdir, POrdinalToString & vid);
254 
255   PMutex          mutex;
256   PStringToString deviceKey;
257   PStringToString userKey;
258   PStringList     inputDeviceNames;
259 };
260 
261 void
Update()262 V4LNames::Update()
263 {
264   PDirectory   procvideo("/proc/video/dev");
265   PString      entry;
266   PStringList  devlist;
267 
268   PWaitAndSignal m(mutex);
269   inputDeviceNames.RemoveAll (); // flush the previous run
270   if (procvideo.Exists()) {
271     if (procvideo.Open(PFileInfo::RegularFile)) {
272       do {
273         entry = procvideo.GetEntryName();
274         if ((entry.Left(5) == "video") || (entry.Left(7) == "capture")) {
275           PString thisDevice = "/dev/video" + entry.Right(1);
276           int videoFd = ::open((const char *)thisDevice, O_RDONLY | O_NONBLOCK);
277 
278           if ((videoFd > 0) || (errno == EBUSY)){
279             PBoolean valid = PFalse;
280             struct video_capability  videoCaps;
281             if (ioctl(videoFd, VIDIOCGCAP, &videoCaps) >= 0 && (videoCaps.type & VID_TYPE_CAPTURE) != 0)
282               valid = PTrue;
283             if (videoFd >= 0)
284               close(videoFd);
285             if (valid)
286               inputDeviceNames += thisDevice;
287           }
288         }
289       } while (procvideo.Next());
290     }
291   }
292   if (inputDeviceNames.GetSize() == 0) {
293     POrdinalToString vid;
294     ReadDeviceDirectory("/dev/", vid);
295 
296     for (PINDEX i = 0; i < vid.GetSize(); i++) {
297       PINDEX cardnum = vid.GetKeyAt(i);
298       int fd = ::open(vid[cardnum], O_RDONLY | O_NONBLOCK);
299       if ((fd >= 0) || (errno == EBUSY)) {
300         if (fd >= 0)
301           ::close(fd);
302         inputDeviceNames += vid[cardnum];
303       }
304     }
305   }
306   PopulateDictionary();
307 }
308 
ReadDeviceDirectory(PDirectory devdir,POrdinalToString & vid)309 void  V4LNames::ReadDeviceDirectory(PDirectory devdir, POrdinalToString & vid)
310 {
311   if (!devdir.Open())
312     return;
313 
314   do {
315     PString filename = devdir.GetEntryName();
316     PString devname = devdir + filename;
317     if (devdir.IsSubDir())
318       ReadDeviceDirectory(devname, vid);
319     else {
320 
321       PFileInfo info;
322       if (devdir.GetInfo(info) && info.type == PFileInfo::CharDevice) {
323         struct stat s;
324         if (lstat(devname, &s) == 0) {
325 #if defined(P_FREEBSD)
326           // device numbers are irrelevant here, so we match on names instead
327           if (filename.GetLength() <= 5 || filename.Left(5) != "video")
328             continue;
329           int num = atoi(filename.Mid(6));
330           if (num < 0 || num > 63)
331             continue;
332           vid.SetAt(num, devname);
333 #else
334           static const int deviceNumbers[] = { 81 };
335           for (PINDEX i = 0; i < PARRAYSIZE(deviceNumbers); i++) {
336             if (MAJOR(s.st_rdev) == deviceNumbers[i]) {
337               PINDEX num = MINOR(s.st_rdev);
338               if (num <= 63 && num >= 0) {
339                 vid.SetAt(num, devname);
340               }
341             }
342           }
343 #endif
344         }
345       }
346     }
347   } while (devdir.Next());
348 }
349 
PopulateDictionary()350 void V4LNames::PopulateDictionary()
351 {
352   PINDEX i, j;
353   PStringToString tempList;
354 
355   for (i = 0; i < inputDeviceNames.GetSize(); i++) {
356     PString ufname = BuildUserFriendly(inputDeviceNames[i]);
357     tempList.SetAt(inputDeviceNames[i], ufname);
358   }
359 
360   //Now, we need to cope with the case where there are two video
361   //devices available, which both have the same user friendly name.
362   //Matching user friendly names have a (X) appended to the name.
363   for (i = 0; i < tempList.GetSize(); i++) {
364     PString userName = tempList.GetDataAt(i);
365 
366     PINDEX matches = 1;
367     for (j = i + 1; j < tempList.GetSize(); j++) {
368       if (tempList.GetDataAt(j) == userName) {
369         matches++;
370         PStringStream revisedUserName;
371         revisedUserName << userName << " (" << matches << ")";
372         tempList.SetDataAt(j, revisedUserName);
373       }
374     }
375   }
376 
377   //At this stage, we have correctly modified the temp list of names.
378   for (j = 0; j < tempList.GetSize(); j++)
379     AddUserDeviceName(tempList.GetDataAt(j), tempList.GetKeyAt(j));
380 }
381 
GetUserFriendly(PString devName)382 PString V4LNames::GetUserFriendly(PString devName)
383 {
384   PWaitAndSignal m(mutex);
385 
386   PString result= deviceKey(devName);
387   if (result.IsEmpty())
388     return devName;
389 
390   return result;
391 }
392 
GetDeviceName(PString userName)393 PString V4LNames::GetDeviceName(PString userName)
394 {
395   PWaitAndSignal m(mutex);
396 
397   for (PINDEX i = 0; i < userKey.GetSize(); i++)
398     if (userKey.GetKeyAt(i).Find(userName) != P_MAX_INDEX)
399       return userKey.GetDataAt(i);
400 
401   return userName;
402 }
403 
AddUserDeviceName(PString userName,PString devName)404 void V4LNames::AddUserDeviceName(PString userName, PString devName)
405 {
406   PWaitAndSignal m(mutex);
407 
408   if (userName != devName) { // must be a real userName!
409     userKey.SetAt(userName, devName);
410     deviceKey.SetAt(devName, userName);
411   } else { // we didn't find a good userName
412     if (!deviceKey.Contains (devName)) { // never met before: fallback
413       userKey.SetAt(userName, devName);
414       deviceKey.SetAt(devName, userName);
415     } // no else: we already know the pair
416   }
417 }
418 
BuildUserFriendly(PString devname)419 PString V4LNames::BuildUserFriendly(PString devname)
420 {
421   PString Result;
422 
423   int fd = ::open((const char *)devname, O_RDONLY);
424   if(fd < 0) {
425     return devname;
426   }
427 
428   struct video_capability videocap;
429   if (::ioctl(fd, VIDIOCGCAP, &videocap) < 0)  {
430       ::close(fd);
431       return devname;
432     }
433 
434   ::close(fd);
435   PString ufname(videocap.name);
436 
437   return ufname;
438 }
439 
440 /*
441   There is a duplication in the list of names.
442   Consequently, opening the device as "ov511++" or "/dev/video0" will work.
443 */
GetInputDeviceNames()444 PStringList V4LNames::GetInputDeviceNames()
445 {
446   PWaitAndSignal m(mutex);
447   PStringList result;
448   for (PINDEX i = 0; i < inputDeviceNames.GetSize(); i++) {
449     result += GetUserFriendly (inputDeviceNames[i]);
450   }
451 
452   return result;
453 }
454 
455 PMutex creationMutex;
456 static
GetNames()457 V4LNames & GetNames()
458 {
459   PWaitAndSignal m(creationMutex);
460   static V4LNames names;
461   names.Update();
462   return names;
463 }
464 
465 ///////////////////////////////////////////////////////////////////////////////
466 // PVideoInputDevice_V4L
467 
PVideoInputDevice_V4L()468 PVideoInputDevice_V4L::PVideoInputDevice_V4L()
469 {
470   videoFd       = -1;
471   hint_index    = PARRAYSIZE(driver_hints) - 1;
472 
473   canMap           = -1;
474   for (int i=0; i<2; i++)
475     pendingSync[i] = PFalse;
476 }
477 
~PVideoInputDevice_V4L()478 PVideoInputDevice_V4L::~PVideoInputDevice_V4L()
479 {
480     Close();
481 }
482 
483 /* From the spca5xx driver and gspca driver */
484 #ifndef VIDEO_PALETTE_RAW_JPEG
485 #define VIDEO_PALETTE_RAW_JPEG  20
486 #define VIDEO_PALETTE_JPEG 21
487 #endif
488 
489 static struct {
490   const char * colourFormat;
491   int code;
492 } colourFormatTab[] = {
493   { "Grey", VIDEO_PALETTE_GREY },  //Entries in this table correspond
494   { "BGR32", VIDEO_PALETTE_RGB32 }, //(line by line) to those in the
495   { "BGR24", VIDEO_PALETTE_RGB24 }, // PVideoDevice ColourFormat table.
496   { "RGB565", VIDEO_PALETTE_RGB565 },
497   { "RGB555", VIDEO_PALETTE_RGB555 },
498   { "YUV422", VIDEO_PALETTE_YUV422 },
499   { "YUV422P", VIDEO_PALETTE_YUV422P },
500   { "YUV411", VIDEO_PALETTE_YUV411 },
501   { "YUV411P", VIDEO_PALETTE_YUV411P },
502   { "YUV420", VIDEO_PALETTE_YUV420 },
503   { "YUV420P", VIDEO_PALETTE_YUV420P },
504   { "YUV410P", VIDEO_PALETTE_YUV410P },
505   { "UYVY422", VIDEO_PALETTE_UYVY },
506   { "MJPEG", VIDEO_PALETTE_JPEG }
507 };
508 
509 
Open(const PString & devName,PBoolean startImmediate)510 PBoolean PVideoInputDevice_V4L::Open(const PString & devName, PBoolean startImmediate)
511 {
512   struct utsname buf;
513   PString version;
514 
515   uname (&buf);
516 
517   if (buf.release)
518     version = PString (buf.release);
519 
520   Close();
521 
522   PTRACE(1,"PVideoInputDevice_V4L: trying to open "<< devName);
523 
524   // check if it is a userfriendly name, and if so, get the real device name
525 
526   PString deviceName = GetNames().GetDeviceName(devName);
527   videoFd = ::open((const char *)deviceName, O_RDWR);
528   if (videoFd < 0) {
529     PTRACE(1,"PVideoInputDevice_V4L::Open failed : "<< ::strerror(errno));
530     return PFalse;
531   }
532 
533   // get the device capabilities
534   if (!RefreshCapabilities()) {
535     ::close (videoFd);
536     videoFd = -1;
537     return PFalse;
538   }
539 
540   if ((videoCapability.type & VID_TYPE_CAPTURE) == 0) {
541     PTRACE(1,"PVideoInputDevice_V4L:: device capablilities reports cannot capture");
542     ::close (videoFd);
543     videoFd = -1;
544     return PFalse;
545   }
546 
547   hint_index = PARRAYSIZE(driver_hints) - 1;
548   PString driver_name(videoCapability.name);
549 
550   // Scan the hint table, looking for regular expression matches with
551   // drivers we hold hints for.
552   PINDEX tbl;
553   for (tbl = 0; tbl < PARRAYSIZE(driver_hints); tbl ++) {
554     PRegularExpression regexp;
555     regexp.Compile(driver_hints[tbl].name_regexp, PRegularExpression::Extended);
556 
557     if (driver_name.FindRegEx(regexp) != P_MAX_INDEX) {
558       PTRACE(1,"PVideoInputDevice_V4L::Open: Found driver hints: " << driver_hints[tbl].name);
559       PTRACE(1,"PVideoInputDevice_V4L::Open: format: " << driver_hints[tbl].pref_palette);
560 
561       if (driver_hints[tbl].version && !version.IsEmpty ()) {
562         if (PString (version) < PString (driver_hints[tbl].version)) {
563           PTRACE(1,"PVideoInputDevice_V4L::Open: Hints applied because kernel version less than " << driver_hints[tbl].version);
564           hint_index = tbl;
565           break;
566         }
567         else {
568           PTRACE(1,"PVideoInputDevice_V4L::Open: Hints not applied because kernel version is not less than " << driver_hints[tbl].version);
569         }
570       }
571       else {
572         hint_index = tbl;
573         break;
574       }
575     }
576   }
577 
578   /*
579    * Some drivers like the spca5xx ou the gspca returns OK for any resolution
580    * between min-max. But the image is crop, and the user doesn't see his face
581    * entirely.
582    * The problem is the drive support more than 200 webcams, and we cannot add
583    * them all to the list of driver_hints[], so we use the sensor description
584    * to enable the hack. The channel name contains the name of the bridge, so
585    * we have only 10 comp to be. But some webcams have a 640x480 bridge, and a
586    * small sensor ...
587    */
588   if (hint_index >= PARRAYSIZE(driver_hints)-1) {
589      struct video_channel channel;
590      memset(&channel, 0, sizeof(struct video_channel));
591      if (::ioctl(videoFd, VIDIOCGCHAN, &channel) == 0) {
592 	/* Only check if the called doesn't return an error */
593 	for (tbl = 0; tbl < PARRAYSIZE(bridges_with_640x480_fixed_width); tbl ++) {
594 	   if (strcmp(bridges_with_640x480_fixed_width[tbl], channel.name) == 0) {
595 	      PBoolean false_positive = PFalse;
596 	      unsigned int idx;
597 	      for (idx = 0; idx < PARRAYSIZE(sensors_with_352x288_fixed_width); idx++) {
598 		 if (strcmp(sensors_with_352x288_fixed_width[idx], videoCapability.name) == 0) {
599 		    false_positive = PTrue;
600 		    break;
601 		 }
602 	      }
603 	      if (false_positive == PFalse) {
604 		 PTRACE(1,"PVideoInputDevice_V4L::Open: Found fixed 640x480 sensor");
605 		 hint_index = 0;
606 		 break;
607 	      }
608 	   }
609 	}
610      }
611   }
612 
613   // Force double-buffering with buggy Quickcam driver.
614   if (HINT (HINT_FORCE_DBLBUF)) {
615 
616 #define QC_IOCTLBASE            220
617 #define VIDIOCQCGCOMPATIBLE     _IOR ('v',QC_IOCTLBASE+10,int)  /* Get enable workaround for bugs, bitfield */
618 #define VIDIOCQCSCOMPATIBLE     _IOWR('v',QC_IOCTLBASE+10,int)  /* Set enable workaround for bugs, bitfield */
619 
620     int reg = 2; /* enable double buffering */
621     ::ioctl (videoFd, VIDIOCQCSCOMPATIBLE, &reg);
622   }
623 
624 
625   // set height and width
626   frameHeight = PMIN (videoCapability.maxheight, QCIFHeight);
627   frameWidth  = PMIN (videoCapability.maxwidth, QCIFWidth);
628 
629 
630   // Init audio
631   struct video_audio videoAudio;
632   if (::ioctl(videoFd, VIDIOCGAUDIO, &videoAudio) >= 0 &&
633                       (videoAudio.flags & VIDEO_AUDIO_MUTABLE) != 0) {
634     videoAudio.flags &= ~VIDEO_AUDIO_MUTE;
635     videoAudio.mode = VIDEO_SOUND_MONO;
636     ::ioctl(videoFd, VIDIOCSAUDIO, &videoAudio);
637     }
638 
639   SetVideoFormat(videoFormat);
640   SetColourFormat(colourFormat);
641 
642   return PTrue;
643 }
644 
645 
IsOpen()646 PBoolean PVideoInputDevice_V4L::IsOpen()
647 {
648   return videoFd >= 0;
649 }
650 
651 
Close()652 PBoolean PVideoInputDevice_V4L::Close()
653 {
654   if (!IsOpen())
655     return PFalse;
656 
657 
658   // Mute audio
659   struct video_audio videoAudio;
660   if (::ioctl(videoFd, VIDIOCGAUDIO, &videoAudio) >= 0 &&
661                       (videoAudio.flags & VIDEO_AUDIO_MUTABLE) != 0) {
662     videoAudio.flags |= VIDEO_AUDIO_MUTE;
663     ::ioctl(videoFd, VIDIOCSAUDIO, &videoAudio);
664   }
665 
666   ClearMapping();
667   ::close(videoFd);
668 
669   videoFd = -1;
670   canMap  = -1;
671 
672   return PTrue;
673 }
674 
675 
Start()676 PBoolean PVideoInputDevice_V4L::Start()
677 {
678   return PTrue;
679 }
680 
681 
Stop()682 PBoolean PVideoInputDevice_V4L::Stop()
683 {
684   return PTrue;
685 }
686 
687 
IsCapturing()688 PBoolean PVideoInputDevice_V4L::IsCapturing()
689 {
690   return IsOpen();
691 }
692 
693 
GetInputDeviceNames()694 PStringList PVideoInputDevice_V4L::GetInputDeviceNames()
695 {
696   return GetNames().GetInputDeviceNames();
697 }
698 
SetVideoFormat(VideoFormat newFormat)699 PBoolean PVideoInputDevice_V4L::SetVideoFormat(VideoFormat newFormat)
700 {
701   if (!PVideoDevice::SetVideoFormat(newFormat)) {
702     PTRACE(1,"PVideoDevice::SetVideoFormat\t failed");
703     return PFalse;
704   }
705 
706   // The channel and format are both set at the same time with one ioctl().
707   // Get the channel information (to check if channel is valid)
708   // Note: If the channel is -1, we need to search for the first valid channel
709   if (channelNumber == -1) {
710     if (!SetChannel(channelNumber)){
711       PTRACE(1,"PVideoDevice::Cannot set default channel in SetVideoFormat");
712       return PFalse;
713     }
714   }
715 
716   struct video_channel channel;
717   channel.channel = channelNumber;
718   if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) {
719     PTRACE(1,"VideoInputDevice Get Channel info failed : "<< ::strerror(errno));
720     return PFalse;
721   }
722 
723   // set channel information
724   static int fmt[4] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC,
725                           VIDEO_MODE_SECAM, VIDEO_MODE_AUTO };
726   channel.norm = fmt[newFormat];
727 
728   // set the information
729   if (::ioctl(videoFd, VIDIOCSCHAN, &channel) >= 0) {
730     // format change might affect frame size limits; grab them again
731     RefreshCapabilities();
732     return PTrue;
733   }
734 
735   PTRACE(1,"VideoInputDevice SetChannel failed : "<< ::strerror(errno));
736 
737   if (newFormat != Auto)
738     return PFalse;
739 
740   if (SetVideoFormat(PAL))
741     return PTrue;
742   if (SetVideoFormat(NTSC))
743     return PTrue;
744   if (SetVideoFormat(SECAM))
745     return PTrue;
746 
747   return PFalse;
748 }
749 
750 
GetNumChannels()751 int PVideoInputDevice_V4L::GetNumChannels()
752 {
753   /* If Opened, return the capability value, else 1 as in videoio.cxx */
754   if (IsOpen ())
755     return videoCapability.channels;
756   else
757     return 1;
758 }
759 
760 
SetChannel(int newChannel)761 PBoolean PVideoInputDevice_V4L::SetChannel(int newChannel)
762 {
763   if (!PVideoDevice::SetChannel(newChannel))
764     return PFalse;
765 
766   // get channel information (to check if channel is valid)
767   struct video_channel channel;
768   channel.channel = channelNumber;
769   if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) {
770     PTRACE(1,"VideoInputDevice:: Get info on channel " << channelNumber << " failed : "<< ::strerror(errno));
771     return PFalse;
772   }
773 
774   // set channel information
775   channel.channel = channelNumber;
776 
777   // set the information
778   if (::ioctl(videoFd, VIDIOCSCHAN, &channel) < 0) {
779     PTRACE(1,"VideoInputDevice:: Set info on channel " << channelNumber << " failed : "<< ::strerror(errno));
780     return PFalse;
781   }
782 
783   // it's unlikely that channel change would affect frame size limits,
784   // but grab them again all the same
785   RefreshCapabilities();
786   return PTrue;
787 }
788 
789 
SetVideoChannelFormat(int newNumber,VideoFormat videoFormat)790 PBoolean PVideoInputDevice_V4L::SetVideoChannelFormat (int newNumber, VideoFormat videoFormat)
791 {
792   if (!PVideoDevice::SetChannel(newNumber))
793     return PFalse;
794 
795   if (!PVideoDevice::SetVideoFormat(videoFormat)) {
796     PTRACE(1,"PVideoDevice::SetVideoFormat\t failed");
797     return PFalse;
798   }
799 
800   static int fmt[4] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC,
801                           VIDEO_MODE_SECAM, VIDEO_MODE_AUTO };
802 
803   // select the specified input and video format
804   // get channel information (to check if channel is valid)
805   struct video_channel channel;
806   channel.channel = channelNumber;
807   if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) {
808     PTRACE(1,"VideoInputDevice Get Channel info failed : "<< ::strerror(errno));
809 
810     return PFalse;
811   }
812 
813   // set channel information
814   channel.norm = fmt[videoFormat];
815   channel.channel = channelNumber;
816 
817   // set the information
818   if (::ioctl(videoFd, VIDIOCSCHAN, &channel) < 0) {
819     PTRACE(1,"VideoInputDevice SetChannel failed : "<< ::strerror(errno));
820 
821     return PFalse;
822   }
823 
824   // format change may affect frame size limits
825   RefreshCapabilities();
826   return PTrue;
827 }
828 
SetColourFormat(const PString & newFormat)829 PBoolean PVideoInputDevice_V4L::SetColourFormat(const PString & newFormat)
830 {
831   PINDEX colourFormatIndex = 0;
832   while (newFormat != colourFormatTab[colourFormatIndex].colourFormat) {
833     colourFormatIndex++;
834     if (colourFormatIndex >= PARRAYSIZE(colourFormatTab))
835       return PFalse;
836   }
837 
838   if (!PVideoDevice::SetColourFormat(newFormat))
839     return PFalse;
840 
841   ClearMapping();
842 
843   // get current picture information
844   struct video_picture pictureInfo;
845   if (::ioctl(videoFd, VIDIOCGPICT, &pictureInfo) < 0) {
846     PTRACE(1,"PVideoInputDevice_V4L::Get pict info failed : "<< ::strerror(errno));
847     return PFalse;
848   }
849 
850   // set colour format
851   colourFormatCode = colourFormatTab[colourFormatIndex].code;
852   pictureInfo.palette = colourFormatCode;
853   if (HINT (HINT_FORCE_DEPTH_16))
854     pictureInfo.depth = 16;
855 
856   // set the information
857   if (::ioctl(videoFd, VIDIOCSPICT, &pictureInfo) < 0) {
858     PTRACE(1,"PVideoInputDevice_V4L::Set pict info failed : "<< ::strerror(errno));
859     PTRACE(1,"PVideoInputDevice_V4L:: used code of "<<colourFormatCode);
860     PTRACE(1,"PVideoInputDevice_V4L:: palette: "<<colourFormatTab[colourFormatIndex].colourFormat);
861     return PFalse;
862   }
863 
864 
865   // Driver only (and always) manages to set the colour format  with call to VIDIOCSPICT.
866   if( (HINT(HINT_ONLY_WORKS_PREF_PALETTE) ) &&
867       ( colourFormatCode == driver_hints[hint_index].pref_palette) ) {
868     PTRACE(3,"PVideoInputDevice_V4L:: SetColourFormat succeeded with "<<newFormat);
869     return PTrue;
870   }
871 
872   // Some drivers always return success for CSPICT, and can't
873   // read the current palette back in CGPICT.  We can't do much
874   // more than just check to see if there is a preferred palette,
875   // and fail if the request isn't the preferred palette.
876 
877   if (HINT(HINT_CSPICT_ALWAYS_WORKS) &&
878       HINT(HINT_CGPICT_DOESNT_SET_PALETTE) &&
879       HINT(HINT_HAS_PREF_PALETTE)) {
880       if (colourFormatCode != driver_hints[hint_index].pref_palette)
881         return PFalse;
882   }
883 
884   // Some V4L drivers can't use CGPICT to check for errors.
885   if (!HINT(HINT_CGPICT_DOESNT_SET_PALETTE)) {
886     if (::ioctl(videoFd, VIDIOCGPICT, &pictureInfo) < 0) {
887       PTRACE(1,"PVideoInputDevice_V4L::Get pict info failed : "<< ::strerror(errno));
888       return PFalse;
889     }
890 
891     if (pictureInfo.palette != colourFormatCode)
892       return PFalse;
893   }
894 
895   // set the new information
896   return SetFrameSizeConverter(frameWidth, frameHeight);
897 }
898 
899 
SetFrameRate(unsigned rate)900 PBoolean PVideoInputDevice_V4L::SetFrameRate(unsigned rate)
901 {
902   if (!PVideoDevice::SetFrameRate(rate))
903     return PFalse;
904 
905   return PTrue;
906 }
907 
908 
GetFrameSizeLimits(unsigned & minWidth,unsigned & minHeight,unsigned & maxWidth,unsigned & maxHeight)909 PBoolean PVideoInputDevice_V4L::GetFrameSizeLimits(unsigned & minWidth,
910                                            unsigned & minHeight,
911                                            unsigned & maxWidth,
912                                            unsigned & maxHeight)
913 {
914   if (!IsOpen())
915     return PFalse;
916 
917   if(HINT(HINT_FORCE_LARGE_SIZE)) {
918     videoCapability.maxheight = 288;
919     videoCapability.maxwidth  = 352;
920     videoCapability.minheight = 288;
921     videoCapability.minwidth  = 352;
922   }
923 
924   maxHeight = videoCapability.maxheight;
925   maxWidth  = videoCapability.maxwidth;
926   minHeight = videoCapability.minheight;
927   minWidth  = videoCapability.minwidth;
928 
929   PTRACE(3,"PVideoInputDevice_V4L:\t GetFrameSizeLimits. "<<minWidth<<"x"<<minHeight<<" -- "<<maxWidth<<"x"<<maxHeight);
930 
931   return PTrue;
932 }
933 
934 
SetFrameSize(unsigned width,unsigned height)935 PBoolean PVideoInputDevice_V4L::SetFrameSize(unsigned width, unsigned height)
936 {
937   PTRACE(5, "PVideoInputDevice_V4L\t SetFrameSize " << width <<"x"<<height << " Initiated.");
938   if (!PVideoDevice::SetFrameSize(width, height)) {
939     PTRACE(3,"PVideoInputDevice_V4L\t SetFrameSize "<<width<<"x"<<height<<" FAILED");
940     return PFalse;
941   }
942 
943   ClearMapping();
944 
945   if (!VerifyHardwareFrameSize(width, height)) {
946     PTRACE(3,"PVideoInputDevice_V4L\t SetFrameSize failed for "<<width<<"x"<<height);
947     PTRACE(3,"VerifyHardwareFrameSize failed.");
948     return PFalse;
949   }
950 
951   frameBytes = CalculateFrameBytes(frameWidth, frameHeight, colourFormat);
952 
953   return PTrue;
954 }
955 
956 
GetMaxFrameBytes()957 PINDEX PVideoInputDevice_V4L::GetMaxFrameBytes()
958 {
959   return GetMaxFrameBytesConverted(frameBytes);
960 }
961 
962 
GetFrameData(BYTE * buffer,PINDEX * bytesReturned)963 PBoolean PVideoInputDevice_V4L::GetFrameData(BYTE *buffer, PINDEX *bytesReturned)
964 {
965   m_pacing.Delay(1000/GetFrameRate());
966   return GetFrameDataNoDelay(buffer, bytesReturned);
967 }
968 
969 
GetFrameDataNoDelay(BYTE * buffer,PINDEX * bytesReturned)970 PBoolean PVideoInputDevice_V4L::GetFrameDataNoDelay(BYTE * buffer, PINDEX * bytesReturned)
971 {
972   if (canMap < 0) {
973     //When canMap is < 0, it is the first use of GetFrameData. Check for memory mapping.
974     if (::ioctl(videoFd, VIDIOCGMBUF, &frame) < 0) {
975       canMap=0;
976       PTRACE(3, "VideoGrabber " << deviceName << " cannot do memory mapping - GMBUF failed.");
977       //This video device cannot do memory mapping.
978     } else {
979       videoBuffer = (BYTE *)::mmap(0, frame.size, PROT_READ|PROT_WRITE, MAP_SHARED, videoFd, 0);
980 
981       if (videoBuffer == MAP_FAILED) {
982         canMap = 0;
983         PTRACE(3, "VideoGrabber " << deviceName << " cannot do memory mapping - ::mmap failed.");
984         //This video device cannot do memory mapping.
985       } else {
986         canMap = 1;
987 
988         frameBuffer[0].frame  = 0;
989         frameBuffer[0].format = colourFormatCode;
990         frameBuffer[0].width  = frameWidth;
991         frameBuffer[0].height = frameHeight;
992 
993         frameBuffer[1].frame  = 1;
994         frameBuffer[1].format = colourFormatCode;
995         frameBuffer[1].width  = frameWidth;
996         frameBuffer[1].height = frameHeight;
997 
998         currentFrame = 0;
999         int ret;
1000         ret = ::ioctl(videoFd, VIDIOCMCAPTURE, &frameBuffer[currentFrame]);
1001         if (ret < 0) {
1002           PTRACE(1,"PVideoInputDevice_V4L::GetFrameData mcapture1 failed : " << ::strerror(errno));
1003           ClearMapping();
1004           canMap = 0;
1005           //This video device cannot do memory mapping.
1006         }
1007         pendingSync[currentFrame] = PTrue;
1008       }
1009     }
1010   }
1011 
1012   if (canMap == 0)
1013     {
1014       return NormalReadProcess(buffer, bytesReturned);
1015     }
1016 
1017   /*****************************
1018    * The xawtv package from http://bytesex.org/xawtv/index.html
1019    * contains a programming-FAQ by Gerd Knorr.
1020    * For streaming video with video4linux at the full frame rate
1021    * (25 hz PAL, 30 hz NTSC) you need to,
1022    *
1023    *   videoiomcapture frame 0                         (setup)
1024    *
1025    * loop:
1026    *   videoiomcapture frame 1   (returns immediately)
1027    *   videoiocsync    frame 0   (waits on the data)
1028    *  goto loop:
1029    *
1030    * the loop body could also have been:
1031    *   videoiomcapture frame 0   (returns immediately)
1032    *   videoiocsync    frame 1   (waits on the data)
1033    *
1034    * The driver requires each mcapture has a corresponding sync.
1035    * Thus, you use the pendingSync array.
1036    *
1037    * After the loop is finished, you need a videoiocsync 0.
1038    */
1039 
1040   // trigger capture of next frame in this buffer.
1041   // fallback to read() on errors.
1042   int ret = -1;
1043 
1044   ret = ::ioctl(videoFd, VIDIOCMCAPTURE, &frameBuffer[ 1 - currentFrame ]);
1045   if ( ret < 0 ) {
1046     PTRACE(1,"PVideoInputDevice_V4L::GetFrameData mcapture2 failed : " << ::strerror(errno));
1047     ClearMapping();
1048     canMap = 0;
1049 
1050     return NormalReadProcess(buffer, bytesReturned);
1051   }
1052   pendingSync[ 1 - currentFrame ] = PTrue;
1053 
1054   // device does support memory mapping, get data
1055 
1056   // wait for the frame to load.
1057   ret = ::ioctl(videoFd, VIDIOCSYNC, &currentFrame);
1058   pendingSync[currentFrame] = PFalse;
1059   if (ret < 0) {
1060     PTRACE(1,"PVideoInputDevice_V4L::GetFrameData csync failed : " << ::strerror(errno));
1061     ClearMapping();
1062     canMap = 0;
1063 
1064     return NormalReadProcess(buffer, bytesReturned);
1065   }
1066 
1067   // If converting on the fly do it from frame store to output buffer, otherwise do
1068   // straight copy.
1069   if (converter != NULL)
1070       converter->Convert(videoBuffer + frame.offsets[currentFrame], buffer, bytesReturned);
1071   else {
1072     memcpy(buffer, videoBuffer + frame.offsets[currentFrame], frameBytes);
1073     if (bytesReturned != NULL)
1074       *bytesReturned = frameBytes;
1075   }
1076 
1077   // change buffers
1078   currentFrame = 1 - currentFrame;
1079 
1080   return PTrue;
1081 }
1082 
1083 //This video device does not support memory mapping - so
1084 // use normal read process to extract a frame of video data.
NormalReadProcess(BYTE * resultBuffer,PINDEX * bytesReturned)1085 PBoolean PVideoInputDevice_V4L::NormalReadProcess(BYTE *resultBuffer, PINDEX *bytesReturned)
1086 {
1087 
1088    ssize_t ret;
1089    ret = -1;
1090    while (ret < 0) {
1091 
1092      ret = ::read(videoFd, resultBuffer, frameBytes);
1093      if ((ret < 0) && (errno == EINTR))
1094        continue;
1095 
1096       if (ret < 0) {
1097         PTRACE(1,"PVideoInputDevice_V4L::NormalReadProcess() failed");
1098         return PFalse;
1099       }
1100     }
1101 
1102     if ((PINDEX)ret != frameBytes) {
1103       PTRACE(1,"PVideoInputDevice_V4L::NormalReadProcess() returned a short read");
1104       // Not a completely fatal. Maybe it should return PFalse instead of a partial
1105       // image though?
1106       // return PFalse;
1107     }
1108 
1109     if (converter != NULL)
1110       return converter->ConvertInPlace(resultBuffer, bytesReturned);
1111 
1112     if (bytesReturned != NULL)
1113       *bytesReturned = frameBytes;
1114 
1115     return PTrue;
1116 }
1117 
ClearMapping()1118 void PVideoInputDevice_V4L::ClearMapping()
1119 {
1120   if ((canMap == 1) && (videoBuffer != NULL)) {
1121     for (int i=0; i<2; i++) {
1122       if (pendingSync[i]) {
1123         int res = ::ioctl(videoFd, VIDIOCSYNC, &i);
1124         if (res < 0)
1125           PTRACE(1,"PVideoInputDevice_V4L::GetFrameData csync failed : " << ::strerror(errno));
1126           pendingSync[i] = PFalse;
1127         }
1128         ::munmap(videoBuffer, frame.size);
1129     }
1130   }
1131 
1132   canMap = -1;
1133   videoBuffer = NULL;
1134 }
1135 
1136 
1137 
VerifyHardwareFrameSize(unsigned width,unsigned height)1138 PBoolean PVideoInputDevice_V4L::VerifyHardwareFrameSize(unsigned width, unsigned height)
1139 {
1140   struct video_window vwin;
1141 
1142   if (HINT(HINT_FORCE_LARGE_SIZE)) {
1143     if(  (width==352) && (height==288) ) {
1144       PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize USB OK  352x288 ");
1145       return PTrue;
1146     } else {
1147       PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize USB FAIL "<<width<<"x"<<height);
1148       return PFalse;
1149     }
1150   }
1151 
1152   if (HINT(HINT_ALWAYS_WORKS_320_240) &&  (width==320) && (height==240) ) {
1153     PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize OK  for  320x240 ");
1154     return PTrue;
1155   }
1156 
1157   if (HINT(HINT_ALWAYS_WORKS_640_480) &&  (width==640) && (height==480) ) {
1158     PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize OK for 640x480 ");
1159     return PTrue;
1160   }
1161 
1162   if (HINT(HINT_CGWIN_FAILS)) {
1163     PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize fails for size "
1164             << width << "x" << height);
1165     return PFalse;
1166   }
1167 
1168   // Request current hardware frame size
1169   if (::ioctl(videoFd, VIDIOCGWIN, &vwin) < 0) {
1170     PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize VIDIOCGWIN1 error::" << ::strerror(errno));
1171     return PFalse;
1172   }
1173 
1174   // Request the width and height
1175   vwin.width  = width;
1176   vwin.height = height;
1177 
1178   // The only defined flags appear to be as status indicators
1179   // returned in the CGWIN call.  At least the bttv driver fails
1180   // when flags isn't zero.  Check the driver hints for clearing
1181   // the flags.
1182   if (HINT(HINT_CSWIN_ZERO_FLAGS)) {
1183     PTRACE(1,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize: Clearing flags field");
1184     vwin.flags = 0;
1185   }
1186 
1187   ::ioctl(videoFd, VIDIOCSWIN, &vwin);
1188 
1189   // Read back settings to be careful about existing (broken) V4L drivers
1190   if (::ioctl(videoFd, VIDIOCGWIN, &vwin) < 0) {
1191     PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize VIDIOCGWIN2 error::" << ::strerror(errno));
1192     return PFalse;
1193   }
1194 
1195   if ((vwin.width != width) || (vwin.height != height)) {
1196     PTRACE(3,"PVideoInputDevice_V4L\t VerifyHardwareFrameSize Size mismatch.");
1197     return PFalse;
1198   }
1199 
1200   return PTrue;
1201 }
1202 
GetBrightness()1203 int PVideoInputDevice_V4L::GetBrightness()
1204 {
1205   if (!IsOpen())
1206     return -1;
1207 
1208   struct video_picture vp;
1209 
1210   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1211     return -1;
1212   frameBrightness = vp.brightness;
1213 
1214   return frameBrightness;
1215 }
1216 
1217 
GetWhiteness()1218 int PVideoInputDevice_V4L::GetWhiteness()
1219 {
1220   if (!IsOpen())
1221     return -1;
1222 
1223   struct video_picture vp;
1224 
1225   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1226     return -1;
1227   frameWhiteness = vp.whiteness;
1228 
1229   return frameWhiteness;
1230 }
1231 
GetColour()1232 int PVideoInputDevice_V4L::GetColour()
1233 {
1234   if (!IsOpen())
1235     return -1;
1236 
1237   struct video_picture vp;
1238 
1239   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1240     return -1;
1241   frameColour = vp.colour;
1242 
1243   return frameColour;
1244 }
1245 
1246 
1247 
GetContrast()1248 int PVideoInputDevice_V4L::GetContrast()
1249 {
1250   if (!IsOpen())
1251     return -1;
1252 
1253   struct video_picture vp;
1254 
1255   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1256     return -1;
1257   frameContrast = vp.contrast;
1258 
1259  return frameContrast;
1260 }
1261 
GetHue()1262 int PVideoInputDevice_V4L::GetHue()
1263 {
1264   if (!IsOpen())
1265     return -1;
1266 
1267   struct video_picture vp;
1268 
1269   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1270     return -1;
1271   frameHue = vp.hue;
1272 
1273   return frameHue;
1274 }
1275 
SetBrightness(unsigned newBrightness)1276 PBoolean PVideoInputDevice_V4L::SetBrightness(unsigned newBrightness)
1277 {
1278   if (!IsOpen())
1279     return PFalse;
1280 
1281   struct video_picture vp;
1282 
1283   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1284     return PFalse;
1285 
1286   vp.brightness = newBrightness;
1287   if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1288     return PFalse;
1289 
1290   frameBrightness=newBrightness;
1291   return PTrue;
1292 }
SetWhiteness(unsigned newWhiteness)1293 PBoolean PVideoInputDevice_V4L::SetWhiteness(unsigned newWhiteness)
1294 {
1295   if (!IsOpen())
1296     return PFalse;
1297 
1298   struct video_picture vp;
1299 
1300   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1301     return PFalse;
1302 
1303   vp.whiteness = newWhiteness;
1304   if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1305     return PFalse;
1306 
1307   frameWhiteness = newWhiteness;
1308   return PTrue;
1309 }
1310 
SetColour(unsigned newColour)1311 PBoolean PVideoInputDevice_V4L::SetColour(unsigned newColour)
1312 {
1313   if (!IsOpen())
1314     return PFalse;
1315 
1316   struct video_picture vp;
1317 
1318   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1319     return PFalse;
1320 
1321   vp.colour = newColour;
1322   if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1323     return PFalse;
1324 
1325   frameColour = newColour;
1326   return PTrue;
1327 }
SetContrast(unsigned newContrast)1328 PBoolean PVideoInputDevice_V4L::SetContrast(unsigned newContrast)
1329 {
1330   if (!IsOpen())
1331     return PFalse;
1332 
1333   struct video_picture vp;
1334 
1335   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1336     return PFalse;
1337 
1338   vp.contrast = newContrast;
1339   if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1340     return PFalse;
1341 
1342   frameContrast = newContrast;
1343   return PTrue;
1344 }
1345 
SetHue(unsigned newHue)1346 PBoolean PVideoInputDevice_V4L::SetHue(unsigned newHue)
1347 {
1348   if (!IsOpen())
1349     return PFalse;
1350 
1351   struct video_picture vp;
1352 
1353   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1354     return PFalse;
1355 
1356   vp.hue = newHue;
1357   if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1358     return PFalse;
1359 
1360    frameHue=newHue;
1361   return PTrue;
1362 }
1363 
GetParameters(int * whiteness,int * brightness,int * colour,int * contrast,int * hue)1364 PBoolean PVideoInputDevice_V4L::GetParameters (int *whiteness, int *brightness,
1365                                       int *colour, int *contrast, int *hue)
1366 {
1367   if (!IsOpen())
1368     return PFalse;
1369 
1370   struct video_picture vp;
1371 
1372   if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1373     {
1374       PTRACE(3, "GetParams bombs out!");
1375       return PFalse;
1376     }
1377 
1378   *brightness = vp.brightness;
1379   *colour     = vp.colour;
1380   *contrast   = vp.contrast;
1381   *hue        = vp.hue;
1382   *whiteness  = vp.whiteness;
1383 
1384   frameBrightness = *brightness;
1385   frameColour     = *colour;
1386   frameContrast   = *contrast;
1387   frameHue        = *hue;
1388   frameWhiteness  = *whiteness;
1389 
1390   return PTrue;
1391 }
1392 
TestAllFormats()1393 PBoolean PVideoInputDevice_V4L::TestAllFormats()
1394 {
1395   return PTrue;
1396 }
1397 
RefreshCapabilities()1398 PBoolean PVideoInputDevice_V4L::RefreshCapabilities()
1399 {
1400   if (::ioctl(videoFd, VIDIOCGCAP, &videoCapability) < 0)  {
1401     PTRACE(1,"PVideoInputV4lDevice:: get device capablilities failed : "<< ::strerror(errno));
1402     return PFalse;
1403   }
1404   return PTrue;
1405 }
1406 
1407 
1408 // End Of File ///////////////////////////////////////////////////////////////
1409