Added PSharedptr class
[pwlib.git] / plugins / vidinput_v4l2 / vidinput_v4l2.cxx
blobff8a5957d27520c6683a28e0b343caf859264e26
1 /*
2 * video4linux2.cxx
4 * Classes to support streaming video input (grabbing) and output.
6 * Portable Windows Library
8 * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
9 * Copyright (c) 2003 March Networks
11 * The contents of this file are subject to the Mozilla Public License
12 * Version 1.0 (the "License"); you may not use this file except in
13 * compliance with the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
16 * Software distributed under the License is distributed on an "AS IS"
17 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
18 * the License for the specific language governing rights and limitations
19 * under the License.
21 * The Original Code is Portable Windows Library.
23 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
25 * First V4L2 capture code written by March Networks
26 * (http://www.marchnetworks.com)
28 * This code is based on the Video4Linux 1 code.
30 * Contributor(s): Guilhem Tardy (gtardy@salyens.com)
32 * TODO:
33 * - fix the devices detection code using the new code from the V4L1 plugin
34 * - make that code work
36 * $Log$
37 * Revision 1.1 2004/09/21 12:54:23 dsandras
38 * Added initial port to the new pwlib API/V4L2 API for the video4linux 2 code of Guilhem Tardy. Thanks!
40 * Revision 1.0 2003/03/03 12:27:00 guilhem
41 * First build.
45 #pragma implementation "vidinput_v4l2.h"
47 #include "vidinput_v4l2.h"
50 PCREATE_VIDINPUT_PLUGIN(V4L2, PVideoInputV4l2Device);
52 #define MAJOR(a) (int)((unsigned short) (a) >> 8)
53 #define MINOR(a) (int)((unsigned short) (a) & 0xFF)
56 ///////////////////////////////////////////////////////////////////////////////
57 // PVideoInputV4l2Device
59 PVideoInputV4l2Device::PVideoInputV4l2Device()
61 videoFd = -1;
62 canRead = FALSE;
63 canStream = FALSE;
64 canSelect = FALSE;
65 canSetFrameRate = FALSE;
66 isMapped = FALSE;
69 PVideoInputV4l2Device::~PVideoInputV4l2Device()
71 Close();
75 #ifndef V4L2_PIX_FMT_H263
76 #define V4L2_PIX_FMT_H263 v4l2_fourcc('H','2','6','3')
77 #endif
80 static struct {
81 const char * colourFormat;
82 __u32 code;
83 } colourFormatTab[] = {
84 { "Grey", V4L2_PIX_FMT_GREY }, //Entries in this table correspond
85 { "RGB32", V4L2_PIX_FMT_RGB32 }, //(line by line) to those in the
86 { "RGB24", V4L2_PIX_FMT_RGB24 }, // PVideoDevice ColourFormat table.
87 { "RGB565", V4L2_PIX_FMT_RGB565 },
88 { "RGB555", V4L2_PIX_FMT_RGB555 },
89 { "YUV411", V4L2_PIX_FMT_Y41P },
90 { "YUV411P", V4L2_PIX_FMT_YUV411P },
91 { "YUV420", V4L2_PIX_FMT_NV21 },
92 { "YUV420P", V4L2_PIX_FMT_YUV420 },
93 { "YUV422", V4L2_PIX_FMT_YYUV },
94 { "YUV422P", V4L2_PIX_FMT_YUV422P },
95 { "JPEG", V4L2_PIX_FMT_JPEG },
96 { "H263", V4L2_PIX_FMT_H263 }
100 BOOL PVideoInputV4l2Device::Open(const PString & devName, BOOL startImmediate)
102 PTRACE(1,"PVidInDev\tOpen()\tvideoFd:" << videoFd);
103 Close();
105 PTRACE(1,"PVidInDev\tOpen()\tdevName:" << devName << " videoFd:" << videoFd);
106 deviceName = devName;
107 videoFd = ::open((const char *)devName, O_RDWR);
108 if (videoFd < 0) {
109 PTRACE(1,"PVidInDev\topen failed : " << ::strerror(errno));
110 return FALSE;
113 PTRACE(6,"PVidInDev\topen, fd=" << videoFd);
115 // get the device capabilities
116 if (::ioctl(videoFd, VIDIOC_QUERYCAP, &videoCapability) < 0) {
117 PTRACE(1,"PVidInDev\tQUERYCAP failed : " << ::strerror(errno));
118 ::close (videoFd);
119 videoFd = -1;
120 return FALSE;
124 canRead = videoCapability.capabilities & V4L2_CAP_READWRITE;
125 canStream = videoCapability.capabilities & V4L2_CAP_STREAMING;
126 canSelect = videoCapability.capabilities & V4L2_CAP_ASYNCIO;
128 // set height and width
129 frameHeight = QCIFHeight;
130 frameWidth = QCIFWidth;
133 // get the capture parameters
134 videoStreamParm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
135 if (::ioctl(videoFd, VIDIOC_G_PARM, &videoStreamParm) < 0) {
136 PTRACE(1,"PVidInDev\tG_PARM failed : " << ::strerror(errno));
137 ::close (videoFd);
138 videoFd = -1;
139 return FALSE;
141 } else {
142 canSetFrameRate = videoStreamParm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME;
143 PVideoDevice::SetFrameRate (10000000 * videoStreamParm.parm.capture.timeperframe.numerator / videoStreamParm.parm.capture.timeperframe.denominator);
146 return TRUE;
150 BOOL PVideoInputV4l2Device::IsOpen()
152 return videoFd >= 0;
156 BOOL PVideoInputV4l2Device::Close()
158 PTRACE(1,"PVidInDev\tClose()\tvideoFd:" << videoFd << " started:" << started);
159 if (!IsOpen())
160 return FALSE;
162 Stop();
163 ClearMapping();
164 ::close(videoFd);
166 PTRACE(6,"PVidInDev\tclose, fd=" << videoFd);
168 videoFd = -1;
169 canRead = FALSE;
170 canStream = FALSE;
171 canSelect = FALSE;
172 canSetFrameRate = FALSE;
173 isMapped = FALSE;
175 PTRACE(1,"PVidInDev\tClose()\tvideoFd:" << videoFd << " started:" << started);
176 return TRUE;
180 BOOL PVideoInputV4l2Device::Start()
182 // automatically set mapping
183 if (!isMapped && !SetMapping()) {
184 ClearMapping();
185 canStream = FALSE; // don't try again
186 return FALSE;
189 if (!started) {
190 PTRACE(6,"PVidInDev\tstart streaming, fd=" << videoFd);
192 struct v4l2_buffer buf;
193 if (::ioctl(videoFd, VIDIOC_QBUF, &buf) < 0) {
194 PTRACE(3,"PVidInDev\tVIDIOC_QBUF failed : " << ::strerror(errno));
195 return FALSE;
197 buf.index = 0;
198 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
200 if (::ioctl(videoFd, VIDIOC_STREAMON, &buf.type) < 0) {
201 PTRACE(3,"PVidInDev\tSTREAMON failed : " << ::strerror(errno));
202 return FALSE;
204 started = TRUE;
206 // requeue all buffers
207 for (buf.index = 0; buf.index < videoBufferCount; buf.index++) {
208 PTRACE(3,"PVidInDev\tQBUF for index:" << buf.index);
209 if (::ioctl(videoFd, VIDIOC_QBUF, &buf) < 0) {
210 PTRACE(3,"PVidInDev\tQBUF failed : " << ::strerror(errno));
211 return FALSE;
216 return TRUE;
220 BOOL PVideoInputV4l2Device::Stop()
222 if (started) {
223 PTRACE(6,"PVidInDev\tstop streaming, fd=" << videoFd);
225 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
227 if (::ioctl(videoFd, VIDIOC_STREAMOFF, &type) < 0) {
228 PTRACE(3,"PVidInDev\tSTREAMOFF failed : " << ::strerror(errno));
229 return FALSE;
231 started = FALSE;
233 // no need to dequeue filled buffers, as this is handled by V4L2 at the next VIDIOC_STREAMON
236 return TRUE;
240 BOOL PVideoInputV4l2Device::IsCapturing()
242 return started;
247 void PVideoInputV4l2Device::ReadDeviceDirectory(PDirectory devdir, POrdinalToString & vid)
249 if (!devdir.Open())
250 return;
252 do {
253 PString filename = devdir.GetEntryName();
254 PString devname = devdir + filename;
255 if (devdir.IsSubDir())
256 ReadDeviceDirectory(devname, vid);
257 else {
259 PFileInfo info;
260 if (devdir.GetInfo(info) && info.type == PFileInfo::CharDevice) {
261 struct stat s;
262 if (lstat(devname, &s) == 0) {
264 static const int deviceNumbers[] = { 81 };
265 for (PINDEX i = 0; i < PARRAYSIZE(deviceNumbers); i++) {
266 if (MAJOR(s.st_rdev) == deviceNumbers[i]) {
268 PINDEX num = MINOR(s.st_rdev);
269 if (num <= 63 && num >= 0) {
270 vid.SetAt(num, devname);
277 } while (devdir.Next());
283 PStringList PVideoInputV4l2Device::GetInputDeviceNames()
285 PDirectory procVideo("/proc/video/dev");
286 PStringList devList;
288 devList.RemoveAll ();
289 if (procVideo.Exists()) {
290 if (procVideo.Open(PFileInfo::RegularFile)) {
291 do {
292 PString entry = procVideo.GetEntryName();
294 if (entry.Left(7) == "capture") {
295 PString thisDevice = "/dev/video" + entry.Mid(7);
296 int videoFd;
298 if ((videoFd = ::open(thisDevice, O_RDONLY)) >= 0) {
299 struct v4l2_capability videoCaps;
301 if (::ioctl(videoFd, VIDIOC_QUERYCAP, &videoCaps) >= 0 &&
302 videoCaps.capabilities == V4L2_CAP_VIDEO_CAPTURE) {
303 devList.AppendString(thisDevice);
305 ::close(videoFd);
308 } while (procVideo.Next());
311 if (devList.GetSize () == 0) {
313 devList += PString ("/dev/video0");
314 devList += PString ("/dev/video1");
316 /* if (devList.GetSize() == 0) {
317 POrdinalToString vid;
318 ReadDeviceDirectory("/dev/", vid);
320 for (PINDEX i = 0; i < vid.GetSize(); i++) {
321 PINDEX cardnum = vid.GetKeyAt(i);
322 int fd = ::open(vid[cardnum], O_RDONLY | O_NONBLOCK);
323 if ((fd >= 0) || (errno == EBUSY)) {
324 if (fd >= 0)
325 ::close(fd);
326 devList += vid[cardnum];
331 return devList;
335 BOOL PVideoInputV4l2Device::SetVideoFormat(VideoFormat newFormat)
337 if (newFormat == Auto) {
338 if (SetVideoFormat(PAL) ||
339 SetVideoFormat(NTSC) ||
340 SetVideoFormat(SECAM))
341 return TRUE;
342 else
343 return FALSE;
346 if (!PVideoDevice::SetVideoFormat(newFormat)) {
347 PTRACE(1,"PVideoDevice::SetVideoFormat failed for format " << newFormat);
348 return FALSE;
351 struct {
352 __u32 code;
353 const char * name;
354 } static const fmt[3] = { {V4L2_STD_PAL, "PAL"},
355 {V4L2_STD_NTSC, "NTSC"},
356 {V4L2_STD_SECAM, "SECAM"} };
358 struct v4l2_standard videoEnumStd;
359 videoEnumStd.index = 0;
360 while (1) {
361 if (::ioctl(videoFd, VIDIOC_ENUMSTD, &videoEnumStd) < 0) {
362 PTRACE(1,"VideoInputDevice\tEnumStd failed : " << ::strerror(errno));
363 return FALSE;
365 if (videoEnumStd.id == fmt[newFormat].code) {
366 break;
368 videoEnumStd.index++;
371 // set the video standard
372 if (::ioctl(videoFd, VIDIOC_S_STD, &videoEnumStd.id) < 0) {
373 PTRACE(1,"VideoInputDevice\tS_STD failed : " << ::strerror(errno));
374 return FALSE;
377 PTRACE(6,"PVidInDev\tset video format \"" << fmt[newFormat].name << "\", fd=" << videoFd);
379 return TRUE;
383 int PVideoInputV4l2Device::GetNumChannels()
385 // if opened, return the capability value, else 1 as in videoio.cxx
386 if (IsOpen ()) {
388 struct v4l2_input videoEnumInput;
389 videoEnumInput.index = 0;
390 while (1) {
391 if (::ioctl(videoFd, VIDIOC_ENUMINPUT, &videoEnumInput) < 0) {
392 PTRACE(1,"VideoInputDevice\tEnumInput failed : " << ::strerror(errno));
393 break;
395 else
396 videoEnumInput.index++;
399 return videoEnumInput.index;
401 else
402 return 1;
406 BOOL PVideoInputV4l2Device::SetChannel(int newChannel)
408 if (!PVideoDevice::SetChannel(newChannel)) {
409 PTRACE(1,"PVideoDevice::SetChannel failed for channel " << newChannel);
410 return FALSE;
413 // set the channel
414 if (::ioctl(videoFd, VIDIOC_S_INPUT, &channelNumber) < 0) {
415 PTRACE(1,"VideoInputDevice\tS_INPUT failed : " << ::strerror(errno));
416 return FALSE;
419 PTRACE(6,"PVidInDev\tset channel " << newChannel << ", fd=" << videoFd);
421 return TRUE;
425 BOOL PVideoInputV4l2Device::SetVideoChannelFormat (int newChannel, VideoFormat videoFormat)
427 if (!SetChannel(newChannel) ||
428 !SetVideoFormat(videoFormat))
429 return FALSE;
431 return TRUE;
435 BOOL PVideoInputV4l2Device::SetColourFormat(const PString & newFormat)
437 PINDEX colourFormatIndex = 0;
438 while (newFormat != colourFormatTab[colourFormatIndex].colourFormat) {
439 colourFormatIndex++;
440 if (colourFormatIndex >= PARRAYSIZE(colourFormatTab))
441 return FALSE;
444 if (!PVideoDevice::SetColourFormat(newFormat)) {
445 PTRACE(3,"PVidInDev\tSetColourFormat failed for colour format " << newFormat);
446 return FALSE;
449 BOOL resume = started;
450 Stop();
451 ClearMapping();
453 struct v4l2_format videoFormat;
454 videoFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
456 // get the colour format
457 if (::ioctl(videoFd, VIDIOC_G_FMT, &videoFormat) < 0) {
458 PTRACE(1,"PVidInDev\tG_FMT failed : " << ::strerror(errno));
459 return FALSE;
462 videoFormat.fmt.pix.pixelformat = colourFormatTab[colourFormatIndex].code;
464 // set the colour format
465 if (::ioctl(videoFd, VIDIOC_S_FMT, &videoFormat) < 0) {
466 PTRACE(1,"PVidInDev\tS_FMT failed : " << ::strerror(errno));
467 PTRACE(1,"\tused code of " << videoFormat.fmt.pix.pixelformat << " for palette: " << colourFormatTab[colourFormatIndex].colourFormat);
468 return FALSE;
471 // get the colour format again to be careful about broken drivers
472 if (::ioctl(videoFd, VIDIOC_G_FMT, &videoFormat) < 0) {
473 PTRACE(1,"PVidInDev\tG_FMT failed : " << ::strerror(errno));
474 return FALSE;
477 if (videoFormat.fmt.pix.pixelformat != colourFormatTab[colourFormatIndex].code) {
478 PTRACE(3,"PVidInDev\tcolour format mismatch.");
479 return FALSE;
482 frameBytes = videoFormat.fmt.pix.sizeimage;
484 PTRACE(6,"PVidInDev\tset colour format \"" << newFormat << "\", fd=" << videoFd);
486 if (resume)
487 return Start();
489 return TRUE;
493 BOOL PVideoInputV4l2Device::SetFrameRate(unsigned rate)
495 if (!PVideoDevice::SetFrameRate(rate)) {
496 PTRACE(3,"PVidInDev\tSetFrameRate failed for rate " << rate);
497 return FALSE;
500 if (canSetFrameRate) {
501 videoStreamParm.parm.capture.timeperframe.numerator = 10000000;
502 videoStreamParm.parm.capture.timeperframe.denominator = (rate ? rate : 1);
504 // set the stream parameters
505 if (::ioctl(videoFd, VIDIOC_S_PARM, &videoStreamParm) < 0) {
506 PTRACE(1,"PVidInDev\tS_PARM failed : "<< ::strerror(errno));
507 return FALSE;
510 PTRACE(6,"PVidInDev\tset frame rate " << rate << "fps, fd=" << videoFd);
513 return TRUE;
517 BOOL PVideoInputV4l2Device::GetFrameSizeLimits(unsigned & minWidth,
518 unsigned & minHeight,
519 unsigned & maxWidth,
520 unsigned & maxHeight)
522 /* Not used in V4L2 */
523 return FALSE;
527 BOOL PVideoInputV4l2Device::SetFrameSize(unsigned width, unsigned height)
529 if (!PVideoDevice::SetFrameSize(width, height)) {
530 PTRACE(3,"PVidInDev\tSetFrameSize failed for size " << width << "x" << height);
531 return FALSE;
534 BOOL resume = started;
535 Stop();
536 ClearMapping();
538 if (!VerifyHardwareFrameSize(width, height)) {
539 PTRACE(3,"PVidInDev\tVerifyHardwareFrameSize failed for size " << width << "x" << height);
540 return FALSE;
543 PTRACE(6,"PVidInDev\tset frame size " << width << "x" << height << ", fd=" << videoFd);
545 if (resume)
546 return Start();
548 return TRUE;
552 PINDEX PVideoInputV4l2Device::GetMaxFrameBytes()
554 if (converter != NULL) {
555 PINDEX bytes = converter->GetMaxDstFrameBytes();
556 if (bytes > frameBytes)
557 return bytes;
560 return frameBytes;
564 BOOL PVideoInputV4l2Device::SetMapping()
566 if (!canStream)
567 return FALSE;
569 struct v4l2_requestbuffers reqbuf;
570 reqbuf.count = 2; // we shouldn't need more
571 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
572 reqbuf.memory = V4L2_MEMORY_MMAP;
574 if (::ioctl(videoFd, VIDIOC_REQBUFS, &reqbuf) < 0 ||
575 reqbuf.count < 2 ||
576 reqbuf.count > NUM_VIDBUF) {
577 PTRACE(3,"PVidInDev\tREQBUFS failed : " << ::strerror(errno));
578 return FALSE;
581 struct v4l2_buffer buf;
582 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
584 videoBufferCount = reqbuf.count;
585 for (buf.index = 0; buf.index < videoBufferCount; buf.index++) {
586 if (::ioctl(videoFd, VIDIOC_QUERYBUF, &buf) < 0) {
587 PTRACE(3,"PVidInDev\tQUERYBUF failed : " << ::strerror(errno));
588 return FALSE;
591 if ((videoBuffer[buf.index] = (BYTE *)::mmap(0, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, videoFd, buf.m.offset)) == MAP_FAILED) {
592 PTRACE(3,"PVidInDev\tmmap failed : " << ::strerror(errno));
593 return FALSE;
597 isMapped = TRUE;
599 PTRACE(7,"PVidInDev\tset mapping for " << videoBufferCount << " buffers, fd=" << videoFd);
602 return TRUE;
606 void PVideoInputV4l2Device::ClearMapping()
608 if (!canStream) // 'isMapped' wouldn't handle partial mappings
609 return;
611 struct v4l2_buffer buf;
612 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
614 for (buf.index = 0; ; buf.index++) {
615 if (::ioctl(videoFd, VIDIOC_QUERYBUF, &buf) < 0)
616 break;
618 ::munmap(videoBuffer[buf.index], buf.length);
621 isMapped = FALSE;
623 PTRACE(7,"PVidInDev\tclear mapping, fd=" << videoFd);
627 BOOL PVideoInputV4l2Device::GetFrame(PBYTEArray & frame)
629 PINDEX returned;
630 if (!GetFrameData(frame.GetPointer(GetMaxFrameBytes()), &returned))
631 return FALSE;
633 frame.SetSize(returned);
634 return TRUE;
638 BOOL PVideoInputV4l2Device::GetFrameData(BYTE * buffer, PINDEX * bytesReturned)
640 PTRACE(1,"PVidInDev\tGetFrameData()");
642 if (frameRate>0) {
643 PTimeInterval delay;
645 do {
646 if (!GetFrameDataNoDelay(buffer, bytesReturned))
647 return FALSE;
649 delay = PTime() - previousFrameTime;
650 } while (delay.GetMilliSeconds() < msBetweenFrames);
652 previousFrameTime = PTime();
654 return TRUE;
657 return GetFrameDataNoDelay(buffer, bytesReturned);
661 BOOL PVideoInputV4l2Device::GetFrameDataNoDelay(BYTE * buffer, PINDEX * bytesReturned)
663 PTRACE(1,"PVidInDev\tGetFrameDataNoDelay()\tstarted:" << started << " canSelect:" << canSelect);
665 if (!started)
666 return NormalReadProcess(buffer, bytesReturned);
669 if (TRUE) {
670 int ret;
671 fd_set rfds;
672 struct timeval tv;
674 FD_ZERO(&rfds);
675 FD_SET(videoFd, &rfds);
676 tv.tv_sec = 2; // wait up to 2 seconds
677 tv.tv_usec = 0;
679 PTRACE(1,"PVidInDev\tselect");
682 ret = ::select(videoFd+1, &rfds, NULL, NULL, &tv);
683 while (ret < 0 && errno == EINTR);
685 if (ret <= 0) {
686 PTRACE(1,"PVidInDev\tselect failed : " << ::strerror(errno));
687 canSelect = FALSE;
691 struct v4l2_buffer buf;
693 PTRACE(1,"PVidInDev\tdqbuf");
695 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
696 buf.index = 0;
697 if (::ioctl(videoFd, VIDIOC_DQBUF, &buf) < 0) {
698 PTRACE(1,"PVidInDev\tDQBUF failed : " << ::strerror(errno));
699 return FALSE;
702 // If converting on the fly do it from frame store to output buffer,
703 // otherwise do straight copy.
704 if (converter != NULL)
705 converter->Convert(videoBuffer[buf.index], buffer, bytesReturned);
706 else {
707 memcpy(buffer, videoBuffer[buf.index], buf.bytesused);
708 if (bytesReturned != NULL)
709 *bytesReturned = buf.bytesused;
712 PTRACE(8,"PVidInDev\tget frame data of " << buf.bytesused << "bytes, fd=" << videoFd);
714 // requeue the buffer
715 if (::ioctl(videoFd, VIDIOC_QBUF, &buf) < 0) {
716 PTRACE(1,"PVidInDev\tQBUF failed : " << ::strerror(errno));
719 return TRUE;
723 // This video device does not support memory mapping - so use
724 // normal read process to extract a frame of video data.
725 BOOL PVideoInputV4l2Device::NormalReadProcess(BYTE * buffer, PINDEX * bytesReturned)
727 if (!canRead)
728 return FALSE;
730 ssize_t bytesRead;
733 bytesRead = ::read(videoFd, buffer, frameBytes);
734 while (bytesRead < 0 && errno == EINTR);
736 if (bytesRead < 0) {
737 PTRACE(1,"PVidInDev\tread failed");
738 return FALSE;
741 if ((PINDEX)bytesRead != frameBytes) {
742 PTRACE(1,"PVidInDev\tread returned fewer bytes than expected");
743 // May result from a compressed format, otherwise indicates an error.
746 if (converter != NULL)
747 return converter->ConvertInPlace(buffer, bytesReturned);
749 if (bytesReturned != NULL)
750 *bytesReturned = (PINDEX)bytesRead;
752 return TRUE;
755 BOOL PVideoInputV4l2Device::VerifyHardwareFrameSize(unsigned width,
756 unsigned height)
758 struct v4l2_format videoFormat;
759 videoFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
761 // get the frame size
762 if (::ioctl(videoFd, VIDIOC_G_FMT, &videoFormat) < 0) {
763 PTRACE(1,"PVidInDev\tG_FMT failed : " << ::strerror(errno));
764 return FALSE;
767 videoFormat.fmt.pix.width = width;
768 videoFormat.fmt.pix.height = height;
770 // set the frame size
771 if (::ioctl(videoFd, VIDIOC_S_FMT, &videoFormat) < 0) {
772 PTRACE(1,"PVidInDev\tS_FMT failed : " << ::strerror(errno));
773 PTRACE(1,"\tused frame size of " << videoFormat.fmt.pix.width << "x" << videoFormat.fmt.pix.height);
774 return FALSE;
777 // get the frame size again to be careful about broken drivers
778 if (::ioctl(videoFd, VIDIOC_G_FMT, &videoFormat) < 0) {
779 PTRACE(1,"PVidInDev\tG_FMT failed : " << ::strerror(errno));
780 return FALSE;
783 if ((videoFormat.fmt.pix.width != width) || (videoFormat.fmt.pix.height != height)) {
784 PTRACE(3,"PVidInDev\tframe size mismatch.");
785 // allow the device to return actual frame size
786 PVideoDevice::SetFrameSize(videoFormat.fmt.pix.width, videoFormat.fmt.pix.height);
787 return FALSE;
790 frameBytes = videoFormat.fmt.pix.sizeimage;
791 return TRUE;
794 int PVideoInputV4l2Device::GetBrightness()
796 if (!IsOpen())
797 return -1;
799 struct v4l2_control c;
800 c.id = V4L2_CID_BRIGHTNESS;
802 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
803 return -1;
805 frameBrightness = c.value;
806 return frameBrightness;
809 int PVideoInputV4l2Device::GetWhiteness()
811 if (!IsOpen())
812 return -1;
814 struct v4l2_control c;
815 c.id = V4L2_CID_WHITENESS;
817 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
818 return -1;
820 frameWhiteness = c.value;
821 return frameWhiteness;
824 int PVideoInputV4l2Device::GetColour()
826 if (!IsOpen())
827 return -1;
829 struct v4l2_control c;
830 c.id = V4L2_CID_SATURATION;
832 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
833 return -1;
835 frameColour = c.value;
836 return frameColour;
839 int PVideoInputV4l2Device::GetContrast()
841 if (!IsOpen())
842 return -1;
844 struct v4l2_control c;
845 c.id = V4L2_CID_CONTRAST;
847 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
848 return -1;
850 frameContrast = c.value;
851 return frameContrast;
854 int PVideoInputV4l2Device::GetHue()
856 if (!IsOpen())
857 return -1;
859 struct v4l2_control c;
860 c.id = V4L2_CID_HUE;
862 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
863 return -1;
865 frameHue = c.value;
866 return frameHue;
869 BOOL PVideoInputV4l2Device::SetBrightness(unsigned newBrightness)
871 if (!IsOpen())
872 return FALSE;
874 struct v4l2_queryctrl q;
875 q.id = V4L2_CID_BRIGHTNESS;
877 if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0)
878 return FALSE;
880 struct v4l2_control c;
881 c.id = V4L2_CID_BRIGHTNESS;
882 c.value = q.minimum + ((q.maximum-q.minimum) * newBrightness) >> 16;
884 if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0)
885 return FALSE;
887 frameBrightness = newBrightness;
888 return TRUE;
891 BOOL PVideoInputV4l2Device::SetWhiteness(unsigned newWhiteness)
893 if (!IsOpen())
894 return FALSE;
896 struct v4l2_queryctrl q;
897 q.id = V4L2_CID_WHITENESS;
899 if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0)
900 return FALSE;
902 struct v4l2_control c;
903 c.id = V4L2_CID_WHITENESS;
904 c.value = q.minimum + ((q.maximum-q.minimum) * newWhiteness) >> 16;
906 if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0)
907 return FALSE;
909 frameWhiteness = newWhiteness;
910 return TRUE;
913 BOOL PVideoInputV4l2Device::SetColour(unsigned newColour)
915 if (!IsOpen())
916 return FALSE;
918 struct v4l2_queryctrl q;
919 q.id = V4L2_CID_SATURATION;
921 if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0)
922 return FALSE;
924 struct v4l2_control c;
925 c.id = V4L2_CID_SATURATION;
926 c.value = q.minimum + ((q.maximum-q.minimum) * newColour) >> 16;
928 if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0)
929 return FALSE;
931 frameColour = newColour;
932 return TRUE;
935 BOOL PVideoInputV4l2Device::SetContrast(unsigned newContrast)
937 if (!IsOpen())
938 return FALSE;
940 struct v4l2_queryctrl q;
941 q.id = V4L2_CID_CONTRAST;
943 if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0)
944 return FALSE;
946 struct v4l2_control c;
947 c.id = V4L2_CID_CONTRAST;
948 c.value = q.minimum + ((q.maximum-q.minimum) * newContrast) >> 16;
950 if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0)
951 return FALSE;
953 frameContrast = newContrast;
954 return TRUE;
957 BOOL PVideoInputV4l2Device::SetHue(unsigned newHue)
959 if (!IsOpen())
960 return FALSE;
962 struct v4l2_queryctrl q;
963 q.id = V4L2_CID_HUE;
965 if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0)
966 return FALSE;
968 struct v4l2_control c;
969 c.id = V4L2_CID_HUE;
970 c.value = q.minimum + ((q.maximum-q.minimum) * newHue) >> 16;
972 if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0)
973 return FALSE;
975 frameHue=newHue;
976 return TRUE;
979 BOOL PVideoInputV4l2Device::GetParameters (int *whiteness, int *brightness,
980 int *colour, int *contrast, int *hue)
982 if (!IsOpen())
983 return FALSE;
985 struct v4l2_control c;
987 c.id = V4L2_CID_WHITENESS;
988 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
989 frameWhiteness = -1;
990 else
991 frameWhiteness = c.value;
992 c.id = V4L2_CID_BRIGHTNESS;
993 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
994 frameBrightness = -1;
995 else
996 frameBrightness = c.value;
997 c.id = V4L2_CID_SATURATION;
998 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
999 frameColour = -1;
1000 else
1001 frameColour = c.value;
1002 c.id = V4L2_CID_CONTRAST;
1003 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
1004 frameContrast = -1;
1005 else
1006 frameContrast = c.value;
1007 c.id = V4L2_CID_HUE;
1008 if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
1009 frameHue = -1;
1010 else
1011 frameHue = c.value;
1013 *whiteness = frameWhiteness;
1014 *brightness = frameBrightness;
1015 *colour = frameColour;
1016 *contrast = frameContrast;
1017 *hue = frameHue;
1019 return TRUE;
1022 BOOL PVideoInputV4l2Device::TestAllFormats()
1024 return TRUE;
1028 // End Of File ///////////////////////////////////////////////////////////////