Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix metadata handling with Bionic #5714

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 39 additions & 27 deletions src/linux/backend-v4l2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ namespace librealsense
memset((byte*)(get_frame_start()) + metadata_offset, 0, MAX_META_DATA_SIZE);
}

//LOG_DEBUG("Enqueue buf " << _buf.index << " for fd " << fd);
//LOG_DEBUG("Enqueue buf " << std::dec << _buf.index << " for fd " << fd);
if (xioctl(fd, VIDIOC_QBUF, &_buf) < 0)
{
LOG_ERROR("xioctl(VIDIOC_QBUF) failed when requesting new frame! fd: " << fd << " error: " << strerror(errno));
Expand Down Expand Up @@ -564,10 +564,17 @@ namespace librealsense
}
closedir(dir);

// Differenciate and merge video and metadata nodes
// Matching video and metadata nodes
// UVC nodes shall be traversed in ascending order for metadata nodes assignment ("dev/video1, Video2..
std::sort(begin(uvc_nodes),end(uvc_nodes),
[](const node_info& lhs, const node_info& rhs){ return lhs.first.id < rhs.first.id; });
// Replace lexicographic with numeric sort to ensure "video2" is listed before "video11"
std::sort(begin(uvc_nodes),end(uvc_nodes),[](const node_info& lhs, const node_info& rhs)
{
std::stringstream index_l(lhs.first.id.substr(lhs.first.id.find_first_of("0123456789")));
std::stringstream index_r(rhs.first.id.substr(rhs.first.id.find_first_of("0123456789")));
int left_id = 0; index_l >> left_id;
int right_id = 0; index_r >> right_id;
return left_id < right_id;
});

// Assume for each metadata node with index N there is a origin streaming node with index (N-1)
for (auto&& cur_node : uvc_nodes)
Expand Down Expand Up @@ -595,7 +602,7 @@ namespace librealsense

if (uvc_node.first.has_metadata_node)
{
LOG_ERROR( "Metadata node for uvc device: " << std::string(uvc_node.first) << " was already been assigned ");
LOG_ERROR( "Metadata node for uvc device: " << std::string(uvc_node.first) << " was previously assigned ");
continue;
}

Expand Down Expand Up @@ -875,8 +882,6 @@ namespace librealsense
else // Check and acquire data buffers from kernel
{
buffers_mgr buf_mgr(_use_memory_map);
// Read metadata from a node
acquire_metadata(buf_mgr,fds);

if(FD_ISSET(_fd, &fds))
{
Expand All @@ -886,13 +891,13 @@ namespace librealsense
buf.memory = _use_memory_map ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
if(xioctl(_fd, VIDIOC_DQBUF, &buf) < 0)
{
LOG_DEBUG("Dequeued empty buf for fd " << _fd);
//LOG_DEBUG("Dequeued empty buf for fd " << std::dec << _fd);
if(errno == EAGAIN)
return;

throw linux_backend_exception(to_string() << "xioctl(VIDIOC_DQBUF) failed for fd: " << _fd);
}
//LOG_DEBUG("Dequeued buf " << buf.index << " for fd " << _fd);
//LOG_DEBUG("Dequeued buf " << std::dec << buf.index << " for fd " << _fd);

auto buffer = _buffers[buf.index];
buf_mgr.handle_buffer(e_video_buf,_fd, buf,buffer);
Expand Down Expand Up @@ -939,22 +944,21 @@ namespace librealsense
auto timestamp = (double)buf.timestamp.tv_sec*1000.f + (double)buf.timestamp.tv_usec/1000.f;
timestamp = monotonic_to_realtime(timestamp);

// read metadata from the frame appendix
// Read metadata. For metadata note performs a blocking call to ensure video and metadata sync
acquire_metadata(buf_mgr,fds,compressed_format);

if (val > 1)
LOG_INFO("Frame buf ready, md size: " << std::dec << (int)buf_mgr.metadata_size() << " seq. id: " << buf.sequence);
frame_object fo{ std::min(buf.bytesused - buf_mgr.metadata_size(), buffer->get_length_frame_only()), buf_mgr.metadata_size(),
buffer->get_frame_start(), buf_mgr.metadata_start(), timestamp };

buffer->attach_buffer(buf);
buf_mgr.handle_buffer(e_video_buf,-1); // transfer new buffer request to the frame callback
buffer->attach_buffer(buf);
buf_mgr.handle_buffer(e_video_buf,-1); // transfer new buffer request to the frame callback

//Invoke user callback and enqueue next frame
_callback(_profile, fo,
[buf_mgr]() mutable {
buf_mgr.request_next_frame();
});
//Invoke user callback and enqueue next frame
_callback(_profile, fo, [buf_mgr]() mutable {
buf_mgr.request_next_frame();
});
}
}
else
Expand All @@ -964,16 +968,16 @@ namespace librealsense
}
else
{
LOG_INFO("FD_ISSET returned false - video node is not signalled (md only)");
LOG_WARNING("FD_ISSET signal false - no data on video node sink");
}
}
}
else // (val==0)
{
LOG_WARNING("Frames didn't arrived within 5 seconds");
librealsense::notification n = {RS2_NOTIFICATION_CATEGORY_FRAMES_TIMEOUT, 0, RS2_LOG_SEVERITY_WARN, "Frames didn't arrived within 5 seconds"};
librealsense::notification n = {RS2_NOTIFICATION_CATEGORY_FRAMES_TIMEOUT, 0, RS2_LOG_SEVERITY_WARN, "Frames didn't arrived within 5 seconds"};

_error_handler(n);
_error_handler(n);
}
}
}
Expand Down Expand Up @@ -1416,6 +1420,8 @@ namespace librealsense
{
throw linux_backend_exception("xioctl(VIDIOC_S_FMT) failed");
}
else
LOG_DEBUG("Streaming node was successfully configured to " << fourcc_to_string(fmt.fmt.pix.pixelformat) << " format" <<", descriptor " << std::dec << _fd);

