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
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)
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
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
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
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
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.
230 /**Philips usb web cameras
231 Native format is 420(P) so use it.
234 { "^Philips [0-9]+ webcam$",
235 "Philips USB webcam",
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
247 "Brooktree BT848 and BT878 based capture boards",
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)",
262 /** Sony Vaio Motion Eye camera
263 Linux kernel 2.4.7 has meye.c driver module.
266 "Sony Vaio Motion Eye Camera",
268 HINT_CGPICT_DOESNT_SET_PALETTE
|
269 HINT_CSPICT_ALWAYS_WORKS
|
270 HINT_ALWAYS_WORKS_320_240
|
271 HINT_ALWAYS_WORKS_640_480
|
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",
282 HINT_FORCE_LARGE_SIZE
,
283 VIDEO_PALETTE_YUV420P
286 /** Creative VideoBlaster Webcam II USB
289 "CPIA which works with cpia and cpia_usb driver modules",
291 HINT_FORCE_DEPTH_16
|
292 HINT_ONLY_WORKS_PREF_PALETTE
|
293 HINT_HAS_PREF_PALETTE
,
297 /** Intel PC Pro Camera
300 { "SPCA50X USB Camera",
301 "Intel PC Pro Camera uses the spca50x driver",
303 HINT_ONLY_WORKS_PREF_PALETTE
|
304 HINT_HAS_PREF_PALETTE
,
309 /** Default device with no special settings
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
);
327 V4LNames() {/* nothing */};
331 PString
GetUserFriendly(PString devName
);
333 PString
GetDeviceName(PString userName
);
335 PStringList
GetInputDeviceNames();
338 void AddUserDeviceName(PString userName
, PString devName
);
340 PString
BuildUserFriendly(PString devname
);
342 void PopulateDictionary();
344 void ReadDeviceDirectory(PDirectory devdir
, POrdinalToString
& vid
);
347 PStringToString deviceKey
;
348 PStringToString userKey
;
349 PStringList inputDeviceNames
;
355 PDirectory
procvideo("/proc/video/dev");
359 inputDeviceNames
.RemoveAll (); // flush the previous run
360 if (procvideo
.Exists()) {
361 if (procvideo
.Open(PFileInfo::RegularFile
)) {
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
)){
370 struct video_capability videoCaps
;
371 if (ioctl(videoFd
, VIDIOCGCAP
, &videoCaps
) >= 0 &&
372 (videoCaps
.type
& VID_TYPE_CAPTURE
) != 0)
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
)) {
393 inputDeviceNames
+= vid
[cardnum
];
397 PopulateDictionary();
400 void V4LNames::ReadDeviceDirectory(PDirectory devdir
, POrdinalToString
& vid
)
406 PString filename
= devdir
.GetEntryName();
407 PString devname
= devdir
+ filename
;
408 if (devdir
.IsSubDir())
409 ReadDeviceDirectory(devname
, vid
);
413 if (devdir
.GetInfo(info
) && info
.type
== PFileInfo::CharDevice
) {
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()
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
);
450 for (j
= i
+ 1; j
< tempList
.GetSize(); j
++) {
451 if (tempList
.GetDataAt(j
) == userName
) {
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())
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
);
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
)
505 int fd
= ::open((const char *)devname
, O_RDONLY
);
510 struct video_capability videocap
;
511 if (::ioctl(fd
, VIDIOCGCAP
, &videocap
) < 0) {
517 PString
ufname(videocap
.name
);
522 PStringList
V4LNames::GetInputDeviceNames()
524 PWaitAndSignal
m(mutex
);
526 for (PINDEX i
= 0; i
< inputDeviceNames
.GetSize(); i
++)
527 result
+= GetUserFriendly (inputDeviceNames
[i
]);
533 V4LNames
& GetNames()
535 static V4LNames names
;
540 ///////////////////////////////////////////////////////////////////////////////
541 // PVideoInputV4lDevice
543 PVideoInputV4lDevice::PVideoInputV4lDevice()
546 hint_index
= PARRAYSIZE(driver_hints
) - 1;
549 for (int i
=0; i
<2; i
++)
550 pendingSync
[i
] = FALSE
;
553 PVideoInputV4lDevice::~PVideoInputV4lDevice()
558 const char * colourFormat
;
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
)
584 version
= PString (buf
.release
);
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
);
595 PTRACE(1,"PVideoInputV4lDevice::Open failed : "<< ::strerror(errno
));
599 // get the device capabilities
600 if (::ioctl(videoFd
, VIDIOCGCAP
, &videoCapability
) < 0) {
601 PTRACE(1,"PVideoInputV4lDevice:: get device capablilities failed : "<< ::strerror(errno
));
607 if ((videoCapability
.type
& VID_TYPE_CAPTURE
) == 0) {
608 PTRACE(1,"PVideoInputV4lDevice:: device capablilities reports cannot capture");
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.
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
);
637 PTRACE(1,"PVideoInputV4lDevice::Open: Hints not applied because kernel version is not less than " << driver_hints
[tbl
].version
);
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
, ®
);
660 // set height and width
661 frameHeight
= PMIN (videoCapability
.maxheight
, QCIFHeight
);
662 frameWidth
= PMIN (videoCapability
.maxwidth
, QCIFWidth
);
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
);
678 BOOL
PVideoInputV4lDevice::IsOpen()
684 BOOL
PVideoInputV4lDevice::Close()
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
);
708 BOOL
PVideoInputV4lDevice::Start()
714 BOOL
PVideoInputV4lDevice::Stop()
720 BOOL
PVideoInputV4lDevice::IsCapturing()
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");
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");
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
));
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)
764 PTRACE(1,"VideoInputDevice SetChannel failed : "<< ::strerror(errno
));
766 if (newFormat
!= Auto
)
769 if (SetVideoFormat(PAL
))
771 if (SetVideoFormat(NTSC
))
773 if (SetVideoFormat(SECAM
))
780 int PVideoInputV4lDevice::GetNumChannels()
782 /* If Opened, return the capability value, else 1 as in videoio.cxx */
784 return videoCapability
.channels
;
790 BOOL
PVideoInputV4lDevice::SetChannel(int newChannel
)
792 if (!PVideoDevice::SetChannel(newChannel
))
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
));
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
));
816 BOOL
PVideoInputV4lDevice::SetVideoChannelFormat (int newNumber
, VideoFormat videoFormat
)
818 if (!PVideoDevice::SetChannel(newNumber
))
821 if (!PVideoDevice::SetVideoFormat(videoFormat
)) {
822 PTRACE(1,"PVideoDevice::SetVideoFormat\t failed");
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
));
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
));
853 BOOL
PVideoInputV4lDevice::SetColourFormat(const PString
& newFormat
)
855 PINDEX colourFormatIndex
= 0;
856 while (newFormat
!= colourFormatTab
[colourFormatIndex
].colourFormat
) {
858 if (colourFormatIndex
>= PARRAYSIZE(colourFormatTab
))
862 if (!PVideoDevice::SetColourFormat(newFormat
))
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
));
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
);
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
);
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
)
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
));
916 if (pictureInfo
.palette
!= colourFormatCode
)
920 // set the new information
921 return SetFrameSizeConverter(frameWidth
, frameHeight
, FALSE
);
925 BOOL
PVideoInputV4lDevice::SetFrameRate(unsigned rate
)
927 if (!PVideoDevice::SetFrameRate(rate
))
934 BOOL
PVideoInputV4lDevice::GetFrameSizeLimits(unsigned & minWidth
,
935 unsigned & minHeight
,
937 unsigned & maxHeight
)
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
);
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");
970 if (!VerifyHardwareFrameSize(width
, height
)) {
971 PTRACE(3,"PVideoInputV4lDevice\t SetFrameSize failed for "<<width
<<"x"<<height
);
972 PTRACE(3,"VerifyHardwareFrameSize failed.");
976 frameBytes
= CalculateFrameBytes(frameWidth
, frameHeight
, colourFormat
);
982 PINDEX
PVideoInputV4lDevice::GetMaxFrameBytes()
984 if (converter
!= NULL
) {
985 PINDEX bytes
= converter
->GetMaxDstFrameBytes();
986 if (bytes
> frameBytes
)
993 BOOL
PVideoInputV4lDevice::GetFrame(PBYTEArray
& frame
)
996 if (!GetFrameData(frame
.GetPointer(GetMaxFrameBytes()), &returned
))
999 frame
.SetSize(returned
);
1003 BOOL
PVideoInputV4lDevice::GetFrameData(BYTE
*buffer
, PINDEX
*bytesReturned
)
1006 frameTimeError
+= msBetweenFrames
;
1009 if ( !GetFrameDataNoDelay(buffer
, bytesReturned
))
1014 PTimeInterval delay
= now
- previousFrameTime
;
1015 frameTimeError
-= (int)delay
.GetMilliSeconds();
1016 previousFrameTime
= now
;
1017 } while(frameTimeError
> 0) ;
1021 return GetFrameDataNoDelay(buffer
, bytesReturned
);
1025 BOOL
PVideoInputV4lDevice::GetFrameDataNoDelay(BYTE
* buffer
, PINDEX
* bytesReturned
)
1028 //When canMap is < 0, it is the first use of GetFrameData. Check for memory mapping.
1029 if (::ioctl(videoFd
, VIDIOCGMBUF
, &frame
) < 0) {
1031 PTRACE(3, "VideoGrabber " << deviceName
<< " cannot do memory mapping - GMBUF failed.");
1032 //This video device cannot do memory mapping.
1034 videoBuffer
= (BYTE
*)::mmap(0, frame
.size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, videoFd
, 0);
1036 if (videoBuffer
< 0) {
1038 PTRACE(3, "VideoGrabber " << deviceName
<< " cannot do memory mapping - ::mmap failed.");
1039 //This video device cannot do memory mapping.
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
;
1055 ret
= ::ioctl(videoFd
, VIDIOCMCAPTURE
, &frameBuffer
[currentFrame
]);
1057 PTRACE(1,"PVideoInputV4lDevice::GetFrameData mcapture1 failed : " << ::strerror(errno
));
1060 //This video device cannot do memory mapping.
1062 pendingSync
[currentFrame
] = TRUE
;
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)
1081 * videoiomcapture frame 1 (returns immediately)
1082 * videoiocsync frame 0 (waits on the data)
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.
1099 ret
= ::ioctl(videoFd
, VIDIOCMCAPTURE
, &frameBuffer
[ 1 - currentFrame
]);
1101 PTRACE(1,"PVideoInputV4lDevice::GetFrameData mcapture2 failed : " << ::strerror(errno
));
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
, ¤tFrame
);
1113 pendingSync
[currentFrame
] = FALSE
;
1115 PTRACE(1,"PVideoInputV4lDevice::GetFrameData csync failed : " << ::strerror(errno
));
1119 return NormalReadProcess(buffer
, bytesReturned
);
1122 // If converting on the fly do it from frame store to output buffer, otherwise do
1124 if (converter
!= NULL
)
1125 converter
->Convert(videoBuffer
+ frame
.offsets
[currentFrame
], buffer
, bytesReturned
);
1127 memcpy(buffer
, videoBuffer
+ frame
.offsets
[currentFrame
], frameBytes
);
1128 if (bytesReturned
!= NULL
)
1129 *bytesReturned
= frameBytes
;
1133 currentFrame
= 1 - currentFrame
;
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
)
1147 ret
= ::read(videoFd
, resultBuffer
, frameBytes
);
1148 if ((ret
< 0) && (errno
== EINTR
))
1152 PTRACE(1,"PVideoInputV4lDevice::NormalReadProcess() failed");
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
1164 if (converter
!= NULL
)
1165 return converter
->ConvertInPlace(resultBuffer
, bytesReturned
);
1167 if (bytesReturned
!= NULL
)
1168 *bytesReturned
= frameBytes
;
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
);
1180 PTRACE(1,"PVideoInputV4lDevice::GetFrameData csync failed : " << ::strerror(errno
));
1181 pendingSync
[i
] = FALSE
;
1183 ::munmap(videoBuffer
, frame
.size
);
1192 BOOL
PVideoInputV4lDevice::VerifyHardwareFrameSize(unsigned width
,
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 ");
1202 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize USB FAIL "<<width
<<"x"<<height
);
1206 if (HINT(HINT_ALWAYS_WORKS_320_240
) && (width
==320) && (height
==240) ) {
1207 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize OK for 320x240 ");
1211 if (HINT(HINT_ALWAYS_WORKS_640_480
) && (width
==640) && (height
==480) ) {
1212 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize OK for 640x480 ");
1216 if (HINT(HINT_CGWIN_FAILS
)) {
1217 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize fails for size "
1218 << width
<< "x" << height
);
1222 // Request current hardware frame size
1223 if (::ioctl(videoFd
, VIDIOCGWIN
, &vwin
) < 0) {
1224 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize VIDIOCGWIN1 error::" << ::strerror(errno
));
1228 // Request the width and height
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
1236 if (HINT(HINT_CSWIN_ZERO_FLAGS
)) {
1237 PTRACE(1,"PVideoInputV4lDevice\t VerifyHardwareFrameSize: Clearing flags field");
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
));
1249 if ((vwin
.width
!= width
) || (vwin
.height
!= height
)) {
1250 PTRACE(3,"PVideoInputV4lDevice\t VerifyHardwareFrameSize Size mismatch.");
1257 int PVideoInputV4lDevice::GetBrightness()
1262 struct video_picture vp
;
1264 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1266 frameBrightness
= vp
.brightness
;
1268 return frameBrightness
;
1272 int PVideoInputV4lDevice::GetWhiteness()
1277 struct video_picture vp
;
1279 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1281 frameWhiteness
= vp
.whiteness
;
1283 return frameWhiteness
;
1286 int PVideoInputV4lDevice::GetColour()
1291 struct video_picture vp
;
1293 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1295 frameColour
= vp
.colour
;
1302 int PVideoInputV4lDevice::GetContrast()
1307 struct video_picture vp
;
1309 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1311 frameContrast
= vp
.contrast
;
1313 return frameContrast
;
1316 int PVideoInputV4lDevice::GetHue()
1321 struct video_picture vp
;
1323 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1330 BOOL
PVideoInputV4lDevice::SetBrightness(unsigned newBrightness
)
1335 struct video_picture vp
;
1337 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1340 vp
.brightness
= newBrightness
;
1341 if (::ioctl(videoFd
, VIDIOCSPICT
, &vp
) < 0)
1344 frameBrightness
=newBrightness
;
1347 BOOL
PVideoInputV4lDevice::SetWhiteness(unsigned newWhiteness
)
1352 struct video_picture vp
;
1354 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1357 vp
.whiteness
= newWhiteness
;
1358 if (::ioctl(videoFd
, VIDIOCSPICT
, &vp
) < 0)
1361 frameWhiteness
= newWhiteness
;
1365 BOOL
PVideoInputV4lDevice::SetColour(unsigned newColour
)
1370 struct video_picture vp
;
1372 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1375 vp
.colour
= newColour
;
1376 if (::ioctl(videoFd
, VIDIOCSPICT
, &vp
) < 0)
1379 frameColour
= newColour
;
1382 BOOL
PVideoInputV4lDevice::SetContrast(unsigned newContrast
)
1387 struct video_picture vp
;
1389 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1392 vp
.contrast
= newContrast
;
1393 if (::ioctl(videoFd
, VIDIOCSPICT
, &vp
) < 0)
1396 frameContrast
= newContrast
;
1400 BOOL
PVideoInputV4lDevice::SetHue(unsigned newHue
)
1405 struct video_picture vp
;
1407 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1411 if (::ioctl(videoFd
, VIDIOCSPICT
, &vp
) < 0)
1418 BOOL
PVideoInputV4lDevice::GetParameters (int *whiteness
, int *brightness
,
1419 int *colour
, int *contrast
, int *hue
)
1424 struct video_picture vp
;
1426 if (::ioctl(videoFd
, VIDIOCGPICT
, &vp
) < 0)
1428 PTRACE(3, "GetParams bombs out!");
1432 *brightness
= vp
.brightness
;
1433 *colour
= vp
.colour
;
1434 *contrast
= vp
.contrast
;
1436 *whiteness
= vp
.whiteness
;
1438 frameBrightness
= *brightness
;
1439 frameColour
= *colour
;
1440 frameContrast
= *contrast
;
1442 frameWhiteness
= *whiteness
;
1447 BOOL
PVideoInputV4lDevice::TestAllFormats()
1452 // End Of File ///////////////////////////////////////////////////////////////