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, ®);
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, ¤tFrame);
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