jtfrey / uvc-util

USB Video Class (UVC) control management utility for Mac OS X
MIT License
108 stars 26 forks source link

Several settings could not be updated #8

Closed dhughes-xumak closed 3 years ago

dhughes-xumak commented 3 years ago

Let me start with thank you. Thank you for making this open source and contributing it to the world. I have nearly 20 years of development experience, and this was the first Objective C project I ever compiled. So there's that.

Unfortunately, the tool only worked for setting some of my camera's controls.

ERROR: unable to write new value to control auto-exposure-mode

I also got this for exposure-time-abs. I suspect the issue may have been in the type handling (U8Int and U32Int), possibly related to the endian swap for some int types. I put a couple hours into trying to debug the issue, but again... first time with Objective C.

In addition to not accepting some of the values for certain settings, I also noticed that some settings/controls aren't accessible for my camera, such as brightness and contrast. These values can be set with other apps, however.

--

So, I ended up moving on and finding https://github.com/mrRay/VVUVCKit, which has a "Test App" with a GUI for configuring the camera's settings. Aside from the Test App, that project contains a framework. I don't have the Objective C chops to do this, but it would be awesome if somebody built a CLI like this project, using the VVUVCKit framework.

With a working CLI, I suspect you could create a service similar to https://github.com/pirj/noclamshell, which could poll ioreg to see if a particular camera is connected, and set the desired config programmatically.

constant-flow commented 3 years ago

Similar story here thanks for this CLI and also here first time Objective-C ... but luckily with success! (@dhughes-xumak funny the last commit is 5 years ago ... and we both struggle the same issue within a week)

We had the same issue with exposure-time-abs and auto-exposure-mode (issue here is the cam reports a value, that is treated as stepSize in the process to realign it to that pattern, the value of the bitmap of exposure mode gets screwed up).

Fix / hack

This is a patch you can apply with git apply patch.txt to the current commit

We now added a different data type to handle the bitmap scheme (ignoring the stepsize which makes no sense for a mask)

Disclaimer

no warranty it works for everything, we tested esp. with the exposure mode. Also we changed the output of the -S be json like.

Examples

read the exposure mode

❯ ./uvc-util -I 0 -S auto-exposure-mode
{
  "name": "auto-exposure-mode",
  "type-description": "single value, unsigned 8-bit bitmap",
  "step-size": 9,
  "default-value": 8,
  "current-value": 1
}

set the exposure mode to manual (manual=1, automatic=8)

❯ ./uvc-util -I 0 -s auto-exposure-mode=1
jtfrey commented 3 years ago

@constant-flow please go ahead and submit a pull request, I'd be happy to look over the changes (adding 8-bit bitmap type) and integrate them into the repository.

constant-flow commented 3 years ago

added PR

for UVC reference (UVC 1.5 Class specification.pdf, page 97)

dhughes-xumak commented 3 years ago

I love open source projects. This is great!

@constant-flow: hilarious that we ran into the exact same issue on a project that has been quiet for so long. Thank you for putting in the extra effort that I didn't, in order to solve the problem and contribute it for the rest of us.

@jtfrey: thank you again for sharing this project, and for coming back to it to review the PR.

jtfrey commented 3 years ago

Please checkout the 714cd3420575579e96750e34047535fa8bc176eb commit (bitmap8 branch). It has the bitmap types implemented as directed in the v1.5 specification. I also added the new Terminal and Processing Unit attributes that arrived in the v1.5 specification. Let me know if it works — I have no USB video devices with which to test this anymore.

constant-flow commented 3 years ago

Wow, you are fast.

I just tested your code. From what i see does it behave as before. All (few) settings, my cam lists do work as expected (auto-exposure-priority doesn't have a noticeable effect, as before too)

auto-exposure-mode only accepts 1 and 8 as before. But you explained it, it is masked in the stepSize right now, which bits are allowed to flip (Just realized that, after scanning your code changes)

❯ ./uvc-util -I 0 -c
UVC controls implemented by this device:
  zoom-abs
  pan-tilt-abs
  exposure-time-abs
  auto-focus
  auto-exposure-priority
  auto-exposure-mode
  focus-abs
❯ ./uvc-util -I 0 -d
------------ -------------- ------------ ------------ ------------------------------------------------
Index        Vend:Prod      LocationID   UVC Version  Device name
------------ -------------- ------------ ------------ ------------------------------------------------
0            0x046d:0x082d  0x14310000   1.00         HD Pro Webcam C920
------------ -------------- ------------ ------------ ------------------------------------------------

❯ ./uvc-util -I 0 -S auto-exposure-mode
auto-exposure-mode {
  type-description: {
    single value, unsigned 8-bit bitmap
  },
  step-size: 9
  default-value: 8
  current-value: 8
}

❯ ./uvc-util -I 0 -s auto-exposure-mode=1
❯ ./uvc-util -I 0 -s auto-exposure-mode=8
❯ ./uvc-util -I 0 -s auto-exposure-mode=2
ERROR:  unable to write new value to control auto-exposure-mode
❯ ./uvc-util -I 0 -s auto-exposure-mode=4
ERROR:  unable to write new value to control auto-exposure-mode
jtfrey commented 3 years ago

@dhughes-xumak Once auto-exposure-mode is changed to 1 (manual) some of the other controls should be usable (e.g. exposure time, iris).

dhughes-xumak commented 3 years ago

Yup, seems to work for me now. I was able to set my camera to auto-exposure-mode 1 (Manual) or 8 (VVUVCKit reports this as Aperture Priority). The VVUVCKit test app also has options for Auto and Shutter Priority, but ./uvc-util -I 0 -g auto-exposure-mode shows me that only Manual and Aperture Priority actually update that value.

VVUVCKit allows me to set several settings which are not available to me with uvc-util, such as brightness and contrast. uvc-util -I 0 -c and uvc-util -I 0 -S * don't list those controls.

However, after setting auto-exposure-mode=1, I'm able to set my camera's exposure-time-abs to some values, most notably 39, 78, and 117 [edit: updated list in my next comment] seemed to result in decent video with varying light levels. From the spec doc, I don't see any significance to these numbers.

for i in `seq 0 200`; do 
  echo $i
  uvc-util -I0 -s exposure-time-abs=$i
  sleep 5
done

This update was sufficient to get me to where I wanted to take this. Thank you again, both.

--

I've added a launch agent to poll for a UVC camera every 5 seconds, and set some default settings when one is found:

  1. Copy uvc-util to /usr/local/bin/uvc-util.

  2. Create file /usr/local/bin/uvcsetcameramanual (755)

    
    #!/usr/bin/env bash

FLAG_FILE=$TMPDIR/uvcsetcameramanual.camera.connected

UVC_UTIL=/usr/local/bin/uvc-util CAMCONNECTED=$($UVC_UTIL -d)

if [ "$CAMCONNECTED" ]; then if [[ ! -f $FLAG_FILE ]]; then touch $FLAG_FILE $UVC_UTIL -I0 -s auto-exposure-mode=8 $UVC_UTIL -I0 -s brightness=30 $UVC_UTIL -I0 -s contrast=1 $UVC_UTIL -I0 -s saturation=125 fi else rm -f $FLAG_FILE fi


3. Create file ~/Library/LaunchAgents/uvc.setcameramanual.plist (544)

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

Labeluvc.setcameramanual ThrottleInterval 5 KeepAlive Program /usr/local/bin/uvcsetcameramanual

4. And load it with `launchctl load ~/Library/LaunchAgents/uvc.setcameramanual.plist`

https://medium.com/swlh/how-to-use-launchd-to-run-services-in-macos-b972ed1e352
jtfrey commented 3 years ago

I pushed another update just now, this one with how control resolution is handled. The VVUVCKit doesn't seem to bother with control resolution. The implementation in uvc-util does check it, but was using the wrong formulation. It was checking (value % resolution) and rounding up/down to the nearest value that is cleanly divisible by resolution. But the UVC specification is such that ((value - minimum) % resolution) is rounded up/down to the nearest cleanly-divisible value. So given

min = 1, max = 101, res = 20

valid values should be 1, 21, 41, 61, 81, 101. But choosing 21:

(21 % 20) = 1

and the previous implementation would subtract 1 from value to yield 20. So just as for bitmap values incorrectly applying resolution to round (when it was actually a bitmask to be AND'ed), the integer controls with resolution were being resolved to incorrect values.

Let me know if all previous tests continue to produce the same results, and if additional controls now work properly.

dhughes-xumak commented 3 years ago

@jtfrey, thanks again. Unfortunately, I don't think that helped me.

This setting actually has a resolution of 1, so the resolution-fixing doesn't apply.

$ uvc-util -I0 -Sexposure-time-abs
exposure-time-abs {
  type-description: {
    single value, unsigned 32-bit integer
  },
  minimum: 5
  maximum: 20000
  step-size: 1
  default-value: 156
  current-value: 78
}

The possible values seem to (more or less) follow a doubling series.
These values are working: 0, 1, 2, 3, 4, 5, 9, 10, 19, 20, 39, 78, 156, 312, 624. 9.75 and 19.5 belong in that series. Interestingly the integers on either side (9/10, 19/20) both work.

Any other value seems to be treated like the max value; 624 looks the same as anything >312.

jtfrey commented 3 years ago

Does VVUVCKit allow a continuous range of values for that control, or the same distinct values? The UVC 1.5 specification indicates that control over exposure-time-abs is partly a function of the frame interval for the device. My guess would be that what you're observing with the series is dependency on the frame rate (which can itself be dependent on other factors). The value 0 is supposed to be a reserved value with no defined meaning in the specification.

dhughes-xumak commented 3 years ago

VVUVCKit provides a continuous slider ranging 5-20000, but it exhibits the same behaviour. Only the values which I identified before worked correctly, all others look just like 624. image

Yes, I imagine these values may be specific to this particular camera.

dhughes-xumak commented 3 years ago

So, I spent some time with the spec and identified that my missing settings (eg, brightness) are processing unit settings (vs camera terminal settings, which I can access).

I've tracked the missing PU settings to here: https://github.com/jtfrey/uvc-util/blob/master/src/UVCController.m#L950

While debugging I found that control->unit was 2. By hard coding different unit values, I can access the additional PU controls; though I get different controls for different unit values.

I was also able to set these PU values after making a corresponding change to setValue here: https://github.com/jtfrey/uvc-util/blob/master/src/UVCController.m#L1021

EDIT: and with a little more effort, I located table A-5 in the spec (which already has corresponding constants in UVCController). image

Based on this, I undid my prior changes and set UVC_PROCESSING_UNIT_ID = VC_INPUT_TERMINAL - 1. This seems to give me the complete set of PU controls. Commit incoming...

jtfrey commented 3 years ago

Please see my comments on the UVC_PROCESSING_UNIT_ID fix. I've pushed another commit to the bitmap8-patch branch that should work regardless of what unit id the PU has for a specific device. E.g. with the default unitId changed to 0xFF and the actual unit now being noted by the UVCController class, the program still works on an Apeman 4K:

$ uvc-util -d
------------ -------------- ------------ ------------ ------------------------------------------------
Index        Vend:Prod      LocationID   UVC Version  Device name
------------ -------------- ------------ ------------ ------------------------------------------------
0            0x2aad:0x6373  0x14200000   1.00         iCatch V37
------------ -------------- ------------ ------------ ------------------------------------------------

$ uvc-util -I 0 -c
UVC controls implemented by this device:
  white-balance-temp
  exposure-time-abs
  auto-focus
  auto-exposure-priority
  auto-exposure-mode
  auto-white-balance-component
  focus-abs

Please try it with your devices.

dhughes-xumak commented 3 years ago

Hmm, with your latest commit, now the util reports no controls for my device. It chugs along for a while, but eventually reports no controls.

$ uvc-util -d
------------ -------------- ------------ ------------ ------------------------------------------------
Index        Vend:Prod      LocationID   UVC Version  Device name
------------ -------------- ------------ ------------ ------------------------------------------------
0            0x045e:0x075d  0x14140000   1.00         (null)
------------ -------------- ------------ ------------ ------------------------------------------------
$ uvc-util -I0 -c
UVC controls implemented by this device:
$ uvc-util -I0 -S*
$

The device is a Microsoft® LifeCam Cinema.

jtfrey commented 3 years ago

I added a chunk of code to dump the entire UVC interface header to a file (e.g. uvc-header-#.bin). Can you collect that for the LifeCam Cinema and get it to me so I can take a look at it?

dhughes-xumak commented 3 years ago

uvc-header-1.bin.txt

$ xxd -b uvc-header-1.bin
00000000: 00001101 00100100 00000001 00000000 00000001 01010101  .$...U
00000006: 00000000 10000000 11000011 11001001 00000001 00000001  ......
0000000c: 00000001 00010010 00100100 00000010 00000001 00000001  ..$...
00000012: 00000010 00000000 00000000 00000000 00000000 00000000  ......
00000018: 00000000 00000000 00000000 00000011 00101010 00001010  ....*.
0000001e: 00000010 00001001 00100100 00000011 00000010 00000001  ..$...
00000024: 00000001 00000000 00000101 00000000 00000111 00100100  .....$
0000002a: 00000100 00000011 00000001 00000001 00000000 00001011  ......
00000030: 00100100 00000101 00000100 00000011 00000000 00000000  $.....
00000036: 00000010 01011011 00010101 00000000 00011011 00100100  .[...$
0000003c: 00000110 00000101 00101001 10100111 10000111 11001001  ..)...
00000042: 11010011 01011001 01101001 01000101 10000100 01100111  .YiE.g
00000048: 11111111 00001000 01001001 11111100 00011001 11101000  ..I...
0000004e: 00010000 00000001 00000100 00000010 11111111 11111111  ......
00000054: 00000000                                               .
jtfrey commented 3 years ago

The PU record wasn't the length I was expecting, until I checked the version: that's a UVC 1.0 device!

There really was nothing wrong with the UVC header, but there was a botched stringify directive in the UVC_CONTROL_INIT macro. Every control had a unit type string of @"U" rather than @"UVC_INPUT_TERMINAL_ID" versus @"UVC_PROCESSING_UNIT_ID", so lookup of the unit when interacting with the device (GET_CUR, et al.) was failing. It should be fixed now.

dhughes-xumak commented 3 years ago

It was, indeed, UVC 1.0. Interestingly, looking back through this issue, it looks like all three of us had UVC 1.0 devices, at least based on the uvc-util -d output that you both posted.

Anyways, I've tested it out and it seems to be working well.

I'm going to go ahead and close this issue now. Thanks again @jtfrey and @constant-flow!

dhughes-xumak commented 3 years ago

PS, don't forget to merge branch bitmap8-patch into master. 😄