Closed pjsg closed 3 years ago
@pjsg: this is an upstream error in node-uvc-control
, due to changes in Node.js. It should be fixed for the upcoming v2 release of node-uvc-control
, but work seems to have stalled.
I've also backported it to node-uvc-control
v1, alongside some fixes for Linux. It "works for me" but I'd appreciate if you tested them. If it works for you as well I am considering creating a release for uvcc
targeting the forked code.
Further details about the different versions in this issue comment. Do they work for you?
@joelpurra I tried the forked code locally on my Mac - Seems like the export just creates an empty file now for me.
I'm running
node index.js --vendor 0x45e --product 0x772 export > "export.json"
@joelpurra I also get an empty export -- but if you add --verbose, then you get
./index.js --vendor 0x45e --product 0x772 export --verbose
Parsed arguments: {
"_": [],
"version": false,
"verbose": true,
"help": false,
"vendor": 1118,
"product": 1906,
"$0": "index.js",
"cmd": "export"
}
Error getting value, ignoring. autoExposurePriority [OperationalError: LIBUSB_TRANSFER_STALL] {
cause: [Error: LIBUSB_TRANSFER_STALL] { errno: 4 },
isOperational: true,
errno: 4
}
Error getting value, ignoring. brightness [OperationalError: LIBUSB_TRANSFER_STALL] {
cause: [Error: LIBUSB_TRANSFER_STALL] { errno: 4 },
isOperational: true,
errno: 4
}
Error getting value, ignoring. contrast [OperationalError: LIBUSB_TRANSFER_STALL] {
cause: [Error: LIBUSB_TRANSFER_STALL] { errno: 4 },
isOperational: true,
errno: 4
}
Error getting value, ignoring. saturation [OperationalError: LIBUSB_TRANSFER_STALL] {
cause: [Error: LIBUSB_TRANSFER_STALL] { errno: 4 },
isOperational: true,
errno: 4
}
Error getting value, ignoring. sharpness [OperationalError: LIBUSB_TRANSFER_STALL] {
cause: [Error: LIBUSB_TRANSFER_STALL] { errno: 4 },
isOperational: true,
errno: 4
}
Error getting value, ignoring. whiteBalanceTemperature [OperationalError: LIBUSB_TRANSFER_STALL] {
cause: [Error: LIBUSB_TRANSFER_STALL] { errno: 4 },
isOperational: true,
errno: 4
}
RangeError [ERR_BUFFER_OUT_OF_BOUNDS]: Attempt to access memory outside buffer bounds
at boundsError (internal/buffer.js:74:11)
at Buffer.readInt16LE (internal/buffer.js:404:5)
at Buffer.readIntLE (internal/buffer.js:339:17)
at readInt (/Users/philip/uvcc/node_modules/uvc-control/index.js:268:19)
at readInts (/Users/philip/uvcc/node_modules/uvc-control/index.js:254:17)
at Device.<anonymous> (/Users/philip/uvcc/node_modules/uvc-control/index.js:180:22)
at Transfer.<anonymous> (/Users/philip/uvcc/node_modules/usb/usb.js:127:15) {
code: 'ERR_BUFFER_OUT_OF_BOUNDS'
} uncaughtException
I added the following line in readints
in uvc-control/index.js
console.log("readints len %d, %d, %d\n", buffer.length, length, fieldSize);
and, rather surprisingly, it output:
readints len 1, 2, 2
i.e. the buffer only had 1 byte in it, in spite of being asked to read 2 bytes.
If I just make this return None, then I get
{
"absoluteExposureTime": 156,
"absoluteFocus": 12,
"absolutePanTilt": [
0,
0
],
"absoluteZoom": 0,
"autoExposureMode": 8,
"autoFocus": 1,
"backlightCompensation": []
}
which looks plausible.
@scarrawaySF: that is the same result as reported in #3. Do you also use a Microsoft® LifeCam Studio(TM)? (Asking to verify that you didn't happen to use the wrong vendor/product ids, although I think there would also be another error trying to close
after the empty output.)
@pjsg: the ERR_BUFFER_OUT_OF_BOUNDS
is from inside the backported fixes (readInts
). That's not a good sign. Edit: just noticed your follow-up comment with debugging values.
@joelpurra Yes I'm also using the Lifecam Studio - happy coincidence I suppose.
@pjsg: you'll find the per-control byte sizes in the same index.js
file. In this case, check for size: 2
. Might be that this particular camera doesn't send a 2-byte value for one of them. Can you figure out which one?
To reduce impact from other fixes in that branch, I've separated the relevant commit in my node-uvc-control
fork, and targeted the fork in a uvcc
branch. If there are fixes I suppose they can go there first.
Successfully tested the branches in both Linux (Ubuntu 19.10) and macOS (10.14.6 Mojave) using a Logitech c920. Tested in both Node.js v12.16.1 and v13.11.0.
Am not exactly an expert in the low-level UVC/USB fields; am mostly relying on the source code of node-uvc-control
and similar. There are official size/offset values in the UVC standard though -- for example 4.2.2.1.14 PanTilt (Absolute) Control on page 89 (104 in the document) in UVC 1.5 Class specification.pdf
. Would have to assume that compliant devices implement them properly, and that the issue lies in node-uvc-control
.
I changed readints to
function readInts(buffer, length, fieldSize) {
if((length%fieldSize)!==0) throw new Error("Not equal-sized fields.");
var output=[];
length = Math.min(length, buffer.length);
for (var i=0;i*fieldSize<length;i++) {
output.push(readInt(buffer.slice(i*fieldSize), Math.min(fieldSize, length - i * fieldSize)));
}
if (output.length === 1) {
return output[0];
}
return output;
}
and things are (sort of) working. This change to readints
lines up with the current version of node-uvc-control (which does the calculations differently, but has the same effect)
After saying all of that, I have found that setting the lifecam studio brightness to 20 is too dark, and setting it to 21 is much too light. The setting only works in autoExposureMode 1. Hmm...
In my case, it was the backlightCompensation control that has a length of 1 (and a range of 1 -> 1!)
@pjsg: the UVC standard seems to say 2 bytes in 4.2.2.3.1 Backlight Compensation Control on page 96 (or 111) in UVC 1.5 Class specification.pdf
, which is what node-uvc-control
uses. Odd that the camera would not send the same number of bytes. I would think (hope) that Microsoft built their cameras to standard, and that something else is wrong.
@pjsg: redefining length
to Math.min(length, buffer.length)
seems like a workaround for the missing second byte. Does the value for backlightCompensation
seem reasonable? Would probably be best to compare to a value from another tool, such as v4l2-ctl --all
if you have a Linux box around.
I think there's a chance that the second byte has a null \0
value -- which might make it "unreadable" by default, if null is a terminator character. Converting values from lower-level libraries to Node.js buffers can have that effect, as reading null values might be "out of the ordinary".
Returns a new
Buffer
that references the same memory as the original, but offset and cropped by thestart
andend
indices.
const originalFourBytes = Buffer.from("abcd");
console.log(originalFourBytes.length, originalFourBytes);
const readThreeBytes = originalFourBytes.slice(0, 3);
console.log(readThreeBytes.length, readThreeBytes);
const readFourBytes = originalFourBytes.slice(0, 4);
console.log(readFourBytes.length, readFourBytes);
// NOTE: only receive four bytes, not five.
const readFiveBytes = originalFourBytes.slice(0, 5);
console.log(readFiveBytes.length, readFiveBytes);
The above hints to having to pad the bytes read from the camera, presumably with \0
, to get the correct value.
This also relates to the "actual" length of the data read from the camera. Apparently there are recent libusb
errors (on Windows at least) with the expected versus actual number of bytes reported, but can't say if it's only for larger actual length or also smaller. node-usb
relies on this value for the slice
.
I've updated the test branch. Am now adding extra \0
bytes at the end1 of the buffer passed to readInts
, before parsing the integers.
The output doesn't change for me though, neither in Linux nor macOS. Does it help anyone else?
1 Since the bytes come from a lower level in the computer hardware (and software) architecture, the byte order and endianess might matter. If so, I am not sure how, and think it should be (have been) handled on a lower level already.
I ran v4l2-ctl --all
on a linux box with the lifecam, and this is the output:
Driver Info (not using libv4l2):
Driver name : uvcvideo
Card type : Microsoft® LifeCam Studio(TM)
Bus info : usb-0000:00:14.0-4
Driver version: 1.0.0
Capabilities : 0x04000001
Video Capture
Streaming
Video input : 0 (Camera 1: ok)
Format Video Capture:
Width/Height : 640/480
Pixel Format : 'YUYV'
Field : None
Bytes per Line: 1280
Size Image : 8320
Colorspace : SRGB
Crop Capability Video Capture:
Bounds : Left 0, Top 0, Width 640, Height 480
Default : Left 0, Top 0, Width 640, Height 480
Pixel Aspect: 1/1
Streaming Parameters Video Capture:
Capabilities : timeperframe
Frames per second: 5.000 (5/1)
Read buffers : 0
brightness (int) : min=30 max=255 step=1 default=133 value=133
contrast (int) : min=0 max=10 step=1 default=5 value=5
saturation (int) : min=0 max=200 step=1 default=103 value=103
white_balance_temperature_auto (bool) : default=1 value=1
power_line_frequency (menu) : min=0 max=2 default=2 value=2
white_balance_temperature (int) : min=2500 max=10000 step=1 default=4500 value=4500
sharpness (int) : min=0 max=50 step=1 default=25 value=25
backlight_compensation (int) : min=0 max=10 step=1 default=0 value=5
exposure_auto (menu) : min=0 max=3 default=3 value=3
exposure_absolute (int) : min=1 max=10000 step=1 default=156 value=156
pan_absolute (int) : min=-529200 max=529200 step=3600 default=0 value=0
tilt_absolute (int) : min=-432000 max=432000 step=3600 default=0 value=0
focus_absolute (int) : min=0 max=40 step=1 default=0 value=0
focus_auto (bool) : default=1 value=1
zoom_absolute (int) : min=0 max=317 step=1 default=0 value=0
brightness (int) : min=30 max=255 step=1 default=133 value=133
contrast (int) : min=0 max=10 step=1 default=5 value=5
saturation (int) : min=0 max=200 step=1 default=103 value=103
white_balance_temperature_auto (bool) : default=1 value=1
power_line_frequency (menu) : min=0 max=2 default=2 value=2
white_balance_temperature (int) : min=2500 max=10000 step=1 default=4500 value=4500
sharpness (int) : min=0 max=50 step=1 default=25 value=25
backlight_compensation (int) : min=0 max=10 step=1 default=0 value=5
@pjsg: are the control's values from the above v4l2-ctl
output the same as you see in uvcc
? Perhaps paste the full output shown with your readInts(...)
fixes, to verify that the integers are parsed correctly.
Interestingly, a whole bunch of the controls are listed twice (with the same name and values) in the v4l2-ctl
output. Am unsure if this is intended, and if not, what causes it. Could it be the camera reporting some UVC properties twice? Perhaps they belong to different units, somehow?
Single
exposure_absolute (int) : min=1 max=10000 step=1 default=156 value=156
exposure_auto (menu) : min=0 max=3 default=3 value=3
focus_absolute (int) : min=0 max=40 step=1 default=0 value=0
focus_auto (bool) : default=1 value=1
pan_absolute (int) : min=-529200 max=529200 step=3600 default=0 value=0
tilt_absolute (int) : min=-432000 max=432000 step=3600 default=0 value=0
zoom_absolute (int) : min=0 max=317 step=1 default=0 value=0
Duplicated
backlight_compensation (int) : min=0 max=10 step=1 default=0 value=5
brightness (int) : min=30 max=255 step=1 default=133 value=133
contrast (int) : min=0 max=10 step=1 default=5 value=5
power_line_frequency (menu) : min=0 max=2 default=2 value=2
saturation (int) : min=0 max=200 step=1 default=103 value=103
sharpness (int) : min=0 max=50 step=1 default=25 value=25
white_balance_temperature_auto (bool) : default=1 value=1
white_balance_temperature (int) : min=2500 max=10000 step=1 default=4500 value=4500
By the way, just found this note about Microsoft LifeCam Studio (045e:0772). Might be a hardware/firmware issue?
15 Some versions of this camera have been reported to randomly time out or stall in response to valid UVC control requests, probably as a result of a race condition bug in the camera firmware. This can sometime lead to the camera failing to be recognized by the kernel. Little can be done to fix the problem.
This is the exact data that I get from ranges
and export
{
"absoluteExposureTime": [
1,
10000
],
"absoluteFocus": [
0,
40
],
"absolutePanTilt": [
[
-529200,
-432000
],
[
529200,
432000
]
],
"absoluteZoom": [
0,
317
],
"backlightCompensation": [
1,
1
]
}
The backlight compensation is shown by v4l2-ctl as being between 1 and 10 rather than 1 to 1.
{
"absoluteExposureTime": 156,
"absoluteFocus": 0,
"absolutePanTilt": [
0,
0
],
"absoluteZoom": 0,
"autoExposureMode": 8,
"autoFocus": 1,
"backlightCompensation": 1
}
The interesting differences are that v4l2-ctl shows the exposure_mode as 3 and type menu. I suspect that this is really meaning bit 3 (i.e. a value of 8). The backlight compensation shows as value 5 in vtl2-ctl whereas uvcc shows 1.
There are some extra parameters shown in the v4l2-ctl, but I expect that those could be added fairly easily.
Wonder if the \0
byte patch I have in the backport branch will make backlightCompensation
range max 1
into 10
then? Could you confirm? I mean, it feels like it shouldn't -- and even so, the value 1
probably wouldn't turn into 5
. (This reminds me that it would be good to list the step
value when available.)
Yeah, the auto exposure mode is a bitmap (4.2.2.1.2 Auto-Exposure Mode Control, page 82/97). The menu
type in v4l2-ctl
is expanded to show options when using other flags.
The upcoming v2 version of node-uvc-control
should have automatic control detection. Could of course add them to v1 as well; perhaps send a pull request to node-uvc-control
?
I thought that you were using your own version of uvc-control.....
I'm going to try and see how this camera behaves on windows. I think that I can capture the USB transactions with wireshark -- and see how they differ from the transactions on OSX.
The windows capture shows backlight compensation being returned as two bytes with the range of 0 to 10. Curiously enough there did appear to be multiple endpoints and may behaved differently. I'm not sure if that is the root cause or not.
When I plug in the camera into OSX and I'm capturing in wireshark, then it enumerates the controls and pulls back the range of 0 - 10 for backlight compensation.
I now understand what is going on (but I don't know how to fix it).
If I change the getUnitOverride method to:
UVCControl.prototype.getUnitOverride = function(unit) {
if (unit == UVC_INPUT_TERMINAL_ID && this.options.inputTerminalId) {
return this.options.inputTerminalId;
}
if (unit == UVC_PROCESSING_UNIT_ID) {
return 4;
}
if (unit == UVC_PROCESSING_UNIT_ID && this.options.processingUnitId) {
return this.options.processingUnitId
}
return unit;
}
Then the output of uvcc ranges is
{
"absoluteExposureTime": [
1,
10000
],
"absoluteFocus": [
0,
40
],
"absolutePanTilt": [
[
-529200,
-432000
],
[
529200,
432000
]
],
"absoluteZoom": [
0,
317
],
"backlightCompensation": [
0,
10
],
"brightness": [
30,
255
],
"contrast": [
0,
10
],
"saturation": [
0,
200
],
"sharpness": [
0,
50
],
"whiteBalanceTemperature": [
2500,
10000
]
}
This is much better and seems to align with what windows sees. The CameraFactory doesn't seem to set these options and I don't know which layer ought to set those options. But I think that fixes this would help immensely.
I think that you need to do a "get configuration descriptor" operation. When the camera is plugged in, the OS seems to do this, and it returns (partially expanded) the blob below. I expanded the bit that shows how to get the value 4 for the Processing Unit.
The OS seemed to do two requests -- the first request was for a length of 9 which returned the CONFIGURATION DESCRIPTOR below -- which includes the total length of the descriptor. The second request was for that length. I've also pasted this operation below.
Frame 610: 2381 bytes on wire (19048 bits), 2381 bytes captured (19048 bits) on interface XHC20, id 0
USB URB
[Source: 19.7.0]
[Destination: host]
Darwin header bcdVersion: 0x0100
Darwin header length: 32
Request type: COMPLETE (1)
I/O length [bytes]: 2349
Request status: kIOReturnSuccess (0x00000000)
Isochronous transfer number of frames: 0
I/O ID: 0x000000000449d0e8
Device location ID: 0x14130000
Device speed: High (2)
USB device index: 7
Endpoint address: 0x80
.... 0000 = Endpoint number: 0, Direction: IN
1... .... = Direction: IN (1)
.... 0000 = Endpoint number: 0
Endpoint transfer type: Control (0)
[Request in: 601]
[Time from request: 0.031064000 seconds]
CONFIGURATION DESCRIPTOR
bLength: 9
bDescriptorType: 0x02 (CONFIGURATION)
wTotalLength: 2349
bNumInterfaces: 5
bConfigurationValue: 1
iConfiguration: 0
Configuration bmAttributes: 0x80 NOT SELF-POWERED NO REMOTE-WAKEUP
bMaxPower: 250 (500mA)
INTERFACE ASSOCIATION DESCRIPTOR
INTERFACE DESCRIPTOR (0.0): class Video
VIDEO CONTROL INTERFACE DESCRIPTOR [Header]
bLength: 13
bDescriptorType: 0x24 (video class interface)
Subtype: Header (1)
bcdUVC: 0x0100
wTotalLength: 87
dwClockFrequency: 30000000
bInCollection: 1
baInterfaceNr: 01
VIDEO CONTROL INTERFACE DESCRIPTOR [Input Terminal] (Entity 1)
bLength: 18
bDescriptorType: 0x24 (video class interface)
Subtype: Input Terminal (2)
bTerminalID: 1
wTerminalType: Camera Input (0x0201)
bAssocTerminal: 0
iTerminal: 0
wObjectiveFocalLengthMin: 0
wObjectiveFocalLengthMax: 0
wOcularFocalLength: 0
bControlSize: 3
bmControl: 0x00020a2a, Auto Exposure Mode, Exposure Time (Absolute), Focus (Absolute), Zoom (Absolute), PanTilt (Absolute), Auto Focus
VIDEO CONTROL INTERFACE DESCRIPTOR [Output Terminal] (Entity 2)
VIDEO CONTROL INTERFACE DESCRIPTOR [Selector Unit] (Entity 3)
VIDEO CONTROL INTERFACE DESCRIPTOR [Processing Unit] (Entity 4)
bLength: 11
bDescriptorType: 0x24 (video class interface)
Subtype: Processing Unit (5)
bUnitID: 4
bSourceID: 3
wMaxMultiplier: 0
bControlSize: 2
bmControl: 0x0000155b, Brightness, Contrast, Saturation, Sharpness, White Balance Temperature, Backlight Compensation, Power Line Frequency, White Balance Temperature, Auto
iProcessing: 0
VIDEO CONTROL INTERFACE DESCRIPTOR [Extension Unit] (Entity 5)
ENDPOINT DESCRIPTOR
VIDEO CONTROL ENDPOINT DESCRIPTOR [Interrupt]
INTERFACE DESCRIPTOR (1.0): class Video
VIDEO STREAMING INTERFACE DESCRIPTOR [Input Header]
VIDEO STREAMING INTERFACE DESCRIPTOR [Format Uncompressed] (Format 1): YUY2
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 1): 640 x 480
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 2): 1280 x 720
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 3): 960 x 544
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 4): 800 x 448
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 5): 640 x 360
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 6): 424 x 240
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 7): 352 x 288
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 8): 320 x 240
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 9): 800 x 600
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 10): 176 x 144
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 11): 160 x 120
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 12): 1920 x 1080
VIDEO STREAMING INTERFACE DESCRIPTOR [Colorformat]
VIDEO STREAMING INTERFACE DESCRIPTOR [Format MJPEG] (Format 2)
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 1): 640 x 480
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 2): 1920 x 1080
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 3): 1280 x 720
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 4): 960 x 544
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 5): 800 x 448
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 6): 640 x 360
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 7): 800 x 600
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 8): 432 x 240
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 9): 352 x 288
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 10): 176 x 144
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 11): 320 x 240
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame MJPEG] (Index 12): 160 x 120
VIDEO STREAMING INTERFACE DESCRIPTOR [Colorformat]
VIDEO STREAMING INTERFACE DESCRIPTOR [Format Uncompressed] (Format 3): M420
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 1): 640 x 480
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 2): 1280 x 720
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 3): 960 x 544
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 4): 800 x 448
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 5): 640 x 360
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 6): 424 x 240
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 7): 352 x 288
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 8): 320 x 240
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 9): 800 x 600
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 10): 176 x 144
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 11): 160 x 120
VIDEO STREAMING INTERFACE DESCRIPTOR [Frame Uncompressed] (Index 12): 1920 x 1080
VIDEO STREAMING INTERFACE DESCRIPTOR [Colorformat]
INTERFACE DESCRIPTOR (1.1): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.2): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.3): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.4): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.5): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.6): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.7): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.8): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.9): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.10): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.11): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.12): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.13): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.14): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.15): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.16): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.17): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.18): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.19): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.20): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.21): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.22): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.23): class Video
ENDPOINT DESCRIPTOR
INTERFACE DESCRIPTOR (1.24): class Video
ENDPOINT DESCRIPTOR
INTERFACE ASSOCIATION DESCRIPTOR
INTERFACE DESCRIPTOR (2.0): class Audio
Class-specific Audio Control Interface Descriptor: Header Descriptor
Class-specific Audio Control Interface Descriptor: Input terminal descriptor
Class-specific Audio Control Interface Descriptor: Feature unit descriptor
Class-specific Audio Control Interface Descriptor: Output terminal descriptor
INTERFACE DESCRIPTOR (3.0): class Audio
INTERFACE DESCRIPTOR (3.1): class Audio
Class-specific Audio Streaming Interface Descriptor: General AS Descriptor
Class-specific Audio Streaming Interface Descriptor: Format type descriptor
ENDPOINT DESCRIPTOR
Class-specific Audio Streaming Endpoint Descriptor
INTERFACE DESCRIPTOR (4.0): class HID
HID DESCRIPTOR
ENDPOINT DESCRIPTOR
Get request
Frame 599: 40 bytes on wire (320 bits), 40 bytes captured (320 bits) on interface XHC20, id 0
USB URB
[Source: 19.7.0]
[Destination: host]
Darwin header bcdVersion: 0x0100
Darwin header length: 32
Request type: SUBMIT (0)
I/O length [bytes]: 9
Request status: kIOReturnSuccess (0x00000000)
Isochronous transfer number of frames: 0
I/O ID: 0x000000000449d0e6
Device location ID: 0x14130000
Device speed: High (2)
USB device index: 7
Endpoint address: 0x80
.... 0000 = Endpoint number: 0, Direction: IN
1... .... = Direction: IN (1)
.... 0000 = Endpoint number: 0
Endpoint transfer type: Control (0)
[Response in: 600]
Setup Data
bmRequestType: 0x80
1... .... = Direction: Device-to-host
.00. .... = Type: Standard (0x0)
...0 0000 = Recipient: Device (0x00)
bRequest: GET DESCRIPTOR (6)
Descriptor Index: 0x00
bDescriptorType: CONFIGURATION (0x02)
Language Id: no language specified (0x0000)
wLength: 9
I am not a JS developer and the intricacies of libusb are a bit beyond me, but I want to say thank you both for the great work and also for such an involved thread.
I added from above,
if (unit == UVC_PROCESSING_UNIT_ID) {
return 4;
}
and suddenly I'm able to run
/usr/local/bin/uvcc --vendor 0x45e --product 0x772 set backlightCompensation 1
and
/usr/local/bin/uvcc --vendor 0x45e --product 0x772 set brightness 50
on my Microsoft Lifecam to adjust the crazy white balance. :)
A few of the other settings don't work as expected, but that was really the biggest one
I changed
absolutePanTilt: {
unit: UVC_INPUT_TERMINAL_ID,
selector: 0x0D,
size: 8 // dwPanAbsolute (4 bytes) + dwTiltAbsolute (4 bytes)
},
to
absolutePanTilt: {
unit: UVC_INPUT_TERMINAL_ID,
selector: 0x0D,
size: 6 // dwPanAbsolute (4 bytes) + dwTiltAbsolute (4 bytes)
},
Nice work @joelpurra
Thank you guys for testing the fixes: @pjsg, @Blisse, @nick-gray!
I thought that you were using your own version of uvc-control.....
@pjsg: yes, but I don't want to maintain a fork. All changes should be merged into the upstream node-uvc-control
. The maintainer even started work on version 2, and announced it ahead of time to uvcc
, but seems to have lost momentum. The Linux fixes I did for node-uvc-control
last year were not verified and merged. It's not always possible to find time for open source projects, so it's understandable.
I think that you need to do a "get configuration descriptor" operation. When the camera is plugged in, the OS seems to do this, and it returns (partially expanded) the blob below. I expanded the bit that shows how to get the value 4 for the Processing Unit.
@pjsg: nice digging! Would not have thought to go as deep as using wireshark. I've cut out a bunch of lines and kept what seems relevant to this issue.
VIDEO CONTROL INTERFACE DESCRIPTOR [Input Terminal] (Entity 1)
Subtype: Input Terminal (2)
bTerminalID: 1
bControlSize: 3
bmControl: 0x00020a2a, Auto Exposure Mode, Exposure Time (Absolute), Focus (Absolute), Zoom (Absolute), PanTilt (Absolute), Auto Focus
VIDEO CONTROL INTERFACE DESCRIPTOR [Processing Unit] (Entity 4)
Subtype: Processing Unit (5)
bUnitID: 4
bControlSize: 2
bmControl: 0x0000155b, Brightness, Contrast, Saturation, Sharpness, White Balance Temperature, Backlight Compensation, Power Line Frequency, White Balance Temperature, Auto
4
for your camera. This clashes with the hardcoded id of 3
in node-uvc-control
v1. This may explain why your fix in getUnitOverride(...)
works for you and @Blisse, since these requests would LIBUSB_TRANSFER_STALL
otherwise.3
bytes for your camera, but the hardcoded value in node-uvc-control
v1 is 2
. This may explain why the fix by @nick-gray works (3
+3
for pan+tilt).~ Edit: the control size bControlSize
is the size of the bitfield bmControls
with the camera's supported controls. For an input terminal the bControlSize
is always 3
(Table 3-6 Camera Terminal Descriptor, page 52 or 67). The size for pan+tilt on the input terminal should still be 8
(4
+4
) according to UVC 1.5 (4.2.2.1.14 PanTilt (Absolute) Control, page 89 or 104).These things seem to have been taken care of in node-uvc-control
v2, which requests these details from the camera in getInterfaceDescriptors(...)
.
There's plenty of intricacies in the UVC/USB standards, down to the bits and bytes level in hardware. Applying the unit id or control byte size fixes above might work for some cameras, but would instead break support for for example my camera. Dynamically detecting these per-camera values is indeed the way to go, meaning it's time to upgrade to node-uvc-control
v2.
Created an experimental v2-next version of uvcc
last year, which should use per-camera detection. Don't think it fixes all issues, as it did not seem to work 100% (tested by @Jip-Hop in #3), even for my camera, but could be worth a shot. Could you guys try it with your cameras, and perhaps post the results you get?
git clone "git@github.com:joelpurra/uvcc.git"
cd uvcc
git checkout feature/uvc-control-v2-next
rm -r node_modules/
npm install
./index.js --verbose ranges
./index.js --verbose export
Please include the vendor and product ids with each post. Does the output look ok? Does it require any fixes?
My output is:
[] philip@chicken:~/uvcc$ ./index.js --vendor 0x45e --product 0x772 ranges
{
"backlight_compensation": {
"min": 0,
"max": 10
},
"brightness": {
"min": 30,
"max": 255
},
"contrast": {
"min": 0,
"max": 10
},
"saturation": {
"min": 0,
"max": 200
},
"sharpness": {
"min": 0,
"max": 50
},
"white_balance_temperature": {
"min": 2500,
"max": 10000
}
}
[] philip@chicken:~/uvcc$ ./index.js --vendor 0x45e --product 0x772 export
{
"auto_exposure_mode": {
"bAutoExposureMode": 6
},
"auto_white_balance_temperature": {
"bWhiteBalanceTemperatureAuto": 1
},
"backlight_compensation": {
"wBacklightCompensation": 1
},
"brightness": {
"wBrightness": 133
},
"contrast": {
"wContrast": 5
},
"power_line_frequency": {
"bPowerLineFrequency": 2
},
"saturation": {
"wSaturation": 103
},
"sharpness": {
"wSharpness": 25
},
"white_balance_temperature": {
"wWhiteBalanceTemperature": 4500
}
}
[] philip@chicken:~/uvcc$
It is missing attributes like the zoom control..... -- but this can be fixed in uvc-control/index.js -- adjust the initialization of this.ids to be:
this.ids = {
processingUnit: descriptors.processingUnit.bUnitID,
cameraInputTerminal: descriptors.cameraInputTerminal.bTerminalID,
}
Then I get:
{
"absolute_focus": {
"wFocusAbsolute": 14
},
"absolute_pan_tilt": {
"dwPanAbsolute": 0
},
"absolute_zoom": {
"wObjectiveFocalLength": 0
},
"auto_exposure_mode": {
"bAutoExposureMode": 8
},
"auto_focus": {
"bFocusAuto": 1
},
"auto_white_balance_temperature": {
"bWhiteBalanceTemperatureAuto": 1
},
"backlight_compensation": {
"wBacklightCompensation": 1
},
"brightness": {
"wBrightness": 133
},
"contrast": {
"wContrast": 5
},
"power_line_frequency": {
"bPowerLineFrequency": 2
},
"saturation": {
"wSaturation": 103
},
"sharpness": {
"wSharpness": 25
},
"white_balance_temperature": {
"wWhiteBalanceTemperature": 4500
}
}
@pjsg: it seems your this.ids = { ... }
is unmodified compared to the file I see in the v2-control-transfer-target-device
branch. Did you make any other modifications?
Judging by the missing controls, which belong to the input terminal, I suspect you made a change affecting cameraInputTerminal
. A few lines down I see what looks like a broken mapping -- the property name ~is~ was expected to be inputTerminal
(not cameraInputTerminal
).
While not up to par with node-uvc-control
v2, I've also fixed a few more basic uvcc
features to get basic uvcc export | uvcc import
functionality working.
git clone "git@github.com:joelpurra/uvcc.git"
cd uvcc
git checkout feature/uvc-control-v2-next
git pull
rm -r node_modules/
npm install
./index.js --verbose ranges
./index.js --verbose export
# NOTE: not all settings can be set if they're in auto-mode -- fix pending.
./index.js --verbose export | ./index.js --verbose import
There are still bugs, both in uvcc
(missing functionality, setting values when they're in auto-mode, etcetera) and node-uvc-control
(spotted some on the byte-reading level). Tested on macOS and Ubuntu using a Logitech C920 (0x46d/0x82d) with node v12.
Hope this also works for cameras other than the c920 =)
My change was to change an inputTerminal
into a cameraInputTerminal
.
Released uvcc
v2.0.0 -- hopefully this has been fixed! Please open a new issue if there are any problems with the new release.
I'm running this on Max OSX 10.14.6 and the export command crashes (I have a Microsoft Lifecam Studio plugged in)
Any thoughts? I'm prepared to do debugging....