LOG_INFO("Trying to configure fourcc " << fourcc_to_string(fmt.fmt.pix.pixelformat));
}
Expand Down Expand Up @@ -1489,7 +1495,11 @@ namespace librealsense
if(_md_fd < 0)
throw linux_backend_exception(to_string() << "Cannot open '" << _md_name);

_fds.push_back(_md_fd);
//The minimal video/metadata nodes syncer will be implemented by using two blocking calls:
// 1. Obtain video node data.
// 2. Obtain metadata
// To revert to multiplexing mode uncomment the next line
// _fds.push_back(_md_fd);
_max_fd = *std::max_element(_fds.begin(),_fds.end());

v4l2_capability cap = {};
Expand Down Expand Up @@ -1542,13 +1552,13 @@ namespace librealsense

if(xioctl(_md_fd, VIDIOC_S_FMT, &fmt) >= 0)
{
LOG_DEBUG("Metadata node was successfully configured to " << fourcc_to_string(request) << " format");
LOG_DEBUG("Metadata node was successfully configured to " << fourcc_to_string(request) << " format" <<", descriptor " << std::dec <<_md_fd);
success =true;
break;
}
else
{
LOG_INFO("Metadata configuration failed for " << fourcc_to_string(request));
LOG_WARNING("Metadata node configuration failed for " << fourcc_to_string(request));
}
}

Expand All @@ -1566,28 +1576,30 @@ namespace librealsense
v4l_uvc_device::prepare_capture_buffers();
}

// retrieve metadata from a dedicated UVC node
// retrieve metadata from a dedicated UVC node. For kernels 4.16+
void v4l_uvc_meta_device::acquire_metadata(buffers_mgr & buf_mgr,fd_set &fds, bool)
{
// Metadata is calculated once per frame
if (buf_mgr.metadata_size())
return;

if(FD_ISSET(_md_fd, &fds))
//Use blocking metadata node polling. Uncomment the next lines to revert to multiplexing I/O mode
//if(FD_ISSET(_md_fd, &fds))
{
FD_CLR(_md_fd,&fds);
//FD_CLR(_md_fd,&fds);
v4l2_buffer buf{};
buf.type = LOCAL_V4L2_BUF_TYPE_META_CAPTURE;
buf.memory = _use_memory_map ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;

// W/O multiplexing this will create a blocking call for metadata node
if(xioctl(_md_fd, VIDIOC_DQBUF, &buf) < 0)
{
if(errno == EAGAIN)
return;

throw linux_backend_exception(to_string() << "xioctl(VIDIOC_DQBUF) failed for metadata fd: " << _md_fd);
}
//LOG_DEBUG("Dequeued buf " << buf.index << " for fd " << _md_fd);
//LOG_DEBUG("Dequeued buf " << std::dec << buf.index << " for fd " << _md_fd);

auto buffer = _md_buffers[buf.index];
buf_mgr.handle_buffer(e_metadata_buf,_md_fd, buf,buffer);
Expand Down
4 changes: 2 additions & 2 deletions src/linux/backend-v4l2.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,13 @@ namespace librealsense
{
if (_data_buf && (!_managed))
{
//LOG_DEBUG("Enqueue buf " << _dq_buf.index << " for fd " << _file_desc);
if ((_file_desc > 0) && (xioctl(_file_desc, (int)VIDIOC_QBUF, &_dq_buf) < 0))
{
LOG_INFO("xioctl(VIDIOC_QBUF) guard failed");
LOG_WARNING("xioctl(VIDIOC_QBUF) guard failed for fd " << std::dec << _file_desc);
}
}
}

std::shared_ptr<platform::buffer> _data_buf=nullptr;
v4l2_buffer _dq_buf{};
int _file_desc=-1;
Expand Down