23#include <linux/media.h>
24#include <linux/v4l2-subdev.h>
25#include <linux/videodev2.h>
40#define CLEAR(x) memset(&(x), 0, sizeof(x))
45 if (interfaceC ==
nullptr)
50 interfaceCApi_ = interfaceC;
56 if (interfaceCApi_ !=
nullptr && ownerCApi_)
58 delete interfaceCApi_;
62bool UltraPythonCameraHelper::openPipeline()
67 int fd = interfaceCApi_->
open_c(mediaName_, O_RDWR);
70 Log(*
this,
Severity::error) <<
"ERROR-cannot open media dev.Are modules loaded?";
78 Log(*
this,
Severity::error) <<
"ERROR-cannot open udev. Is libudev installed?";
83 struct media_entity_desc
info;
84 int subdeviceIndex = 0;
85 for (
int id = 0;;
id =
info.id)
88 info.id =
id | MEDIA_ENT_ID_FLAG_NEXT;
101 if (device ==
nullptr)
103 udev_device_unref(device);
107 const char *deviceName;
111 if ((std::strcmp(
info.name, pipelineVideoName) == 0))
113 mainSubdeviceFd_ = interfaceCApi_->
open_c(deviceName, O_RDWR | O_NONBLOCK, 0);
114 if (mainSubdeviceFd_ == -1)
116 Log(*
this,
Severity::error) <<
"ERROR-cannot open device:" << std::string(deviceName);
119 Log(*
this,
Severity::debug) <<
"open no pipeline:" << std::string(deviceName);
129 if (std::strcmp(
info.name, pipelinePythonName) == 0)
131 if (sourceSubDeviceIndex1_ == -1)
133 sourceSubDeviceIndex1_ = subdeviceIndex;
137 sourceSubDeviceIndex2_ = subdeviceIndex;
140 else if (std::strstr(
info.name, pipelineTpgName))
142 tpgIndex_ = subdeviceIndex;
144 else if (std::strstr(
info.name, pipelineCscName))
146 cscIndex_ = subdeviceIndex;
148 else if (std::strstr(
info.name, pipelineImgfusionName))
150 imgfusionIndex_ = subdeviceIndex;
152 else if (std::strstr(
info.name, pipelinePacket32Name))
154 packet32Index_ = subdeviceIndex;
156 else if (std::strcmp(
info.name, pipelineRxifName) == 0)
158 if (rxif1Index_ == -1)
160 rxif1Index_ = subdeviceIndex;
164 rxif2Index_ = subdeviceIndex;
167 pipelineSubdeviceFd_[subdeviceIndex] = interfaceCApi_->
open_c(deviceName, O_RDWR | O_NONBLOCK, 0);
168 if (pipelineSubdeviceFd_[subdeviceIndex] == -1)
170 Log(*
this,
Severity::error) <<
"ERROR-cannot open device:" << std::string(deviceName);
173 Log(*
this,
Severity::debug) <<
"Open pipeline devicename:" << std::string(deviceName) <<
" info name:" <<
info.name <<
" fd:" << pipelineSubdeviceFd_[subdeviceIndex]
174 <<
" index:" << subdeviceIndex;
183bool UltraPythonCameraHelper::checkIndex()
185 if (mainSubdeviceFd_ == -1)
190 if (sourceSubDeviceIndex1_ == -1)
195 if (sourceSubDeviceIndex2_ == -1)
200 if (rxif1Index_ == -1)
205 if (rxif2Index_ == -1)
220 if (imgfusionIndex_ == -1)
228bool UltraPythonCameraHelper::setSubDevFormat(
int width,
int height)
233 struct v4l2_subdev_format fmt;
235 for (i = 0; pipelineSubdeviceFd_[i] != -1; i++)
237 if (i == imgfusionIndex_)
245 for (j = 0; j < n; j++)
248 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
250 if (-1 == interfaceCApi_->
xioctl(pipelineSubdeviceFd_[i], VIDIOC_SUBDEV_G_FMT, &fmt))
252 Log(*
this,
Severity::error) <<
"VIDIOC_SUBDEV_G_FMT. subdev" << i <<
"pad" << j;
256 fmt.format.width = width;
257 fmt.format.height = height;
262 fmt.format.code = MEDIA_BUS_FMT_UYVY8_1X16;
266 if ((imgfusionIndex_ != -1) && (i == cscIndex_))
268 fmt.format.width *= 2;
271 if ((imgfusionIndex_ != -1) && (i == packet32Index_))
273 fmt.format.width *= 2;
276 if ((imgfusionIndex_ != -1) && (i == tpgIndex_))
278 fmt.format.width *= 2;
284 fmt.format.width *= 2;
288 Log(*
this,
Severity::debug) <<
"subdev idx:" << i <<
" pad" << j <<
" setting format:" << fmt.format.width <<
":" << fmt.format.height;
290 if (-1 == interfaceCApi_->
xioctl(pipelineSubdeviceFd_[i], VIDIOC_SUBDEV_S_FMT, &fmt))
292 Log(*
this,
Severity::error) <<
"VIDIOC_SUBDEV_S_FMT. subdev" << i <<
"pad" << j;
296 if ((i == sourceSubDeviceIndex1_) || (i == sourceSubDeviceIndex2_))
305bool UltraPythonCameraHelper::setFormat()
307 struct v4l2_format fmt;
310 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
312 if (forceFormatProperty_ || cropEnabledProperty_)
315 fmt.fmt.pix.width = cropEnabledProperty_ ? cropWidth_ : nativeWidth_;
316 fmt.fmt.pix.height = cropEnabledProperty_ ? cropHeight_ : nativeHeight_;
318 if (subsamplingEnabledProperty_)
320 fmt.fmt.pix.width /= 2;
321 fmt.fmt.pix.height /= 2;
326 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
330 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
334 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
337 fmt.fmt.pix.field = 1;
338 fmt.fmt.pix.colorspace = 8;
340 if (!setSubDevFormat(fmt.fmt.pix.width, fmt.fmt.pix.height))
345 if (imgfusionIndex_ != -1)
347 fmt.fmt.pix.width *= 2;
350 if (-1 == interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_S_FMT, &fmt))
359 if (interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_G_FMT, &fmt) == -1)
367bool UltraPythonCameraHelper::crop(
int top,
int left,
int w,
int h,
int mytry)
371 Log(*
this,
Severity::debug) <<
"crop is" << std::string(cropEnabledProperty_ ?
"ENABLED" :
"DISABLED");
372 if (!cropEnabledProperty_)
377 struct v4l2_subdev_crop _crop;
379 _crop.rect.left = left;
380 _crop.rect.top = top;
381 _crop.rect.width = w;
382 _crop.rect.height = h;
384 _crop.which = mytry ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
387 if (-1 == interfaceCApi_->
xioctl(pipelineSubdeviceFd_[sourceSubDeviceIndex1_], VIDIOC_SUBDEV_S_CROP, &_crop))
391 if (sourceSubDeviceIndex2_ != -1)
393 if (-1 == interfaceCApi_->
xioctl(pipelineSubdeviceFd_[sourceSubDeviceIndex2_], VIDIOC_SUBDEV_S_CROP, &_crop))
401bool UltraPythonCameraHelper::setSubsampling()
403 Log(*
this,
Severity::debug) <<
"subsampling is" << std::string(subsamplingEnabledProperty_ ?
"ENABLED" :
"DISABLED");
404 int subSamplingValue = 0;
405 if (subsamplingEnabledProperty_)
407 subSamplingValue = 1;
411 struct v4l2_control ctrl;
414 ctrl.value = subSamplingValue;
415 if (-1 == interfaceCApi_->
xioctl(pipelineSubdeviceFd_[sourceSubDeviceIndex1_], VIDIOC_S_CTRL, &ctrl))
421 if (sourceSubDeviceIndex2_ != -1)
423 if (-1 == interfaceCApi_->
xioctl(pipelineSubdeviceFd_[sourceSubDeviceIndex2_], VIDIOC_S_CTRL, &ctrl))
431 ctrl.value = subSamplingValue;
432 if (-1 == interfaceCApi_->
xioctl(pipelineSubdeviceFd_[rxif1Index_], VIDIOC_S_CTRL, &ctrl))
438 if (rxif2Index_ != -1)
440 if (-1 == interfaceCApi_->
xioctl(pipelineSubdeviceFd_[rxif2Index_], VIDIOC_S_CTRL, &ctrl))
449bool UltraPythonCameraHelper::checkDevice(
int mainSubdeviceFd)
451 struct v4l2_capability cap;
452 if (-1 == interfaceCApi_->
xioctl(mainSubdeviceFd, VIDIOC_QUERYCAP, &cap))
464bool UltraPythonCameraHelper::initDevice()
468 if (!checkDevice(mainSubdeviceFd_))
472 if (!setSubsampling())
480 if (!crop(cropTop_, cropLeft_, cropWidth_, cropHeight_, 0))
492bool UltraPythonCameraHelper::cropCheck()
494 struct v4l2_cropcap cropcap;
495 struct v4l2_crop tmpCrop;
498 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
499 if (0 == interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_CROPCAP, &cropcap))
501 tmpCrop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
502 tmpCrop.c = cropcap.defrect;
504 if (-1 == interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_S_CROP, &tmpCrop))
524bool UltraPythonCameraHelper::initMmap()
527 struct v4l2_requestbuffers req;
531 req.count = requestBufferNumber_;
532 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
533 req.memory = V4L2_MEMORY_MMAP;
535 if (-1 == interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_REQBUFS, &req))
552 for (
unsigned int currentUsedBufferIndex = 0; currentUsedBufferIndex < req.count; ++currentUsedBufferIndex)
554 struct v4l2_buffer buf;
558 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
559 buf.memory = V4L2_MEMORY_MMAP;
560 buf.index = currentUsedBufferIndex;
562 if (-1 == interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_QUERYBUF, &buf))
567 mMapBuffers_[currentUsedBufferIndex].
length = buf.length;
568 mMapBuffers_[currentUsedBufferIndex].
start =
569 interfaceCApi_->
mmap_c(
nullptr , buf.length, PROT_READ | PROT_WRITE , MAP_SHARED , mainSubdeviceFd_, buf.m.offset);
571 if (MAP_FAILED == mMapBuffers_[currentUsedBufferIndex].start)
579bool UltraPythonCameraHelper::startCapturing()
582 enum v4l2_buf_type type;
584 for (
size_t i = 0; i < requestBufferNumber_; ++i)
586 struct v4l2_buffer buf;
589 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
590 buf.memory = V4L2_MEMORY_MMAP;
593 if (-1 == interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_QBUF, &buf))
599 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
600 if (-1 == interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_STREAMON, &type))
611 static int sequence = 0;
620 FD_SET(mainSubdeviceFd_, &fds);
622 int ret = interfaceCApi_->
select_c(mainSubdeviceFd_ + 1, &fds,
nullptr,
nullptr, &tv);
640 seq = readFrame(yarpbuffer);
645 if (seq != sequence++)
656int UltraPythonCameraHelper::readFrame(
unsigned char *yarpbuffer)
658 struct v4l2_buffer buf;
662 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
663 buf.memory = V4L2_MEMORY_MMAP;
665 if (interfaceCApi_->
xioctl_v4l2(mainSubdeviceFd_, VIDIOC_DQBUF, &buf) == -1)
679 if (buf.index >= requestBufferNumber_)
685 if (buf.flags & V4L2_BUF_FLAG_ERROR)
693 memcpy(yarpbuffer, mMapBuffers_[buf.index].start,
695 processImage(mMapBuffers_[buf.index].start, buf.bytesused);
697 memset(mMapBuffers_[buf.index].start, 111, buf.bytesused);
699 if (interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_QBUF, &buf) == -1)
708void UltraPythonCameraHelper::processImage(
const void *p,
int size)
710 if (injectedProcessImage_ ==
nullptr)
714 injectedProcessImage_(p, size);
719 if (!stopCapturing())
727 if (!closePipeline())
734bool UltraPythonCameraHelper::unInitDevice()
739 for (i = 0; i < requestBufferNumber_; ++i)
741 if (-1 == munmap(mMapBuffers_[i].start, mMapBuffers_[i].length))
750bool UltraPythonCameraHelper::stopCapturing()
752 enum v4l2_buf_type type;
754 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
755 if (-1 == interfaceCApi_->
xioctl(mainSubdeviceFd_, VIDIOC_STREAMOFF, &type))
763bool UltraPythonCameraHelper::closePipeline()
767 for (i = 0; pipelineSubdeviceFd_[i] != -1; i++)
769 if (-1 == close(pipelineSubdeviceFd_[i]))
780 injectedProcessImage_ = toinJect;
793 subsamplingEnabledProperty_ = value;
819 if (!setDefaultControl())
824 if (!startCapturing())
858 if (value > 1.0 || value < 0.0)
860 Log(*
this,
Severity::error) <<
"Not absolute settings should be between 0,1:" << v4lCtrl;
865 if (!FeatureHelper::isV4Lcontrol(v4lCtrl))
869 case YARP_FEATURE_HONOR_FPS:
873 Log(*
this,
Severity::error) <<
"setControl wrong not v4l control id:" << v4lCtrl;
877 if (!internalHasControl(v4lCtrl))
879 Log(*
this,
Severity::error) <<
"setControl Missing ctr id:" << v4lCtrl;
882 Log(*
this,
Severity::debug) <<
"try setControl for:" << v4lCtrl <<
" value:" << value;
886 return setGain(value, absolute);
888 case V4L2_CID_BRIGHTNESS:
891 out =
setControl(v4lCtrl, pipelineSubdeviceFd_[sourceSubDeviceIndex1_], value, absolute);
892 out = out &
setControl(v4lCtrl, pipelineSubdeviceFd_[sourceSubDeviceIndex2_], value, absolute);
900 return setControl(v4lCtrl, mainSubdeviceFd_, value, absolute);
916 struct v4l2_control control;
925 Log(*
this,
Severity::error) <<
"Cannot setControl1 value:" << value <<
" fd:" << fd;
929 Log(*
this,
Severity::error) <<
"Cannot setControl2 value:" << value <<
" fd:" << fd;
934 if (
queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
939 memset(&control, 0,
sizeof(control));
940 control.id = v4lCtrl;
944 queryctrl.maximum = maxPermittedExposition_;
945 queryctrl.minimum = minPermittedExposition_;
953 control.value =
static_cast<int32_t
>(value);
958 double limit = control.value + deadTime_ + 2;
959 if (stepPeriod_ <= limit)
963 Log(*
this,
Severity::warning) <<
"Exposition will decrease FPS no honorfps. Limit:" << limit <<
" current step:" << stepPeriod_;
967 Log(*
this,
Severity::error) <<
"Exposition will decrease FPS honorfps so blocked. Limit:" << limit <<
" current step:" << stepPeriod_;
973 Log(*
this,
Severity::debug) <<
"Exposition will mantain current FPS Limit:" << limit <<
" current step:" << stepPeriod_;
975 currentExposure_ = control.value;
985 Log(*
this,
Severity::debug) <<
"SetControl done --> Ctrl name:" <<
queryctrl.name <<
" Ctrl value:" << control.value <<
" Ctrl id:" << control.id;
991 if (!FeatureHelper::isV4Lcontrol(v4lCtrl))
995 case YARP_FEATURE_HONOR_FPS:
997 case YARP_FEATURE_FPS:
998 return statistics_.
getFps();
999 case YARP_FEATURE_SUBSAMPLING:
1000 if (subsamplingEnabledProperty_)
1004 Log(*
this,
Severity::error) <<
"getControl wrong not v4l control id:" << v4lCtrl;
1009 if (!internalHasControl(v4lCtrl))
1011 Log(*
this,
Severity::error) <<
"getControl Missing ctr id:" << v4lCtrl;
1019 case V4L2_CID_BRIGHTNESS:
1022 double left =
getControl(v4lCtrl, pipelineSubdeviceFd_[sourceSubDeviceIndex1_], absolute);
1023 double right =
getControl(v4lCtrl, pipelineSubdeviceFd_[sourceSubDeviceIndex2_], absolute);
1036 return getControl(v4lCtrl, mainSubdeviceFd_, absolute);
1044 if (v4lCtrl == V4L2_CID_GAIN)
1046 double min = gainMap_.begin()->first;
1047 double max = gainMap_.end()->first;
1049 return currentGainValue_;
1050 return (currentGainValue_ - min) / (max - min);
1054 struct v4l2_control control;
1056 memset(&control, 0,
sizeof(control));
1059 control.id = v4lCtrl;
1064 if (errno != EINVAL)
1066 Log(*
this,
Severity::error) <<
"getControl VIDIOC_QUERYCTRL:" << v4lCtrl;
1071 if (
queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
1077 if (interfaceCApi_->
ioctl_control_c(fd, VIDIOC_G_CTRL, control) == -1)
1079 Log(*
this,
Severity::error) <<
"getControl VIDIOC_G_CTRL:" << v4lCtrl;
1086 queryctrl.maximum = maxPermittedExposition_;
1087 queryctrl.minimum = minPermittedExposition_;
1091 return control.value;
1095bool UltraPythonCameraHelper::internalHasControl(uint32_t v4lCtrl)
const
1102 case V4L2_CID_BRIGHTNESS:
1115 Log(*
this,
Severity::debug) <<
"internalHasControl for original:" << v4lCtrl <<
" value:" <<
ret;
1119bool UltraPythonCameraHelper::setDefaultControl()
1130bool UltraPythonCameraHelper::setGain(
double value,
bool absolute)
1132 double min = gainMap_.begin()->first;
1133 double max = gainMap_.end()->first;
1134 int absoluteValue =
static_cast<int32_t
>(value);
1137 absoluteValue =
static_cast<int32_t
>(value * (max - min) + min);
1140 auto it = gainMap_.find(absoluteValue);
1141 if (it == gainMap_.end())
1147 auto current = gainMap_.at(absoluteValue);
1148 currentGainValue_ = absoluteValue;
1149 Log(*
this,
Severity::debug) <<
"gain:" << absoluteValue <<
" digital:" << current.first <<
" analog:" << current.second;
1151 setControl(V4L2_CID_GAIN, pipelineSubdeviceFd_[sourceSubDeviceIndex1_], current.first,
true);
1152 setControl(V4L2_CID_GAIN, pipelineSubdeviceFd_[sourceSubDeviceIndex2_], current.first,
true);
1160 return cropEnabledProperty_;
1164 return forceFormatProperty_;
1177 return currentExposure_;
1183 mMapBuffers_[index].
start = tofillWith;
struct v4l2_queryctrl queryctrl
virtual int xioctl_v4l2(int fh, int request, struct v4l2_buffer *arg)
virtual int ioctl_query_c(int fd, int value, struct v4l2_queryctrl &info)
virtual struct udev * udev_new_c()
virtual struct udev_device * udev_device_new_from_devnum_c(struct udev *udev, char type, dev_t devnum)
virtual dev_t makedev_c(int major, int minor)
virtual int open_c(const char *path, int oflag)
virtual struct udev_device * udev_device_unref_c(struct udev_device *udev_device)
virtual const char * udev_device_get_devnode_c(struct udev_device *udev_device)
virtual int xioctl(int fh, int request, void *arg)
virtual int ioctl_media_c(int fd, int value, struct media_entity_desc &info)
virtual int select_c(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
virtual void * mmap_c(void *addr, size_t len, int prot, int flags, int fd, __off_t offset)
virtual int ioctl_control_c(int fd, int value, struct v4l2_control &info)
void setExposure(double value)
static constexpr unsigned int V4L2_ANALOGGAIN_ULTRA_PYTHON
void setInjectedUnlock(std::function< void()> toinJect)
~UltraPythonCameraHelper()
void setInjectedLog(std::function< void(const std::string &, Severity severity)> toinJect)
void mapBufferFill(unsigned char *tofillWith, unsigned int index)
double getStepPeriod() const
bool getCropEnabledProperty() const
bool getForceFormatProperty() const
static constexpr unsigned int V4L2_EXTTRIGGER_ULTRA_PYTHON
static constexpr unsigned int V4L2_CONTRAST_ULTRA_PYTHON
static constexpr unsigned int V4L2_BLUEBALANCE_ULTRA_PYTHON
bool step(unsigned char *yarpbuffer)
void setInjectedLock(std::function< void()> toinJect)
void setInjectedProcess(std::function< void(const void *, int)> toinJect)
double getCurrentExposure() const
void setHonorFps(bool value)
static constexpr unsigned int V4L2_DEADTIME_ULTRA_PYTHON
void setStepPeriod(double msec)
UltraPythonCameraHelper(InterfaceForCApi *interfaceCt)
static constexpr unsigned int V4L2_EXPOSURE_ULTRA_PYTHON
bool setControl(uint32_t v4lCtrl, double value, bool absolute)
static constexpr unsigned int V4L2_GREENBALANCE_ULTRA_PYTHON
double getControl(uint32_t v4lCtrl, bool absolute)
static constexpr unsigned int V4L2_REDBALANCE_ULTRA_PYTHON
void setSubsamplingProperty(bool value)
#define V4L2_CID_XILINX_PYTHON1300_SUBSAMPLING
#define V4L2_CID_XILINX_PYTHON1300_RXIF_REMAPPER_MODE