You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1776 lines
70 KiB
1776 lines
70 KiB
// License: Apache 2.0. See LICENSE file in root directory.
|
|
// Copyright(c) 2024 Intel Corporation. All Rights Reserved.
|
|
|
|
#include "post-processing-filters-list.h"
|
|
#include "post-processing-block-model.h"
|
|
#include <imgui_internal.h>
|
|
|
|
#include "metadata-helper.h"
|
|
#include "subdevice-model.h"
|
|
|
|
namespace rs2
|
|
{
|
|
static void width_height_from_resolution(rs2_sensor_mode mode, int& width, int& height)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case RS2_SENSOR_MODE_VGA:
|
|
width = 640;
|
|
height = 480;
|
|
break;
|
|
case RS2_SENSOR_MODE_XGA:
|
|
width = 1024;
|
|
height = 768;
|
|
break;
|
|
case RS2_SENSOR_MODE_QVGA:
|
|
width = 320;
|
|
height = 240;
|
|
break;
|
|
default:
|
|
width = height = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int get_resolution_id_from_sensor_mode(rs2_sensor_mode sensor_mode,
|
|
const std::vector< std::pair< int, int > >& res_values)
|
|
{
|
|
int width = 0, height = 0;
|
|
width_height_from_resolution(sensor_mode, width, height);
|
|
auto iter = std::find_if(res_values.begin(),
|
|
res_values.end(),
|
|
[width, height](std::pair< int, int > res) {
|
|
if (((res.first == width) && (res.second == height))
|
|
|| ((res.first == height) && (res.second == width)))
|
|
return true;
|
|
return false;
|
|
});
|
|
if (iter != res_values.end())
|
|
{
|
|
return static_cast<int>(std::distance(res_values.begin(), iter));
|
|
}
|
|
|
|
throw std::runtime_error("cannot convert sensor mode to resolution ID");
|
|
}
|
|
|
|
std::vector<const char*> get_string_pointers(const std::vector<std::string>& vec)
|
|
{
|
|
std::vector<const char*> res;
|
|
for (auto&& s : vec) res.push_back(s.c_str());
|
|
return res;
|
|
}
|
|
|
|
std::string get_device_sensor_name(subdevice_model* sub)
|
|
{
|
|
std::stringstream ss;
|
|
ss << configurations::viewer::post_processing
|
|
<< "." << sub->dev.get_info(RS2_CAMERA_INFO_NAME)
|
|
<< "." << sub->s->get_info(RS2_CAMERA_INFO_NAME);
|
|
return ss.str();
|
|
}
|
|
|
|
void subdevice_model::populate_options( const std::string & opt_base_label,
|
|
bool * options_invalidated,
|
|
std::string & error_message )
|
|
{
|
|
for (rs2::option_value option : s->get_supported_option_values())
|
|
{
|
|
options_metadata[option->id]
|
|
= create_option_model( option, opt_base_label, this, s, options_invalidated, error_message );
|
|
}
|
|
try
|
|
{
|
|
s->on_options_changed( [this]( const options_list & list )
|
|
{
|
|
for( auto changed_option : list )
|
|
{
|
|
auto it = options_metadata.find( changed_option->id );
|
|
if( it != options_metadata.end() && ! _destructing ) // Callback runs in different context, check options_metadata still valid
|
|
{
|
|
it->second.value = changed_option;
|
|
}
|
|
}
|
|
} );
|
|
}
|
|
catch( const std::exception & e )
|
|
{
|
|
if( viewer.not_model )
|
|
viewer.not_model->add_log( e.what(), RS2_LOG_SEVERITY_WARN );
|
|
}
|
|
}
|
|
|
|
// to be moved to processing-block-model
|
|
bool restore_processing_block(const char* name,
|
|
std::shared_ptr<rs2::processing_block> pb, bool enable)
|
|
{
|
|
for (auto opt : pb->get_supported_options())
|
|
{
|
|
std::string key = name;
|
|
key += ".";
|
|
key += pb->get_option_name(opt);
|
|
if (config_file::instance().contains(key.c_str()))
|
|
{
|
|
float val = config_file::instance().get(key.c_str());
|
|
try
|
|
{
|
|
auto range = pb->get_option_range(opt);
|
|
if (val >= range.min && val <= range.max)
|
|
pb->set_option(opt, val);
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string key = name;
|
|
key += ".enabled";
|
|
if (config_file::instance().contains(key.c_str()))
|
|
{
|
|
return config_file::instance().get(key.c_str());
|
|
}
|
|
return enable;
|
|
}
|
|
|
|
subdevice_model::subdevice_model(
|
|
device& dev,
|
|
std::shared_ptr<sensor> s,
|
|
std::shared_ptr< atomic_objects_in_frame > device_detected_objects,
|
|
std::string& error_message,
|
|
viewer_model& viewer,
|
|
bool new_device_connected
|
|
)
|
|
: s(s), dev(dev), ui(), last_valid_ui(),
|
|
streaming(false), _pause(false),
|
|
depth_colorizer(std::make_shared<rs2::gl::colorizer>()),
|
|
yuy2rgb(std::make_shared<rs2::gl::yuy_decoder>()),
|
|
y411(std::make_shared<rs2::gl::y411_decoder>()),
|
|
viewer(viewer),
|
|
detected_objects(device_detected_objects),
|
|
_destructing( false )
|
|
{
|
|
supported_options = s->get_supported_options();
|
|
restore_processing_block("colorizer", depth_colorizer);
|
|
restore_processing_block("yuy2rgb", yuy2rgb);
|
|
restore_processing_block("y411", y411);
|
|
|
|
std::string device_name(dev.get_info(RS2_CAMERA_INFO_NAME));
|
|
std::string sensor_name(s->get_info(RS2_CAMERA_INFO_NAME));
|
|
|
|
std::stringstream ss;
|
|
ss << configurations::viewer::post_processing
|
|
<< "." << device_name
|
|
<< "." << sensor_name;
|
|
auto key = ss.str();
|
|
|
|
bool const is_rgb_camera = s->is< color_sensor >();
|
|
|
|
if (config_file::instance().contains(key.c_str()))
|
|
{
|
|
post_processing_enabled = config_file::instance().get(key.c_str());
|
|
}
|
|
|
|
try
|
|
{
|
|
if (s->supports(RS2_OPTION_ENABLE_AUTO_EXPOSURE))
|
|
auto_exposure_enabled = s->get_option(RS2_OPTION_ENABLE_AUTO_EXPOSURE) > 0;
|
|
}
|
|
catch (...)
|
|
{
|
|
|
|
}
|
|
|
|
try
|
|
{
|
|
if (s->supports(RS2_OPTION_DEPTH_UNITS))
|
|
depth_units = s->get_option(RS2_OPTION_DEPTH_UNITS);
|
|
}
|
|
catch (...) {}
|
|
|
|
try
|
|
{
|
|
if (s->supports(RS2_OPTION_STEREO_BASELINE))
|
|
stereo_baseline = s->get_option(RS2_OPTION_STEREO_BASELINE);
|
|
}
|
|
catch (...) {}
|
|
|
|
auto filters = s->get_recommended_filters();
|
|
|
|
for (auto&& f : s->get_recommended_filters())
|
|
{
|
|
auto shared_filter = std::make_shared<filter>(f);
|
|
auto model = std::make_shared<processing_block_model>(
|
|
this, shared_filter->get_info(RS2_CAMERA_INFO_NAME), shared_filter,
|
|
[=](rs2::frame f) { return shared_filter->process(f); }, error_message);
|
|
|
|
if (shared_filter->is<hole_filling_filter>())
|
|
model->enable(false);
|
|
|
|
if (shared_filter->is<sequence_id_filter>())
|
|
model->enable(false);
|
|
|
|
if (shared_filter->is<decimation_filter>())
|
|
{
|
|
if (is_rgb_camera)
|
|
model->enable(false);
|
|
}
|
|
|
|
if (shared_filter->is<threshold_filter>())
|
|
{
|
|
if (s->supports(RS2_CAMERA_INFO_PRODUCT_ID))
|
|
{
|
|
// using short range for D405
|
|
std::string device_pid = s->get_info(RS2_CAMERA_INFO_PRODUCT_ID);
|
|
if (device_pid == "0B5B")
|
|
{
|
|
std::string error_msg;
|
|
auto threshold_pb = shared_filter->as<threshold_filter>();
|
|
threshold_pb.set_option(RS2_OPTION_MIN_DISTANCE, SHORT_RANGE_MIN_DISTANCE);
|
|
threshold_pb.set_option(RS2_OPTION_MAX_DISTANCE, SHORT_RANGE_MAX_DISTANCE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (shared_filter->is<hdr_merge>())
|
|
{
|
|
// processing block will be skipped if the requested option is not supported
|
|
auto supported_options = s->get_supported_options();
|
|
if (std::find(supported_options.begin(), supported_options.end(), RS2_OPTION_SEQUENCE_ID) == supported_options.end())
|
|
continue;
|
|
}
|
|
|
|
post_processing.push_back(model);
|
|
}
|
|
|
|
if (is_rgb_camera)
|
|
{
|
|
for (auto& create_filter : post_processing_filters_list::get())
|
|
{
|
|
auto filter = create_filter();
|
|
if (!filter)
|
|
continue;
|
|
filter->start(*this);
|
|
std::shared_ptr< processing_block_model > model(
|
|
new post_processing_block_model{
|
|
this, filter,
|
|
[=](rs2::frame f) { return filter->process(f); },
|
|
error_message
|
|
});
|
|
post_processing.push_back(model);
|
|
}
|
|
}
|
|
|
|
auto colorizer = std::make_shared<processing_block_model>(
|
|
this, "Depth Visualization", depth_colorizer,
|
|
[=](rs2::frame f) { return depth_colorizer->colorize(f); }, error_message);
|
|
const_effects.push_back(colorizer);
|
|
|
|
|
|
if (s->supports(RS2_CAMERA_INFO_PRODUCT_ID))
|
|
{
|
|
std::string device_pid = s->get_info(RS2_CAMERA_INFO_PRODUCT_ID);
|
|
|
|
// using short range for D405
|
|
if (device_pid == "0B5B")
|
|
{
|
|
std::string error_msg;
|
|
depth_colorizer->set_option(RS2_OPTION_MIN_DISTANCE, SHORT_RANGE_MIN_DISTANCE);
|
|
depth_colorizer->set_option(RS2_OPTION_MAX_DISTANCE, SHORT_RANGE_MAX_DISTANCE);
|
|
}
|
|
}
|
|
|
|
// Hack to restore "Enable Histogram Equalization" flag if needed.
|
|
// The flag is set to true by colorizer constructor, but setting min/max_distance options above or during
|
|
// restore_processing_block earlier, causes the registered observer to unset it, which is not the desired
|
|
// behaviour. Observer should affect only if a user is setting the values after construction phase is over.
|
|
if (depth_colorizer->supports(RS2_OPTION_VISUAL_PRESET))
|
|
{
|
|
auto option_value = depth_colorizer->get_option(RS2_OPTION_VISUAL_PRESET);
|
|
depth_colorizer->set_option(RS2_OPTION_VISUAL_PRESET, option_value);
|
|
}
|
|
|
|
ss.str("");
|
|
ss << "##" << dev.get_info(RS2_CAMERA_INFO_NAME)
|
|
<< "/" << s->get_info(RS2_CAMERA_INFO_NAME)
|
|
<< "/" << (long long)this;
|
|
|
|
if (s->supports(RS2_CAMERA_INFO_PHYSICAL_PORT) && dev.supports(RS2_CAMERA_INFO_PRODUCT_LINE))
|
|
{
|
|
std::string product = dev.get_info(RS2_CAMERA_INFO_PRODUCT_LINE);
|
|
std::string id = s->get_info(RS2_CAMERA_INFO_PHYSICAL_PORT);
|
|
|
|
bool has_metadata = !rs2::metadata_helper::instance().can_support_metadata(product)
|
|
|| rs2::metadata_helper::instance().is_enabled(id);
|
|
static bool showed_metadata_prompt = false;
|
|
|
|
if (!has_metadata && !showed_metadata_prompt)
|
|
{
|
|
auto n = std::make_shared<metadata_warning_model>();
|
|
viewer.not_model->add_notification(n);
|
|
showed_metadata_prompt = true;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
auto sensor_profiles = s->get_stream_profiles();
|
|
reverse(begin(sensor_profiles), end(sensor_profiles));
|
|
std::map<int, rs2_format> def_format{ {0, RS2_FORMAT_ANY} };
|
|
auto default_resolution = std::make_pair(1280, 720);
|
|
auto default_fps = 30;
|
|
for (auto&& profile : sensor_profiles)
|
|
{
|
|
std::stringstream res;
|
|
if (auto vid_prof = profile.as<video_stream_profile>())
|
|
{
|
|
if (profile.is_default())
|
|
{
|
|
default_resolution = std::pair<int, int>(vid_prof.width(), vid_prof.height());
|
|
default_fps = profile.fps();
|
|
|
|
if (is_rgb_camera)
|
|
{
|
|
auto intrinsics = vid_prof.get_intrinsics();
|
|
if (intrinsics.model == RS2_DISTORTION_INVERSE_BROWN_CONRADY
|
|
&& (std::abs(intrinsics.coeffs[0]) > std::numeric_limits< float >::epsilon() ||
|
|
std::abs(intrinsics.coeffs[1]) > std::numeric_limits< float >::epsilon() ||
|
|
std::abs(intrinsics.coeffs[2]) > std::numeric_limits< float >::epsilon() ||
|
|
std::abs(intrinsics.coeffs[3]) > std::numeric_limits< float >::epsilon() ||
|
|
std::abs(intrinsics.coeffs[4]) > std::numeric_limits< float >::epsilon()))
|
|
{
|
|
uvmapping_calib_full = true;
|
|
}
|
|
}
|
|
}
|
|
res << vid_prof.width() << " x " << vid_prof.height();
|
|
push_back_if_not_exists(res_values, std::pair<int, int>(vid_prof.width(), vid_prof.height()));
|
|
push_back_if_not_exists(resolutions, res.str());
|
|
push_back_if_not_exists(resolutions_per_stream[profile.stream_type()], std::pair<int, int>(vid_prof.width(), vid_prof.height()));
|
|
push_back_if_not_exists(profile_id_to_res[profile.unique_id()], std::pair<int, int>(vid_prof.width(), vid_prof.height()));
|
|
}
|
|
|
|
std::stringstream fps;
|
|
fps << profile.fps();
|
|
push_back_if_not_exists(fps_values_per_stream[profile.unique_id()], profile.fps());
|
|
push_back_if_not_exists(shared_fps_values, profile.fps());
|
|
push_back_if_not_exists(fpses_per_stream[profile.unique_id()], fps.str());
|
|
push_back_if_not_exists(shared_fpses, fps.str());
|
|
stream_display_names[profile.unique_id()] = profile.stream_name();
|
|
|
|
std::string format = rs2_format_to_string(profile.format());
|
|
|
|
push_back_if_not_exists(formats[profile.unique_id()], format);
|
|
push_back_if_not_exists(format_values[profile.unique_id()], profile.format());
|
|
|
|
if (profile.is_default())
|
|
{
|
|
stream_enabled[profile.unique_id()] = true;
|
|
def_format[profile.unique_id()] = profile.format();
|
|
}
|
|
|
|
profiles.push_back(profile);
|
|
}
|
|
auto any_stream_enabled = std::any_of(std::begin(stream_enabled), std::end(stream_enabled), [](const std::pair<int, bool>& p) { return p.second; });
|
|
if (!any_stream_enabled)
|
|
{
|
|
if (sensor_profiles.size() > 0)
|
|
stream_enabled[sensor_profiles.rbegin()->unique_id()] = true;
|
|
}
|
|
|
|
for (auto&& fps_list : fps_values_per_stream)
|
|
{
|
|
sort_together(fps_list.second, fpses_per_stream[fps_list.first]);
|
|
}
|
|
sort_together(shared_fps_values, shared_fpses);
|
|
for (auto&& res_list : resolutions_per_stream)
|
|
{
|
|
sort_resolutions(res_list.second);
|
|
}
|
|
sort_together(res_values, resolutions);
|
|
|
|
show_single_fps_list = is_there_common_fps();
|
|
|
|
int selection_index{};
|
|
|
|
if (!show_single_fps_list)
|
|
{
|
|
for (auto fps_array : fps_values_per_stream)
|
|
{
|
|
if (get_default_selection_index(fps_array.second, default_fps, &selection_index))
|
|
{
|
|
ui.selected_fps_id[fps_array.first] = selection_index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (get_default_selection_index(shared_fps_values, default_fps, &selection_index))
|
|
ui.selected_shared_fps_id = selection_index;
|
|
}
|
|
|
|
for (auto format_array : format_values)
|
|
{
|
|
if (get_default_selection_index(format_array.second, def_format[format_array.first], &selection_index))
|
|
{
|
|
ui.selected_format_id[format_array.first] = selection_index;
|
|
}
|
|
}
|
|
|
|
if (is_multiple_resolutions_supported())
|
|
{
|
|
ui.is_multiple_resolutions = true;
|
|
auto default_res = std::make_pair(1280, 960);
|
|
for (auto res_array : profile_id_to_res)
|
|
{
|
|
if (get_default_selection_index(res_array.second, default_res, &selection_index))
|
|
{
|
|
ui.selected_res_id_map[res_array.first] = selection_index;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
get_default_selection_index(res_values, default_resolution, &selection_index);
|
|
ui.selected_res_id = selection_index;
|
|
}
|
|
|
|
if (new_device_connected)
|
|
{
|
|
// Have the various preset options automatically update based on the resolution of the
|
|
// (closed) stream...
|
|
// TODO we have no res_values when loading color rosbag, and color sensor isn't
|
|
// even supposed to support SENSOR_MODE... see RS5-7726
|
|
if (s->supports(RS2_OPTION_SENSOR_MODE) && !res_values.empty())
|
|
{
|
|
// Watch out for read-only options in the playback sensor!
|
|
try
|
|
{
|
|
auto requested_sensor_mode = static_cast<float>(resolution_from_width_height(
|
|
res_values[ui.selected_res_id].first,
|
|
res_values[ui.selected_res_id].second));
|
|
|
|
auto currest_sensor_mode = s->get_option(RS2_OPTION_SENSOR_MODE);
|
|
|
|
if (requested_sensor_mode != currest_sensor_mode)
|
|
s->set_option(RS2_OPTION_SENSOR_MODE, requested_sensor_mode);
|
|
}
|
|
catch (not_implemented_error const&)
|
|
{
|
|
// Just ignore for now: need to figure out a way to write to playback sensors...
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ui.is_multiple_resolutions)
|
|
{
|
|
for (auto it = ui.selected_res_id_map.begin(); it != ui.selected_res_id_map.end(); ++it)
|
|
{
|
|
while (it->second >= 0 && !is_selected_combination_supported())
|
|
it->second--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (ui.selected_res_id >= 0 && !is_selected_combination_supported())
|
|
ui.selected_res_id--;
|
|
}
|
|
last_valid_ui = ui;
|
|
}
|
|
catch (const error& e)
|
|
{
|
|
error_message = error_to_string(e);
|
|
}
|
|
populate_options(ss.str().c_str(), &_options_invalidated, error_message);
|
|
|
|
}
|
|
|
|
subdevice_model::~subdevice_model()
|
|
{
|
|
_destructing = true;
|
|
try
|
|
{
|
|
s->on_options_changed( []( const options_list & list ) {} );
|
|
}
|
|
catch( ... )
|
|
{
|
|
}
|
|
}
|
|
|
|
void subdevice_model::sort_resolutions(std::vector<std::pair<int, int>>& resolutions) const
|
|
{
|
|
std::sort(resolutions.begin(), resolutions.end(),
|
|
[](const std::pair<int, int>& a, const std::pair<int, int>& b) {
|
|
if (a.first != b.first)
|
|
return (a.first < b.first);
|
|
return (a.second <= b.second);
|
|
});
|
|
}
|
|
|
|
bool subdevice_model::is_there_common_fps()
|
|
{
|
|
std::vector<int> first_fps_group;
|
|
size_t group_index = 0;
|
|
for (; group_index < fps_values_per_stream.size(); ++group_index)
|
|
{
|
|
if (!fps_values_per_stream[(rs2_stream)group_index].empty())
|
|
{
|
|
first_fps_group = fps_values_per_stream[(rs2_stream)group_index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (size_t i = group_index + 1; i < fps_values_per_stream.size(); ++i)
|
|
{
|
|
auto fps_group = fps_values_per_stream[(rs2_stream)i];
|
|
if (fps_group.empty())
|
|
continue;
|
|
|
|
auto fps1 = first_fps_group[0];
|
|
auto it = std::find_if( std::begin( fps_group ),
|
|
std::end( fps_group ),
|
|
[&]( const int & fps2 ) { return fps2 == fps1; } );
|
|
if( it == std::end( fps_group ) )
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool subdevice_model::draw_resolutions(std::string& error_message, std::string& label, std::function<void()> streaming_tooltip, float col0, float col1)
|
|
{
|
|
bool res = false;
|
|
|
|
// Draw combo-box with all resolution options for this device
|
|
auto res_chars = get_string_pointers(resolutions);
|
|
if (res_chars.size() > 0)
|
|
{
|
|
ImGui::Text("Resolution:");
|
|
streaming_tooltip();
|
|
ImGui::SameLine(); ImGui::SetCursorPosX(col1);
|
|
|
|
label = rsutils::string::from() << "##" << dev.get_info(RS2_CAMERA_INFO_NAME)
|
|
<< s->get_info(RS2_CAMERA_INFO_NAME) << " resolution";
|
|
|
|
if (!allow_change_resolution_while_streaming && streaming)
|
|
{
|
|
ImGui::Text("%s", res_chars[ui.selected_res_id]);
|
|
streaming_tooltip();
|
|
}
|
|
else
|
|
{
|
|
ImGui::PushItemWidth(-1);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, { 1,1,1,1 });
|
|
auto tmp_selected_res_id = ui.selected_res_id;
|
|
if (ImGui::Combo(label.c_str(), &tmp_selected_res_id, res_chars.data(),
|
|
static_cast<int>(res_chars.size())))
|
|
{
|
|
res = true;
|
|
_options_invalidated = true;
|
|
|
|
// Set sensor mode only at the Viewer app,
|
|
// DQT app will handle the sensor mode when the streaming is off (while reseting the stream)
|
|
if (s->supports(RS2_OPTION_SENSOR_MODE) && !allow_change_resolution_while_streaming)
|
|
{
|
|
auto width = res_values[tmp_selected_res_id].first;
|
|
auto height = res_values[tmp_selected_res_id].second;
|
|
auto res = resolution_from_width_height(width, height);
|
|
if (res >= RS2_SENSOR_MODE_VGA && res < RS2_SENSOR_MODE_COUNT)
|
|
{
|
|
try
|
|
{
|
|
s->set_option(RS2_OPTION_SENSOR_MODE, float(res));
|
|
}
|
|
catch (const error& e)
|
|
{
|
|
error_message = error_to_string(e);
|
|
}
|
|
|
|
// Only update the cached value once set_option is done! That way, if it doesn't change anything...
|
|
try
|
|
{
|
|
int sensor_mode_val = static_cast<int>(s->get_option(RS2_OPTION_SENSOR_MODE));
|
|
{
|
|
ui.selected_res_id = get_resolution_id_from_sensor_mode(
|
|
static_cast<rs2_sensor_mode>(sensor_mode_val),
|
|
res_values);
|
|
}
|
|
}
|
|
catch (...) {}
|
|
}
|
|
else
|
|
{
|
|
error_message = rsutils::string::from() << "Resolution " << width << "x" << height
|
|
<< " is not supported on this device";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ui.selected_res_id = tmp_selected_res_id;
|
|
}
|
|
}
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopItemWidth();
|
|
}
|
|
ImGui::SetCursorPosX(col0);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
bool subdevice_model::draw_fps(std::string& error_message, std::string& label, std::function<void()> streaming_tooltip, float col0, float col1)
|
|
{
|
|
bool res = false;
|
|
// FPS
|
|
if (show_single_fps_list)
|
|
{
|
|
auto fps_chars = get_string_pointers(shared_fpses);
|
|
ImGui::Text("Frame Rate (FPS):");
|
|
streaming_tooltip();
|
|
ImGui::SameLine(); ImGui::SetCursorPosX(col1);
|
|
|
|
label = rsutils::string::from()
|
|
<< "##" << dev.get_info(RS2_CAMERA_INFO_NAME) << s->get_info(RS2_CAMERA_INFO_NAME) << " fps";
|
|
|
|
if (!allow_change_fps_while_streaming && streaming)
|
|
{
|
|
ImGui::Text("%s", fps_chars[ui.selected_shared_fps_id]);
|
|
streaming_tooltip();
|
|
}
|
|
else
|
|
{
|
|
ImGui::PushItemWidth(-1);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, { 1,1,1,1 });
|
|
if (ImGui::Combo(label.c_str(), &ui.selected_shared_fps_id, fps_chars.data(),
|
|
static_cast<int>(fps_chars.size())))
|
|
{
|
|
res = true;
|
|
}
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopItemWidth();
|
|
}
|
|
|
|
ImGui::SetCursorPosX(col0);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
bool subdevice_model::draw_streams_and_formats(std::string& error_message, std::string& label, std::function<void()> streaming_tooltip, float col0, float col1)
|
|
{
|
|
bool res = false;
|
|
|
|
if (!streaming)
|
|
{
|
|
ImGui::Text("Available Streams:");
|
|
}
|
|
|
|
// Draw combo-box with all format options for current device
|
|
for (auto&& f : formats)
|
|
{
|
|
// Format
|
|
if (f.second.size() == 0)
|
|
continue;
|
|
|
|
auto formats_chars = get_string_pointers(f.second);
|
|
if (!streaming || (streaming && stream_enabled[f.first]))
|
|
{
|
|
if (streaming)
|
|
{
|
|
label = rsutils::string::from()
|
|
<< stream_display_names[f.first] << (show_single_fps_list ? "" : " stream:");
|
|
ImGui::Text("%s", label.c_str());
|
|
streaming_tooltip();
|
|
}
|
|
else
|
|
{
|
|
auto tmp = stream_enabled;
|
|
label = rsutils::string::from() << stream_display_names[f.first] << "##" << f.first;
|
|
if (ImGui::Checkbox(label.c_str(), &stream_enabled[f.first]))
|
|
{
|
|
prev_stream_enabled = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (stream_enabled[f.first])
|
|
{
|
|
if (show_single_fps_list)
|
|
{
|
|
ImGui::SameLine();
|
|
ImGui::SetCursorPosX(col1);
|
|
}
|
|
|
|
label = rsutils::string::from()
|
|
<< "##" << dev.get_info(RS2_CAMERA_INFO_NAME) << s->get_info(RS2_CAMERA_INFO_NAME) << " "
|
|
<< f.first << " format";
|
|
|
|
if (!show_single_fps_list)
|
|
{
|
|
ImGui::Text("Format:");
|
|
streaming_tooltip();
|
|
ImGui::SameLine(); ImGui::SetCursorPosX(col1);
|
|
}
|
|
|
|
if (streaming)
|
|
{
|
|
ImGui::Text("%s", formats_chars[ui.selected_format_id[f.first]]);
|
|
streaming_tooltip();
|
|
}
|
|
else
|
|
{
|
|
ImGui::PushItemWidth(-1);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, { 1,1,1,1 });
|
|
ImGui::Combo(label.c_str(), &ui.selected_format_id[f.first], formats_chars.data(),
|
|
static_cast<int>(formats_chars.size()));
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopItemWidth();
|
|
}
|
|
ImGui::SetCursorPosX(col0);
|
|
// FPS
|
|
// Draw combo-box with all FPS options for this device
|
|
if (!show_single_fps_list && !fpses_per_stream[f.first].empty() && stream_enabled[f.first])
|
|
{
|
|
auto fps_chars = get_string_pointers(fpses_per_stream[f.first]);
|
|
ImGui::Text("Frame Rate (FPS):");
|
|
streaming_tooltip();
|
|
ImGui::SameLine(); ImGui::SetCursorPosX(col1);
|
|
|
|
label = rsutils::string::from() << "##" << s->get_info(RS2_CAMERA_INFO_NAME)
|
|
<< s->get_info(RS2_CAMERA_INFO_NAME) << f.first << " fps";
|
|
|
|
if (streaming)
|
|
{
|
|
ImGui::Text("%s", fps_chars[ui.selected_fps_id[f.first]]);
|
|
streaming_tooltip();
|
|
}
|
|
else
|
|
{
|
|
ImGui::PushItemWidth(-1);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, { 1,1,1,1 });
|
|
ImGui::Combo(label.c_str(), &ui.selected_fps_id[f.first], fps_chars.data(),
|
|
static_cast<int>(fps_chars.size()));
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopItemWidth();
|
|
}
|
|
ImGui::SetCursorPosX(col0);
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
bool subdevice_model::draw_resolutions_combo_box_multiple_resolutions(std::string& error_message, std::string& label, std::function<void()> streaming_tooltip, float col0, float col1,
|
|
int stream_type_id, int depth_res_id)
|
|
{
|
|
bool res = false;
|
|
|
|
rs2_stream stream_type = RS2_STREAM_DEPTH;
|
|
if (stream_type_id != depth_res_id)
|
|
stream_type = RS2_STREAM_INFRARED;
|
|
|
|
|
|
auto res_pairs = resolutions_per_stream[stream_type];
|
|
std::vector<std::string> resolutions_str;
|
|
for (int i = 0; i < res_pairs.size(); ++i)
|
|
{
|
|
std::stringstream ss;
|
|
ss << res_pairs[i].first << "x" << res_pairs[i].second;
|
|
resolutions_str.push_back(ss.str());
|
|
}
|
|
|
|
auto res_chars = get_string_pointers(resolutions_str);
|
|
if (res_chars.size() > 0)
|
|
{
|
|
if (!(streaming && !streaming_map[stream_type_id]))
|
|
{
|
|
// resolution
|
|
// Draw combo-box with all resolution options for this stream type
|
|
ImGui::Text("Resolution:");
|
|
streaming_tooltip();
|
|
ImGui::SameLine(); ImGui::SetCursorPosX(col1);
|
|
|
|
label = rsutils::string::from() << "##" << dev.get_info(RS2_CAMERA_INFO_NAME)
|
|
<< s->get_info(RS2_CAMERA_INFO_NAME) << " resolution for " << rs2_stream_to_string(stream_type);
|
|
|
|
if (!allow_change_resolution_while_streaming && streaming)
|
|
{
|
|
ImGui::Text("%s", res_chars[ui.selected_res_id_map[stream_type_id]]);
|
|
streaming_tooltip();
|
|
}
|
|
else
|
|
{
|
|
ImGui::PushItemWidth(-1);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, { 1,1,1,1 });
|
|
auto tmp_selected_res_id = ui.selected_res_id_map[stream_type_id];
|
|
if (ImGui::Combo(label.c_str(), &tmp_selected_res_id, res_chars.data(),
|
|
static_cast<int>(res_chars.size())))
|
|
{
|
|
res = true;
|
|
_options_invalidated = true;
|
|
|
|
// Set sensor mode only at the Viewer app,
|
|
// DQT app will handle the sensor mode when the streaming is off (while reseting the stream)
|
|
if (s->supports(RS2_OPTION_SENSOR_MODE) && !allow_change_resolution_while_streaming)
|
|
{
|
|
auto width = res_values[tmp_selected_res_id].first;
|
|
auto height = res_values[tmp_selected_res_id].second;
|
|
auto res = resolution_from_width_height(width, height);
|
|
if (res >= RS2_SENSOR_MODE_VGA && res < RS2_SENSOR_MODE_COUNT)
|
|
{
|
|
try
|
|
{
|
|
s->set_option(RS2_OPTION_SENSOR_MODE, float(res));
|
|
}
|
|
catch (const error& e)
|
|
{
|
|
error_message = error_to_string(e);
|
|
}
|
|
|
|
// Only update the cached value once set_option is done! That way, if it doesn't change anything...
|
|
try
|
|
{
|
|
int sensor_mode_val = static_cast<int>(s->get_option(RS2_OPTION_SENSOR_MODE));
|
|
{
|
|
ui.selected_res_id = get_resolution_id_from_sensor_mode(
|
|
static_cast<rs2_sensor_mode>(sensor_mode_val),
|
|
res_values);
|
|
}
|
|
}
|
|
catch (...) {}
|
|
}
|
|
else
|
|
{
|
|
error_message = rsutils::string::from() << "Resolution " << width << "x" << height
|
|
<< " is not supported on this device";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ui.selected_res_id_map[stream_type_id] = tmp_selected_res_id;
|
|
}
|
|
}
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopItemWidth();
|
|
}
|
|
}
|
|
ImGui::SetCursorPosX(col0);
|
|
}
|
|
|
|
|
|
return res;
|
|
}
|
|
|
|
bool subdevice_model::draw_formats_combo_box_multiple_resolutions(std::string& error_message, std::string& label, std::function<void()> streaming_tooltip, float col0, float col1,
|
|
int stream_type_id)
|
|
{
|
|
bool res = false;
|
|
|
|
std::map<rs2_stream, std::vector<int>> stream_to_index;
|
|
int depth_res_id, ir1_res_id, ir2_res_id;
|
|
get_depth_ir_mismatch_resolutions_ids(depth_res_id, ir1_res_id, ir2_res_id);
|
|
stream_to_index[RS2_STREAM_DEPTH] = { depth_res_id };
|
|
stream_to_index[RS2_STREAM_INFRARED] = { ir1_res_id, ir2_res_id };
|
|
|
|
rs2_stream stream_type = RS2_STREAM_DEPTH;
|
|
if (stream_type_id != depth_res_id)
|
|
stream_type = RS2_STREAM_INFRARED;
|
|
|
|
|
|
for (auto&& f : formats)
|
|
{
|
|
if (f.second.size() == 0)
|
|
continue;
|
|
|
|
if (std::find(stream_to_index[stream_type].begin(), stream_to_index[stream_type].end(), f.first) == stream_to_index[stream_type].end())
|
|
continue;
|
|
|
|
auto formats_chars = get_string_pointers(f.second);
|
|
if (!streaming || (streaming && stream_enabled[f.first]))
|
|
{
|
|
if (streaming)
|
|
{
|
|
label = rsutils::string::from()
|
|
<< stream_display_names[f.first] << (show_single_fps_list ? "" : " stream:");
|
|
ImGui::Text("%s", label.c_str());
|
|
streaming_tooltip();
|
|
}
|
|
else
|
|
{
|
|
res = true;
|
|
auto tmp = stream_enabled;
|
|
label = rsutils::string::from() << stream_display_names[f.first] << "##" << f.first;
|
|
if (ImGui::Checkbox(label.c_str(), &stream_enabled[f.first]))
|
|
{
|
|
prev_stream_enabled = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (stream_enabled[f.first])
|
|
{
|
|
if (show_single_fps_list)
|
|
{
|
|
ImGui::SameLine();
|
|
ImGui::SetCursorPosX(col1);
|
|
}
|
|
|
|
label = rsutils::string::from()
|
|
<< "##" << dev.get_info(RS2_CAMERA_INFO_NAME) << s->get_info(RS2_CAMERA_INFO_NAME) << " "
|
|
<< f.first << " format";
|
|
|
|
if (!show_single_fps_list)
|
|
{
|
|
ImGui::Text("Format:");
|
|
streaming_tooltip();
|
|
ImGui::SameLine(); ImGui::SetCursorPosX(col1);
|
|
}
|
|
|
|
if (streaming)
|
|
{
|
|
ImGui::Text("%s", formats_chars[ui.selected_format_id[f.first]]);
|
|
streaming_tooltip();
|
|
}
|
|
else
|
|
{
|
|
ImGui::PushItemWidth(-1);
|
|
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, { 1,1,1,1 });
|
|
ImGui::Combo(label.c_str(), &ui.selected_format_id[f.first], formats_chars.data(),
|
|
static_cast<int>(formats_chars.size()));
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopItemWidth();
|
|
}
|
|
ImGui::SetCursorPosX(col0);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
bool subdevice_model::draw_res_stream_formats(std::string& error_message, std::string& label, std::function<void()> streaming_tooltip, float col0, float col1)
|
|
{
|
|
bool res = false;
|
|
|
|
if (!ui.is_multiple_resolutions)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int depth_res_id, ir1_res_id, ir2_res_id;
|
|
get_depth_ir_mismatch_resolutions_ids(depth_res_id, ir1_res_id, ir2_res_id);
|
|
|
|
std::vector<uint32_t> stream_types_ids;
|
|
stream_types_ids.push_back(depth_res_id);
|
|
stream_types_ids.push_back(ir1_res_id);
|
|
for (auto&& stream_type_id : stream_types_ids)
|
|
{
|
|
// resolution
|
|
// Draw combo-box with all resolution options for this stream type
|
|
res &= draw_resolutions_combo_box_multiple_resolutions(error_message, label, streaming_tooltip, col0, col1, stream_type_id, depth_res_id);
|
|
|
|
// stream and formats
|
|
// Draw combo-box with all format options for current stream type
|
|
res &= draw_formats_combo_box_multiple_resolutions(error_message, label, streaming_tooltip, col0, col1, stream_type_id);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
// The function returns true if one of the configuration parameters changed
|
|
bool subdevice_model::draw_stream_selection(std::string& error_message)
|
|
{
|
|
bool res = false;
|
|
|
|
std::string label = rsutils::string::from()
|
|
<< "Stream Selection Columns##" << dev.get_info(RS2_CAMERA_INFO_NAME)
|
|
<< s->get_info(RS2_CAMERA_INFO_NAME);
|
|
|
|
auto streaming_tooltip = [&]() {
|
|
if ((!allow_change_resolution_while_streaming && streaming)
|
|
&& ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("Can't modify while streaming");
|
|
};
|
|
|
|
auto col0 = ImGui::GetCursorPosX();
|
|
auto col1 = 9.f * (float)config_file::instance().get( configurations::window::font_size );
|
|
|
|
if (ui.is_multiple_resolutions && !strcmp(s->get_info(RS2_CAMERA_INFO_NAME), "Stereo Module"))
|
|
{
|
|
if (draw_fps_selector)
|
|
{
|
|
res |= draw_fps(error_message, label, streaming_tooltip, col0, col1);
|
|
}
|
|
|
|
if (draw_streams_selector)
|
|
{
|
|
if (!streaming)
|
|
{
|
|
ImGui::Text("Available Streams:");
|
|
}
|
|
|
|
res |= draw_res_stream_formats(error_message, label, streaming_tooltip, col0, col1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
res |= draw_resolutions(error_message, label, streaming_tooltip, col0, col1);
|
|
|
|
if (draw_fps_selector)
|
|
{
|
|
res |= draw_fps(error_message, label, streaming_tooltip, col0, col1);
|
|
}
|
|
|
|
if (draw_streams_selector)
|
|
{
|
|
res |= draw_streams_and_formats(error_message, label, streaming_tooltip, col0, col1);
|
|
}
|
|
}
|
|
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
|
return res;
|
|
}
|
|
|
|
bool subdevice_model::is_selected_combination_supported()
|
|
{
|
|
bool enforce_inter_stream_policies = false;
|
|
std::vector<stream_profile> results = get_selected_profiles(enforce_inter_stream_policies);
|
|
|
|
if (results.size() == 0)
|
|
return false;
|
|
// Verify that the number of found matches corrseponds to the number of the requested streams
|
|
// TODO - review whether the comparison can be made strict (==)
|
|
return results.size() >= size_t(std::count_if(stream_enabled.begin(), stream_enabled.end(), [](const std::pair<int, bool>& kpv)-> bool { return kpv.second == true; }));
|
|
}
|
|
|
|
void subdevice_model::update_ui(std::vector<stream_profile> profiles_vec)
|
|
{
|
|
if (profiles_vec.empty())
|
|
return;
|
|
for (auto& s : stream_enabled)
|
|
s.second = false;
|
|
for (auto& p : profiles_vec)
|
|
{
|
|
stream_enabled[p.unique_id()] = true;
|
|
|
|
// update format
|
|
auto format_vec = format_values[p.unique_id()];
|
|
for (int i = 0; i < format_vec.size(); i++)
|
|
{
|
|
if (format_vec[i] == p.format())
|
|
{
|
|
ui.selected_format_id[p.unique_id()] = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// update resolution
|
|
if (!ui.is_multiple_resolutions)
|
|
{
|
|
for (int i = 0; i < res_values.size(); i++)
|
|
{
|
|
if (auto vid_prof = p.as<video_stream_profile>())
|
|
if (res_values[i].first == vid_prof.width() && res_values[i].second == vid_prof.height())
|
|
{
|
|
ui.selected_res_id = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto res_vec = profile_id_to_res[p.unique_id()];
|
|
for (int i = 0; i < res_vec.size(); i++)
|
|
{
|
|
if (auto vid_prof = p.as<video_stream_profile>())
|
|
if (res_vec[i].first == vid_prof.width() && res_vec[i].second == vid_prof.height())
|
|
{
|
|
ui.selected_res_id_map[p.unique_id()] = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// update fps
|
|
for (int i = 0; i < shared_fps_values.size(); i++)
|
|
{
|
|
if (shared_fps_values[i] == p.fps())
|
|
{
|
|
ui.selected_shared_fps_id = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
last_valid_ui = ui;
|
|
prev_stream_enabled = stream_enabled; // prev differs from curr only after user changes
|
|
}
|
|
|
|
template<typename T, typename V>
|
|
bool subdevice_model::check_profile(stream_profile p, T cond, std::map<V, std::map<int, stream_profile>>& profiles_map,
|
|
std::vector<stream_profile>& results, V key, int num_streams, stream_profile& def_p)
|
|
{
|
|
bool found = false;
|
|
if (auto vid_prof = p.as<video_stream_profile>())
|
|
{
|
|
for (auto& s : stream_enabled)
|
|
{
|
|
// find profiles that have an enabled stream and match the required condition
|
|
if (s.second == true && vid_prof.unique_id() == s.first && cond(vid_prof))
|
|
{
|
|
profiles_map[key].insert(std::pair<int, stream_profile>(p.unique_id(), p));
|
|
if (profiles_map[key].size() == num_streams)
|
|
{
|
|
results.clear(); // make sure only current profiles are saved
|
|
for (auto& it : profiles_map[key])
|
|
results.push_back(it.second);
|
|
found = true;
|
|
}
|
|
else if (results.empty() && num_streams > 1 && profiles_map[key].size() == num_streams - 1)
|
|
{
|
|
for (auto& it : profiles_map[key])
|
|
results.push_back(it.second);
|
|
}
|
|
}
|
|
else if (!def_p.get() && cond(vid_prof))
|
|
def_p = p; // in case no matching profile for current stream will be found, we'll use some profile that matches the condition
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
|
|
void subdevice_model::get_sorted_profiles(std::vector<stream_profile>& profiles)
|
|
{
|
|
auto fps = shared_fps_values[ui.selected_shared_fps_id];
|
|
int width = 0;
|
|
int height = 0;
|
|
std::vector<std::pair<int, int>> selected_resolutions;
|
|
if (!ui.is_multiple_resolutions)
|
|
{
|
|
width = res_values[ui.selected_res_id].first;
|
|
height = res_values[ui.selected_res_id].second;
|
|
}
|
|
else
|
|
{
|
|
for (auto it = profile_id_to_res.begin(); it != profile_id_to_res.end(); ++it)
|
|
{
|
|
selected_resolutions.push_back(it->second[ui.selected_res_id_map[it->first]]);
|
|
}
|
|
}
|
|
std::sort(profiles.begin(), profiles.end(), [&](stream_profile a, stream_profile b) {
|
|
int score_a = 0, score_b = 0;
|
|
if (a.fps() != fps)
|
|
score_a++;
|
|
if (b.fps() != fps)
|
|
score_b++;
|
|
|
|
if (a.format() != format_values[a.unique_id()][ui.selected_format_id[a.unique_id()]])
|
|
score_a++;
|
|
if (b.format() != format_values[b.unique_id()][ui.selected_format_id[b.unique_id()]])
|
|
score_b++;
|
|
|
|
auto a_vp = a.as<video_stream_profile>();
|
|
auto b_vp = a.as<video_stream_profile>();
|
|
if (!a_vp || !b_vp)
|
|
return score_a < score_b;
|
|
|
|
if (!ui.is_multiple_resolutions)
|
|
{
|
|
if (a_vp.width() != width || a_vp.height() != height)
|
|
score_a++;
|
|
if (b_vp.width() != width || b_vp.height() != height)
|
|
score_b++;
|
|
}
|
|
else
|
|
{
|
|
bool a_same_res_found = false;
|
|
bool b_same_res_found = false;
|
|
for (int i = 0; i < selected_resolutions.size(); ++i)
|
|
{
|
|
if (a_vp.width() == selected_resolutions[i].first && a_vp.height() == selected_resolutions[i].second)
|
|
a_same_res_found = true;
|
|
if (b_vp.width() == selected_resolutions[i].first && b_vp.height() == selected_resolutions[i].second)
|
|
b_same_res_found = true;
|
|
}
|
|
if (!a_same_res_found)
|
|
score_a++;
|
|
if (!b_same_res_found)
|
|
score_b++;
|
|
}
|
|
|
|
return score_a < score_b;
|
|
});
|
|
}
|
|
|
|
std::vector<stream_profile> subdevice_model::get_supported_profiles()
|
|
{
|
|
std::vector<stream_profile> results;
|
|
if (!show_single_fps_list || res_values.size() == 0)
|
|
return results;
|
|
|
|
int num_streams = 0;
|
|
for (auto& s : stream_enabled)
|
|
if (s.second == true)
|
|
num_streams++;
|
|
stream_profile def_p;
|
|
auto fps = shared_fps_values[ui.selected_shared_fps_id];
|
|
int width = 0;
|
|
int height = 0;
|
|
std::vector<std::pair<int, int>> selected_resolutions;
|
|
if (!ui.is_multiple_resolutions)
|
|
{
|
|
width = res_values[ui.selected_res_id].first;
|
|
height = res_values[ui.selected_res_id].second;
|
|
}
|
|
else
|
|
{
|
|
for (auto it = profile_id_to_res.begin(); it != profile_id_to_res.end(); ++it)
|
|
{
|
|
selected_resolutions.push_back(it->second[ui.selected_res_id_map[it->first]]);
|
|
}
|
|
}
|
|
|
|
std::vector<stream_profile> sorted_profiles = profiles;
|
|
|
|
if (!ui.is_multiple_resolutions && (ui.selected_res_id != last_valid_ui.selected_res_id))
|
|
{
|
|
get_sorted_profiles(sorted_profiles);
|
|
std::map<int, std::map<int, stream_profile>> profiles_by_fps;
|
|
for (auto&& p : sorted_profiles)
|
|
{
|
|
if (check_profile(p, [&](video_stream_profile vsp)
|
|
{ return (vsp.width() == width && vsp.height() == height); },
|
|
profiles_by_fps, results, p.fps(), num_streams, def_p))
|
|
break;
|
|
}
|
|
}
|
|
else if (ui.is_multiple_resolutions && (ui.selected_res_id_map != last_valid_ui.selected_res_id_map))
|
|
{
|
|
get_sorted_profiles(sorted_profiles);
|
|
std::map<int, std::map<int, stream_profile>> profiles_by_fps;
|
|
for (auto&& p : sorted_profiles)
|
|
{
|
|
if (check_profile(p, [&](video_stream_profile vsp)
|
|
{
|
|
bool res = false;
|
|
std::pair<int, int> cur_res;
|
|
if (p.stream_type() == RS2_STREAM_DEPTH)
|
|
cur_res = selected_resolutions[0];
|
|
else
|
|
cur_res = selected_resolutions[1];
|
|
return (vsp.width() == cur_res.first && vsp.height() == cur_res.second);
|
|
},
|
|
profiles_by_fps, results, p.fps(), num_streams, def_p))
|
|
break;
|
|
}
|
|
}
|
|
else if (ui.selected_shared_fps_id != last_valid_ui.selected_shared_fps_id)
|
|
{
|
|
get_sorted_profiles(sorted_profiles);
|
|
std::map<std::tuple<int, int>, std::map<int, stream_profile>> profiles_by_res;
|
|
|
|
for (auto&& p : sorted_profiles)
|
|
{
|
|
if (auto vid_prof = p.as<video_stream_profile>())
|
|
{
|
|
if (check_profile(p, [&](video_stream_profile vsp) { return (vsp.fps() == fps); },
|
|
profiles_by_res, results, std::make_tuple(vid_prof.width(), vid_prof.height()), num_streams, def_p))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (ui.selected_format_id != last_valid_ui.selected_format_id)
|
|
{
|
|
if (num_streams == 0)
|
|
{
|
|
last_valid_ui = ui;
|
|
return results;
|
|
}
|
|
get_sorted_profiles(sorted_profiles);
|
|
std::vector<stream_profile> matching_profiles;
|
|
std::map<std::tuple<int, int, int>, std::map<int, stream_profile>> profiles_by_fps_res; //fps, width, height
|
|
rs2_format format;
|
|
int stream_id;
|
|
// find the stream to which the user made changes
|
|
for (auto& it : ui.selected_format_id)
|
|
{
|
|
if (stream_enabled[it.first])
|
|
{
|
|
auto last_valid_it = last_valid_ui.selected_format_id.find(it.first);
|
|
if ((last_valid_it == last_valid_ui.selected_format_id.end() || it.second != last_valid_it->second))
|
|
{
|
|
format = format_values[it.first][it.second];
|
|
stream_id = it.first;
|
|
}
|
|
}
|
|
}
|
|
for (auto&& p : sorted_profiles)
|
|
{
|
|
if (auto vid_prof = p.as<video_stream_profile>())
|
|
if (p.unique_id() == stream_id && p.format() == format) // && stream_enabled[stream_id]
|
|
{
|
|
profiles_by_fps_res[std::make_tuple(p.fps(), vid_prof.width(), vid_prof.height())].insert(std::pair<int, stream_profile>(p.unique_id(), p));
|
|
matching_profiles.push_back(p);
|
|
if (!def_p.get())
|
|
def_p = p;
|
|
}
|
|
}
|
|
// take profiles not in matching_profiles with enabled stream and fps+resolution matching some profile in matching_profiles
|
|
for (auto&& p : sorted_profiles)
|
|
{
|
|
if (auto vid_prof = p.as<video_stream_profile>())
|
|
{
|
|
if (check_profile(p, [&](stream_profile prof) { return (std::find_if(matching_profiles.begin(), matching_profiles.end(), [&](stream_profile sp)
|
|
{ return (stream_id != p.unique_id() && sp.fps() == p.fps() && sp.as<video_stream_profile>().width() == vid_prof.width() &&
|
|
sp.as<video_stream_profile>().height() == vid_prof.height()); }) != matching_profiles.end()); },
|
|
profiles_by_fps_res, results, std::make_tuple(p.fps(), vid_prof.width(), vid_prof.height()), num_streams, def_p))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (stream_enabled != prev_stream_enabled)
|
|
{
|
|
if (num_streams == 0)
|
|
return results;
|
|
get_sorted_profiles(sorted_profiles);
|
|
std::vector<stream_profile> matching_profiles;
|
|
std::map<rs2_format, std::map<int, stream_profile>> profiles_by_format;
|
|
|
|
for (auto&& p : sorted_profiles)
|
|
{
|
|
// first try to find profile from the new stream to match the current configuration
|
|
if (!ui.is_multiple_resolutions)
|
|
{
|
|
if (check_profile(p, [&](video_stream_profile vid_prof)
|
|
{ return (p.fps() == fps && vid_prof.width() == width && vid_prof.height() == height); },
|
|
profiles_by_format, results, p.format(), num_streams, def_p))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (check_profile(p, [&](video_stream_profile vid_prof)
|
|
{
|
|
bool res = false;
|
|
for (int i = 0; i < selected_resolutions.size(); ++i)
|
|
{
|
|
auto cur_res = selected_resolutions[i];
|
|
if (p.fps() == fps && vid_prof.width() == cur_res.first && vid_prof.height() == cur_res.second)
|
|
{
|
|
res = true;
|
|
break;
|
|
}
|
|
}
|
|
return res;
|
|
},
|
|
profiles_by_format, results, p.format(), num_streams, def_p))
|
|
break;
|
|
}
|
|
}
|
|
if (results.size() < num_streams)
|
|
{
|
|
results.clear();
|
|
std::map<std::tuple<int, int, int>, std::map<int, stream_profile>> profiles_by_fps_res;
|
|
for (auto&& p : sorted_profiles)
|
|
{
|
|
if (auto vid_prof = p.as<video_stream_profile>())
|
|
{
|
|
// if no stream with current configuration was found, try to find some configuration to match all enabled streams
|
|
if (check_profile(p, [&](video_stream_profile vsp) { return true; }, profiles_by_fps_res, results,
|
|
std::make_tuple(p.fps(), vid_prof.width(), vid_prof.height()), num_streams, def_p))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (results.empty())
|
|
results.push_back(def_p);
|
|
update_ui(results);
|
|
return results;
|
|
}
|
|
|
|
bool subdevice_model::is_ir_calibration_profile() const
|
|
{
|
|
// checking format
|
|
bool is_cal_format = false;
|
|
// checking that the SKU is D405 - otherwise, this method should return false
|
|
if (dev.supports(RS2_CAMERA_INFO_PRODUCT_ID) && !strcmp(dev.get_info(RS2_CAMERA_INFO_PRODUCT_ID), "0B5B"))
|
|
{
|
|
for (auto it = stream_enabled.begin(); it != stream_enabled.end(); ++it)
|
|
{
|
|
if (it->second)
|
|
{
|
|
int selected_format_index = -1;
|
|
if (ui.selected_format_id.count(it->first) > 0)
|
|
selected_format_index = ui.selected_format_id.at(it->first);
|
|
|
|
if (format_values.count(it->first) > 0 && selected_format_index > -1)
|
|
{
|
|
auto formats = format_values.at(it->first);
|
|
if (formats.size() > selected_format_index)
|
|
{
|
|
auto format = formats[selected_format_index];
|
|
if (format == RS2_FORMAT_Y16)
|
|
{
|
|
is_cal_format = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return is_cal_format;
|
|
}
|
|
|
|
std::pair<int, int> subdevice_model::get_max_resolution(rs2_stream stream) const
|
|
{
|
|
if (resolutions_per_stream.count(stream) > 0)
|
|
return resolutions_per_stream.at(stream).back();
|
|
|
|
std::stringstream error_message;
|
|
error_message << "The stream ";
|
|
error_message << rs2_stream_to_string(stream);
|
|
error_message << " is not available with this sensor ";
|
|
error_message << s->get_info(RS2_CAMERA_INFO_NAME);
|
|
throw std::runtime_error(error_message.str());
|
|
}
|
|
|
|
std::vector<stream_profile> subdevice_model::get_selected_profiles(bool enforce_inter_stream_policies)
|
|
{
|
|
std::vector<stream_profile> results;
|
|
|
|
std::stringstream error_message;
|
|
error_message << "The profile ";
|
|
|
|
bool is_cal_profile = is_ir_calibration_profile();
|
|
|
|
for (auto&& f : formats)
|
|
{
|
|
auto stream = f.first;
|
|
if (stream_enabled[stream])
|
|
{
|
|
auto format = format_values[stream][ui.selected_format_id[stream]];
|
|
|
|
auto fps = 0;
|
|
if (show_single_fps_list)
|
|
fps = shared_fps_values[ui.selected_shared_fps_id];
|
|
else
|
|
fps = fps_values_per_stream[stream][ui.selected_fps_id[stream]];
|
|
|
|
for (auto&& p : profiles)
|
|
{
|
|
if (auto vid_prof = p.as<video_stream_profile>())
|
|
{
|
|
if (res_values.size() > 0)
|
|
{
|
|
int width = 0;
|
|
int height = 0;
|
|
std::vector<std::pair<int, int>> selected_resolutions;
|
|
if (!ui.is_multiple_resolutions)
|
|
{
|
|
width = res_values[ui.selected_res_id].first;
|
|
height = res_values[ui.selected_res_id].second;
|
|
error_message << "\n{" << stream_display_names[stream] << ","
|
|
<< width << "x" << height << " at " << fps << "Hz, "
|
|
<< rs2_format_to_string(format) << "} ";
|
|
}
|
|
else
|
|
{
|
|
for (auto it = profile_id_to_res.begin(); it != profile_id_to_res.end(); ++it)
|
|
{
|
|
selected_resolutions.push_back(it->second[ui.selected_res_id_map[it->first]]);
|
|
}
|
|
error_message << "\n{" << stream_display_names[stream] << ","
|
|
<< selected_resolutions[0].first << "x" << selected_resolutions[0].second << " at " << fps << "Hz, "
|
|
<< rs2_format_to_string(format) << "} ";
|
|
}
|
|
|
|
if (p.unique_id() == stream && p.fps() == fps && p.format() == format)
|
|
{
|
|
// permitting to add color stream profile to depth sensor
|
|
// when infrared calibration is active
|
|
if (is_cal_profile && p.stream_type() == RS2_STREAM_COLOR)
|
|
{
|
|
auto max_color_res = get_max_resolution(RS2_STREAM_COLOR);
|
|
if (vid_prof.width() == max_color_res.first && vid_prof.height() == max_color_res.second)
|
|
results.push_back(p);
|
|
}
|
|
else
|
|
{
|
|
if (!ui.is_multiple_resolutions)
|
|
{
|
|
if (vid_prof.width() == width && vid_prof.height() == height)
|
|
results.push_back(p);
|
|
}
|
|
else
|
|
{
|
|
std::pair<int, int> cur_res;
|
|
if (p.stream_type() == RS2_STREAM_DEPTH)
|
|
cur_res = selected_resolutions[0];
|
|
else
|
|
cur_res = selected_resolutions[1];
|
|
if (vid_prof.width() == cur_res.first && vid_prof.height() == cur_res.second)
|
|
results.push_back(p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error_message << "\n{" << stream_display_names[stream] << ", at " << fps << "Hz, "
|
|
<< rs2_format_to_string(format) << "} ";
|
|
|
|
if (p.fps() == fps &&
|
|
p.unique_id() == stream &&
|
|
p.format() == format)
|
|
results.push_back(p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (results.size() == 0 && enforce_inter_stream_policies)
|
|
{
|
|
error_message << " is unsupported!";
|
|
throw std::runtime_error(error_message.str());
|
|
}
|
|
return results;
|
|
}
|
|
|
|
void subdevice_model::stop(std::shared_ptr<notifications_model> not_model)
|
|
{
|
|
if (not_model)
|
|
not_model->add_log("Stopping streaming");
|
|
|
|
streaming = false;
|
|
_pause = false;
|
|
|
|
if (ui.is_multiple_resolutions)
|
|
{
|
|
int depth_res_id, ir1_res_id, ir2_res_id;
|
|
get_depth_ir_mismatch_resolutions_ids(depth_res_id, ir1_res_id, ir2_res_id);
|
|
streaming_map[depth_res_id] = false;
|
|
streaming_map[ir1_res_id] = false;
|
|
streaming_map[ir2_res_id] = false;
|
|
}
|
|
|
|
if (profiles[0].stream_type() == RS2_STREAM_COLOR)
|
|
{
|
|
std::lock_guard< std::mutex > lock(detected_objects->mutex);
|
|
detected_objects->clear();
|
|
detected_objects->sensor_is_on = false;
|
|
}
|
|
else if (profiles[0].stream_type() == RS2_STREAM_DEPTH)
|
|
{
|
|
viewer.disable_measurements();
|
|
}
|
|
|
|
s->stop();
|
|
|
|
_options_invalidated = true;
|
|
|
|
queues.foreach([&](frame_queue& q)
|
|
{
|
|
frame f;
|
|
while (q.poll_for_frame(&f));
|
|
});
|
|
|
|
s->close();
|
|
}
|
|
|
|
bool subdevice_model::is_paused() const
|
|
{
|
|
return _pause.load();
|
|
}
|
|
|
|
void subdevice_model::pause()
|
|
{
|
|
_pause = true;
|
|
}
|
|
|
|
void subdevice_model::resume()
|
|
{
|
|
_pause = false;
|
|
}
|
|
|
|
//The function decides if specific frame should be sent to the syncer
|
|
bool subdevice_model::is_synchronized_frame(viewer_model& viewer, const frame& f)
|
|
{
|
|
if (!viewer.is_3d_view || viewer.is_3d_depth_source(f) || viewer.is_3d_texture_source(f))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void subdevice_model::play(const std::vector<stream_profile>& profiles, viewer_model& viewer, std::shared_ptr<rs2::asynchronous_syncer> syncer)
|
|
{
|
|
std::stringstream ss;
|
|
ss << "Starting streaming of ";
|
|
for (size_t i = 0; i < profiles.size(); i++)
|
|
{
|
|
ss << profiles[i].stream_type();
|
|
if (i < profiles.size() - 1) ss << ", ";
|
|
}
|
|
ss << "...";
|
|
viewer.not_model->add_log(ss.str());
|
|
|
|
s->open(profiles);
|
|
try {
|
|
s->start([&, syncer](frame f)
|
|
{
|
|
// The condition here must match the condition inside render_loop()!
|
|
if (viewer.synchronization_enable)
|
|
{
|
|
syncer->invoke(f);
|
|
}
|
|
else
|
|
{
|
|
auto id = f.get_profile().unique_id();
|
|
viewer.ppf.frames_queue[id].enqueue(f);
|
|
|
|
on_frame();
|
|
}
|
|
});
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
s->close();
|
|
throw;
|
|
}
|
|
|
|
_options_invalidated = true;
|
|
streaming = true;
|
|
|
|
if (ui.is_multiple_resolutions)
|
|
{
|
|
int depth_res_id, ir1_res_id, ir2_res_id;
|
|
get_depth_ir_mismatch_resolutions_ids(depth_res_id, ir1_res_id, ir2_res_id);
|
|
streaming_map[depth_res_id] = true;
|
|
streaming_map[ir1_res_id] = true;
|
|
streaming_map[ir2_res_id] = true;
|
|
}
|
|
|
|
if (s->is< color_sensor >())
|
|
{
|
|
std::lock_guard< std::mutex > lock(detected_objects->mutex);
|
|
detected_objects->sensor_is_on = true;
|
|
}
|
|
}
|
|
void subdevice_model::update(std::string& error_message, notifications_model& notifications)
|
|
{
|
|
if (_options_invalidated)
|
|
{
|
|
next_option = 0;
|
|
_options_invalidated = false;
|
|
|
|
save_processing_block_to_config_file("colorizer", depth_colorizer);
|
|
save_processing_block_to_config_file("yuy2rgb", yuy2rgb);
|
|
save_processing_block_to_config_file("y411", y411);
|
|
|
|
for (auto&& pbm : post_processing) pbm->save_to_config_file();
|
|
}
|
|
|
|
if (next_option < supported_options.size())
|
|
{
|
|
auto next = supported_options[next_option];
|
|
if (options_metadata.find(static_cast<rs2_option>(next)) != options_metadata.end())
|
|
{
|
|
auto& opt_md = options_metadata[static_cast<rs2_option>(next)];
|
|
opt_md.update_all_fields(error_message, notifications);
|
|
|
|
if (next == RS2_OPTION_ENABLE_AUTO_EXPOSURE)
|
|
{
|
|
auto old_ae_enabled = auto_exposure_enabled;
|
|
auto_exposure_enabled = opt_md.value->as_float > 0;
|
|
|
|
if (!old_ae_enabled && auto_exposure_enabled)
|
|
{
|
|
try
|
|
{
|
|
if (s->is<roi_sensor>())
|
|
{
|
|
auto r = s->as<roi_sensor>().get_region_of_interest();
|
|
roi_rect.x = static_cast<float>(r.min_x);
|
|
roi_rect.y = static_cast<float>(r.min_y);
|
|
roi_rect.w = static_cast<float>(r.max_x - r.min_x);
|
|
roi_rect.h = static_cast<float>(r.max_y - r.min_y);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
auto_exposure_enabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (next == RS2_OPTION_DEPTH_UNITS)
|
|
{
|
|
opt_md.dev->depth_units = opt_md.value->as_float;
|
|
}
|
|
|
|
if (next == RS2_OPTION_STEREO_BASELINE)
|
|
opt_md.dev->stereo_baseline = opt_md.value->as_float;
|
|
}
|
|
|
|
next_option++;
|
|
}
|
|
}
|
|
|
|
void subdevice_model::draw_options(const std::vector<rs2_option>& drawing_order,
|
|
bool update_read_only_options, std::string& error_message,
|
|
notifications_model& notifications)
|
|
{
|
|
for (auto& opt : drawing_order)
|
|
{
|
|
draw_option(opt, update_read_only_options, error_message, notifications);
|
|
}
|
|
|
|
for (auto i = 0; i < RS2_OPTION_COUNT; i++)
|
|
{
|
|
auto opt = static_cast<rs2_option>(i);
|
|
if (viewer.is_option_skipped(opt)) continue;
|
|
if (std::find(drawing_order.begin(), drawing_order.end(), opt) == drawing_order.end())
|
|
{
|
|
draw_option(opt, update_read_only_options, error_message, notifications);
|
|
}
|
|
}
|
|
}
|
|
|
|
uint64_t subdevice_model::num_supported_non_default_options() const
|
|
{
|
|
return (uint64_t)std::count_if(
|
|
std::begin(options_metadata),
|
|
std::end(options_metadata),
|
|
[&](const std::pair<int, option_model>& p) {return p.second.supported && !viewer.is_option_skipped(p.second.opt); });
|
|
}
|
|
|
|
bool subdevice_model::supports_on_chip_calib()
|
|
{
|
|
bool is_d400 = s->supports(RS2_CAMERA_INFO_PRODUCT_LINE) ?
|
|
std::string(s->get_info(RS2_CAMERA_INFO_PRODUCT_LINE)) == "D400" : false;
|
|
|
|
std::string fw_version = s->supports(RS2_CAMERA_INFO_FIRMWARE_VERSION) ?
|
|
s->get_info(RS2_CAMERA_INFO_FIRMWARE_VERSION) : "";
|
|
|
|
bool supported_fw = s->supports(RS2_CAMERA_INFO_FIRMWARE_VERSION) ?
|
|
is_upgradeable("05.11.12.0", fw_version) : false;
|
|
|
|
return s->is<rs2::depth_sensor>() && is_d400 && supported_fw;
|
|
// TODO: Once auto-calib makes it into the API, switch to querying camera info
|
|
}
|
|
|
|
void subdevice_model::get_depth_ir_mismatch_resolutions_ids(int& depth_res_id, int& ir1_res_id, int& ir2_res_id) const
|
|
{
|
|
auto it = profile_id_to_res.begin();
|
|
if (it != profile_id_to_res.end())
|
|
{
|
|
depth_res_id = it->first;
|
|
if (++it != profile_id_to_res.end())
|
|
{
|
|
ir1_res_id = it->first;
|
|
if (++it != profile_id_to_res.end())
|
|
{
|
|
ir2_res_id = it->first;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|