9 #if defined(USING_UDEV) 12 #include "../polling-device-watcher.h" 43 #include <sys/ioctl.h> 44 #include <sys/sysmacros.h> 45 #include <linux/usb/video.h> 46 #include <linux/media.h> 47 #include <linux/uvcvideo.h> 48 #include <linux/videodev2.h> 54 #include <sys/signalfd.h> 56 #pragma GCC diagnostic ignored "-Woverflow" 61 #include "../tm2/tm-boot.h" 110 int lockf64(
int fd,
int cmd, off64_t
length)
114 memset(&fl, 0,
sizeof(fl));
115 fl.l_whence = SEEK_CUR;
119 if (cmd == F_ULOCK) {
122 return fcntl(fd, F_SETLK64, &fl);
127 return fcntl(fd, F_SETLKW64, &fl);
130 if (cmd == F_TLOCK) {
132 return fcntl(fd, F_SETLK64, &fl);
136 if (fcntl(fd, F_GETLK64, &fl) == -1)
return -1;
137 if (fl.l_type == F_UNLCK || fl.l_pid == getpid())
return 0;
148 return lockf64(fd,
cmd, length);
161 : _device_path(device_path),
164 _object_lock_counter(0)
202 auto ret = lockf(
_fildes, F_TLOCK, 0);
226 auto ret = lockf(
_fildes, F_LOCK, 0);
253 auto ret = lockf(
_fildes, F_ULOCK, 0);
255 err_msg =
to_string() <<
"lockf(...) failed";
260 err_msg =
to_string() <<
"close(...) failed";
267 if (!err_msg.empty())
272 static int xioctl(
int fh,
unsigned long request,
void *
arg)
276 r = ioctl(fh, request, arg);
277 }
while (r < 0 && errno == EINTR);
282 : _type(type), _use_memory_map(use_memory_map), _index(index)
284 v4l2_buffer
buf = {};
286 buf.memory = use_memory_map ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
288 if(
xioctl(fd, VIDIOC_QUERYBUF, &buf) < 0)
299 PROT_READ | PROT_WRITE, MAP_SHARED,
315 v4l2_buffer
buf = {};
323 buf.m.userptr =
reinterpret_cast<unsigned long>(
_start);
325 if(
xioctl(fd, VIDIOC_QBUF, &buf) < 0)
328 LOG_DEBUG_V4L(
"prepare_for_streaming fd " << std::dec << fd);
372 LOG_ERROR(
"xioctl(VIDIOC_QBUF) failed when requesting new frame! fd: " << fd <<
" error: " << strerror(errno));
382 std::shared_ptr<platform::buffer> data_buf
392 this->
buffers.at(buf_type)._managed =
true;
396 buffers.at(buf_type)._file_desc = file_desc;
397 buffers.at(buf_type)._managed =
false;
398 buffers.at(buf_type)._data_buf = data_buf;
399 buffers.at(buf_type)._dq_buf = v4l_buf;
408 if (
buf._data_buf && (
buf._file_desc >= 0))
409 buf._data_buf->request_next_frame(
buf._file_desc);
417 void* md_start =
nullptr;
422 static const int d4xx_md_size = 248;
429 auto md_appendix_sz = 0L;
430 if (compressed && (dq.bytesused < fr_payload_size))
431 md_appendix_sz = d4xx_md_size;
433 md_appendix_sz = long(dq.bytesused) - fr_payload_size;
435 if (md_appendix_sz >0 )
438 md_size = (*(
static_cast<uint8_t*
>(md_start)));
439 int md_flags = (*(
static_cast<uint8_t*
>(md_start)+1));
441 if ((md_appendix_sz != md_size) || (!
val_in_range(md_flags, {0x8e, 0x8f})))
449 if (
nullptr == md_start)
453 set_md_attributes(static_cast<uint8_t>(md_size),md_start);
462 LOG_ERROR(
"Non-sequential Video and Metadata v4l buffers - video seq = " <<
buffers[
e_video_buf]._dq_buf.sequence <<
", md seq = " <<
buffers[e_metadata_buf]._dq_buf.sequence);
481 char usb_actual_path[PATH_MAX] = {0};
482 if (realpath(path.c_str(), usb_actual_path) !=
nullptr)
484 path = std::string(usb_actual_path);
486 if(!(std::ifstream(path +
"/version") >> val))
490 [&
val](
const std::pair<usb_spec, std::string>& kpv){
return (std::string::npos !=val.find(kpv.second));});
501 std::unique_ptr<int, std::function<void(int*)> > fd(
502 new int (open(dev_name.c_str(), O_RDWR | O_NONBLOCK, 0)),
503 [](
int*
d){
if (
d && (*
d)) {::close(*
d); }
delete d; });
508 v4l2_capability cap = {};
509 if(
xioctl(*fd, VIDIOC_QUERYCAP, &cap) < 0)
517 return cap.device_caps;
533 v4l2_memory mem_type, v4l2_buf_type
type)
535 struct v4l2_requestbuffers req = {
count,
type, mem_type, {}};
537 if(
xioctl(fd, VIDIOC_REQBUFS, &req) < 0)
540 LOG_ERROR(dev_name +
" does not support memory mapping");
550 std::vector<std::string> video_paths;
552 DIR *
dir = opendir(
"/sys/class/video4linux");
555 LOG_INFO(
"Cannot access /sys/class/video4linux");
558 while (dirent * entry = readdir(dir))
560 std::string
name = entry->d_name;
561 if(name ==
"." || name ==
"..")
continue;
564 static const std::regex video_dev_pattern(
"(\\/video\\d+)$");
566 std::string
path =
"/sys/class/video4linux/" +
name;
567 std::string real_path{};
568 char buff[PATH_MAX] = {0};
569 if (realpath(path.c_str(), buff) !=
nullptr)
571 real_path = std::string(buff);
572 if (real_path.find(
"virtual") != std::string::npos)
574 if (!std::regex_search(real_path, video_dev_pattern))
580 video_paths.push_back(real_path);
587 std::sort(video_paths.begin(), video_paths.end(),
588 [](
const std::string&
first,
const std::string& second)
591 std::string first_video = first.substr(first.find_last_of(
'/') + 1);
592 std::string second_video = second.substr(second.find_last_of(
'/') + 1);
595 std::stringstream first_index(first_video.substr(first_video.find_first_of(
"0123456789")));
596 std::stringstream second_index(second_video.substr(second_video.find_first_of(
"0123456789")));
597 int left_id = 0, right_id = 0;
598 first_index >> left_id;
599 second_index >> right_id;
600 return left_id < right_id;
606 std::string& busnum, std::string& devnum, std::string& devpath)
609 if(stat(dev_name.c_str(), &
st) < 0)
613 if(!S_ISCHR(st.st_mode))
617 auto valid_path =
false;
618 std::ostringstream ss;
619 ss <<
"/sys/dev/char/" <<
major(st.st_rdev) <<
":" <<
minor(st.st_rdev) <<
"/device/";
621 auto char_dev_path = ss.str();
625 if(std::ifstream(char_dev_path +
"busnum") >> busnum)
627 if(std::ifstream(char_dev_path +
"devnum") >> devnum)
629 if(std::ifstream(char_dev_path +
"devpath") >> devpath)
636 char_dev_path +=
"../";
643 std::string busnum, devnum, devpath;
644 auto dev_name =
"/dev/" +
name;
646 if (!is_usb_path_valid(video_path, dev_name, busnum, devnum, devpath))
651 LOG_INFO(
"Failed to read busnum/devnum. Device Path: " << (
"/sys/class/video4linux/" + name));
656 LOG_INFO(
"Enumerating UVC " << name <<
" realpath=" << video_path);
660 std::string modalias;
661 if(!(std::ifstream(
"/sys/class/video4linux/" + name +
"/device/modalias") >> modalias))
663 if(modalias.size() < 14 || modalias.substr(0,5) !=
"usb:v" || modalias[9] !=
'p')
669 if(!(std::ifstream(
"/sys/class/video4linux/" + name +
"/device/bInterfaceNumber") >> std::hex >> mi))
686 info.device_path = video_path;
687 info.unique_id = busnum +
"-" + devpath +
"-" + devnum;
688 info.conn_spec = usb_specification;
695 std::string& bus_info, std::string& card)
697 struct v4l2_capability vcap;
698 int fd = open(dev_name.c_str(), O_RDWR);
701 int err = ioctl(fd, VIDIOC_QUERYCAP, &vcap);
704 struct media_device_info mdi;
706 err = ioctl(fd, MEDIA_IOC_DEVICE_INFO, &mdi);
710 bus_info = mdi.bus_info;
712 bus_info = std::string(
"platform:") + mdi.driver;
722 bus_info =
reinterpret_cast<const char *
>(vcap.bus_info);
723 card =
reinterpret_cast<const char *
>(vcap.card);
732 std::string bus_info, card;
734 auto dev_name =
"/dev/" +
name;
736 get_mipi_device_info(dev_name, bus_info, card);
746 if (std::regex_search(name, match, video_dev_index))
752 LOG_WARNING(
"Unresolved Video4Linux device pattern: " << name <<
", device is skipped");
763 static int first_video_index =
ind;
764 ind = (
ind - first_video_index) % 6;
767 else if (
ind == 1 |
ind == 3)
773 LOG_WARNING(
"Unresolved Video4Linux device mi, device is skipped");
782 info.device_path = video_path;
788 info.unique_id = bus_info;
789 info.conn_spec = usb_specification;
797 static const std::regex uvc_pattern(
"(\\/usb\\d+\\/)\\w+");
798 return std::regex_search(video_path, uvc_pattern);
803 const std::string&)>
action)
805 std::vector<std::string> video_paths = get_video_paths();
808 typedef std::pair<uvc_device_info,std::string> node_info;
809 std::vector<node_info> uvc_nodes,uvc_devices;
811 for(
auto&& video_path : video_paths)
814 auto name = video_path.substr(video_path.find_last_of(
'/') + 1);
819 if (is_usb_device_path(video_path))
821 info = get_info_from_usb_device_path(video_path,
name);
825 info = get_info_from_mipi_device_path(video_path,
name);
828 auto dev_name =
"/dev/" +
name;
829 uvc_nodes.emplace_back(
info, dev_name);
831 catch(
const std::exception &
e)
833 LOG_INFO(
"Not a USB video device: " << e.what());
840 for (
auto&& cur_node : uvc_nodes)
845 uvc_devices.emplace_back(cur_node);
848 if (uvc_devices.empty())
850 LOG_ERROR(
"UVC meta-node with no video streaming node encountered: " << std::string(cur_node.first));
855 auto uvc_node = uvc_devices.back();
859 LOG_ERROR(
"Consequtive UVC meta-nodes encountered: " << std::string(uvc_node.first) <<
" and " << std::string(cur_node.first) );
863 if (uvc_node.first.has_metadata_node)
865 LOG_ERROR(
"Metadata node for uvc device: " << std::string(uvc_node.first) <<
" was previously assigned ");
870 uvc_node.first.has_metadata_node =
true;
871 uvc_node.first.metadata_node_id = cur_node.first.id;
872 uvc_devices.back() = uvc_node;
875 catch(
const std::exception &
e)
877 LOG_ERROR(
"Failed to map meta-node " << std::string(cur_node.first) <<
", error encountered: " << e.what());
884 for (
auto&&
dev : uvc_devices)
887 catch(
const std::exception &
e)
889 LOG_ERROR(
"Registration of UVC device failed: " << e.what());
895 bool is_kpi_violated =
false;
896 long int timestamp_usec =
static_cast<long int> (timestamp.tv_sec * 1000000 + timestamp.tv_usec);
899 auto it = std::find_if(drops_per_stream.begin(), drops_per_stream.end(),
900 [
profile](std::pair<stream_profile, std::deque<long int>>& sp_deq)
901 {
return profile == sp_deq.first; });
905 if (
it != drops_per_stream.end())
911 int max_num_of_drops = profile.
fps * _kpi_frames_drops_pct * time_limit;
913 auto& queue_for_profile =
it->second;
915 while (queue_for_profile.size() > 0)
917 auto delta_ts_usec = timestamp_usec - queue_for_profile.front();
918 if (delta_ts_usec > (time_limit * 1000000))
920 queue_for_profile.pop_front();
926 if (queue_for_profile.size() >= max_num_of_drops)
928 is_kpi_violated =
true;
929 queue_for_profile.clear();
932 queue_for_profile.push_back(timestamp_usec);
937 std::deque<long int> deque_to_add;
938 deque_to_add.push_back(timestamp_usec);
939 drops_per_stream.push_back(std::make_pair(profile, deque_to_add));
941 return is_kpi_violated;
945 :
_name(
""), _info(),
946 _is_capturing(false),
977 for (
auto&& fd :
_fds)
979 try {
if (fd)
::close(fd);}
catch (...) {}
987 v4l2_fmtdesc pixel_format = {};
988 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
990 while (ioctl(
_fd, VIDIOC_ENUM_FMT, &pixel_format) == 0)
992 v4l2_frmsizeenum frame_size = {};
993 frame_size.pixel_format = pixel_format.pixelformat;
997 if (pixel_format.pixelformat == 0)
1002 static const std::set<std::string> pending_formats = {
1003 "00000050-0000-0010-8000-00aa003",
1004 "00000032-0000-0010-8000-00aa003",
1008 pending_formats.end(),
1009 (
const char*)pixel_format.description) ==
1010 pending_formats.end())
1012 const std::string
s(
to_string() <<
"!" << pixel_format.description);
1016 if (std::regex_search(s.begin(), s.end(), match, rgx))
1018 std::stringstream ss;
1021 ss >> std::hex >>
id;
1024 if (fourcc == profile.
format)
1027 <<
"' is not natively supported by the running Linux kernel and likely requires a patch");
1032 ++pixel_format.index;
1037 v4l2_streamparm parm = {};
1038 parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1039 if(
xioctl(
_fd, VIDIOC_G_PARM, &parm) < 0)
1042 parm.parm.capture.timeperframe.numerator = 1;
1043 parm.parm.capture.timeperframe.denominator = profile.
fps;
1044 if(
xioctl(
_fd, VIDIOC_S_PARM, &parm) < 0)
1132 char fourcc_buff[
sizeof(device_fourcc)+1];
1134 fourcc_buff[
sizeof(device_fourcc)] = 0;
1157 auto ms = duration_cast<milliseconds>(
now.time_since_epoch()) % 1000;
1160 auto timer = system_clock::to_time_t(
now);
1163 std::tm bt = *std::localtime(&timer);
1165 std::ostringstream oss;
1167 oss << std::put_time(&bt,
"%H:%M:%S");
1168 oss <<
'.' << std::setfill(
'0') << std::setw(3) << ms.count();
1176 for (
auto fd :
_fds)
1181 struct timespec mono_time;
1182 int ret = clock_gettime(CLOCK_MONOTONIC, &mono_time);
1185 struct timeval expiration_time = { mono_time.tv_sec + 5, mono_time.tv_nsec / 1000 };
1192 struct timeval remaining;
1193 ret = clock_gettime(CLOCK_MONOTONIC, &mono_time);
1196 struct timeval current_time = { mono_time.tv_sec, mono_time.tv_nsec / 1000 };
1197 timersub(&expiration_time, ¤t_time, &remaining);
1198 if (timercmp(¤t_time, &expiration_time, <)) {
1199 val = select(
_max_fd + 1, &fds,
nullptr,
nullptr, &remaining);
1207 LOG_DEBUG_V4L(
"Select interrupted, val = " << val <<
", error = " << errno);
1208 }
while (val < 0 && errno == EINTR);
1232 LOG_ERROR(
"Stop pipe was signalled during streaming");
1238 bool md_extracted =
false;
1239 bool keep_md =
false;
1240 bool wa_applied =
false;
1245 md_extracted =
true;
1256 md_extracted =
true;
1265 if(FD_ISSET(
_fd, &fds))
1268 v4l2_buffer
buf = {};
1269 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1270 buf.memory =
_use_memory_map ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
1275 LOG_DEBUG_V4L(
"Dequeued buf " << std::dec << buf.index <<
" for fd " <<
_fd <<
" seq " << buf.sequence);
1282 if(buf.bytesused == 0)
1284 LOG_DEBUG_V4L(
"Empty video frame arrived, index " << buf.index);
1291 if (partial_frame || overflow_frame)
1294 std::stringstream
s;
1297 s <<
"Incomplete video frame detected!\nSize " << buf.bytesused
1302 LOG_ERROR(
"Corrupted UVC frame data, underflow and overflow reported:\n" << s.str().c_str());
1308 s <<
"overflow video frame detected!\nSize " << buf.bytesused
1311 LOG_DEBUG(
"Incomplete frame received: " << s.str());
1322 LOG_WARNING(
"Metadata was present when partial frame arrived, mark md as extracted");
1323 md_extracted =
true;
1324 LOG_DEBUG_V4L(
"Discarding md due to invalid video payload");
1326 md_buf._data_buf->request_next_frame(md_buf._file_desc,
true);
1335 auto timestamp = (double)buf.timestamp.tv_sec*1000.f + (
double)buf.timestamp.tv_usec/1000.f;
1340 md_extracted =
true;
1365 LOG_WARNING(
"Video frame dropped, video and metadata buffers inconsistency");
1370 auto timestamp = (double)buf.timestamp.tv_sec * 1000.f + (
double)buf.timestamp.tv_usec / 1000.f;
1405 LOG_WARNING(
"Video frame dropped, video and metadata buffers inconsistency");
1426 LOG_DEBUG(
"FD_ISSET: no data on video node sink");
1435 LOG_WARNING(
"Frames didn't arrived within 5 seconds");
1453 *md_start = &meta_data;
1460 std::shared_ptr<v4l2_buffer> video_v4l2_buffer;
1461 std::shared_ptr<v4l2_buffer> md_v4l2_buffer;
1465 int video_fd = -1, md_fd = -1;
1470 video_buffer->attach_buffer(*video_v4l2_buffer);
1481 auto metadata_buffer =
get_md_buffer(md_v4l2_buffer->index);
1483 metadata_buffer->attach_buffer(*md_v4l2_buffer);
1491 auto frame_sz = buf_mgr.
md_node_present() ? video_v4l2_buffer->bytesused :
1493 video_buffer->get_length_frame_only());
1495 auto timestamp = (double)video_v4l2_buffer->timestamp.tv_sec * 1000.f + (
double)video_v4l2_buffer->timestamp.tv_usec / 1000.f;
1501 video_buffer->get_frame_start(), buf_mgr.
metadata_start(), timestamp };
1510 LOG_DEBUG(
"video_md_syncer - synchronized video and md could not be pulled");
1519 md_start + uvc_md_start_offset);
1553 static_cast<uint16_t>(size),
const_cast<uint8_t *
>(
data)};
1554 if(
xioctl(
_fd, UVCIOC_CTRL_QUERY, &q) < 0)
1556 if (errno == EIO || errno == EAGAIN)
1566 memset(data, 0, size);
1568 static_cast<uint16_t>(size),
const_cast<uint8_t *
>(
data)};
1569 if(
xioctl(
_fd, UVCIOC_CTRL_QUERY, &q) < 0)
1571 if (errno == EIO || errno == EAGAIN || errno == EBUSY)
1588 struct uvc_xu_control_query xquery = {};
1589 memset(&xquery, 0,
sizeof(xquery));
1594 xquery.selector = control;
1595 xquery.unit = xu.
unit;
1596 xquery.data = (__u8 *)&size;
1598 if(-1 == ioctl(
_fd,UVCIOC_CTRL_QUERY,&xquery)){
1604 std::vector<uint8_t>
buf;
1605 auto buf_size = std::max((
size_t)len,
sizeof(__u32));
1606 buf.resize(buf_size);
1610 xquery.selector = control;
1611 xquery.unit = xu.
unit;
1612 xquery.data = buf.data();
1613 if(-1 == ioctl(
_fd,UVCIOC_CTRL_QUERY,&xquery)){
1616 result.min.resize(buf_size);
1617 std::copy(buf.begin(), buf.end(), result.min.begin());
1621 xquery.selector = control;
1622 xquery.unit = xu.
unit;
1623 xquery.data = buf.data();
1624 if(-1 == ioctl(
_fd,UVCIOC_CTRL_QUERY,&xquery)){
1627 result.max.resize(buf_size);
1628 std::copy(buf.begin(), buf.end(), result.max.begin());
1632 xquery.selector = control;
1633 xquery.unit = xu.
unit;
1634 xquery.data = buf.data();
1635 if(-1 == ioctl(
_fd,UVCIOC_CTRL_QUERY,&xquery)){
1638 result.def.resize(buf_size);
1639 std::copy(buf.begin(), buf.end(), result.def.begin());
1643 xquery.selector = control;
1644 xquery.unit = xu.
unit;
1645 xquery.data = buf.data();
1646 if(-1 == ioctl(
_fd,UVCIOC_CTRL_QUERY,&xquery)){
1649 result.step.resize(buf_size);
1650 std::copy(buf.begin(), buf.end(), result.step.begin());
1657 struct v4l2_control control = {
get_cid(opt), 0};
1658 if (
xioctl(
_fd, VIDIOC_G_CTRL, &control) < 0)
1660 if (errno == EIO || errno == EAGAIN)
1667 value = control.value;
1674 struct v4l2_control control = {
get_cid(opt), value};
1682 std::unique_ptr< uint32_t, std::function< void( uint32_t * ) > > unsubscriber(
1688 auto local_id = *id;
1690 unsubscribe_from_ctrl_event( local_id );
1697 if (
xioctl(
_fd, VIDIOC_S_CTRL, &control) < 0)
1699 if (errno == EIO || errno == EAGAIN)
1716 static const int32_t min = 0, max = 1, step = 1, def = 1;
1722 struct v4l2_queryctrl query = {};
1724 if (
xioctl(
_fd, VIDIOC_QUERYCTRL, &query) < 0)
1729 query.minimum = query.maximum = 0;
1739 std::vector<stream_profile> results;
1743 v4l2_fmtdesc pixel_format = {};
1744 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1745 while (ioctl(
_fd, VIDIOC_ENUM_FMT, &pixel_format) == 0)
1747 v4l2_frmsizeenum frame_size = {};
1748 frame_size.pixel_format = pixel_format.pixelformat;
1752 if (pixel_format.pixelformat == 0)
1757 std::set<std::string> known_problematic_formats = {
1758 "00000050-0000-0010-8000-00aa003",
1759 "00000032-0000-0010-8000-00aa003",
1762 if (
std::find(known_problematic_formats.begin(),
1763 known_problematic_formats.end(),
1764 (
const char*)pixel_format.description) ==
1765 known_problematic_formats.end())
1767 const std::string
s(
to_string() <<
"!" << pixel_format.description);
1771 if (std::regex_search(s.begin(), s.end(), match, rgx))
1773 std::stringstream ss;
1776 ss >> std::hex >>
id;
1780 LOG_WARNING(
"Pixel format " << pixel_format.description <<
" likely requires patch for fourcc code " << format_str <<
"!");
1786 LOG_DEBUG(
"Recognized pixel-format " << pixel_format.description);
1789 while (ioctl(
_fd, VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0)
1791 v4l2_frmivalenum frame_interval = {};
1792 frame_interval.pixel_format = pixel_format.pixelformat;
1793 frame_interval.width = frame_size.discrete.width;
1794 frame_interval.height = frame_size.discrete.height;
1795 while (ioctl(
_fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval) == 0)
1797 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE)
1799 if (frame_interval.discrete.numerator != 0)
1802 static_cast<float>(frame_interval.discrete.denominator) /
1803 static_cast<float>(frame_interval.discrete.numerator);
1807 p.width = frame_size.discrete.width;
1808 p.height = frame_size.discrete.height;
1810 if (fourcc != 0) results.push_back(
p);
1814 ++frame_interval.index;
1820 ++pixel_format.index;
1865 catch (
const std::exception& ex)
1894 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1918 _fd = open(
_name.c_str(), O_RDWR | O_NONBLOCK, 0);
1931 v4l2_capability cap = {};
1932 if(
xioctl(
_fd, VIDIOC_QUERYCAP, &cap) < 0)
1939 if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
1942 if(!(cap.capabilities & V4L2_CAP_STREAMING))
1946 v4l2_cropcap cropcap = {};
1947 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1948 if(
xioctl(
_fd, VIDIOC_CROPCAP, &cropcap) == 0)
1950 v4l2_crop
crop = {};
1951 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1952 crop.c = cropcap.defrect;
1953 if(
xioctl(
_fd, VIDIOC_S_CROP, &crop) < 0)
1981 v4l2_format
fmt = {};
1982 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1983 fmt.fmt.pix.width = profile.
width;
1984 fmt.fmt.pix.height = profile.
height;
1986 fmt.fmt.pix.field = V4L2_FIELD_NONE;
1992 LOG_INFO(
"Video node was successfully configured to " <<
fourcc_to_string(fmt.fmt.pix.pixelformat) <<
" format" <<
", fd " << std::dec <<
_fd);
1999 struct v4l2_event_subscription event_subscription ;
2000 event_subscription.flags = V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK;
2001 event_subscription.type = V4L2_EVENT_CTRL;
2002 event_subscription.id = control_id;
2003 memset(event_subscription.reserved,0,
sizeof(event_subscription.reserved));
2004 if (
xioctl(
_fd, VIDIOC_SUBSCRIBE_EVENT, &event_subscription) < 0)
2012 struct v4l2_event_subscription event_subscription ;
2013 event_subscription.flags = V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK;
2014 event_subscription.type = V4L2_EVENT_CTRL;
2015 event_subscription.id = control_id;
2016 memset(event_subscription.reserved,0,
sizeof(event_subscription.reserved));
2017 if (
xioctl(
_fd, VIDIOC_UNSUBSCRIBE_EVENT, &event_subscription) < 0)
2026 struct v4l2_event event;
2027 memset(&event, 0 ,
sizeof(event));
2030 static int MAX_POLL_RETRIES = 10;
2031 for (
int i = 0 ;
i < MAX_POLL_RETRIES &&
event.type != V4L2_EVENT_CTRL ;
i++)
2033 if(
xioctl(
_fd, VIDIOC_DQEVENT, &event) < 0)
2035 std::this_thread::sleep_for(std::chrono::milliseconds(2));
2039 return event.type == V4L2_EVENT_CTRL;
2045 _md_name(info.metadata_node_id)
2137 v4l2_capability cap = {};
2149 if(!(cap.capabilities & V4L2_CAP_STREAMING))
2191 memcpy(
fmt.fmt.raw_data,&request,
sizeof(request));
2232 LOG_WARNING(
"Metadata override requested but avoided skipped");
2240 md_buf._data_buf->request_next_frame(md_buf._file_desc,
true);
2256 auto hwts = *(
uint32_t*)((mdbuf+2));
2257 auto fn = *(
uint32_t*)((mdbuf+38));
2259 <<
" fn " << fn <<
" hw ts " << hwts
2260 <<
" v4lbuf ts usec " <<
buf.timestamp.tv_usec);
2296 v4l2_ext_control control{
get_cid(opt), 0, 0, 0};
2298 v4l2_ext_controls ctrls_block { control.id&0xffff0000, 1, 0, 0, 0, &control};
2300 if (
xioctl(
_fd, VIDIOC_G_EXT_CTRLS, &ctrls_block) < 0)
2302 if (errno == EIO || errno == EAGAIN)
2309 control.value = (V4L2_EXPOSURE_MANUAL==control.value) ? 0 : 1;
2310 value = control.value;
2317 v4l2_ext_control control{
get_cid(opt), 0, 0, value};
2319 control.value = value ? V4L2_EXPOSURE_APERTURE_PRIORITY : V4L2_EXPOSURE_MANUAL;
2322 v4l2_ext_controls ctrls_block{ control.id & 0xffff0000, 1, 0, 0, 0, &control };
2323 if (
xioctl(
_fd, VIDIOC_S_EXT_CTRLS, &ctrls_block) < 0)
2325 if (errno == EIO || errno == EAGAIN)
2339 case 1: xctrl.value = *(
reinterpret_cast<const uint8_t*
>(
data));
break;
2340 case 2: xctrl.value = *
reinterpret_cast<const uint16_t*
>(
data);
break;
2341 case 4: xctrl.value = *
reinterpret_cast<const int32_t*
>(
data);
break;
2342 case 8: xctrl.value64 = *
reinterpret_cast<const int64_t*
>(
data);
break;
2347 if (control == RS_ENABLE_AUTO_EXPOSURE)
2348 xctrl.value = xctrl.value ? V4L2_EXPOSURE_APERTURE_PRIORITY : V4L2_EXPOSURE_MANUAL;
2351 v4l2_ext_controls ctrls_block { xctrl.id&0xffff0000, 1, 0, 0, 0, &xctrl };
2353 int retVal =
xioctl(
_fd, VIDIOC_S_EXT_CTRLS, &ctrls_block);
2356 if (errno == EIO || errno == EAGAIN)
2369 v4l2_ext_controls ext {xctrl.id & 0xffff0000, 1, 0, 0, 0, &xctrl};
2376 int ret =
xioctl(
_fd, VIDIOC_G_EXT_CTRLS, &ext);
2383 if (control == RS_ENABLE_AUTO_EXPOSURE)
2384 xctrl.value = (V4L2_EXPOSURE_MANUAL == xctrl.value) ? 0 : 1;
2388 if (size <
sizeof(__s64))
2389 memcpy(data,(
void*)(&xctrl.value), size);
2395 if (errno == EIO || errno == EAGAIN)
2402 v4l2_query_ext_ctrl xctrl_query{};
2405 if(0 > ioctl(
_fd,VIDIOC_QUERY_EXT_CTRL,&xctrl_query)){
2409 if ((xctrl_query.elems !=1 ) ||
2411 (xctrl_query.maximum > std::numeric_limits<int32_t>::max()))
2413 <<
" is not compliant with backend interface: [min,max,default,step]:\n" 2414 << xctrl_query.minimum <<
", " << xctrl_query.maximum <<
", " 2415 << xctrl_query.default_value <<
", " << xctrl_query.step
2416 <<
"\n Elements = " << xctrl_query.elems);
2418 if (control == RS_ENABLE_AUTO_EXPOSURE)
2419 return {0, 1, 1, 1};
2420 return {
static_cast<int32_t>(xctrl_query.minimum), static_cast<int32_t>(xctrl_query.maximum),
2421 static_cast<int32_t>(xctrl_query.step), static_cast<int32_t>(xctrl_query.default_value)};
2462 case RS_EXPOSURE:
return V4L2_CID_EXPOSURE_ABSOLUTE;
2483 bool mipi_device = 0xABCD == info.
pid;
2484 auto v4l_uvc_dev = mipi_device ? std::make_shared<v4l_mipi_device>(
info) :
2486 std::make_shared<v4l_uvc_meta_device>(info));
2488 return std::make_shared<platform::retry_controls_work_around>(v4l_uvc_dev);
2493 std::vector<uvc_device_info> uvc_nodes;
2497 uvc_nodes.push_back(i);
2507 return std::make_shared<platform::command_transfer_usb>(
dev);
2517 std::this_thread::sleep_for(std::chrono::milliseconds(2000));
2520 return device_infos;
2525 return std::make_shared<v4l_hid_device>(
info);
2530 std::vector<hid_device_info> results;
2532 results.push_back(hid_dev_info);
2538 return std::make_shared<os_time_service>();
2543 #if defined(USING_UDEV) 2544 return std::make_shared< udev_device_watcher >( this );
2546 return std::make_shared< polling_device_watcher >( this );
2552 return std::make_shared<v4l_backend>();
2557 std::lock_guard<std::mutex>
lock(_syncer_mutex);
2560 LOG_DEBUG_V4L(
"video_md_syncer - push_video called but syncer not ready");
2563 _video_queue.push(video_buffer);
2567 if (_video_queue.size() > 2)
2570 enqueue_front_buffer_before_throwing_it(_video_queue);
2576 std::lock_guard<std::mutex>
lock(_syncer_mutex);
2579 LOG_DEBUG_V4L(
"video_md_syncer - push_metadata called but syncer not ready");
2583 if (_md_queue.size() > 0 && _md_queue.front()._v4l2_buf->sequence == md_buffer.
_v4l2_buf->sequence)
2585 LOG_DEBUG_V4L(
"video_md_syncer - calling enqueue_front_buffer_before_throwing_it - md buf " << md_buffer.
_buffer_index <<
" and md buf " << _md_queue.front()._buffer_index <<
" have same sequence");
2586 enqueue_front_buffer_before_throwing_it(_md_queue);
2588 _md_queue.push(md_buffer);
2590 LOG_DEBUG_V4L(
"video_md_syncer - md queue size = " << _md_queue.size());
2593 if (_md_queue.size() > 2)
2595 LOG_DEBUG_V4L(
"video_md_syncer - calling enqueue_front_buffer_before_throwing_it - md queue size is: " << _md_queue.size());
2597 enqueue_front_buffer_before_throwing_it(_md_queue);
2602 int& video_fd,
int& md_fd)
2604 std::lock_guard<std::mutex>
lock(_syncer_mutex);
2607 LOG_DEBUG_V4L(
"video_md_syncer - pull_video_with_metadata called but syncer not ready");
2610 if (_video_queue.empty())
2616 if (_md_queue.empty())
2622 sync_buffer video_candidate = _video_queue.front();
2626 video_fd = video_candidate.
_fd;
2627 md_fd = md_candidate.
_fd;
2632 video_buffer = video_candidate.
_v4l2_buf;
2637 LOG_DEBUG_V4L(
"video_md_syncer - video and md pulled with sequence " << video_candidate.
_v4l2_buf->sequence);
2641 LOG_DEBUG_V4L(
"video_md_syncer - video_candidate seq " << video_candidate.
_v4l2_buf->sequence <<
", md_candidate seq " << md_candidate.
_v4l2_buf->sequence);
2643 if (video_candidate.
_v4l2_buf->sequence > md_candidate.
_v4l2_buf->sequence && _md_queue.size() > 1)
2646 enqueue_buffer_before_throwing_it(md_candidate);
2650 auto alternative_md_candidate = _md_queue.front();
2652 if (video_candidate.
_v4l2_buf->sequence == alternative_md_candidate._v4l2_buf->sequence)
2654 video_buffer = video_candidate.
_v4l2_buf;
2655 md_buffer = alternative_md_candidate._v4l2_buf;
2659 LOG_DEBUG_V4L(
"video_md_syncer - video and md pulled with sequence " << video_candidate.
_v4l2_buf->sequence);
2663 if (video_candidate.
_v4l2_buf->sequence < md_candidate.
_v4l2_buf->sequence && _video_queue.size() > 1)
2666 enqueue_buffer_before_throwing_it(video_candidate);
2670 auto alternative_video_candidate = _video_queue.front();
2672 if (alternative_video_candidate._v4l2_buf->sequence == md_candidate.
_v4l2_buf->sequence)
2674 video_buffer = alternative_video_candidate._v4l2_buf;
2679 LOG_DEBUG_V4L(
"video_md_syncer - video and md pulled with sequence " << md_candidate.
_v4l2_buf->sequence);
2692 LOG_ERROR(
"xioctl(VIDIOC_QBUF) failed when requesting new frame! fd: " << sb.
_fd <<
" error: " << strerror(errno));
2699 LOG_DEBUG_V4L(
"video_md_syncer - Enqueue buf " << std::dec << sync_queue.front()._buffer_index <<
" for fd " << sync_queue.front()._fd <<
" before dropping it");
2700 if (
xioctl(sync_queue.front()._fd, VIDIOC_QBUF, sync_queue.front()._v4l2_buf.get()) < 0)
2702 LOG_ERROR(
"xioctl(VIDIOC_QBUF) failed when requesting new frame! fd: " << sync_queue.front()._fd <<
" error: " << strerror(errno));
2717 LOG_DEBUG_V4L(
"video_md_syncer - flush video and md queues");
2718 std::lock_guard<std::mutex>
lock(_syncer_mutex);
2719 while(!_video_queue.empty())
2723 while(!_md_queue.empty())
2727 LOG_DEBUG_V4L(
"video_md_syncer - flush video and md queues done - mq_q size = " << _md_queue.size() <<
", video_q size = " << _video_queue.size());
static const textual_icon lock
constexpr uint32_t RS_CAMERA_CID_LASER_POWER_MODE
std::istringstream istringstream
GLuint const GLchar * name
rs2_option
Defines general configuration controls. These can generally be mapped to camera UVC controls...
constexpr uint32_t RS_CAMERA_CID_LASER_POWER_LEVEL
#define V4L2_META_FMT_D4XX
constexpr uint32_t RS_CAMERA_DEPTH_CALIBRATION_TABLE_SET
bool val_in_range(const T &val, const std::initializer_list< T > &list)
constexpr uint32_t RS_CAMERA_CID_MANUAL_EXPOSURE
#define V4L2_CAP_META_CAPTURE
#define V4L2_META_FMT_UVC
const uint8_t MAX_META_DATA_SIZE
constexpr uint32_t RS_CAMERA_CID_LASER_POWER
constexpr uint32_t RS_CAMERA_DEPTH_CALIBRATION_TABLE_GET
constexpr uint32_t RS_CAMERA_CID_AE_SETPOINT_GET
constexpr uint32_t RS_CAMERA_CID_AE_ROI_GET
void sort(sort_type m_sort_type, const std::string &in, const std::string &out)
constexpr uint32_t RS_CAMERA_CID_WHITE_BALANCE_MODE
const size_t MAX_DEV_PARENT_DIR
GLenum GLuint GLenum GLsizei const GLchar * buf
def info(name, value, persistent=False)
constexpr uint32_t RS_CAMERA_CID_ERB
constexpr uint8_t metadata_imu_report_size
constexpr uint32_t RS_CAMERA_CID_FW_VERSION
constexpr uint32_t RS_CAMERA_CID_PRESET
#define assert(condition)
constexpr auto LOCAL_V4L2_BUF_TYPE_META_CAPTURE
unsigned __int64 uint64_t
#define LOG_DEBUG_V4L(...)
constexpr uint32_t RS_CAMERA_CID_HWMC_LEGACY
constexpr uint32_t RS_STREAM_CONFIG_0
constexpr uint32_t RS_CAMERA_CID_EWB
constexpr uint32_t RS_CAMERA_CID_AE_ROI_SET
constexpr uint32_t RS_CAMERA_CID_MANUAL_LASER_POWER
double monotonic_to_realtime(double monotonic)
LOG_INFO("Log message using LOG_INFO()")
constexpr uint32_t RS_CAMERA_COEFF_CALIBRATION_TABLE_SET
GLdouble GLdouble GLdouble q
constexpr uint32_t RS_CAMERA_CID_EMITTER_FREQUENCY
GLbitfield GLuint64 timeout
const double DEFAULT_KPI_FRAME_DROPS_PERCENTAGE
constexpr uint32_t RS_CAMERA_COEFF_CALIBRATION_TABLE_GET
int stoi(const std::string &value)
#define offsetof(STRUCTURE, FIELD)
GLenum GLuint GLenum GLsizei length
constexpr uint32_t RS_CAMERA_CID_AE_SETPOINT_SET
constexpr uint32_t RS_CAMERA_CID_HWMC
constexpr uint32_t RS_CAMERA_CID_BASE
constexpr uint32_t RS_CAMERA_CID_GVD
constexpr uint32_t RS_CAMERA_CID_EXPOSURE_MODE
void copy(void *dst, void const *src, size_t size)
std::string to_string(T value)