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 deadlock on pipeline.stop() with playback device in realtime=false mode #4758

Merged
merged 6 commits into from
Sep 2, 2019
Merged
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
6 changes: 5 additions & 1 deletion include/librealsense2/hpp/rs_device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,16 @@ namespace rs2
error::handle(e);
}

// Enter the device to update state, this will cause the updatable device to disconnect and reconnect as update device.
// Move the device to update state, this will cause the updatable device to disconnect and reconnect as an update device.
void enter_update_state() const
{
rs2_error* e = nullptr;
rs2_enter_update_state(_dev.get(), &e);
error::handle(e);
}

// Create backup of camera flash memory. Such backup does not constitute valid firmware image, and cannot be
// loaded back to the device, but it does contain all calibration and device information."
std::vector<uint8_t> create_flash_backup() const
{
std::vector<uint8_t> results;
Expand Down Expand Up @@ -227,13 +229,15 @@ namespace rs2
return results;
}

// Update an updatable device to the provided unsigned firmware. This call is executed on the caller's thread.
void update_unsigned(const std::vector<uint8_t>& image, int update_mode = RS2_UNSIGNED_UPDATE_MODE_UPDATE) const
{
rs2_error* e = nullptr;
rs2_update_firmware_unsigned_cpp(_dev.get(), image.data(), (int)image.size(), nullptr, update_mode, &e);
error::handle(e);
}

// Update an updatable device to the provided unsigned firmware. This call is executed on the caller's thread and it supports progress notifications via the callback.
template<class T>
void update_unsigned(const std::vector<uint8_t>& image, T callback, int update_mode = RS2_UNSIGNED_UPDATE_MODE_UPDATE) const
{
Expand Down
4 changes: 2 additions & 2 deletions include/librealsense2/hpp/rs_frame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ namespace rs2
{
public:
/**
* Inherit depth_frame class with additional disparity related attributs/functions
* Extend depth_frame class with additional disparity related attributes/functions
* \param[in] frame - existing frame instance
*/
disparity_frame(const frame& f)
Expand All @@ -794,7 +794,7 @@ namespace rs2
error::handle(e);
}
/**
* Retrieve back the distance between two IR sensors.
* Retrieve the distance between the two IR sensors.
* \return float - baseline.
*/
float get_baseline(void) const
Expand Down
4 changes: 2 additions & 2 deletions include/librealsense2/hpp/rs_pipeline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ namespace rs2

/**
* Start the pipeline streaming with its default configuration.
* The pipeline captures samples from the device, and delivers them to the through the provided frame callback.
* The pipeline captures samples from the device, and delivers them to the provided frame callback.
* Starting the pipeline is possible only when it is not started. If the pipeline was started, an exception is raised.
* When starting the pipeline with a callback both \c wait_for_frames() and \c poll_for_frames() will throw exception.
*
Expand All @@ -452,7 +452,7 @@ namespace rs2

/**
* Start the pipeline streaming according to the configuraion.
* The pipeline captures samples from the device, and delivers them to the through the provided frame callback.
* The pipeline captures samples from the device, and delivers them to the provided frame callback.
* Starting the pipeline is possible only when it is not started. If the pipeline was started, an exception is raised.
* When starting the pipeline with a callback both \c wait_for_frames() and \c poll_for_frames() will throw exception.
* The pipeline selects and activates the device upon start, according to configuration or a default configuration.
Expand Down
2 changes: 1 addition & 1 deletion include/librealsense2/hpp/rs_sensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ namespace rs2
}

/**
* Retrieve the stereoscopic baseline value from sensor
* Retrieve the stereoscopic baseline value from the sensor.
*/
float get_stereo_baseline() const
{
Expand Down
8 changes: 2 additions & 6 deletions src/concurrency.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class single_consumer_queue

void blocking_enqueue(T&& item)
{
auto pred = [this]()->bool { return _queue.size() <= _cap; };
auto pred = [this]()->bool { return _queue.size() < _cap || _need_to_flush; };

std::unique_lock<std::mutex> lock(_mutex);
if (_accepting)
Expand Down Expand Up @@ -116,6 +116,7 @@ class single_consumer_queue
_accepting = false;
_need_to_flush = true;

_enq_cv.notify_all();
while (_queue.size() > 0)
{
auto item = std::move(_queue.front());
Expand Down Expand Up @@ -179,11 +180,6 @@ class single_consumer_frame_queue
_queue.start();
}

void flush()
{
_queue.flush();
}

size_t size()
{
return _queue.size();
Expand Down
21 changes: 20 additions & 1 deletion src/pipeline/aggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ namespace librealsense
processing_block("aggregator"),
_queue(new single_consumer_frame_queue<frame_holder>(1)),
_streams_to_aggregate_ids(streams_to_aggregate),
_streams_to_sync_ids(streams_to_sync)
_streams_to_sync_ids(streams_to_sync),
_accepting(true)
{
auto processing_callback = [&](frame_holder frame, synthetic_source_interface* source)
{
Expand All @@ -26,6 +27,13 @@ namespace librealsense

void aggregator::handle_frame(frame_holder frame, synthetic_source_interface* source)
{
if (!_accepting) {
// If this causes stopping a pipeline with realtime=false playback device to
// generate high CPU utilization for a significant length of time, adding a
// short sleep here should mitigate it.
// std::this_thread::sleep_for(std::chrono::milliseconds(10));
return;
}
std::lock_guard<std::mutex> lock(_mutex);
auto comp = dynamic_cast<composite_frame*>(frame.frame);
if (comp)
Expand Down Expand Up @@ -103,5 +111,16 @@ namespace librealsense
{
return _queue->try_dequeue(item);
}

void aggregator::start()
{
_accepting = true;
}

void aggregator::stop()
{
_accepting = false;
_queue->clear();
}
}
}
3 changes: 3 additions & 0 deletions src/pipeline/aggregator.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ namespace librealsense
std::unique_ptr<single_consumer_frame_queue<frame_holder>> _queue;
std::vector<int> _streams_to_aggregate_ids;
std::vector<int> _streams_to_sync_ids;
std::atomic<bool> _accepting;
void handle_frame(frame_holder frame, synthetic_source_interface* source);
public:
aggregator(const std::vector<int>& streams_to_aggregate, const std::vector<int>& streams_to_sync);
bool dequeue(frame_holder* item, unsigned int timeout_ms);
bool try_dequeue(frame_holder* item);
void start();
void stop();
};
}
}
1 change: 1 addition & 0 deletions src/pipeline/pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ namespace librealsense
{
try
{
_aggregator->stop();
auto dev = _active_profile->get_device();
if (auto playback = As<librealsense::playback_device>(dev))
{
Expand Down
12 changes: 7 additions & 5 deletions wrappers/matlab/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ set(MATLAB_H Factory.h MatlabParamParser.h rs2_type_traits.h types.h)
set(MATLAB_M align.m camera_info.m colorizer.m config.m context.m
decimation_filter.m depth_frame.m depth_sensor.m
depth_stereo_sensor.m device.m device_hub.m disparity_frame.m
disparity_transform.m depth_example.m format.m frame.m frameset.m
frame_metadata_value.m frame_queue.m hole_filling_filter.m
disparity_transform.m filter.m format.m frame.m
frame_metadata_value.m frame_queue.m frameset.m hole_filling_filter.m
motion_frame.m motion_stream_profile.m option.m options.m pipeline.m
pipeline_profile.m playback.m playback_status.m pointcloud.m points.m
pose_frame.m processing_block.m recorder.m roi_sensor.m
rosbag_example.m sensor.m spatial_filter.m stream.m stream_profile.m
syncer.m temporal_filter.m timestamp_domain.m video_frame.m video_stream_profile.m
pose_frame.m recorder.m roi_sensor.m save_single_frameset.m
save_to_ply.m sensor.m spatial_filter.m stream.m stream_profile.m
syncer.m temporal_filter.m timestamp_domain.m video_frame.m
video_stream_profile.m
)
set(MATLAB_EXAMPLES depth_example.m pointcloud_example.m rosbag_example.m)

matlab_add_mex(NAME librealsense_mex
SRC ${MATLAB_CPP} ${MATLAB_H}
Expand Down
4 changes: 2 additions & 2 deletions wrappers/matlab/save_single_frameset.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
% Wraps librealsense2 save_to_ply class
classdef save_single_frameset < realsense.processing_block
classdef save_single_frameset < realsense.filter
methods
% Constructor
function this = save_single_frameset(filename)
Expand All @@ -10,7 +10,7 @@
validateattributes(filename, {'char', 'string'}, {'scalartext'});
out = realsense.librealsense_mex('rs2::save_single_frameset', 'new', filename);
end
this = this@realsense.processing_block(out);
this = this@realsense.filter(out);
end

% Destructor (uses base class destructor)
Expand Down
4 changes: 2 additions & 2 deletions wrappers/matlab/save_to_ply.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
% Wraps librealsense2 save_to_ply class
classdef save_to_ply < realsense.processing_block
classdef save_to_ply < realsense.filter
properties (Constant=true)
option_ignore_color = realsense.option.count + 1;
end
Expand All @@ -17,7 +17,7 @@
validateattributes(pc, {'realsense.pointcloud'}, {'scalar'});
out = realsense.librealsense_mex('rs2::save_to_ply', 'new', filename, pc.objectHandle);
end
this = this@realsense.processing_block(out);
this = this@realsense.filter(out);
end

% Destructor (uses base class destructor)
Expand Down
20 changes: 19 additions & 1 deletion wrappers/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,25 @@ set(DEPENDENCIES realsense2)

add_subdirectory(third_party/pybind11)

pybind11_add_module(pyrealsense2 SHARED python.cpp)
set(PYRS_CPP
python.cpp
c_files.cpp
rs_advanced_mode.cpp
rs_context.cpp
rs_device.cpp
rs_export.cpp
rs_frame.cpp
rs_internal.cpp
rs_options.cpp
rs_pipeline.cpp
rs_processing.cpp
rs_record_playback.cpp
rs_sensor.cpp
rs_types.cpp
rsutil.cpp
)

pybind11_add_module(pyrealsense2 SHARED python.hpp ${PYRS_CPP})
target_link_libraries(pyrealsense2 PRIVATE ${DEPENDENCIES})
set_target_properties(pyrealsense2 PROPERTIES VERSION
${REALSENSE_VERSION_STRING} SOVERSION "${REALSENSE_VERSION_MAJOR}.${REALSENSE_VERSION_MINOR}")
Expand Down
129 changes: 129 additions & 0 deletions wrappers/python/c_files.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* License: Apache 2.0. See LICENSE file in root directory.
Copyright(c) 2017 Intel Corporation. All Rights Reserved. */

#include "python.hpp"
#include "../include/librealsense2/rs.h"

std::string make_pythonic_str(std::string str)
{
std::transform(begin(str), end(str), begin(str), ::tolower); //Make lower case
std::replace(begin(str), end(str), ' ', '_'); //replace spaces with underscore
if (str == "6dof") //Currently this is the only enum that starts with a digit
{
return "six_dof";
}
return str;
}


void init_c_files(py::module &m) {
/** Binding of rs2_* enums */
BIND_ENUM(m, rs2_notification_category, RS2_NOTIFICATION_CATEGORY_COUNT, "Category of the librealsense notification.")
// rs2_exception_type
BIND_ENUM(m, rs2_distortion, RS2_DISTORTION_COUNT, "Distortion model: defines how pixel coordinates should be mapped to sensor coordinates.")
BIND_ENUM(m, rs2_log_severity, RS2_LOG_SEVERITY_COUNT, "Severity of the librealsense logger.")
BIND_ENUM(m, rs2_extension, RS2_EXTENSION_COUNT, "Specifies advanced interfaces (capabilities) objects may implement.")
// rs2_matchers
BIND_ENUM(m, rs2_camera_info, RS2_CAMERA_INFO_COUNT, "This information is mainly available for camera debug and troubleshooting and should not be used in applications.")
BIND_ENUM(m, rs2_stream, RS2_STREAM_COUNT, "Streams are different types of data provided by RealSense devices.")
BIND_ENUM(m, rs2_format, RS2_FORMAT_COUNT, "A stream's format identifies how binary data is encoded within a frame.")
BIND_ENUM(m, rs2_timestamp_domain, RS2_TIMESTAMP_DOMAIN_COUNT, "Specifies the clock in relation to which the frame timestamp was measured.")
BIND_ENUM(m, rs2_frame_metadata_value, RS2_FRAME_METADATA_COUNT, "Per-Frame-Metadata is the set of read-only properties that might be exposed for each individual frame.")
BIND_ENUM(m, rs2_option, RS2_OPTION_COUNT, "Defines general configuration controls. These can generally be mapped to camera UVC controls, and can be set / queried at any time unless stated otherwise.")
// rs2_sr300_visual_preset
// rs2_rs400_visual_preset
BIND_ENUM(m, rs2_playback_status, RS2_PLAYBACK_STATUS_COUNT, "") // No docstring in C++

/** rs_types.h **/
py::class_<rs2_intrinsics> intrinsics(m, "intrinsics", "Video stream intrinsics.");
intrinsics.def(py::init<>())
.def_readwrite("width", &rs2_intrinsics::width, "Width of the image in pixels")
.def_readwrite("height", &rs2_intrinsics::height, "Height of the image in pixels")
.def_readwrite("ppx", &rs2_intrinsics::ppx, "Horizontal coordinate of the principal point of the image, as a pixel offset from the left edge")
.def_readwrite("ppy", &rs2_intrinsics::ppy, "Vertical coordinate of the principal point of the image, as a pixel offset from the top edge")
.def_readwrite("fx", &rs2_intrinsics::fx, "Focal length of the image plane, as a multiple of pixel width")
.def_readwrite("fy", &rs2_intrinsics::fy, "Focal length of the image plane, as a multiple of pixel height")
.def_readwrite("model", &rs2_intrinsics::model, "Distortion model of the image")
.def_property(BIND_RAW_ARRAY_PROPERTY(rs2_intrinsics, coeffs, float, 5), "Distortion coefficients")
.def("__repr__", [](const rs2_intrinsics& self) {
std::stringstream ss;
ss << "width: " << self.width << ", ";
ss << "height: " << self.height << ", ";
ss << "ppx: " << self.ppx << ", ";
ss << "ppy: " << self.ppy << ", ";
ss << "fx: " << self.fx << ", ";
ss << "fy: " << self.fy << ", ";
ss << "model: " << self.model << ", ";
ss << "coeffs: " << array_to_string(self.coeffs);
return ss.str();
});

py::class_<rs2_motion_device_intrinsic> motion_device_intrinsic(m, "motion_device_intrinsic", "Motion device intrinsics: scale, bias, and variances.");
motion_device_intrinsic.def(py::init<>())
.def_property(BIND_RAW_2D_ARRAY_PROPERTY(rs2_motion_device_intrinsic, data, float, 3, 4), "3x4 matrix with 3x3 scale and cross axis and 3x1 biases")
.def_property(BIND_RAW_ARRAY_PROPERTY(rs2_motion_device_intrinsic, noise_variances, float, 3), "Variance of noise for X, Y, and Z axis")
.def_property(BIND_RAW_ARRAY_PROPERTY(rs2_motion_device_intrinsic, bias_variances, float, 3), "Variance of bias for X, Y, and Z axis")
.def("__repr__", [](const rs2_motion_device_intrinsic& self) {
std::stringstream ss;
ss << "data: " << matrix_to_string(self.data) << ", ";
ss << "noise_variances: " << array_to_string(self.noise_variances) << ", ";
ss << "bias_variances: " << array_to_string(self.bias_variances);
return ss.str();
});

// rs2_vertex
// rs2_pixel

py::class_<rs2_vector> vector(m, "vector", "3D vector in Euclidean coordinate space.");
vector.def(py::init<>())
.def_readwrite("x", &rs2_vector::x)
.def_readwrite("y", &rs2_vector::y)
.def_readwrite("z", &rs2_vector::z)
.def("__repr__", [](const rs2_vector& self) {
std::stringstream ss;
ss << "x: " << self.x << ", ";
ss << "y: " << self.y << ", ";
ss << "z: " << self.z;
return ss.str();
});

py::class_<rs2_quaternion> quaternion(m, "quaternion", "Quaternion used to represent rotation.");
quaternion.def(py::init<>())
.def_readwrite("x", &rs2_quaternion::x)
.def_readwrite("y", &rs2_quaternion::y)
.def_readwrite("z", &rs2_quaternion::z)
.def_readwrite("w", &rs2_quaternion::w)
.def("__repr__", [](const rs2_quaternion& self) {
std::stringstream ss;
ss << "x: " << self.x << ", ";
ss << "y: " << self.y << ", ";
ss << "z: " << self.z << ", ";
ss << "w: " << self.w;
return ss.str();
});

py::class_<rs2_pose> pose(m, "pose"); // No docstring in C++
pose.def(py::init<>())
.def_readwrite("translation", &rs2_pose::translation, "X, Y, Z values of translation, in meters (relative to initial position)")
.def_readwrite("velocity", &rs2_pose::velocity, "X, Y, Z values of velocity, in meters/sec")
.def_readwrite("acceleration", &rs2_pose::acceleration, "X, Y, Z values of acceleration, in meters/sec^2")
.def_readwrite("rotation", &rs2_pose::rotation, "Qi, Qj, Qk, Qr components of rotation as represented in quaternion rotation (relative to initial position)")
.def_readwrite("angular_velocity", &rs2_pose::angular_velocity, "X, Y, Z values of angular velocity, in radians/sec")
.def_readwrite("angular_acceleration", &rs2_pose::angular_acceleration, "X, Y, Z values of angular acceleration, in radians/sec^2")
.def_readwrite("tracker_confidence", &rs2_pose::tracker_confidence, "Pose confidence 0x0 - Failed, 0x1 - Low, 0x2 - Medium, 0x3 - High")
.def_readwrite("mapper_confidence", &rs2_pose::mapper_confidence, "Pose map confidence 0x0 - Failed, 0x1 - Low, 0x2 - Medium, 0x3 - High");
/** end rs_types.h **/

/** rs_sensor.h **/
py::class_<rs2_extrinsics> extrinsics(m, "extrinsics", "Cross-stream extrinsics: encodes the topology describing how the different devices are oriented.");
extrinsics.def(py::init<>())
.def_property(BIND_RAW_ARRAY_PROPERTY(rs2_extrinsics, rotation, float, 9), "Column - major 3x3 rotation matrix")
.def_property(BIND_RAW_ARRAY_PROPERTY(rs2_extrinsics, translation, float, 3), "Three-element translation vector, in meters")
.def("__repr__", [](const rs2_extrinsics &e) {
std::stringstream ss;
ss << "rotation: " << array_to_string(e.rotation);
ss << "\ntranslation: " << array_to_string(e.translation);
return ss.str();
});
/** end rs_sensor.h **/
}
Loading