📄 vidinput_v4l2.cxx
字号:
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 PVideoInputDevice_V4L2::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 PVideoInputDevice_V4L2::VerifyHardwareFrameSize(unsigned width, unsigned height)
{
struct v4l2_format videoFormat;
videoFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
struct v4l2_streamparm streamParm;
unsigned int fi_n = 0, fi_d = 0;
streamParm.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;
}
// get the frame rate so we can preserve it throughout the S_FMT call
// Sidenote: V4L2 gives us the frame interval, i.e. 1/fps.
if (::ioctl(videoFd, VIDIOC_G_PARM, &streamParm) == 0 &&
streamParm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
fi_n = streamParm.parm.capture.timeperframe.numerator;
fi_d = streamParm.parm.capture.timeperframe.denominator;
} else {
PTRACE(1,"PVidInDev\tG_PARM failed (preserving frame rate may not work) : " << ::strerror(errno));
}
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;
}
// reset the frame rate because it may have been overridden by the call to S_FMT
if (fi_n == 0 || fi_d == 0 || ::ioctl(videoFd, VIDIOC_S_PARM, &streamParm) < 0) {
PTRACE(3,"PVidInDev\tunable to reset frame rate.");
} else if (streamParm.parm.capture.timeperframe.numerator != fi_n ||
streamParm.parm.capture.timeperframe.denominator != fi_d) {
PTRACE(3, "PVidInDev\tnew frame interval (" << streamParm.parm.capture.timeperframe.numerator
<< "/" << streamParm.parm.capture.timeperframe.denominator
<< ") differs from what was requested (" << fi_n << "/" << fi_d << ").");
}
frameBytes = videoFormat.fmt.pix.sizeimage;
return TRUE;
}
/**
* Query the current control setting
* @param control is v4l2 control id (V4L2_CID_BRIGHTNESS, V4L2_CID_WHITENESS, ...)
* @return -1 control is unknown, or an error occured
* >=0 current value in a range [0-65535]
*/
int PVideoInputDevice_V4L2::GetControlCommon(unsigned int control, int *value)
{
if (!IsOpen())
return -1;
struct v4l2_queryctrl q;
memset(&q, 0, sizeof(struct v4l2_queryctrl));
q.id = control;
if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0)
return -1;
struct v4l2_control c;
memset(&c, 0, sizeof(struct v4l2_control));
c.id = control;
if (::ioctl(videoFd, VIDIOC_G_CTRL, &c) < 0)
return -1;
*value = ((c.value - q.minimum) * 65536) / ((q.maximum-q.minimum));
return *value;
}
int PVideoInputDevice_V4L2::GetBrightness()
{
return GetControlCommon(V4L2_CID_BRIGHTNESS, &frameBrightness);
}
int PVideoInputDevice_V4L2::GetWhiteness()
{
return GetControlCommon(V4L2_CID_WHITENESS, &frameWhiteness);
}
int PVideoInputDevice_V4L2::GetColour()
{
return GetControlCommon(V4L2_CID_SATURATION, &frameColour);
}
int PVideoInputDevice_V4L2::GetContrast()
{
return GetControlCommon(V4L2_CID_CONTRAST, &frameContrast);
}
int PVideoInputDevice_V4L2::GetHue()
{
return GetControlCommon(V4L2_CID_HUE, &frameHue);
}
/**
* Set a control to a new value
*
* @param control: V4L2_CID_BRIGHTNESS, V4L2_CID_WHITENESS, ...
* @param newValue: 0-65535 Set this control to this range
* -1 Set the default value
* @return FALSE, if an error occur or the control is not supported
*/
BOOL PVideoInputDevice_V4L2::SetControlCommon(unsigned int control, int newValue)
{
PTRACE(1,"PVidInDev\t" << __FUNCTION__ << "() videoFd=" << videoFd);
if (!IsOpen())
return FALSE;
struct v4l2_queryctrl q;
memset(&q, 0, sizeof(struct v4l2_queryctrl));
q.id = control;
if (::ioctl(videoFd, VIDIOC_QUERYCTRL, &q) < 0)
return FALSE;
struct v4l2_control c;
memset(&c, 0, sizeof(struct v4l2_control));
c.id = control;
if (newValue < 0)
c.value = q.default_value;
else
c.value = q.minimum + ((q.maximum-q.minimum) * newValue)/65535;
if (::ioctl(videoFd, VIDIOC_S_CTRL, &c) < 0)
return FALSE;
return TRUE;
}
BOOL PVideoInputDevice_V4L2::SetBrightness(unsigned newBrightness)
{
if (!SetControlCommon(V4L2_CID_BRIGHTNESS, newBrightness))
return FALSE;
frameBrightness = newBrightness;
return TRUE;
}
BOOL PVideoInputDevice_V4L2::SetWhiteness(unsigned newWhiteness)
{
if (!SetControlCommon(V4L2_CID_WHITENESS, newWhiteness))
return FALSE;
frameWhiteness = newWhiteness;
return TRUE;
}
BOOL PVideoInputDevice_V4L2::SetColour(unsigned newColour)
{
if (!SetControlCommon(V4L2_CID_SATURATION, newColour))
return FALSE;
frameColour = newColour;
return TRUE;
}
BOOL PVideoInputDevice_V4L2::SetContrast(unsigned newContrast)
{
if (!SetControlCommon(V4L2_CID_CONTRAST, newContrast))
return FALSE;
frameContrast = newContrast;
return TRUE;
}
BOOL PVideoInputDevice_V4L2::SetHue(unsigned newHue)
{
if (!SetControlCommon(V4L2_CID_HUE, newHue))
return FALSE;
frameHue=newHue;
return TRUE;
}
BOOL PVideoInputDevice_V4L2::GetParameters (int *whiteness, int *brightness, int *colour, int *contrast, int *hue)
{
if (!IsOpen())
return FALSE;
frameWhiteness = -1;
frameBrightness = -1;
frameColour = -1;
frameContrast = -1;
frameHue = -1;
GetWhiteness();
GetBrightness();
GetColour();
GetContrast();
GetHue();
*whiteness = frameWhiteness;
*brightness = frameBrightness;
*colour = frameColour;
*contrast = frameContrast;
*hue = frameHue;
return TRUE;
}
BOOL PVideoInputDevice_V4L2::TestAllFormats()
{
return TRUE;
}
// this is used to get more userfriendly names:
void
V4L2Names::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 + -