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

Enable metadata with a single click on Windows #5678

Merged
merged 4 commits into from
Jan 23, 2020

Conversation

dorodnic
Copy link
Contributor

UVC frame metadata on Windows is causing a lot of questions and confusion, adding a single click solution that would be applicable from within the Viewer.
Alternative solution is to download and install Intel-RealSense-D400-Series-Universal-Windows-Platform-UWP-Driver-for-Windows but from our experience a lot of users don't do this.
Related to #5669

"software synchronization between different\n"
"camera streams.\n"
"It must be explicitly enabled on Windows OS\n";
last_progress_time = system_clock::now();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is draw_progress_bar() called at all? Where is this last_progress_time being used? If not used, is the inheritance from process_notification_model needed? Maybe inherit directly from notification_model?

enable_dismiss = true;
update_state = 0;
pinned = true;
message = "Frame Metadata is device feature allowing\n"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a device feature


bool operator==(const device_id& a, const device_id& b)
{
return (to_lower(a.pid) == to_lower(b.pid) &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strcasecmp() would compare just as well without all the extra allocations/transformations

public:
static bool parse_device_id(std::string id, device_id* res)
{
static const std::regex regex("[\\s\\S]*pid_([0-9a-fA-F]+)&mi_([0-9]+)#[0-9]&([0-9a-fA-F]+)&[\\s\\S]*\\{([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\\}[\\s\\S]*");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't "[\s\S]" the same as "."? And is not needed at the beginning/end of the regex if we use regex_search() instead of regex_match()?
If we're using a-fA-F, then no need to use to_lower(), and then can pass the string in with 'const &'?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't "[\s\S]" the same as "."?

Apparently no, I had problems matching special symbols with .*

And is not needed at the beginning/end of the regex if we use regex_search() instead of regex_match()

Make sense, I'll give it a try

If we're using a-fA-F, then no need to use to_lower()

Ultimately, to_lower is only used for comparisons. If we switch all comparisons to strcasecmp as you suggested it may be redundant

Copy link
Collaborator

@maloel maloel Jan 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't "[\s\S]" the same as "."?

Apparently no, I had problems matching special symbols with .*

According to this, ". doesn't catch line terminators (like new line) by default" but I don't think that would cover your difficulties. I wonder what kind of special characters...

But OK, keep it at [/s/S] but please comment so the next wise-guy like me won't try to "optimize" :)

return false;
}

static void do_foreach_device(std::vector<device_id> devices,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass devices by 'const &'

NULL,
NULL,
&ftLastWriteTime);
if (retCode == ERROR_SUCCESS)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of errors, do we usually LOG_DEBUG() it?
What about the successes? Do we want to debug-log any of this so we can see what happened?

if (rdid == did)
{
std::wstringstream ss;
ss << ws << "\\" << ke << "\\#GLOBAL\\Device Parameters";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can build the whole key path here instead of building ws ahead of time, so it'll be:

ss << "SYSTEM\\CurrentControlSet\\Control\\DeviceClasses\\{" << guid << "}"
   << "\\" << ke << "\\#GLOBAL\\Device Parameters";

That way it's clearer (and ws doesn't get re-defined inside this block).

{
std::wstringstream ss;
ss << ws << "\\" << ke << "\\#GLOBAL\\Device Parameters";
auto s = ss.str();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this a wstring? Why do we need ws on the next line?

// Heuristic that determines how many media-pins UVC device is expected to have
static int number_of_mediapins(std::string pid, std::string mi)
{
if (mi == "00")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole function is very confusing unless you know things by heart.

Isn't there a way to programmatically get all these magic numbers (which could conceivably change in the future)?
If not programmatically, isn't there a header somewhere with constants that will make this both more understandable and easier to maintain?
The way I understand it, "media pins" is the same as the streams that a device sensor exposes?

std::wstring wcmd(cmd_line.begin(), cmd_line.end());
sei.lpParameters = wcmd.c_str();

ShellExecuteEx(&sei); // not checking return code - what you are going to do? retry? why?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the very least, I think this should be logged somehow?

}

static void do_foreach_device(std::vector<device_id> devices,
std::function<void(device_id&, std::wstring)> action)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear what the wstring is representing... it's a device path, right? Can we name the argument? There might be an issue with the compiler (it's ambiguous in the standard, so depends on the compiler)...

Maybe name the function 'foreach_device_path'?

The device_id should be passed as 'const &'.

DWORD MetadataBufferSizeInKB = 5;
RegSetValueEx(key, metadatakey.c_str(), 0, REG_DWORD,
(const BYTE*)&MetadataBufferSizeInKB, sizeof(DWORD));
// What to do if failed???
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log it, at the very least.

// Enable metadata for all connected devices
virtual void enable_metadata() { }

static std::string get_command_line_param() { return "--enable_metadata"; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// This is the command-line parameter that gets passed to another process (running as admin) in order to enable metadata -- see WinMain

virtual bool is_enabled(std::string id) const { return true; }

// Enable metadata for all connected devices
virtual void enable_metadata() { }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, it could fail, so I'd suggest to return a bool, even if the implementation always "succeeds"

if (s == rs2::metadata_helper::get_command_line_param())
{
rs2::metadata_helper::instance().enable_metadata();
exit(0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exit 1 on failure (if you change the return value)

public:
static metadata_helper& instance();

// Check if metadata is enabled using Physical Port ID
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd help readability if we gave an example of a port ID string here, and explained is can be retrieved with device::get_info(RS2_CAMERA_INFO_PHYSICAL_PORT)

std::string product = dev.get_info(RS2_CAMERA_INFO_PRODUCT_LINE);
std::string id = dev.get_info(RS2_CAMERA_INFO_PHYSICAL_PORT);
bool has_metadata = rs2::metadata_helper::instance().is_enabled(id) ||
!(product == "D400" || product == "SR300" || product == "L500");
Copy link
Collaborator

@maloel maloel Jan 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we abstract these product names into the metadata_helper class, such that we can simply ask:

auto & metadata = rs2::metadata_helper::instance();
bool has_metadata = metadata.is_enabled( dev );

That way, the product names will be local to the helper class and this information is contained centrally.

key,
metadatakey.c_str(),
NULL,
NULL,
(LPBYTE)(&MetadataBufferSizeInKB),
&len);
&len) != ERROR_SUCCESS)
rs2::log(RS2_LOG_SEVERITY_DEBUG, "Unable to read metadata registry key!");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to include the key path in the message, otherwise it lacks context and will be repetitive if it happens multiple times

}

static void foreach_device_path(const std::vector<device_id>& devices,
std::function<void(device_id&, /* matched device */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any special reason device_id is not const?

{
try
{
DebugBreak();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to remove :)


if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("%s", "You will be prompted to enabled metadata on the device");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"to enable" (there's an extra d in there)

May I suggest:

"Enables metadata on connected devices (you may be prompted for administrator privileges)"

@@ -12,11 +12,18 @@ namespace rs2
static metadata_helper& instance();

// Check if metadata is enabled using Physical Port ID
// (can be retrieved with device::get_info(RS2_CAMERA_INFO_PHYSICAL_PORT))
virtual bool is_enabled(std::string id) const { return true; }

// Enable metadata for all connected devices
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add that it will throw a runtime_error on failure

Copy link
Collaborator

@maloel maloel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, see comments above

@dorodnic dorodnic merged commit 6006739 into IntelRealSense:development Jan 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants