4 minute read

A while back, I blogged about a command line hack to set the focus for a web cam. I was using a Microsoft LifeCam HD-5000 and it has the annoying habit of refocusing if you move around in your seat.

It’s two years later and I have had a request for a compiled version of the FocusUF. It wasn’t much more than a paragraph of code and I put it up on GitHub for anyone to use. That’s all I had wanted to do, just the share the code and move on.

It’s not a product, it’s a block of code. I had resisted putting a compiled version up because it’s not something I wanted to support. But if you are not a .NET developer, it’s big ask to take that code and make a tiny command line tool. I get it. I decided to add a compiled version of the code to the GitHub repository. For use as is, no support.

I went back to the project and fired it up. It’s been two years and management has made some changes. I’m using Visual Studio 2019 and I no longer use that web cam. I upgraded to a Logitech c922 and no longer use the LifeCam.

The good news is the code compiled with no changes from VS 2019. Which is what I expected. When I ran it, tt crashed and burned with an error. Which I did not expect. It literally dies on the second line of code. The first two lines of code look like this:

// Get the list of connected video cameras
DsDevice[] devs = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

// Filter that list down to the one with hyper-aggressive focus
var dev = devs
  .Where(d => d.Name.Equals("Microsoft® LifeCam HD-5000"))

I broke the second line into multiple lines to make this a little easier to follow. I was getting a null exception on the highlighted line, specifically on d.Name.

For some reason, one of the items in the devs array has null for a name and that broke my code. It was never a problem before, because the LifeCam was first in the list returned by GetDevicesOfCat. Since I no longer had that web cam plugged in, the LINQ query was going through the entire list. And then erroring out trying to call Equals() on a null value. [SPOILER ALERT! That assumption was completely wrong.]

I was curious to see what was null. When I want to quickly visually data structures, I like to use LINQPad. So I copied and pasted those two lines into LINQPad and pulled in the nuget package for DirectShowLib. I then used the Dump() extension method to look at what was being returned for GetDevicesOfCat.

DevicePath Name
@device:pnp:\?\usb#vid_046d&pid_085c&mi_00#7&18173bf5&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global c922 Pro Stream Webcam
@device:pnp:\?\root#psycamera#0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}{9f25a503-ac24-460f-9196-8553ad691ef0} null
@device:sw:{860BB310-5D01-11D0-BD3B-00A0C911CE86}{3403512D-FE5D-4D68-B053-E86D662E4D58} ChromaCam

And there’s the null value. That was odd and we’ll get back that in minute. In the meantime, let’s fix that code. Instead of trying to be clever and use the Equals() function, I changed the code to just use the equals operator and let it handle the null check. That one line becomes:

var dev = devs
  .Where(d => d.Name == "Microsoft® LifeCam HD-5000")

I compiled the code and ran it. And it did nothing. Which is what I expected since I no longer had the LifeCam plugged in. More importantly, it didn’t throw an error.

I went back and added some Console.Writeln() statements so the app would at least say what it was doing or not doing. I built it again, zipped up the .dll & .exe files and added the zip file to a new win32 folder in the GitHub repository. So if you don’t have access to Visual Studio, you can grab just that zip file and get the FocusUF.exe app. But I’m not supporting that app. If it doesn’t work for you, just grab the code and compile it.

With the repo updated, it’s time to see what is our little null friend. If you look at the DevicePath, it has a wierd name buried in it. What is psycamera? If you google it, you find that a lot of people mispell “spy camera”. So that was no help. Names that are null set off my spidey senses. I wasn’t going to let that one just sit there with a look at it.

Going with the path of least resistance, I fired up Device Manager to see if something looked unfamilair or out of place. Sure enough, under “Cameras”, there was a new item named “Personify Virtual Camera Universal”. The Personify name was vaguely familiar [SPOILER ALERT] and I had a pretty good idea of what was going on, but I decided to double click on it and drill into the details.

Literally into the details. I selected the Details tab and select Device Instance Path from the drop-down list. That gave us this:

Device manager

And there is the mystery psycamera. Going back to the LINQPad dump, the third item that the list returned by GetDevicesOfCat was named ChromaCam. ChromaCam is a virtual webcam. It lets you replace your background with an image. And ChromaCam is made by a company named Personify. I’m not sure exactly what they are doing with the psycamera device, but it’s fairly innocuous. When I wrote the code two years ago, I did not have ChromaCam, so my code back then only had to deal with a single item in the devs list.

I did see if the code would compile with Visual Studio code and I think it would, but not out of the box. It looks like it would be more trouble than its worth. But I do recommend ChromaCam, it’s fun to play with.