📄 vidinput_v4l.cxx
字号:
for (PINDEX i = 0; i < userKey.GetSize(); i++) if (userKey.GetKeyAt(i).Find(userName) != P_MAX_INDEX) return userKey.GetDataAt(i); return userName;}void V4LNames::AddUserDeviceName(PString userName, PString devName){ if (userName != devName) { // must be a real userName! userKey.SetAt(userName, devName); deviceKey.SetAt(devName, userName); } else { // we didn't find a good userName if (!deviceKey.Contains (devName)) { // never met before: fallback userKey.SetAt(userName, devName); deviceKey.SetAt(devName, userName); } // no else: we already know the pair }}PString V4LNames::BuildUserFriendly(PString devname){ PString Result; int fd = ::open((const char *)devname, O_RDONLY); if(fd < 0) { return devname; } struct video_capability videocap; if (::ioctl(fd, VIDIOCGCAP, &videocap) < 0) { ::close(fd); return devname; } ::close(fd); PString ufname(videocap.name); return ufname;}/* There is a duplication in the list of names. Consequently, opening the device as "ov511++" or "/dev/video0" will work.*/PStringList V4LNames::GetInputDeviceNames(){ PWaitAndSignal m(mutex); PStringList result; for (PINDEX i = 0; i < inputDeviceNames.GetSize(); i++) { result += GetUserFriendly (inputDeviceNames[i]); //result += inputDeviceNames[i]; } return result;}static V4LNames & GetNames(){ static V4LNames names; names.Update(); return names;} ///////////////////////////////////////////////////////////////////////////////// PVideoInputV4lDevicePVideoInputV4lDevice::PVideoInputV4lDevice(){ videoFd = -1; hint_index = PARRAYSIZE(driver_hints) - 1; canMap = -1; for (int i=0; i<2; i++) pendingSync[i] = FALSE;}PVideoInputV4lDevice::~PVideoInputV4lDevice(){ Close();}static struct { const char * colourFormat; int code;} colourFormatTab[] = { { "Grey", VIDEO_PALETTE_GREY }, //Entries in this table correspond { "RGB32", VIDEO_PALETTE_RGB32 }, //(line by line) to those in the { "RGB24", VIDEO_PALETTE_RGB24 }, // PVideoDevice ColourFormat table. { "RGB565", VIDEO_PALETTE_RGB565 }, { "RGB555", VIDEO_PALETTE_RGB555 }, { "YUV422", VIDEO_PALETTE_YUV422 }, { "YUV422P", VIDEO_PALETTE_YUV422P }, { "YUV411", VIDEO_PALETTE_YUV411 }, { "YUV411P", VIDEO_PALETTE_YUV411P }, { "YUV420", VIDEO_PALETTE_YUV420 }, { "YUV420P", VIDEO_PALETTE_YUV420P }, { "YUV410P", VIDEO_PALETTE_YUV410P }};BOOL PVideoInputV4lDevice::Open(const PString & devName, BOOL startImmediate){ struct utsname buf; PString version; uname (&buf); if (buf.release) version = PString (buf.release); Close(); PTRACE(1,"PVideoInputV4lDevice: trying to open "<< devName); // check if it is a userfriendly name, and if so, get the real device name PString deviceName = GetNames().GetDeviceName(devName); videoFd = ::open((const char *)deviceName, O_RDWR); if (videoFd < 0) { PTRACE(1,"PVideoInputV4lDevice::Open failed : "<< ::strerror(errno)); return FALSE; } // get the device capabilities if (::ioctl(videoFd, VIDIOCGCAP, &videoCapability) < 0) { PTRACE(1,"PVideoInputV4lDevice:: get device capablilities failed : "<< ::strerror(errno)); ::close (videoFd); videoFd = -1; return FALSE; } if ((videoCapability.type & VID_TYPE_CAPTURE) == 0) { PTRACE(1,"PVideoInputV4lDevice:: device capablilities reports cannot capture"); ::close (videoFd); videoFd = -1; return FALSE; } hint_index = PARRAYSIZE(driver_hints) - 1; PString driver_name(videoCapability.name); // Scan the hint table, looking for regular expression matches with // drivers we hold hints for. PINDEX tbl; for (tbl = 0; tbl < PARRAYSIZE(driver_hints); tbl ++) { PRegularExpression regexp; regexp.Compile(driver_hints[tbl].name_regexp, PRegularExpression::Extended); if (driver_name.FindRegEx(regexp) != P_MAX_INDEX) { PTRACE(1,"PVideoInputV4lDevice::Open: Found driver hints: " << driver_hints[tbl].name); PTRACE(1,"PVideoInputV4lDevice::Open: format: " << driver_hints[tbl].pref_palette); if (driver_hints[tbl].version && !version.IsEmpty ()) if (PString (version) < PString (driver_hints[tbl].version)) { PTRACE(1,"PVideoInputV4lDevice::Open: Hints applied because kernel version less than " << driver_hints[tbl].version); hint_index = tbl; break; } else { PTRACE(1,"PVideoInputV4lDevice::Open: Hints not applied because kernel version is not less than " << driver_hints[tbl].version); } else { hint_index = tbl; break; } } } // Force double-buffering with buggy Quickcam driver. if (HINT (HINT_FORCE_DBLBUF)) {#define QC_IOCTLBASE 220#define VIDIOCQCGCOMPATIBLE _IOR ('v',QC_IOCTLBASE+10,int) /* Get enable workaround for bugs, bitfield */#define VIDIOCQCSCOMPATIBLE _IOWR('v',QC_IOCTLBASE+10,int) /* Set enable workaround for bugs, bitfield */ int reg = 2; /* enable double buffering */ ::ioctl (videoFd, VIDIOCQCSCOMPATIBLE, ®); } // set height and width frameHeight = PMIN (videoCapability.maxheight, QCIFHeight); frameWidth = PMIN (videoCapability.maxwidth, QCIFWidth); // Init audio struct video_audio videoAudio; if (::ioctl(videoFd, VIDIOCGAUDIO, &videoAudio) >= 0 && (videoAudio.flags & VIDEO_AUDIO_MUTABLE) != 0) { videoAudio.flags &= ~VIDEO_AUDIO_MUTE; videoAudio.mode = VIDEO_SOUND_MONO; ::ioctl(videoFd, VIDIOCSAUDIO, &videoAudio); } return TRUE;}BOOL PVideoInputV4lDevice::IsOpen() { return videoFd >= 0;}BOOL PVideoInputV4lDevice::Close(){ if (!IsOpen()) return FALSE; // Mute audio struct video_audio videoAudio; if (::ioctl(videoFd, VIDIOCGAUDIO, &videoAudio) >= 0 && (videoAudio.flags & VIDEO_AUDIO_MUTABLE) != 0) { videoAudio.flags |= VIDEO_AUDIO_MUTE; ::ioctl(videoFd, VIDIOCSAUDIO, &videoAudio); } ClearMapping(); ::close(videoFd); videoFd = -1; canMap = -1; return TRUE;}BOOL PVideoInputV4lDevice::Start(){ return TRUE;}BOOL PVideoInputV4lDevice::Stop(){ return TRUE;}BOOL PVideoInputV4lDevice::IsCapturing(){ return IsOpen();}PStringList PVideoInputV4lDevice::GetInputDeviceNames(){ return GetNames().GetInputDeviceNames();}BOOL PVideoInputV4lDevice::SetVideoFormat(VideoFormat newFormat){ if (!PVideoDevice::SetVideoFormat(newFormat)) { PTRACE(1,"PVideoDevice::SetVideoFormat\t failed"); return FALSE; } // The channel and format are both set at the same time with one ioctl(). // Get the channel information (to check if channel is valid) // Note: If the channel is -1, we need to search for the first valid channel if (channelNumber == -1) { if (!SetChannel(channelNumber)){ PTRACE(1,"PVideoDevice::Cannot set default channel in SetVideoFormat"); return FALSE; } } struct video_channel channel; channel.channel = channelNumber; if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) { PTRACE(1,"VideoInputDevice Get Channel info failed : "<< ::strerror(errno)); return FALSE; } // set channel information static int fmt[4] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM, VIDEO_MODE_AUTO }; channel.norm = fmt[newFormat]; // set the information if (::ioctl(videoFd, VIDIOCSCHAN, &channel) >= 0) return TRUE; PTRACE(1,"VideoInputDevice SetChannel failed : "<< ::strerror(errno)); if (newFormat != Auto) return FALSE; if (SetVideoFormat(PAL)) return TRUE; if (SetVideoFormat(NTSC)) return TRUE; if (SetVideoFormat(SECAM)) return TRUE; return FALSE;}int PVideoInputV4lDevice::GetNumChannels() { /* If Opened, return the capability value, else 1 as in videoio.cxx */ if (IsOpen ()) return videoCapability.channels; else return 1;}BOOL PVideoInputV4lDevice::SetChannel(int newChannel){ if (!PVideoDevice::SetChannel(newChannel)) return FALSE; // get channel information (to check if channel is valid) struct video_channel channel; channel.channel = channelNumber; if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) { PTRACE(1,"VideoInputDevice:: Get info on channel " << channelNumber << " failed : "<< ::strerror(errno)); return FALSE; } // set channel information channel.channel = channelNumber; // set the information if (::ioctl(videoFd, VIDIOCSCHAN, &channel) < 0) { PTRACE(1,"VideoInputDevice:: Set info on channel " << channelNumber << " failed : "<< ::strerror(errno)); return FALSE; } return TRUE;}BOOL PVideoInputV4lDevice::SetVideoChannelFormat (int newNumber, VideoFormat videoFormat) { if (!PVideoDevice::SetChannel(newNumber)) return FALSE; if (!PVideoDevice::SetVideoFormat(videoFormat)) { PTRACE(1,"PVideoDevice::SetVideoFormat\t failed"); return FALSE; } static int fmt[4] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM, VIDEO_MODE_AUTO }; // select the specified input and video format // get channel information (to check if channel is valid) struct video_channel channel; channel.channel = channelNumber; if (::ioctl(videoFd, VIDIOCGCHAN, &channel) < 0) { PTRACE(1,"VideoInputDevice Get Channel info failed : "<< ::strerror(errno)); return FALSE; } // set channel information channel.norm = fmt[videoFormat]; channel.channel = channelNumber; // set the information if (::ioctl(videoFd, VIDIOCSCHAN, &channel) < 0) { PTRACE(1,"VideoInputDevice SetChannel failed : "<< ::strerror(errno)); return FALSE; } return TRUE;}BOOL PVideoInputV4lDevice::SetColourFormat(const PString & newFormat){ PINDEX colourFormatIndex = 0; while (newFormat != colourFormatTab[colourFormatIndex].colourFormat) { colourFormatIndex++; if (colourFormatIndex >= PARRAYSIZE(colourFormatTab)) return FALSE; } if (!PVideoDevice::SetColourFormat(newFormat)) return FALSE; ClearMapping(); // get current picture information struct video_picture pictureInfo; if (::ioctl(videoFd, VIDIOCGPICT, &pictureInfo) < 0) { PTRACE(1,"PVideoInputV4lDevice::Get pict info failed : "<< ::strerror(errno)); return FALSE; } // set colour format colourFormatCode = colourFormatTab[colourFormatIndex].code; pictureInfo.palette = colourFormatCode; if (HINT (HINT_FORCE_DEPTH_16)) pictureInfo.depth = 16; // set the information if (::ioctl(videoFd, VIDIOCSPICT, &pictureInfo) < 0) { PTRACE(1,"PVideoInputV4lDevice::Set pict info failed : "<< ::strerror(errno)); PTRACE(1,"PVideoInputV4lDevice:: used code of "<<colourFormatCode); PTRACE(1,"PVideoInputV4lDevice:: palette: "<<colourFormatTab[colourFormatIndex].colourFormat); return FALSE; } // Driver only (and always) manages to set the colour format with call to VIDIOCSPICT. if( (HINT(HINT_ONLY_WORKS_PREF_PALETTE) ) && ( colourFormatCode == driver_hints[hint_index].pref_palette) ) { PTRACE(3,"PVideoInputV4lDevice:: SetColourFormat succeeded with "<<newFormat); return TRUE; } // Some drivers always return success for CSPICT, and can't // read the current palette back in CGPICT. We can't do much // more than just check to see if there is a preferred palette, // and fail if the request isn't the preferred palette. if (HINT(HINT_CSPICT_ALWAYS_WORKS) && HINT(HINT_CGPICT_DOESNT_SET_PALETTE) && HINT(HINT_HAS_PREF_PALETTE)) { if (colourFormatCode != driver_hints[hint_index].pref_palette) return FALSE; } // Some V4L drivers can't use CGPICT to check for errors. if (!HINT(HINT_CGPICT_DOESNT_SET_PALETTE)) { if (::ioctl(videoFd, VIDIOCGPICT, &pictureInfo) < 0) { PTRACE(1,"PVideoInputV4lDevice::Get pict info failed : "<< ::strerror(errno)); return FALSE; } if (pictureInfo.palette != colourFormatCode) return FALSE; } // set the new information return SetFrameSizeConverter(frameWidth, frameHeight, FALSE);}BOOL PVideoInputV4lDevice::SetFrameRate(unsigned rate){ if (!PVideoDevice::SetFrameRate(rate)) return FALSE; return TRUE;}BOOL PVideoInputV4lDevice::GetFrameSizeLimits(unsigned & minWidth, unsigned & minHeight, unsigned & maxWidth, unsigned & maxHeight) { if (!IsOpen()) return FALSE; if(HINT(HINT_FORCE_LARGE_SIZE)) { videoCapability.maxheight = 288; videoCapability.maxwidth = 352; videoCapability.minheight = 288; videoCapability.minwidth = 352; } maxHeight = videoCapability.maxheight; maxWidth = videoCapability.maxwidth; minHeight = videoCapability.minheight; minWidth = videoCapability.minwidth; PTRACE(3,"PVideoInputV4lDevice:\t GetFrameSizeLimits. "<<minWidth<<"x"<<minHeight<<" -- "<<maxWidth<<"x"<<maxHeight); return TRUE;}BOOL PVideoInputV4lDevice::SetFrameSize(unsigned width, unsigned height){ PTRACE(5, "PVideoInputV4lDevice\t SetFrameSize " << width <<"x"<<height << " Initiated."); if (!PVideoDevice::SetFrameSize(width, height)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -