📄 vidinput_v4l2.cxx
字号:
struct v4l2_requestbuffers reqbuf; reqbuf.count = 1; // we shouldn't need more reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.memory = V4L2_MEMORY_MMAP; if (::ioctl(videoFd, VIDIOC_REQBUFS, &reqbuf) < 0 || reqbuf.count < 1 || reqbuf.count > NUM_VIDBUF) { PTRACE(3,"PVidInDev\tREQBUFS failed : " << ::strerror(errno)); return FALSE; } struct v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; videoBufferCount = reqbuf.count; for (buf.index = 0; buf.index < videoBufferCount; buf.index++) { if (::ioctl(videoFd, VIDIOC_QUERYBUF, &buf) < 0) { PTRACE(3,"PVidInDev\tQUERYBUF failed : " << ::strerror(errno)); return FALSE; } if ((videoBuffer[buf.index] = (BYTE *)::mmap(0, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, videoFd, buf.m.offset)) == MAP_FAILED) { PTRACE(3,"PVidInDev\tmmap failed : " << ::strerror(errno)); return FALSE; } } isMapped = TRUE; PTRACE(7,"PVidInDev\tset mapping for " << videoBufferCount << " buffers, fd=" << videoFd); return TRUE;}void PVideoInputV4l2Device::ClearMapping(){ if (!canStream) // 'isMapped' wouldn't handle partial mappings return; struct v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; for (buf.index = 0; ; buf.index++) { if (::ioctl(videoFd, VIDIOC_QUERYBUF, &buf) < 0) break; ::munmap(videoBuffer[buf.index], buf.length); } isMapped = FALSE; PTRACE(7,"PVidInDev\tclear mapping, fd=" << videoFd);}BOOL PVideoInputV4l2Device::GetFrame(PBYTEArray & frame){ PINDEX returned; if (!GetFrameData(frame.GetPointer(GetMaxFrameBytes()), &returned)) return FALSE; frame.SetSize(returned); return TRUE;}BOOL PVideoInputV4l2Device::GetFrameData(BYTE * buffer, PINDEX * bytesReturned){ PTRACE(1,"PVidInDev\tGetFrameData()"); if (frameRate>0) { PTimeInterval delay; do { if (!GetFrameDataNoDelay(buffer, bytesReturned)) return FALSE; delay = PTime() - previousFrameTime; } while (delay.GetMilliSeconds() < msBetweenFrames); previousFrameTime = PTime(); return TRUE; } return GetFrameDataNoDelay(buffer, bytesReturned);}BOOL PVideoInputV4l2Device::GetFrameDataNoDelay(BYTE * buffer, PINDEX * bytesReturned){ PTRACE(1,"PVidInDev\tGetFrameDataNoDelay()\tstarted:" << started << " canSelect:" << canSelect); if (!started) return NormalReadProcess(buffer, bytesReturned); struct v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.index = 0; if (::ioctl(videoFd, VIDIOC_DQBUF, &buf) < 0) { PTRACE(1,"PVidInDev\tDQBUF failed : " << ::strerror(errno)); return FALSE; } // If converting on the fly do it from frame store to output buffer, // otherwise do straight copy. if (converter != NULL) converter->Convert(videoBuffer[buf.index], buffer, bytesReturned); else { memcpy(buffer, videoBuffer[buf.index], buf.bytesused); if (bytesReturned != NULL) *bytesReturned = buf.bytesused; } PTRACE(8,"PVidInDev\tget frame data of " << buf.bytesused << "bytes, fd=" << videoFd); // requeue the buffer if (::ioctl(videoFd, VIDIOC_QBUF, &buf) < 0) { PTRACE(1,"PVidInDev\tQBUF failed : " << ::strerror(errno)); } return TRUE;}// This video device does not support memory mapping - so use// normal read process to extract a frame of video data.BOOL PVideoInputV4l2Device::NormalReadProcess(BYTE * buffer, PINDEX * bytesReturned){ if (!canRead) return FALSE; ssize_t bytesRead; do bytesRead = ::read(videoFd, buffer, frameBytes); while (bytesRead < 0 && errno == EINTR); if (bytesRead < 0) { PTRACE(1,"PVidInDev\tread failed (read = "<<bytesRead<< " expected " << frameBytes <<")"); bytesRead = frameBytes; } if ((PINDEX)bytesRead != frameBytes) { PTRACE(1,"PVidInDev\tread returned fewer bytes than expected"); // May result from a compressed format, otherwise indicates an error. } if (converter != NULL) return converter->ConvertInPlace(buffer, bytesReturned); if (bytesReturned != NULL) *bytesReturned = (PINDEX)bytesRead; return TRUE;}BOOL PVideoInputV4l2Device::VerifyHardwareFrameSize(unsigned width, unsigned height){ struct v4l2_format videoFormat; videoFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // get the frame size if (::ioctl(videoFd, VIDIOC_G_FMT, &videoFormat) < 0) { PTRACE(1,"PVidInDev\tG_FMT failed : " << ::strerror(errno)); return FALSE; } videoFormat.fmt.pix.width = width; videoFormat.fmt.pix.height = height; // set the frame size if (::ioctl(videoFd, VIDIOC_S_FMT, &videoFormat) < 0) { PTRACE(1,"PVidInDev\tS_FMT failed : " << ::strerror(errno)); PTRACE(1,"\tused frame size of " << videoFormat.fmt.pix.width << "x" << videoFormat.fmt.pix.height); return FALSE; } // get the frame size again to be careful about broken drivers if (::ioctl(videoFd, VIDIOC_G_FMT, &videoFormat) < 0) { PTRACE(1,"PVidInDev\tG_FMT failed : " << ::strerror(errno)); return FALSE; } if ((videoFormat.fmt.pix.width != width) || (videoFormat.fmt.pix.height != height)) { PTRACE(3,"PVidInDev\tframe size mismatch."); // allow the device to return actual frame size PVideoDevice::SetFrameSize(videoFormat.fmt.pix.width, videoFormat.fmt.pix.height); return FALSE; } frameBytes = videoFormat.fmt.pix.sizeimage; return TRUE;}int PVideoInputV4l2Device::GetBrightness() { if (!IsOpen()) return -1; struct v4l2_control c; c.id = V4L2_CID_BRIGHTNESS; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) return -1; frameBrightness = c.value; return frameBrightness; }int PVideoInputV4l2Device::GetWhiteness() { if (!IsOpen()) return -1; struct v4l2_control c; c.id = V4L2_CID_WHITENESS; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) return -1; frameWhiteness = c.value; return frameWhiteness;}int PVideoInputV4l2Device::GetColour() { if (!IsOpen()) return -1; struct v4l2_control c; c.id = V4L2_CID_SATURATION; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) return -1; frameColour = c.value; return frameColour; }int PVideoInputV4l2Device::GetContrast() { if (!IsOpen()) return -1; struct v4l2_control c; c.id = V4L2_CID_CONTRAST; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) return -1; frameContrast = c.value; return frameContrast; }int PVideoInputV4l2Device::GetHue() { if (!IsOpen()) return -1; struct v4l2_control c; c.id = V4L2_CID_HUE; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) return -1; frameHue = c.value; return frameHue; }BOOL PVideoInputV4l2Device::SetBrightness(unsigned newBrightness) { if (!IsOpen()) return FALSE; struct v4l2_queryctrl q; q.id = V4L2_CID_BRIGHTNESS; if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0) return FALSE; struct v4l2_control c; c.id = V4L2_CID_BRIGHTNESS; c.value = q.minimum + ((q.maximum-q.minimum) * newBrightness) >> 16; if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0) return FALSE; frameBrightness = newBrightness; return TRUE;}BOOL PVideoInputV4l2Device::SetWhiteness(unsigned newWhiteness) { if (!IsOpen()) return FALSE; struct v4l2_queryctrl q; q.id = V4L2_CID_WHITENESS; if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0) return FALSE; struct v4l2_control c; c.id = V4L2_CID_WHITENESS; c.value = q.minimum + ((q.maximum-q.minimum) * newWhiteness) >> 16; if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0) return FALSE; frameWhiteness = newWhiteness; return TRUE;}BOOL PVideoInputV4l2Device::SetColour(unsigned newColour) { if (!IsOpen()) return FALSE; struct v4l2_queryctrl q; q.id = V4L2_CID_SATURATION; if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0) return FALSE; struct v4l2_control c; c.id = V4L2_CID_SATURATION; c.value = q.minimum + ((q.maximum-q.minimum) * newColour) >> 16; if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0) return FALSE; frameColour = newColour; return TRUE;}BOOL PVideoInputV4l2Device::SetContrast(unsigned newContrast) { if (!IsOpen()) return FALSE; struct v4l2_queryctrl q; q.id = V4L2_CID_CONTRAST; if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0) return FALSE; struct v4l2_control c; c.id = V4L2_CID_CONTRAST; c.value = q.minimum + ((q.maximum-q.minimum) * newContrast) >> 16; if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0) return FALSE; frameContrast = newContrast; return TRUE;}BOOL PVideoInputV4l2Device::SetHue(unsigned newHue) { if (!IsOpen()) return FALSE; struct v4l2_queryctrl q; q.id = V4L2_CID_HUE; if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0) return FALSE; struct v4l2_control c; c.id = V4L2_CID_HUE; c.value = q.minimum + ((q.maximum-q.minimum) * newHue) >> 16; if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0) return FALSE; frameHue=newHue; return TRUE;}BOOL PVideoInputV4l2Device::GetParameters (int *whiteness, int *brightness, int *colour, int *contrast, int *hue){ if (!IsOpen()) return FALSE; struct v4l2_control c; c.id = V4L2_CID_WHITENESS; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) frameWhiteness = -1; else frameWhiteness = c.value; c.id = V4L2_CID_BRIGHTNESS; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) frameBrightness = -1; else frameBrightness = c.value; c.id = V4L2_CID_SATURATION; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) frameColour = -1; else frameColour = c.value; c.id = V4L2_CID_CONTRAST; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) frameContrast = -1; else frameContrast = c.value; c.id = V4L2_CID_HUE; if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0) frameHue = -1; else frameHue = c.value; *whiteness = frameWhiteness; *brightness = frameBrightness; *colour = frameColour; *contrast = frameContrast; *hue = frameHue; return TRUE;}BOOL PVideoInputV4l2Device::TestAllFormats(){ return TRUE;}// this is used to get more userfriendly names:voidV4L2Names::Update(){ PTRACE(1,"Detecting V4L2 devices"); PDirectory procvideo2_4("/proc/video/dev"); PDirectory procvideo2_6("/sys/class/video4linux"); PDirectory * procvideo; PString entry; PStringList devlist; PString oldDevName; // Try and guess kernel version if (procvideo2_6.Exists()) { kernelVersion = K2_6; procvideo=&procvideo2_6; } else if (procvideo2_4.Exists()) { kernelVersion=K2_4; procvideo=&procvideo2_4; } else { kernelVersion=KUNKNOWN; procvideo=0; } inputDeviceNames.RemoveAll (); // flush the previous run if (procvideo) { PTRACE(2,"PV4L2Plugin\tdetected device metadata at "<<*procvideo); if ((kernelVersion==K2_6 && procvideo->Open(PFileInfo::SubDirectory) || (procvideo->Open(PFileInfo::RegularFile)))) { do { entry = procvideo->GetEntryName(); if ((entry.Left(5) == "video")) { PString thisDevice = "/dev/" + entry; int videoFd=::open((const char *)thisDevice, O_RDONLY | O_NONBLOCK); if ((videoFd > 0) || (errno == EBUSY)) { BOOL valid = FALSE; struct v4l2_capability videoCaps; memset(&videoCaps,0,sizeof(videoCaps)); if ((errno == EBUSY) || (::ioctl(videoFd, VIDIOC_QUERYCAP, &videoCaps) >= 0 && (videoCaps.capabilities & V4L2_CAP_VIDEO_CAPTURE))) { PTRACE(1,"PV4L2Plugin\tdetected capture device " << videoCaps.card); valid = TRUE; } else { PTRACE(1,"PV4L2Plugin\t" << thisDevice << "is not deemed valid"); } if (videoFd>0) ::close(videoFd); if(valid) inputDeviceNames += thisDevice; } else { PTRACE(1,"PV4L2Plugin\tcould not open " << thisDevice); } } } while (procvideo->Next()); } } else { PTRACE(1,"Unable to detect v4l2 directory"); } if (inputDeviceNames.GetSize() == 0) { POrdinalToString vid; ReadDeviceDirectory("/dev/", vid); for (PINDEX i = 0; i < vid.GetSize(); i++) { PINDEX cardnum = vid.GetKeyAt(i); int fd = ::open(vid[cardnum], O_RDONLY | O_NONBLOCK); if ((fd >= 0) || (errno == EBUSY)) { if (fd >= 0) ::close(fd); inputDeviceNames += vid[cardnum]; } } } PopulateDictionary();}PString V4L2Names::BuildUserFriendly(PString devname){ PString Result; int fd = ::open((const char *)devname, O_RDONLY); if(fd < 0) { return devname; } struct v4l2_capability videocap; memset(&videocap,0,sizeof(videocap)); if (::ioctl(fd, VIDIOC_QUERYCAP, &videocap) < 0) { ::close(fd); return devname; } ::close(fd); PString ufname((const char*)videocap.card); return ufname;}// End Of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -