Skip to content

Commit

Permalink
Adding better error messages when cannot resolve pipeline request
Browse files Browse the repository at this point in the history
  • Loading branch information
dorodnic committed Mar 20, 2019
1 parent 41a0c88 commit 8efd899
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 24 deletions.
1 change: 1 addition & 0 deletions src/core/streaming.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ namespace librealsense

using on_frame = std::function<void(frame_interface*)>;
using stream_profiles = std::vector<std::shared_ptr<stream_profile_interface>>;
using unique_profiles = std::set<std::shared_ptr<stream_profile_interface>>;
using processing_blocks = std::vector<std::shared_ptr<processing_block_interface>>;


Expand Down
4 changes: 2 additions & 2 deletions src/pipeline/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ namespace librealsense
if (!dev->supports_info(RS2_CAMERA_INFO_SERIAL_NUMBER))
{
throw std::runtime_error(to_string() << "Failed to resolve request. "
"Conflic between enable_device_from_file(\"" << _device_request.filename
"Conflict between enable_device_from_file(\"" << _device_request.filename
<< "\") and enable_device(\"" << _device_request.serial << "\"), "
"File does not contain a device with such serial");
}
Expand All @@ -232,7 +232,7 @@ namespace librealsense
if (s != _device_request.serial)
{
throw std::runtime_error(to_string() << "Failed to resolve request. "
"Conflic between enable_device_from_file(\"" << _device_request.filename
"Conflict between enable_device_from_file(\"" << _device_request.filename
<< "\") and enable_device(\"" << _device_request.serial << "\"), "
"File contains device with different serial number (" << s << "\")");
}
Expand Down
125 changes: 103 additions & 22 deletions src/pipeline/resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,30 @@ namespace librealsense
uint32_t width, height;
rs2_format format;
uint32_t fps;

std::string to_string() const
{
std::stringstream ss;
if (stream_index == -1) ss << "Any ";
ss << stream;
if (stream_index != -1) ss << " " << stream_index;
if (format != RS2_FORMAT_ANY) ss << " as " << format;
if (width != 0 || height != 0)
{
ss << " ";
if (width == 0) ss << "_";
else ss << width;
ss << "x";
if (height == 0) ss << "_";
else ss << height;
ss << " px";
}
if (fps > 0)
{
ss << " at " << fps << " Hz";
}
return ss.str();
}
};

struct index_type
Expand Down Expand Up @@ -84,26 +108,32 @@ namespace librealsense
return true;
}

static bool match(stream_profile_interface* a, const request_type& b)
// Match score method evaluates if stream profile a is a match for request b
// and gives back match score.
// If the score is > 1, the stream profile is a match
// If the score is < 1, the stream profile is not a match
// and the score measures how close the stream profile is to what the user wanted
static double match_score(stream_profile_interface* a, const request_type& b)
{
double score = 1.2;
if (a->get_stream_type() != RS2_STREAM_ANY && b.stream != RS2_STREAM_ANY && (a->get_stream_type() != b.stream))
return false;
score /= 100 * fabs(a->get_stream_type() - b.stream);
if (a->get_stream_index() != -1 && b.stream_index != -1 && (a->get_stream_index() != b.stream_index))
return false;
score /= fabs(a->get_stream_index() - b.stream_index);
if (a->get_format() != RS2_FORMAT_ANY && b.format != RS2_FORMAT_ANY && (a->get_format() != b.format))
return false;
score /= 50 * fabs(a->get_format() - b.format);
if (a->get_framerate() != 0 && b.fps != 0 && (a->get_framerate() != b.fps))
return false;
score /= fabs(a->get_framerate() - b.fps);

if (auto vid_a = dynamic_cast<video_stream_profile_interface*>(a))
{
if (vid_a->get_width() != 0 && b.width != 0 && (vid_a->get_width() != b.width))
return false;
score /= fabs(vid_a->get_width() - b.width);
if (vid_a->get_height() != 0 && b.height != 0 && (vid_a->get_height() != b.height))
return false;
score /= fabs(vid_a->get_height() - b.height);
}

return true;
return score;
}

static bool contradicts(stream_profile_interface* a, stream_profiles others)
Expand Down Expand Up @@ -411,7 +441,7 @@ namespace librealsense
if (!has_wildcards(request)) continue;
for (auto candidate : candidates)
{
if (match(candidate.get(), request) && !contradicts(candidate.get(), requests))
if (match_score(candidate.get(), request) > 1.0 && !contradicts(candidate.get(), requests))
{
request = to_request(candidate.get());
break;
Expand Down Expand Up @@ -442,7 +472,9 @@ namespace librealsense
return r;
}

stream_profiles map_sub_device(stream_profiles profiles, std::set<index_type> satisfied_streams) const
stream_profiles map_sub_device(stream_profiles profiles,
std::set<index_type> satisfied_streams,
unique_profiles& best_alternatives) const
{
stream_profiles rv;
try
Expand All @@ -455,14 +487,24 @@ namespace librealsense
if (satisfied_streams.count(kvp.first)) continue; // skip satisfied requests

// if any profile on the subdevice can supply this request, consider it satisfiable
auto it = std::find_if(begin(profiles), end(profiles), [&kvp](const std::shared_ptr<stream_profile_interface>& profile)
auto it = std::max_element(begin(profiles), end(profiles),
[&kvp](const std::shared_ptr<stream_profile_interface>& a,
const std::shared_ptr<stream_profile_interface>& b)
{
return match(profile.get(), kvp.second);
return match_score(a.get(), kvp.second) <
match_score(b.get(), kvp.second);
});
if (it != end(profiles))
{
targets.push_back(kvp.second); // store that this request is going to this subdevice
satisfied_streams.insert(kvp.first); // mark stream as satisfied
if (match_score(it->get(), kvp.second) > 1.0)
{
targets.push_back(kvp.second); // store that this request is going to this subdevice
satisfied_streams.insert(kvp.first); // mark stream as satisfied
}
else
{
best_alternatives.insert(*it);
}
}
}

Expand All @@ -472,12 +514,22 @@ namespace librealsense

for (auto && t : targets)
{
for (auto && p : profiles)
auto it = std::max_element(begin(profiles), end(profiles),
[&t](const std::shared_ptr<stream_profile_interface>& a,
const std::shared_ptr<stream_profile_interface>& b)
{
return match_score(a.get(), t) <
match_score(b.get(), t);
});
if (it != end(profiles))
{
if (match(p.get(), t))
if (match_score(it->get(), t) > 1.0)
{
rv.push_back(*it);
}
else
{
rv.push_back(p);
break;
best_alternatives.insert(*it);
}
}
}
Expand All @@ -495,14 +547,16 @@ namespace librealsense
std::multimap<int, std::shared_ptr<stream_profile_interface>> out;
std::set<index_type> satisfied_streams;

unique_profiles suggestions;

// Algorithm assumes get_adjacent_devices always
// returns the devices in the same order
for (size_t i = 0; i < dev->get_sensors_count(); ++i)
{
auto&& sub = dev->get_sensor(i);

auto default_profiles = map_sub_device(sub.get_stream_profiles(profile_tag::PROFILE_TAG_SUPERSET), satisfied_streams);
auto any_profiles = map_sub_device(sub.get_stream_profiles(profile_tag::PROFILE_TAG_ANY), satisfied_streams);
auto default_profiles = map_sub_device(sub.get_stream_profiles(profile_tag::PROFILE_TAG_SUPERSET), satisfied_streams, suggestions);
auto any_profiles = map_sub_device(sub.get_stream_profiles(profile_tag::PROFILE_TAG_ANY), satisfied_streams, suggestions);

//use any streams if default streams wasn't satisfy
auto profiles = default_profiles.size() == any_profiles.size() ? default_profiles : any_profiles;
Expand All @@ -511,8 +565,35 @@ namespace librealsense
out.emplace((int)i, p);
}

if(_requests.size() != out.size())
throw std::runtime_error(std::string("Couldn't resolve requests"));
if (_requests.size() != out.size())
{
// Print better error message:
std::stringstream ss;
ss << "Couldn't resolve requests!\n";
ss << "Requested:\n";
for (auto&& r : _requests)
{
ss << " " << r.second.to_string() << "\n";
}
ss << "Possible Alternatives:\n";
for (auto&& p : suggestions)
{
std::stringstream st;
st << p->get_stream_type();
if (p->get_stream_index() > 0) st << " " << p->get_stream_index();
ss << " " << std::left << std::setw(10) << st.str();
ss << " as " << std::left << std::setw(6) << p->get_format();
if (auto vid = dynamic_cast<video_stream_profile_interface*>(p.get()))
{
std::stringstream wh;
wh << vid->get_width() << "x" << vid->get_height() << " px";
ss << " " << std::left << std::setw(12) << wh.str();
}
ss << " at " << p->get_framerate() << " Hz\n";
}

throw std::runtime_error(ss.str());
}

return out;
}
Expand Down

0 comments on commit 8efd899

Please sign in to comment.