Removed warnings under Solaris
[pwlib.git] / plugins / vidinput_v4l / vidinput_v4l.cxx
bloba31c08c7eabe0f8805f6706a67a663991f3d3619
1 /*
2 * video4linux.cxx
4 * Classes to support streaming video input (grabbing) and output.
6 * Portable Windows Library
8 * Copyright (c) 1993-2000 Equivalence Pty. Ltd.
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/
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.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): Derek Smithies (derek@indranet.co.nz)
25 * Mark Cooke (mpc@star.sr.bham.ac.uk)
27 * $Log$
28 * Revision 1.10 2004/05/13 22:22:14 dereksmithies
29 * Fix a problem with duplicate user friendly names.
31 * Revision 1.9 2004/02/15 22:10:10 anoncvs_net-mud
32 * Applied patch from Frédéric Crozat <fcrozat@mandrakesoft.com> for buggy
33 * Quickcam driver.
35 * Revision 1.8 2004/02/12 08:09:51 csoutheren
36 * Patch for ALSA driver, thanks to Julien Puydt
38 * Revision 1.7 2004/02/06 22:21:17 dominance
39 * fixed device detection when refreshing the device list. Patch supplied by PUYDT Julien <julien.puydt@laposte.net>. Thanks to Damien Sandras to point out this and for Julien to provide the fix this fast!
41 * Revision 1.6 2004/01/18 14:22:12 dereksmithies
42 * Use names that are substrings of the actual device name, to open the device.
44 * Revision 1.5 2004/01/18 11:13:08 dereksmithies
45 * Tidy up code & make more clear. Guarantee that tables of names are populated.
47 * Revision 1.4 2003/12/07 21:03:32 dominance
48 * bttv of 2.4.23 doesn't seem to need anymore the hinting workaround.
50 * Revision 1.3 2003/11/25 22:55:13 dsandras
51 * Added fallback using major and minor numbers for detection of devices when /proc/video doesn't exist (some 2.4 kernels and all 2.6 kernels).
53 * Revision 1.2 2003/11/18 10:42:09 csoutheren
54 * Changed to work with new plugins
56 * Revision 1.1 2003/11/14 06:15:37 csoutheren
57 * Initial version thanks to Snark and Damien
59 * Revision 1.39 2003/03/20 23:38:06 dereks
60 * Fixes in handling of flags, and test for device opening
62 * Revision 1.38 2003/03/17 07:52:52 robertj
63 * Removed canCaptureVideo variable as this is really a virtual function to
64 * distinguish PVideoOutputDevice from PVideoInputDevice, it is not dynamic.
66 * Revision 1.37 2003/03/06 02:43:43 dereks
67 * Make error messages slightly more descriptive.
69 * Revision 1.36 2002/09/09 22:16:54 dereks
70 * update hints for spca50x camera.
72 * Revision 1.35 2002/09/08 22:01:56 dereks
73 * Add support for Intel PC Pro Camera, spca50x driver, Thanks Dennis Gilmore!
75 * Revision 1.34 2002/06/05 12:29:16 craigs
76 * Changes for gcc 3.1
78 * Revision 1.33 2002/04/21 22:02:35 dereks
79 * Tidy up test for existance of video devices. Thanks Guilhem Tardy.
81 * Revision 1.32 2002/04/17 21:54:06 dereks
82 * Improve searching of proc file system for video device names. Thanks Guilhem Tardy.
84 * Revision 1.31 2002/04/13 07:54:38 rogerh
85 * Add CPiA camera hint to work around driver bug.
86 * From Damien Sandras and Keith Packard.
88 * Revision 1.30 2002/04/08 21:18:24 rogerh
89 * Emulate original behaviour of pwlib when Open and then SetVideoFormat
90 * are called. Tested by Mark Cooke.
92 * Revision 1.29 2002/04/05 06:41:54 rogerh
93 * Apply video changes from Damien Sandras <dsandras@seconix.com>.
94 * The Video Channel and Format are no longer set in Open(). Instead
95 * call the new SetVideoChannelFormat() method. This makes video capture
96 * and GnomeMeeting more stable with certain Linux video capture devices.
98 * Revision 1.28 2002/01/26 23:58:15 craigs
99 * Changed for GCC 3.0 compatibility, thanks to manty@manty.net
101 * Revision 1.27 2002/01/16 03:43:01 dereks
102 * Match every VIDIOCMCAPTURE with a VIDIOCSYNC.
104 * Revision 1.26 2002/01/04 04:11:45 dereks
105 * Add video flip code from Walter Whitlock, which flips code at the grabber.
107 * Revision 1.25 2001/12/10 22:22:48 dereks
108 * Add hint so Logitech USB Camera will only grab in large video size.
110 * Revision 1.24 2001/12/08 00:59:44 robertj
111 * Added hint for BT879 chips, thanks Damian Sandras.
113 * Revision 1.23 2001/12/06 22:15:09 dereks
114 * Additional debugging lines
116 * Revision 1.22 2001/11/30 00:14:46 dereks
117 * Fix frame rate limitation.
119 * Revision 1.21 2001/11/28 05:10:19 robertj
120 * Added enable of TV card sound when grabbing, thanks Santiago Garcia Mantinan
122 * Revision 1.20 2001/11/28 00:07:32 dereks
123 * Locking added to PVideoChannel, allowing reader/writer to be changed mid call
124 * Enabled adjustment of the video frame rate
125 * New fictitous image, a blank grey area
127 * Revision 1.19 2001/11/05 01:03:20 dereks
128 * Fix error in collection of video data. Frame rate is now double of that
129 * obtained previously.
131 * Revision 1.18 2001/08/22 02:04:43 robertj
132 * Resolved confusion with YUV411P and YUV420P video formats, thanks Mark Cooke.
134 * Revision 1.17 2001/08/20 07:01:26 robertj
135 * Fixed wierd problems with YUV411P and YUV420P formats, thanks Mark Cooke.
137 * Revision 1.16 2001/08/03 04:21:51 dereks
138 * Add colour/size conversion for YUV422->YUV411P
139 * Add Get/Set Brightness,Contrast,Hue,Colour for PVideoDevice, and
140 * Linux PVideoInputDevice.
141 * Add lots of PTRACE statement for debugging colour conversion.
142 * Add support for Sony Vaio laptop under linux. Requires 2.4.7 kernel.
144 * Revision 1.15 2001/03/20 02:21:57 robertj
145 * More enhancements from Mark Cooke
147 * Revision 1.14 2001/03/08 23:08:28 robertj
148 * Fixed incorrect usage of VIDIOCSYNC, thanks Thorsten Westheider
150 * Revision 1.13 2001/03/08 21:46:11 dereks
151 * Removed check when setting framesize. Thanks Mark Cooke
153 * Revision 1.12 2001/03/08 08:31:34 robertj
154 * Numerous enhancements to the video grabbing code including resizing
155 * infrastructure to converters. Thanks a LOT, Mark Cooke.
157 * Revision 1.11 2001/03/08 03:59:13 robertj
158 * Fixed previous change, needed to allow for -1 as chammelNumber in Open().
160 * Revision 1.10 2001/03/08 02:23:17 robertj
161 * Added improved defaulting of video formats so Open() does not fail.
163 * Revision 1.9 2001/03/07 23:46:18 robertj
164 * Double check the v4l device did actually change colour format, thanks Mark Cooke.
166 * Revision 1.8 2001/03/07 01:42:59 dereks
167 * miscellaneous video fixes. Works on linux now. Add debug statements
168 * (at PTRACE level of 1)
170 * Revision 1.7 2001/03/07 00:10:05 robertj
171 * Improved the device list, uses /proc, thanks Thorsten Westheider.
173 * Revision 1.6 2001/03/03 23:25:07 robertj
174 * Fixed use of video conversion function, returning bytes in destination frame.
176 * Revision 1.5 2001/03/03 06:13:01 robertj
177 * Major upgrade of video conversion and grabbing classes.
179 * Revision 1.4 2000/12/19 22:20:26 dereks
180 * Add video channel classes to connect to the PwLib PVideoInputDevice class.
181 * Add PFakeVideoInput class to generate test images for video.
183 * Revision 1.3 2000/07/30 03:54:28 robertj
184 * Added more colour formats to video device enum.
186 * Revision 1.2 2000/07/26 06:13:25 robertj
187 * Added missing pragma implementation for GNU headers.
189 * Revision 1.1 2000/07/26 02:40:30 robertj
190 * Added video I/O devices.
194 #pragma implementation "vidinput_v4l.h"
196 #include "vidinput_v4l.h"
197 #include <sys/utsname.h>
199 PCREATE_VIDINPUT_PLUGIN(V4L, PVideoInputV4lDevice);
201 ///////////////////////////////////////////////////////////////////////////////
202 // Linux Video4Linux Driver Hints Tables.
204 // In an ideal API, we wouldn't need these hints on setup. There are enough
205 // wrinkles it seems we have to provide a static list of hints for known
206 // issues.
208 #define HINT_CSWIN_ZERO_FLAGS 0x0001
209 #define HINT_CSPICT_ALWAYS_WORKS 0x0002 /// ioctl return value indicates pict was set ok.
210 #define HINT_CGPICT_DOESNT_SET_PALETTE 0x0004
211 #define HINT_HAS_PREF_PALETTE 0x0008 /// use this palette with this camera.
212 #define HINT_ALWAYS_WORKS_320_240 0x0010 /// Camera always opens OK at this size.
213 #define HINT_ALWAYS_WORKS_640_480 0x0020 /// Camera always opens OK at this size.
214 #define HINT_ONLY_WORKS_PREF_PALETTE 0x0040 /// Camera always (and only) opens at pref palette.
215 #define HINT_CGWIN_FAILS 0x0080 /// ioctl VIDIOCGWIN always fails.
216 #define HINT_FORCE_LARGE_SIZE 0x0100 /// driver does not work in small video size.
217 #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.
218 #define HINT_FORCE_DBLBUF 0x0400 /// Force double buffering on quickcam express
220 static struct {
221 char *name_regexp; // String used to match the driver name
222 char *name; // String used for ptrace output
223 char *version; // Apply the hint if kernel
224 // version < given version,
225 // 0 means always apply
226 unsigned hints; // Hint flags
227 int pref_palette; // Preferred palette.
228 } driver_hints[] = {
230 /**Philips usb web cameras
231 Native format is 420(P) so use it.
234 { "^Philips [0-9]+ webcam$",
235 "Philips USB webcam",
236 NULL,
237 HINT_HAS_PREF_PALETTE,
238 VIDEO_PALETTE_YUV420P },
240 /**Brooktree based capture boards.
242 The current bttv driver doesn't fail CSPICT calls with unsupported
243 palettes. It also doesn't return a useful value from CGPICT calls
244 to readback the palette. Not needed anymore from 2.4.23
246 { "^BT8(4|7)(8|9)",
247 "Brooktree BT848 and BT878 based capture boards",
248 "2.4.23",
249 HINT_CSWIN_ZERO_FLAGS |
250 HINT_CSPICT_ALWAYS_WORKS |
251 HINT_CGPICT_DOESNT_SET_PALETTE |
252 HINT_HAS_PREF_PALETTE,
253 VIDEO_PALETTE_YUV420P },
255 /** Quickcam Express (qc-usb driver) */
256 { "Logitech USB Camera",
257 "Quickcam Express (qc-usb driver)",
258 NULL,
259 HINT_FORCE_DBLBUF,
262 /** Sony Vaio Motion Eye camera
263 Linux kernel 2.4.7 has meye.c driver module.
265 { "meye",
266 "Sony Vaio Motion Eye Camera",
267 NULL,
268 HINT_CGPICT_DOESNT_SET_PALETTE |
269 HINT_CSPICT_ALWAYS_WORKS |
270 HINT_ALWAYS_WORKS_320_240 |
271 HINT_ALWAYS_WORKS_640_480 |
272 HINT_CGWIN_FAILS |
273 HINT_ONLY_WORKS_PREF_PALETTE |
274 HINT_HAS_PREF_PALETTE,
275 VIDEO_PALETTE_YUV422 },
277 /** USB camera, which only works in large size.
279 { "Logitech USB Webcam",
280 "Logitech USB Webcam which works in large size only",
281 NULL,
282 HINT_FORCE_LARGE_SIZE,
283 VIDEO_PALETTE_YUV420P
286 /** Creative VideoBlaster Webcam II USB
288 {"CPiA Camera",
289 "CPIA which works with cpia and cpia_usb driver modules",
290 NULL,
291 HINT_FORCE_DEPTH_16 |
292 HINT_ONLY_WORKS_PREF_PALETTE |
293 HINT_HAS_PREF_PALETTE,
294 VIDEO_PALETTE_YUV422
297 /** Intel PC Pro Camera
300 { "SPCA50X USB Camera",
301 "Intel PC Pro Camera uses the spca50x driver",
302 NULL,
303 HINT_ONLY_WORKS_PREF_PALETTE |
304 HINT_HAS_PREF_PALETTE,
305 VIDEO_PALETTE_RGB24
309 /** Default device with no special settings
311 { "",
312 "V4L Supported Device",
319 #define HINT(h) ((driver_hints[hint_index].hints & h) ? TRUE : FALSE)
320 #define MAJOR(a) (int)((unsigned short) (a) >> 8)
321 #define MINOR(a) (int)((unsigned short) (a) & 0xFF)
322 // this is used to get more userfriendly names:
323 class V4LNames : public PObject
325 PCLASSINFO(V4LNames, PObject);
326 public:
327 V4LNames() {/* nothing */};
329 void Update ();
331 PString GetUserFriendly(PString devName);
333 PString GetDeviceName(PString userName);
335 PStringList GetInputDeviceNames();
337 protected:
338 void AddUserDeviceName(PString userName, PString devName);
340 PString BuildUserFriendly(PString devname);
342 void PopulateDictionary();
344 void ReadDeviceDirectory(PDirectory devdir, POrdinalToString & vid);
346 PMutex mutex;
347 PStringToString deviceKey;
348 PStringToString userKey;
349 PStringList inputDeviceNames;
352 void
353 V4LNames::Update()
355 PDirectory procvideo("/proc/video/dev");
356 PString entry;
357 PStringList devlist;
359 inputDeviceNames.RemoveAll (); // flush the previous run
360 if (procvideo.Exists()) {
361 if (procvideo.Open(PFileInfo::RegularFile)) {
362 do {
363 entry = procvideo.GetEntryName();
364 if ((entry.Left(5) == "video") || (entry.Left(7) == "capture")) {
365 PString thisDevice = "/dev/video" + entry.Right(1);
366 int videoFd = ::open((const char *)thisDevice, O_RDONLY | O_NONBLOCK);
368 if ((videoFd > 0) || (errno == EBUSY)){
369 BOOL valid = FALSE;
370 struct video_capability videoCaps;
371 if (ioctl(videoFd, VIDIOCGCAP, &videoCaps) >= 0 &&
372 (videoCaps.type & VID_TYPE_CAPTURE) != 0)
373 valid = TRUE;
374 if (videoFd >= 0)
375 close(videoFd);
376 if(valid)
377 inputDeviceNames += thisDevice;
380 } while (procvideo.Next());
383 if (inputDeviceNames.GetSize() == 0) {
384 POrdinalToString vid;
385 ReadDeviceDirectory("/dev/", vid);
387 for (PINDEX i = 0; i < vid.GetSize(); i++) {
388 PINDEX cardnum = vid.GetKeyAt(i);
389 int fd = ::open(vid[cardnum], O_RDONLY | O_NONBLOCK);
390 if ((fd >= 0) || (errno == EBUSY)) {
391 if (fd >= 0)
392 ::close(fd);
393 inputDeviceNames += vid[cardnum];
397 PopulateDictionary();
400 void V4LNames::ReadDeviceDirectory(PDirectory devdir, POrdinalToString & vid)
402 if (!devdir.Open())
403 return;
405 do {
406 PString filename = devdir.GetEntryName();
407 PString devname = devdir + filename;
408 if (devdir.IsSubDir())
409 ReadDeviceDirectory(devname, vid);
410 else {
412 PFileInfo info;
413 if (devdir.GetInfo(info) && info.type == PFileInfo::CharDevice) {
414 struct stat s;
415 if (lstat(devname, &s) == 0) {
417 static const int deviceNumbers[] = { 81 };
418 for (PINDEX i = 0; i < PARRAYSIZE(deviceNumbers); i++) {
419 if (MAJOR(s.st_rdev) == deviceNumbers[i]) {
421 PINDEX num = MINOR(s.st_rdev);
422 if (num <= 63 && num >= 0) {
423 vid.SetAt(num, devname);
430 } while (devdir.Next());
433 void V4LNames::PopulateDictionary()
435 PINDEX i, j;
436 PStringToString tempList;
438 for (i = 0; i < inputDeviceNames.GetSize(); i++) {
439 PString ufname = BuildUserFriendly(inputDeviceNames[i]);
440 tempList.SetAt(inputDeviceNames[i], ufname);
443 //Now, we need to cope with the case where there are two video
444 //devices available, which both have the same user friendly name.
445 //Matching user friendly names have a (X) appended to the name.
446 for (i = 0; i < tempList.GetSize(); i++) {
447 PString userName = tempList.GetDataAt(i);
449 PINDEX matches = 1;
450 for (j = i + 1; j < tempList.GetSize(); j++) {
451 if (tempList.GetDataAt(j) == userName) {
452 matches++;
453 PStringStream revisedUserName;
454 revisedUserName << userName << " (" << matches << ")";
455 tempList.SetDataAt(j, revisedUserName);
460 //At this stage, we have correctly modified the temp list of names.
461 for (j = 0; j < tempList.GetSize(); j++)
462 AddUserDeviceName(tempList.GetDataAt(j), tempList.GetKeyAt(j));
465 PString V4LNames::GetUserFriendly(PString devName)
467 PWaitAndSignal m(mutex);
470 PString result= deviceKey(devName);
471 if (result.IsEmpty())
472 return devName;
474 return result;
477 PString V4LNames::GetDeviceName(PString userName)
479 PWaitAndSignal m(mutex);
481 for (PINDEX i = 0; i < userKey.GetSize(); i++)
482 if (userKey.GetKeyAt(i).Find(userName) != P_MAX_INDEX)
483 return userKey.GetDataAt(i);
485 return userName;
488 void V4LNames::AddUserDeviceName(PString userName, PString devName)
490 if (userName != devName) { // must be a real userName!
491 userKey.SetAt(userName, devName);
492 deviceKey.SetAt(devName, userName);
493 } else { // we didn't find a good userName
494 if (!deviceKey.Contains (devName)) { // never met before: fallback
495 userKey.SetAt(userName, devName);
496 deviceKey.SetAt(devName, userName);
497 } // no else: we already know the pair
501 PString V4LNames::BuildUserFriendly(PString devname)
503 PString Result;
505 int fd = ::open((const char *)devname, O_RDONLY);
506 if(fd < 0) {
507 return devname;
510 struct video_capability videocap;
511 if (::ioctl(fd, VIDIOCGCAP, &videocap) < 0) {
512 ::close(fd);
513 return devname;
516 ::close(fd);
517 PString ufname(videocap.name);
519 return ufname;
522 PStringList V4LNames::GetInputDeviceNames()
524 PWaitAndSignal m(mutex);
525 PStringList result;
526 for (PINDEX i = 0; i < inputDeviceNames.GetSize(); i++)
527 result += GetUserFriendly (inputDeviceNames[i]);
529 return result;
532 static
533 V4LNames & GetNames()
535 static V4LNames names;
536 names.Update();
537 return names;
540 ///////////////////////////////////////////////////////////////////////////////
541 // PVideoInputV4lDevice
543 PVideoInputV4lDevice::PVideoInputV4lDevice()
545 videoFd = -1;
546 hint_index = PARRAYSIZE(driver_hints) - 1;
548 canMap = -1;
549 for (int i=0; i<2; i++)
550 pendingSync[i] = FALSE;
553 PVideoInputV4lDevice::~PVideoInputV4lDevice()
555 Close();
557 static struct {
558 const char * colourFormat;
559 int code;
560 } colourFormatTab[] = {
561 { "Grey", VIDEO_PALETTE_GREY }, //Entries in this table correspond
562 { "RGB32", VIDEO_PALETTE_RGB32 }, //(line by line) to those in the
563 { "RGB24", VIDEO_PALETTE_RGB24 }, // PVideoDevice ColourFormat table.
564 { "RGB565", VIDEO_PALETTE_RGB565 },
565 { "RGB555", VIDEO_PALETTE_RGB555 },
566 { "YUV422", VIDEO_PALETTE_YUV422 },
567 { "YUV422P", VIDEO_PALETTE_YUV422P },
568 { "YUV411", VIDEO_PALETTE_YUV411 },
569 { "YUV411P", VIDEO_PALETTE_YUV411P },
570 { "YUV420", VIDEO_PALETTE_YUV420 },
571 { "YUV420P", VIDEO_PALETTE_YUV420P },
572 { "YUV410P", VIDEO_PALETTE_YUV410P }
576 BOOL PVideoInputV4lDevice::Open(const PString & devName, BOOL startImmediate)
578 struct utsname buf;
579 PString version;
581 uname (&buf);
583 if (buf.release)
584 version = PString (buf.release);
586 Close();
588 PTRACE(1,"PVideoInputV4lDevice: trying to open "<< devName);
590 // check if it is a userfriendly name, and if so, get the real device name
592 PString deviceName = GetNames().GetDeviceName(devName);
593 videoFd = ::open((const char *)deviceName, O_RDWR);
594 if (videoFd < 0) {
595 PTRACE(1,"PVideoInputV4lDevice::Open failed : "<< ::strerror(errno));
596 return FALSE;
599 // get the device capabilities
600 if (::ioctl(videoFd, VIDIOCGCAP, &videoCapability) < 0) {
601 PTRACE(1,"PVideoInputV4lDevice:: get device capablilities failed : "<< ::strerror(errno));
602 ::close (videoFd);
603 videoFd = -1;
604 return FALSE;
607 if ((videoCapability.type & VID_TYPE_CAPTURE) == 0) {
608 PTRACE(1,"PVideoInputV4lDevice:: device capablilities reports cannot capture");
609 ::close (videoFd);
610 videoFd = -1;
611 return FALSE;
614 hint_index = PARRAYSIZE(driver_hints) - 1;
615 PString driver_name(videoCapability.name);
617 // Scan the hint table, looking for regular expression matches with
618 // drivers we hold hints for.
619 PINDEX tbl;
620 for (tbl = 0; tbl < PARRAYSIZE(driver_hints); tbl ++) {
621 PRegularExpression regexp;
622 regexp.Compile(driver_hints[tbl].name_regexp, PRegularExpression::Extended);
624 if (driver_name.FindRegEx(regexp) != P_MAX_INDEX) {
625 PTRACE(1,"PVideoInputV4lDevice::Open: Found driver hints: " << driver_hints[tbl].name);
626 PTRACE(1,"PVideoInputV4lDevice::Open: format: " << driver_hints[tbl].pref_palette);
628 if (driver_hints[tbl].version && !version.IsEmpty ())
629 if (PString (version) < PString (driver_hints[tbl].version)) {
631 PTRACE(1,"PVideoInputV4lDevice::Open: Hints applied because kernel version less than " << driver_hints[tbl].version);
632 hint_index = tbl;
633 break;
635 else {
637 PTRACE(1,"PVideoInputV4lDevice::Open: Hints not applied because kernel version is not less than " << driver_hints[tbl].version);
639 else {
641 hint_index = tbl;
642 break;
648 // Force double-buffering with buggy Quickcam driver.
649 if (HINT (HINT_FORCE_DBLBUF)) {
651 #define QC_IOCTLBASE 220
652 #define VIDIOCQCGCOMPATIBLE _IOR ('v',QC_IOCTLBASE+10,int) /* Get enable workaround for bugs, bitfield */
653 #define VIDIOCQCSCOMPATIBLE _IOWR('v',QC_IOCTLBASE+10,int) /* Set enable workaround for bugs, bitfield */
655 int reg = 2; /* enable double buffering */
656 ::ioctl (videoFd, VIDIOCQCSCOMPATIBLE, &reg);
660 // set height and width
661 frameHeight = PMIN (videoCapability.maxheight, QCIFHeight);
662 frameWidth = PMIN (videoCapability.maxwidth, QCIFWidth);
665 // Init audio
666 struct video_audio videoAudio;
667 if (::ioctl(videoFd, VIDIOCGAUDIO, &videoAudio) >= 0 &&
668 (videoAudio.flags & VIDEO_AUDIO_MUTABLE) != 0) {
669 videoAudio.flags &= ~VIDEO_AUDIO_MUTE;
670 videoAudio.mode = VIDEO_SOUND_MONO;
671 ::ioctl(videoFd, VIDIOCSAUDIO, &videoAudio);
674 return TRUE;
678 BOOL PVideoInputV4lDevice::IsOpen()
680 return videoFd >= 0;
684 BOOL PVideoInputV4lDevice::Close()
686 if (!IsOpen())
687 return FALSE;
690 // Mute audio
691 struct video_audio videoAudio;
692 if (::ioctl(videoFd, VIDIOCGAUDIO, &videoAudio) >= 0 &&
693 (videoAudio.flags & VIDEO_AUDIO_MUTABLE) != 0) {
694 videoAudio.flags |= VIDEO_AUDIO_MUTE;
695 ::ioctl(videoFd, VIDIOCSAUDIO, &videoAudio);
698 ClearMapping();
699 ::close(videoFd);
701 videoFd = -1;
702 canMap = -1;
704 return TRUE;
708 BOOL PVideoInputV4lDevice::Start()
710 return TRUE;
714 BOOL PVideoInputV4lDevice::Stop()
716 return TRUE;
720 BOOL PVideoInputV4lDevice::IsCapturing()
722 return IsOpen();
726 PStringList PVideoInputV4lDevice::GetInputDeviceNames()
728 return GetNames().GetInputDeviceNames();
731 BOOL PVideoInputV4lDevice::SetVideoFormat(VideoFormat newFormat)
733 if (!PVideoDevice::SetVideoFormat(newFormat)) {
734 PTRACE(1,"PVideoDevice::SetVideoFormat\t failed");
735 return FALSE;
738 // The channel and format are both set at the same time with one ioctl().
739 // Get the channel information (to check if channel is valid)
740 // Note: If the channel is -1, we need to search for the first valid channel
741 if (channelNumber == -1) {
742 if (!SetChannel(channelNumber)){
743 PTRACE(1,"PVideoDevice::Cannot set default channel in SetVideoFormat");
744 return FALSE;
748 struct video_channel channel;
749 channel.channel = channelNumber;
750 if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) {
751 PTRACE(1,"VideoInputDevice Get Channel info failed : "<< ::strerror(errno));
752 return FALSE;
755 // set channel information
756 static int fmt[4] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC,
757 VIDEO_MODE_SECAM, VIDEO_MODE_AUTO };
758 channel.norm = fmt[newFormat];
760 // set the information
761 if (::ioctl(videoFd, VIDIOCSCHAN, &channel) >= 0)
762 return TRUE;
764 PTRACE(1,"VideoInputDevice SetChannel failed : "<< ::strerror(errno));
766 if (newFormat != Auto)
767 return FALSE;
769 if (SetVideoFormat(PAL))
770 return TRUE;
771 if (SetVideoFormat(NTSC))
772 return TRUE;
773 if (SetVideoFormat(SECAM))
774 return TRUE;
776 return FALSE;
780 int PVideoInputV4lDevice::GetNumChannels()
782 /* If Opened, return the capability value, else 1 as in videoio.cxx */
783 if (IsOpen ())
784 return videoCapability.channels;
785 else
786 return 1;
790 BOOL PVideoInputV4lDevice::SetChannel(int newChannel)
792 if (!PVideoDevice::SetChannel(newChannel))
793 return FALSE;
795 // get channel information (to check if channel is valid)
796 struct video_channel channel;
797 channel.channel = channelNumber;
798 if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) {
799 PTRACE(1,"VideoInputDevice:: Get info on channel " << channelNumber << " failed : "<< ::strerror(errno));
800 return FALSE;
803 // set channel information
804 channel.channel = channelNumber;
806 // set the information
807 if (::ioctl(videoFd, VIDIOCSCHAN, &channel) < 0) {
808 PTRACE(1,"VideoInputDevice:: Set info on channel " << channelNumber << " failed : "<< ::strerror(errno));
809 return FALSE;
812 return TRUE;
816 BOOL PVideoInputV4lDevice::SetVideoChannelFormat (int newNumber, VideoFormat videoFormat)
818 if (!PVideoDevice::SetChannel(newNumber))
819 return FALSE;
821 if (!PVideoDevice::SetVideoFormat(videoFormat)) {
822 PTRACE(1,"PVideoDevice::SetVideoFormat\t failed");
823 return FALSE;
826 static int fmt[4] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC,
827 VIDEO_MODE_SECAM, VIDEO_MODE_AUTO };
829 // select the specified input and video format
830 // get channel information (to check if channel is valid)
831 struct video_channel channel;
832 channel.channel = channelNumber;
833 if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) {
834 PTRACE(1,"VideoInputDevice Get Channel info failed : "<< ::strerror(errno));
836 return FALSE;
839 // set channel information
840 channel.norm = fmt[videoFormat];
841 channel.channel = channelNumber;
843 // set the information
844 if (::ioctl(videoFd, VIDIOCSCHAN, &channel) < 0) {
845 PTRACE(1,"VideoInputDevice SetChannel failed : "<< ::strerror(errno));
847 return FALSE;
850 return TRUE;
853 BOOL PVideoInputV4lDevice::SetColourFormat(const PString & newFormat)
855 PINDEX colourFormatIndex = 0;
856 while (newFormat != colourFormatTab[colourFormatIndex].colourFormat) {
857 colourFormatIndex++;
858 if (colourFormatIndex >= PARRAYSIZE(colourFormatTab))
859 return FALSE;
862 if (!PVideoDevice::SetColourFormat(newFormat))
863 return FALSE;
865 ClearMapping();
867 // get current picture information
868 struct video_picture pictureInfo;
869 if (::ioctl(videoFd, VIDIOCGPICT, &pictureInfo) < 0) {
870 PTRACE(1,"PVideoInputV4lDevice::Get pict info failed : "<< ::strerror(errno));
871 return FALSE;
874 // set colour format
875 colourFormatCode = colourFormatTab[colourFormatIndex].code;
876 pictureInfo.palette = colourFormatCode;
877 if (HINT (HINT_FORCE_DEPTH_16))
878 pictureInfo.depth = 16;
880 // set the information
881 if (::ioctl(videoFd, VIDIOCSPICT, &pictureInfo) < 0) {
882 PTRACE(1,"PVideoInputV4lDevice::Set pict info failed : "<< ::strerror(errno));
883 PTRACE(1,"PVideoInputV4lDevice:: used code of "<<colourFormatCode);
884 PTRACE(1,"PVideoInputV4lDevice:: palette: "<<colourFormatTab[colourFormatIndex].colourFormat);
885 return FALSE;
889 // Driver only (and always) manages to set the colour format with call to VIDIOCSPICT.
890 if( (HINT(HINT_ONLY_WORKS_PREF_PALETTE) ) &&
891 ( colourFormatCode == driver_hints[hint_index].pref_palette) ) {
892 PTRACE(3,"PVideoInputV4lDevice:: SetColourFormat succeeded with "<<newFormat);
893 return TRUE;
896 // Some drivers always return success for CSPICT, and can't
897 // read the current palette back in CGPICT. We can't do much
898 // more than just check to see if there is a preferred palette,
899 // and fail if the request isn't the preferred palette.
901 if (HINT(HINT_CSPICT_ALWAYS_WORKS) &&
902 HINT(HINT_CGPICT_DOESNT_SET_PALETTE) &&
903 HINT(HINT_HAS_PREF_PALETTE)) {
904 if (colourFormatCode != driver_hints[hint_index].pref_palette)
905 return FALSE;
908 // Some V4L drivers can't use CGPICT to check for errors.
909 if (!HINT(HINT_CGPICT_DOESNT_SET_PALETTE)) {
911 if (::ioctl(videoFd, VIDIOCGPICT, &pictureInfo) < 0) {
912 PTRACE(1,"PVideoInputV4lDevice::Get pict info failed : "<< ::strerror(errno));
913 return FALSE;
916 if (pictureInfo.palette != colourFormatCode)
917 return FALSE;
920 // set the new information
921 return SetFrameSizeConverter(frameWidth, frameHeight, FALSE);
925 BOOL PVideoInputV4lDevice::SetFrameRate(unsigned rate)
927 if (!PVideoDevice::SetFrameRate(rate))
928 return FALSE;
930 return TRUE;
934 BOOL PVideoInputV4lDevice::GetFrameSizeLimits(unsigned & minWidth,
935 unsigned & minHeight,
936 unsigned & maxWidth,
937 unsigned & maxHeight)
939 if (!IsOpen())
940 return FALSE;
942 if(HINT(HINT_FORCE_LARGE_SIZE)) {
943 videoCapability.maxheight = 288;
944 videoCapability.maxwidth = 352;
945 videoCapability.minheight = 288;
946 videoCapability.minwidth = 352;
949 maxHeight = videoCapability.maxheight;
950 maxWidth = videoCapability.maxwidth;
951 minHeight = videoCapability.minheight;
952 minWidth = videoCapability.minwidth;
954 PTRACE(3,"PVideoInputV4lDevice:\t GetFrameSizeLimits. "<<minWidth<<"x"<<minHeight<<" -- "<<maxWidth<<"x"<<maxHeight);
956 return TRUE;
960 BOOL PVideoInputV4lDevice::SetFrameSize(unsigned width, unsigned height)
962 PTRACE(5, "PVideoInputV4lDevice\t SetFrameSize " << width <<"x"<<height << " Initiated.");
963 if (!PVideoDevice::SetFrameSize(width, height)) {
964 PTRACE(3,"PVideoInputV4lDevice\t SetFrameSize "<<width<<"x"<<height<<" FAILED");
965 return FALSE;
968 ClearMapping();
970 if (!VerifyHardwareFrameSize(width, height)) {
971 PTRACE(3,"PVideoInputV4lDevice\t SetFrameSize failed for "<<width<<"x"<<height);
972 PTRACE(3,"VerifyHardwareFrameSize failed.");
973 return FALSE;
976 frameBytes = CalculateFrameBytes(frameWidth, frameHeight, colourFormat);
978 return TRUE;
982 PINDEX PVideoInputV4lDevice::GetMaxFrameBytes()
984 if (converter != NULL) {
985 PINDEX bytes = converter->GetMaxDstFrameBytes();
986 if (bytes > frameBytes)
987 return bytes;
990 return frameBytes;
993 BOOL PVideoInputV4lDevice::GetFrame(PBYTEArray & frame)
995 PINDEX returned;
996 if (!GetFrameData(frame.GetPointer(GetMaxFrameBytes()), &returned))
997 return FALSE;
999 frame.SetSize(returned);
1000 return TRUE;
1003 BOOL PVideoInputV4lDevice::GetFrameData(BYTE *buffer, PINDEX *bytesReturned)
1005 if(frameRate>0) {
1006 frameTimeError += msBetweenFrames;
1008 do {
1009 if ( !GetFrameDataNoDelay(buffer, bytesReturned))
1011 return FALSE;
1013 PTime now;
1014 PTimeInterval delay = now - previousFrameTime;
1015 frameTimeError -= (int)delay.GetMilliSeconds();
1016 previousFrameTime = now;
1017 } while(frameTimeError > 0) ;
1019 return TRUE;
1021 return GetFrameDataNoDelay(buffer, bytesReturned);
1025 BOOL PVideoInputV4lDevice::GetFrameDataNoDelay(BYTE * buffer, PINDEX * bytesReturned)
1027 if (canMap < 0) {
1028 //When canMap is < 0, it is the first use of GetFrameData. Check for memory mapping.
1029 if (::ioctl(videoFd, VIDIOCGMBUF, &frame) < 0) {
1030 canMap=0;
1031 PTRACE(3, "VideoGrabber " << deviceName << " cannot do memory mapping - GMBUF failed.");
1032 //This video device cannot do memory mapping.
1033 } else {
1034 videoBuffer = (BYTE *)::mmap(0, frame.size, PROT_READ|PROT_WRITE, MAP_SHARED, videoFd, 0);
1036 if (videoBuffer < 0) {
1037 canMap = 0;
1038 PTRACE(3, "VideoGrabber " << deviceName << " cannot do memory mapping - ::mmap failed.");
1039 //This video device cannot do memory mapping.
1040 } else {
1041 canMap = 1;
1043 frameBuffer[0].frame = 0;
1044 frameBuffer[0].format = colourFormatCode;
1045 frameBuffer[0].width = frameWidth;
1046 frameBuffer[0].height = frameHeight;
1048 frameBuffer[1].frame = 1;
1049 frameBuffer[1].format = colourFormatCode;
1050 frameBuffer[1].width = frameWidth;
1051 frameBuffer[1].height = frameHeight;
1053 currentFrame = 0;
1054 int ret;
1055 ret = ::ioctl(videoFd, VIDIOCMCAPTURE, &frameBuffer[currentFrame]);
1056 if (ret < 0) {
1057 PTRACE(1,"PVideoInputV4lDevice::GetFrameData mcapture1 failed : " << ::strerror(errno));
1058 ClearMapping();
1059 canMap = 0;
1060 //This video device cannot do memory mapping.
1062 pendingSync[currentFrame] = TRUE;
1067 if (canMap == 0)
1069 return NormalReadProcess(buffer, bytesReturned);
1072 /*****************************
1073 * The xawtv package from http://bytesex.org/xawtv/index.html
1074 * contains a programming-FAQ by Gerd Knorr.
1075 * For streaming video with video4linux at the full frame rate
1076 * (25 hz PAL, 30 hz NTSC) you need to,
1078 * videoiomcapture frame 0 (setup)
1080 * loop:
1081 * videoiomcapture frame 1 (returns immediately)
1082 * videoiocsync frame 0 (waits on the data)
1083 * goto loop:
1085 * the loop body could also have been:
1086 * videoiomcapture frame 0 (returns immediately)
1087 * videoiocsync frame 1 (waits on the data)
1089 * The driver requires each mcapture has a corresponding sync.
1090 * Thus, you use the pendingSync array.
1092 * After the loop is finished, you need a videoiocsync 0.
1095 // trigger capture of next frame in this buffer.
1096 // fallback to read() on errors.
1097 int ret = -1;
1099 ret = ::ioctl(videoFd, VIDIOCMCAPTURE, &frameBuffer[ 1 - currentFrame ]);
1100 if ( ret < 0 ) {
1101 PTRACE(1,"PVideoInputV4lDevice::GetFrameData mcapture2 failed : " << ::strerror(errno));
1102 ClearMapping();
1103 canMap = 0;
1105 return NormalReadProcess(buffer, bytesReturned);
1107 pendingSync[ 1 - currentFrame ] = TRUE;
1109 // device does support memory mapping, get data
1111 // wait for the frame to load.
1112 ret = ::ioctl(videoFd, VIDIOCSYNC, &currentFrame);
1113 pendingSync[currentFrame] = FALSE;
1114 if (ret < 0) {
1115 PTRACE(1,"PVideoInputV4lDevice::GetFrameData csync failed : " << ::strerror(errno));
1116 ClearMapping();
1117 canMap = 0;
1119 return NormalReadProcess(buffer, bytesReturned);
1122 // If converting on the fly do it from frame store to output buffer, otherwise do
1123 // straight copy.
1124 if (converter != NULL)
1125 converter->Convert(videoBuffer + frame.offsets[currentFrame], buffer, bytesReturned);
1126 else {
1127 memcpy(buffer, videoBuffer + frame.offsets[currentFrame], frameBytes);
1128 if (bytesReturned != NULL)
1129 *bytesReturned = frameBytes;
1132 // change buffers
1133 currentFrame = 1 - currentFrame;
1135 return TRUE;
1138 //This video device does not support memory mapping - so
1139 // use normal read process to extract a frame of video data.
1140 BOOL PVideoInputV4lDevice::NormalReadProcess(BYTE *resultBuffer, PINDEX *bytesReturned)
1143 ssize_t ret;
1144 ret = -1;
1145 while (ret < 0) {
1147 ret = ::read(videoFd, resultBuffer, frameBytes);
1148 if ((ret < 0) && (errno == EINTR))
1149 continue;
1151 if (ret < 0) {
1152 PTRACE(1,"PVideoInputV4lDevice::NormalReadProcess() failed");
1153 return FALSE;
1157 if ((PINDEX)ret != frameBytes) {
1158 PTRACE(1,"PVideoInputV4lDevice::NormalReadProcess() returned a short read");
1159 // Not a completely fatal. Maybe it should return FALSE instead of a partial
1160 // image though?
1161 // return FALSE;
1164 if (converter != NULL)
1165 return converter->ConvertInPlace(resultBuffer, bytesReturned);
1167 if (bytesReturned != NULL)
1168 *bytesReturned = frameBytes;
1170 return TRUE;
1173 void PVideoInputV4lDevice::ClearMapping()
1175 if ((canMap == 1) && (videoBuffer != NULL)) {
1176 for (int i=0; i<2; i++)
1177 if (pendingSync[i]) {
1178 int res = ::ioctl(videoFd, VIDIOCSYNC, &i);
1179 if (res < 0)
1180 PTRACE(1,"PVideoInputV4lDevice::GetFrameData csync failed : " << ::strerror(errno));
1181 pendingSync[i] = FALSE;
1183 ::munmap(videoBuffer, frame.size);
1186 canMap = -1;
1187 videoBuffer = NULL;
1192 BOOL PVideoInputV4lDevice::VerifyHardwareFrameSize(unsigned width,
1193 unsigned height)
1195 struct video_window vwin;
1197 if (HINT(HINT_FORCE_LARGE_SIZE))
1198 if( (width==352) && (height==288) ) {
1199 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize USB OK 352x288 ");
1200 return TRUE;
1201 } else {
1202 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize USB FAIL "<<width<<"x"<<height);
1203 return FALSE;
1206 if (HINT(HINT_ALWAYS_WORKS_320_240) && (width==320) && (height==240) ) {
1207 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize OK for 320x240 ");
1208 return TRUE;
1211 if (HINT(HINT_ALWAYS_WORKS_640_480) && (width==640) && (height==480) ) {
1212 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize OK for 640x480 ");
1213 return TRUE;
1216 if (HINT(HINT_CGWIN_FAILS)) {
1217 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize fails for size "
1218 << width << "x" << height);
1219 return FALSE;
1222 // Request current hardware frame size
1223 if (::ioctl(videoFd, VIDIOCGWIN, &vwin) < 0) {
1224 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize VIDIOCGWIN1 error::" << ::strerror(errno));
1225 return FALSE;
1228 // Request the width and height
1229 vwin.width = width;
1230 vwin.height = height;
1232 // The only defined flags appear to be as status indicators
1233 // returned in the CGWIN call. At least the bttv driver fails
1234 // when flags isn't zero. Check the driver hints for clearing
1235 // the flags.
1236 if (HINT(HINT_CSWIN_ZERO_FLAGS)) {
1237 PTRACE(1,"PVideoInputV4lDevice\t VerifyHardwareFrameSize: Clearing flags field");
1238 vwin.flags = 0;
1241 ::ioctl(videoFd, VIDIOCSWIN, &vwin);
1243 // Read back settings to be careful about existing (broken) V4L drivers
1244 if (::ioctl(videoFd, VIDIOCGWIN, &vwin) < 0) {
1245 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize VIDIOCGWIN2 error::" << ::strerror(errno));
1246 return FALSE;
1249 if ((vwin.width != width) || (vwin.height != height)) {
1250 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize Size mismatch.");
1251 return FALSE;
1254 return TRUE;
1257 int PVideoInputV4lDevice::GetBrightness()
1259 if (!IsOpen())
1260 return -1;
1262 struct video_picture vp;
1264 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1265 return -1;
1266 frameBrightness = vp.brightness;
1268 return frameBrightness;
1272 int PVideoInputV4lDevice::GetWhiteness()
1274 if (!IsOpen())
1275 return -1;
1277 struct video_picture vp;
1279 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1280 return -1;
1281 frameWhiteness = vp.whiteness;
1283 return frameWhiteness;
1286 int PVideoInputV4lDevice::GetColour()
1288 if (!IsOpen())
1289 return -1;
1291 struct video_picture vp;
1293 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1294 return -1;
1295 frameColour = vp.colour;
1297 return frameColour;
1302 int PVideoInputV4lDevice::GetContrast()
1304 if (!IsOpen())
1305 return -1;
1307 struct video_picture vp;
1309 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1310 return -1;
1311 frameContrast = vp.contrast;
1313 return frameContrast;
1316 int PVideoInputV4lDevice::GetHue()
1318 if (!IsOpen())
1319 return -1;
1321 struct video_picture vp;
1323 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1324 return -1;
1325 frameHue = vp.hue;
1327 return frameHue;
1330 BOOL PVideoInputV4lDevice::SetBrightness(unsigned newBrightness)
1332 if (!IsOpen())
1333 return FALSE;
1335 struct video_picture vp;
1337 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1338 return FALSE;
1340 vp.brightness = newBrightness;
1341 if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1342 return FALSE;
1344 frameBrightness=newBrightness;
1345 return TRUE;
1347 BOOL PVideoInputV4lDevice::SetWhiteness(unsigned newWhiteness)
1349 if (!IsOpen())
1350 return FALSE;
1352 struct video_picture vp;
1354 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1355 return FALSE;
1357 vp.whiteness = newWhiteness;
1358 if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1359 return FALSE;
1361 frameWhiteness = newWhiteness;
1362 return TRUE;
1365 BOOL PVideoInputV4lDevice::SetColour(unsigned newColour)
1367 if (!IsOpen())
1368 return FALSE;
1370 struct video_picture vp;
1372 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1373 return FALSE;
1375 vp.colour = newColour;
1376 if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1377 return FALSE;
1379 frameColour = newColour;
1380 return TRUE;
1382 BOOL PVideoInputV4lDevice::SetContrast(unsigned newContrast)
1384 if (!IsOpen())
1385 return FALSE;
1387 struct video_picture vp;
1389 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1390 return FALSE;
1392 vp.contrast = newContrast;
1393 if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1394 return FALSE;
1396 frameContrast = newContrast;
1397 return TRUE;
1400 BOOL PVideoInputV4lDevice::SetHue(unsigned newHue)
1402 if (!IsOpen())
1403 return FALSE;
1405 struct video_picture vp;
1407 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1408 return FALSE;
1410 vp.hue = newHue;
1411 if (::ioctl(videoFd, VIDIOCSPICT, &vp) < 0)
1412 return FALSE;
1414 frameHue=newHue;
1415 return TRUE;
1418 BOOL PVideoInputV4lDevice::GetParameters (int *whiteness, int *brightness,
1419 int *colour, int *contrast, int *hue)
1421 if (!IsOpen())
1422 return FALSE;
1424 struct video_picture vp;
1426 if (::ioctl(videoFd, VIDIOCGPICT, &vp) < 0)
1428 PTRACE(3, "GetParams bombs out!");
1429 return FALSE;
1432 *brightness = vp.brightness;
1433 *colour = vp.colour;
1434 *contrast = vp.contrast;
1435 *hue = vp.hue;
1436 *whiteness = vp.whiteness;
1438 frameBrightness = *brightness;
1439 frameColour = *colour;
1440 frameContrast = *contrast;
1441 frameHue = *hue;
1442 frameWhiteness = *whiteness;
1444 return TRUE;
1447 BOOL PVideoInputV4lDevice::TestAllFormats()
1449 return TRUE;
1452 // End Of File ///////////////////////////////////////////////////////////////