diff --git a/collector/.gitignore b/collector/.gitignore index 6303e0308010020fc95d87b545ce1f95f5d46ff3..929dc8a56158131cec61e53f347762d65562d7ee 100644 --- a/collector/.gitignore +++ b/collector/.gitignore @@ -28,6 +28,8 @@ venv_lite/ .claude/ keypoints_output/ exports/ +# 本地取回的录制素材与上色产物(双目原视频等,体积大且属外部数据) +rec001(1)/ tools/weights/ wheels/ # scripts/pack_wheels.py 生成的离线部署包(不入库,拷给客户用) imgui.ini diff --git a/collector/README.md b/collector/README.md index d763fd2f114717fe15c1477d8973b49c47b890a7..4865074423eab6112b2b9d563c03cc0bef856be8 100644 --- a/collector/README.md +++ b/collector/README.md @@ -1,6 +1,6 @@ # collector — Multimodal Data Acquisition SDK · 多模态数据采集 SDK -![Version](https://img.shields.io/badge/version-1.3.4-blue) +![Version](https://img.shields.io/badge/version-1.3.5-blue) ![Python](https://img.shields.io/badge/python-3.12-blue) ![License](https://img.shields.io/badge/license-TBD-lightgrey) @@ -361,6 +361,128 @@ are documented in [docs/index.md](docs/index.md#开发约定). ### Changelog +- **v1.3.5** — the camera service heals itself, and gripper scan pairing moved + from USB root ports to NVS serials. + **Cameras:** the UVC cameras (DECXIN `1bcf:2d4f` plus two Sightac `0c45:636f`) + can wedge silently with no process touching them — on 2026-09-15 the right + Sightac was streaming normally at 21:53 and simply refused to start at 09:24, + with no usbfs or uvcvideo message in between and the machine awake all night. + What the user sees ("RGB shows only the first frame", "camera-service did not + obtain valid MJPG frames from all cameras within the time limit") is really a + failure to recover, not a failure to stay up. Two different wedges need two + different cures: a **stall** (stream running, `received` freezes, not a single + kernel message, 6–82 s at random, load-correlated) recovers from rebuilding + the libusb context alone (6/6 and 5/5 measured — a USB reset is a wasted + cost), while a **hard failure** (`uvc_start_streaming failed: I/O error`, + `UVC format/interface negotiation failed: Invalid mode`, or + `negotiated_payload` alternating 3072/0) does not (9 consecutive attempts + failed; the device firmware is wedged) and only a USB reset / re-enumeration + clears it. Added a 3-second stall watchdog (`STREAM_STALL_TIMEOUT_SECONDS`, + 4 s for the first frame); stalls rebuild the libusb context, hard failures + escalate to a USB reset after **2 consecutive** attempts (capped at + `USB_RESET_LIMIT` 3, since without a cap a genuinely dead device would reset + every 2 seconds and pin the two neighbours on the same hub), and a stall + clears that counter so stalls can never add up into a spurious reset. The + reset now happens **before** `uvc_stop_streaming` (`teardown_failed_open`): + on a wedged device `uvc_stop_streaming` waits for isochronous transfers that + never return, which measurably burns the client's 2-second grace period and + gets the process SIGKILLed mid-teardown, leaving the device on an active alt + setting so the next start fails the same way. Every threshold is derived + backwards from the client's `SERVICE_START_TIMEOUT_S = 10.0` (second failure + at t≈2 s → reset → frames by t≈3 s); the old "reset after 20 s of zero + frames" gate could never fire in a real start, and was attached to the + zero-frame branch the observed `I/O error` never reaches. Measured reset + semantics: on a healthy device it is an in-place port reset (kernel logs + `reset high-speed USB device number N`, devnum unchanged); on a wedged device + the device drops and re-enumerates (devnum changes) — that is what heals it, + and libusb reports `rc=-4 (No such device)` during that window, which is + misleading but harmless. Also fixed the per-second fps reporting baseline + (it counted from zero, so a restart reported the whole process lifetime as + one window: 164/207/251 fake fps). + **RGB disconnects, root cause:** self-healing was only half the story — the + camera still dropped out afterwards. DECXIN stalls silently every 68–116 s + while running the high-bandwidth isochronous setting alt7, on **both** + controllers tested (AMD `1022:43fc`/PCI `0000:0a:00.0` and + `1022:15b7`/`0000:74:00.4`). The mechanism is **not determined**: measured + throughput at the moment of the stalls was only 1.66 MB/s mean / 2.63 peak, + far under the 10.24 MB/s alt7 reserves, so "not enough bandwidth" does not + explain it. alt6 holds, and both rungs deliver **identical 30.00 fps**, so + alt7's extra per-frame headroom (327680 vs 241664 B) buys nothing observable. + Two earlier conclusions are retracted: *"alt7 is fine on bus 1"* — that + supposedly clean leg never ran at alt7 at all, because the old binary's ini + fields were inert and the service merely echoed them, so the only trustworthy + indicator of a leg's real setting is the `[LIBUVC-QUIRK] ... alt=N payload=M + ... xfers=` line; and the controller-specific claim that followed from it. + `forced_altsetting`/`forced_payload` are now **authoritative** through a new + libuvc runtime API `uvc_set_altsetting_override()` (declared in `libuvc.h`, + implemented in `device.c`) — before this they were only validated and + printed, so editing the ini changed nothing, which is very easy to misread. + The starting rung is chosen in Python, not hardcoded per machine: learned > + the table's most conservative rung > the scanner's preferred one, because the + rack's bus is not permanent. A ladder then steps down one rung and persists + the conclusion under `vid:pid × controller PCI path × camera serial` after 2 + consecutive stalls or 3 consecutive failed opens (the latter covers a + setting that will not fit at STREAMON, where the stream never starts and the + stall path can never fire); `CLEAN_RUN_SECONDS = 300` clears the stall + counter. A downgrade must clear **both** counters — the thresholds are + equality tests, so a counter left standing on its threshold never fires + again and the failed-open path would jam after a single step. Both log lines + capture the count *before* the downgrade clears it. The scanner truthfully + reports the descriptor's preferred rung (alt7); the app checks it is *any* + rung of the ladder and refuses only on a genuine desync. The C source and its + build recipe moved into `core/gripper/camera_service_src/` (`./build.sh` is + the single entry point), and `--test` now runs `ctest` — the ladder test was + registered with `add_test` but had never actually been executed, and the + jam-bug above fell exactly inside what it should have covered. Verified on + hardware: forced alt7 stalled at 78 s and 116 s, the service logged the + downgrade and recovered to alt6 for 169 s at 30 fps with zero stalls; the + app-generated ini (alt6 default) then ran **600 s across three legs with 0 + stalls / 0 rebuilds / 0 failed opens / 0 resets** (17513/17496/17487 frames), + and a post-install 300 s regression on the deployed binary was clean too. The + ladder test was reverse-verified as non-vacuous: removing the counter reset + makes it abort. + **Grippers:** ported the scan chain from the delivery package + `设备扫描逻辑与程序_20260914`. Pairing used to go through USB root + ports/controllers — a premise that was simply wrong, since the Fays is a + USB3/FT602 device on its own 5000M bus and never shared a root with the + UVC/ESP32 devices. The chain is now: UVC group → the unique ESP32 (path + starting `bus-outer.`) → send `QF` over serial to read the Fays serial bound + in its NVS → match against the official SDK's enumerated `device.serial`, + with a clear refusal when any step is not unique and no fallback to guessing + by port or enumeration order. The SDK probe is preceded by a + `validate_fays_superspeed` pre-check and then enumerates serials fast + (`--serial-only-fast`; a timeout now decodes stdout/stderr and appends the + last 20 lines instead of reporting a bare timeout). Dual-rig runs skip a + device another rig holds instead of claiming it. On the serial side the fixed + boot delay became a 2-second polling `?` handshake, the port is opened + `exclusive=True`, and `QF` (query) / `WF:` (write) commands were + added; `GripperSerial.send()` looked commands up by their first character + only (`[:1]`), so `"QF"` could never match its own expected list. Prerequisite: + the ESP32 firmware must understand `QF`/`WF:` — the current `online/esp32_proc` + firmware does not, and will fail closed with "查询 Fays 序列号失败: ERR". + Added the offline self-check `tools/tests/test_gripper_fays_pairing.py`. + **s80c colorize tool:** fixed a duplicated-every-other-frame bug in + `tools/s80c_arm_convert/convert_arm_dataset.py` (an independent fix committed + after v1.3.4). `pooled_episodes_v1` recordings write **two rows per frame** + (`frame_index` = 0,0,1,1,…, with identical `timestamp`/`hardware_ns` in both + rows) while the video has one frame; the tool used the row count as the frame + count and then indexed `hw_ns[i]` by video frame number, so every timestamp + was sent twice — and the offline ISP reuses the previous output for a + duplicate timestamp, which is what duplicated every other frame. Measured on + rec001's lossless output: 394 of 833 frames byte-identical to their + predecessor, all 394 at odd positions (the second of each timestamp pair), + versus 0 in the source video. The same root cause also **halved the IMU + sidecar** — `hw_ns[:n_frames]` only reached the 417th timestamp and every + later IMU sample was dropped by the "later than the last frame" rule, leaving + 416 rows / 13.8 s; after the fix, 832 rows / 27.7 s against a 27.8 s video. + Redundant rows are now folded by `frame_index`, but **only when every row + under that index has identical `timestamp` and `hardware_ns`**; otherwise it + warns and leaves the data untouched. Of the 142 parquets carrying + `frame_index`, 129 already had one row per frame (no-op), 1 was genuinely + redundant (rec001, 1666 rows → 833 frames), and 12 had differing timestamps + between rows (folding would lose them, so they are warn-only). The colorize + chain itself is untouched: same config, same offline ISP, `--sdk-wb-auto` as + before, with grey-world gains bit-identical to the pre-fix run. - **v1.3.4** — a newly plugged-in gripper now generates its own runtime calibration and connects, with no manual step. Previously onboarding a new Fays S80M took two manual steps — click `device_setup` on the gripper's host @@ -833,6 +955,47 @@ i18n 文案经 `tr()` 翻译、PyQt5 信号参数用 `object` 封送大整数、 ### 更新记录 +- **v1.3.5** — 相机服务能自愈了;夹爪扫描配对从 USB 根端口改走 NVS 序列号。 + **相机侧**:UVC 相机(DECXIN `1bcf:2d4f` 与两个 Sightac `0c45:636f`)会**静默 + 卡死、且不需要任何进程碰它**——2026-09-15 实证右目 Sightac 是自己夜里坏的 + (21:53 还在正常推流,09:24 启动就坏,中间没有任何进程打开过它、内核无 + usbfs/uvcvideo 消息,机器整夜没睡)。用户看到的「RGB 只剩第一帧」「未在限定 + 时间取得全部相机的有效 MJPG 帧」,根子是**服务不会自愈**,不是**服务会倒**。 + 两种卡死要分开治:**停摆**(开着流突然不出帧、`received` 冻住、内核一条消息 + 都没有,6~82 秒随机、与负载正相关)**重建 libusb 上下文就够**(实测 6/6、5/5 + 全恢复,USB 复位是白付的代价);**开不起来**(`uvc_start_streaming failed: + I/O error`、`UVC format/interface negotiation failed: Invalid mode`、 + `negotiated_payload` 在 3072↔0 之间跳)**重建上下文救不回来**(实测连试 9 次 + 全败,设备固件侧卡死了),只有 USB 复位/重枚举能洗。新增 3 秒停滞看门狗 + (`STREAM_STALL_TIMEOUT_SECONDS`,首帧 4 秒);停摆(`rc>0`)重建 libusb + 上下文;开不起来(`rc<0`)**连续 2 次**升级成 USB 复位,`USB_RESET_LIMIT` 3 次 + 封顶(设备真坏了时不设上限会变成每 2 秒复位一次、把同 Hub 的另外两路一直按在 + 地上),而停摆会清零该计数,免得几次停摆凑数误触发复位去打扰邻居。**复位要抢在 + `uvc_stop_streaming` 之前**(`teardown_failed_open`)——卡死设备上 + `uvc_stop_streaming` 会一直等它那批永远回不来的等时传输,实测能把客户端那 2 秒 + 宽限耗光而被 SIGKILL,进程死在这中间、设备就停在激活的 alt setting 上,下一轮 + 照样起不来(09:24 的日志正是断在 startup failed 与 usb reset 之间)。所有阈值由 + 客户端窗口 `SERVICE_START_TIMEOUT_S = 10.0` 倒推:第 2 次失败在 t≈2 秒触发复位、 + t≈3 秒就能出帧;旧的「重开 20 秒零帧才复位」在真实启动场景**永远够不到**,且只 + 挂在零帧分支上。复位语义实测:打在**健康**设备上是原地端口复位(devnum 不变), + 打在**卡死**设备上是掉线重枚举(devnum 变了)**这才会好**,libusb 在那窗口里返回 + `rc=-4 (No such device)` 是报错但事办了。真机验证:第 1 次失败不复位、第 2 次 + `usb reset: rc=0 (Success)`、打满 3 次后停手;三路 90 秒回归 0 停摆 0 误复位 + (2694/2683/2684 帧 ≈29.9fps);SIGTERM 退出 1.16 秒,不超客户端 2 秒宽限。 + **夹爪侧**:移植交付包「设备扫描逻辑与程序_20260914」。配对从 **USB 根端口/ + 控制器**改走 **NVS 序列号**——旧规则(外加「同一 USB2 总线出现双 rig 就拒扫」) + 的前提就是错的:Fays 是 USB3/FT602 挂在配套的 5000M 总线上,跟 UVC/ESP32 本来 + 就不共根,只能靠猜。新链路:UVC 组 → 唯一 ESP32(`bus-outer.` 开头)→ 串口发 + `QF` 读它 NVS 里绑定的 Fays 序列号 → 与官方 SDK 枚举出的 `device.serial` 比对, + 任一步不唯一就明确拒绝,不再按端口或枚举顺序猜。SDK 探测前先做超速预检,再以 + `--serial-only-fast` 快速枚举序列号(超时不再只报一句 timeout,解码 + stdout/stderr 并附最后 20 行);双 rig 会「在用时跳过」另一 rig 正持有的设备 + 而不是占用。串口侧:固定 2 秒死等改成轮询 `?` 握手,端口加 `exclusive=True`, + 新增 `QF` 查询 / `WF:` 写入;顺带修 `send()` 只拿首字符查命令表 + (`[:1]`)导致 `"QF"` 永远匹配不上自己期望表的 bug。**前置条件:ESP32 固件必须 + 认识 `QF`/`WF:`,当前 `online/esp32_proc` 的固件还不认识,会失败关闭并报 + 「查询 Fays 序列号失败: ERR」,需先烧固件。** 新增离线自检 + `tools/tests/test_gripper_fays_pairing.py`。 - **v1.3.4** — 新夹爪接入即自动生成运行标定并连接,不再需要任何人工步骤。 此前接入一只新 Fays S80M 要人工两步——先在夹爪上位机点 `device_setup`、 再在采集机跑 `tools/import_gripper_calibration.py` 导入,漏掉任一步主程序 diff --git a/collector/config/__init__.py b/collector/config/__init__.py index ca2c81cbd360c517306910e77f2e1ae3a3a508f0..efc3d2e1ed1e748e36b02141ccb60f3776c7886c 100755 --- a/collector/config/__init__.py +++ b/collector/config/__init__.py @@ -3,4 +3,4 @@ 版本号集中定义于此:settings.APP_VERSION 及其他模块均从这里取值。 """ -__version__ = "1.3.4" # 新夹爪接入即自动生成运行标定并连接(Fays S80M):此前接入一只新夹爪要人工两步——先在夹爪上位机点 `device_setup`、再在采集机跑 `tools/import_gripper_calibration.py` 导入,漏掉任一步主程序直接拒绝启动(「当前 Fays 缺少运行标定文件…请先在夹爪上位机中运行 device_setup」);现在 `SingleFaysLease.acquire()` 发现 per-serial YAML 缺失时,就在设备锁内调厂商导出程序从**这只夹爪自身**读出厂标定、生成 SDK YAML 与 ORB YAML(鱼眼 `stereoRectify` 求 P1/R1 + IMU 外参 `T_b_c1` + 探针读五项噪声/频率),复核落盘路径后直接连上,已有标定走 `isfile` 快路径(启动零额外开销、不碰设备)——这两个文件是**逐设备**出厂标定不可跨设备复用(实测 098/099 三组全不同),只能现场读;设备面板夹爪条目右键加「重新读取出厂标定」(录制中禁用,标定前自动关该夹爪、完成后开回),`tools/import_gripper_calibration.py` 加 `--generate`(旧文件先备份 `.bak_<时间戳>`)供命令行强制重生成;顺带修掉生成产物第 3 行的出处注释——厂商模板写死指向 `3500000261870088`,照抄会让每只新夹爪的 IMU 外参都被记成「取自另一台设备」,现改写成本机序列号(历史产物不动)。承接 v1.3.3 的力矩阵/触觉力与 RGB 视频的时间戳对齐:**力侧此前完全没有时间戳**——同一行里的 RGB 帧和力样本不是同时刻采集的,RGB 走外部帧源队列取队头最旧帧、力/矩阵走 latest-wins 单槽取当下最新,于是「行号相同」≠「时刻相同」,力恒领先 RGB 且领先量随录制时长增长(RGB 源 30.84fps vs 写线程 30fps,实测约 1 帧/秒,下游观测到的滞后 3 帧就是这么来的),力矩阵走独立泵线程还与 3 向量力各记各的时刻。修法是让每行自描述:`tactile_ready` 加第 5 个载荷 `capture_ns`(在 SDK 回调入口取),`pipeline.write_tactile_force/_force_matrix` 落成独立的 `observation.gripper_{side}_force_ns` / `_force_matrix_ns` 稀疏 int64 列(与 `hardware_ns` 同宿主单调钟时基,features 里声明 `encoding: host_monotonic_ns`),下游按时间取最近邻即可还原真实配对,精度上界=半个力样本间隔;顺带修 `rgb_frame_ready`/`stereo_frame_ready` 的 `pyqtSignal(int)` 把 `time.monotonic_ns()` 按 C++ qint32 静默截断成负数(每 2.147s 翻符号),改 `object` 封送——这也解释了此前用 `hardware_ns` 解回卷时凭空造出上百帧假漂移、把"中位 5.8 帧 / 最大 ±80 帧"报成对齐误差(真值是 ~3 帧,正确规则是**无符号**:单调钟 + FIFO 消费 ⇒ 真步长恒非负);新增 `scripts/align_modalities.py` 处理端最近邻对齐工具,对 v1.3.3 之前录的 episode 明确报「无法对齐(只能重录)」而不用增长率去猜。承接 v1.3.2 的 SLAM 陈旧帧入库前拦截与轨迹显示深拷贝修复。:桥接按「连续回退次数」判定——单帧脏读丢弃、连丢 30 帧才判定时钟真跳变并换基准放行(此前每一帧回退都会让核心库清空 IMU 队并重建地图、位姿停发 0.2–1.34 s,静止时更久),新增 `[TIME_DROP]`/`[TIME_REBASE]` 现场行并**无条件**打进 GUI 日志(此前落进未匹配行被 50 条上限吃掉——实测原生日志 4 次回退、GUI 日志 0 条,真出事时反而看不见),且带 `seq`/`prev_seq` 对比结论以区分「SDK 乱序投递 / 重复投递同一帧 / 帧配了旧时间戳」三种成因(时间戳上三者长得一模一样,对策完全不同);逐秒遥测 `[FPS_DATA]` 改「只在异常时出声」(健康静默、进入异常与恢复各一行、持续异常每 30 s 重复,全量逐秒流仍在原生日志里),并修 `wait_sdk_ready` 就绪门被**粘滞** `state.error` 锁死——任何信息性输出(如 ld.so 的 `cannot be preloaded ... ignored.`)都会让标定明明已完成的这一次返回 False、报出误导的「未等到 [FAYS-CALIB] 标记」(2026-09-10 18:32 假超时事故,文案白名单 + 去掉粘滞判断双管修);原生日志在 runtime 目录 `rmtree` 之前留档到 `logs/slam_native/`(保留最近 20 份),修「一次干净退出的会话其原生日志不可恢复」——排查 SLAM 崩溃时唯一的证据曾随目录一起被删;轨迹显示去掉 Qt 主线程上的整条深拷贝(正是这次拷贝让 `_rendered_trajectory is traj` 判等恒为假、每个位姿都在主线程复制随会话线性增长的点列,即「画一段时间后帧率变低」的直接原因),显示上限 400→6000,并以向量化投影 + 一次 `drawPolyline` 绘制,修「十几秒后轨迹显出折角」(降采样按 stride 翻倍使顶点数恒落 [上限/2, 上限],上限 400 时每段跨 67 ms 且随 stride 每翻一倍继续变粗,观感像 SLAM 出点变慢而数据一直满 30 Hz,是绘制侧丢的);RGB 外部队列在录制开始/结束/中止三个边界排空,修「上一段残留 + 本段启动窗口累积被写成新视频开头」(实测每段开头约 28 帧与上一段 episode 末帧逐帧匹配,队列满时还占 ~110 MB/槽);任务进度只上报后端当前任务列表里存在的任务(本地自建任务平台没这个项目,上报必被拒 400),且后端该项目口径为 `"sessions"`(从没收到过任何上报)时首次送本机**全量**当基线——只送增量会把后端计数从 session 数砸成增量本身(现场:3/3/3 的项目再录一条变 1)。承接 v1.3.1 的力矩阵 5 档落盘与 SLAM 停落 slam_pose 列。 +__version__ = "1.3.5" # 夹爪扫描配对改走 ESP32 NVS 序列号 + camera-service 自愈(两个都是「不恢复」的毛病,不是「会坏」的毛病)。相机侧:UVC 相机(DECXIN 1bcf:2d4f + 两个 Sightac 0c45:636f)会**静默卡死且不需要任何进程碰它**,用户看到的「RGB 只剩第一帧」「camera-service 未在限定时间取得全部相机的有效 MJPG 帧」根子是**服务不会自愈**——实证 2026-09-15 右目 Sightac 是自己夜里坏的(21:53 还在正常推流,09:24 启动就坏,中间没有任何进程打开过它、内核无 usbfs/uvcvideo 消息,机器整夜没睡、14.9 万条内核日志里查不到肇事者)→ 别再去查「谁把它弄脏的」,服务必须能自愈。两种卡死要分开治:**停摆**(开着流突然不出帧、`received` 冻住、内核一条消息都没有,6~82 秒随机、与负载正相关)**重建 libusb 上下文就够**(实测 6/6、5/5 全恢复,USB 复位是白付的代价);**开不起来**(`uvc_start_streaming failed: I/O error` / `UVC format/interface negotiation failed: Invalid mode` / `negotiated_payload` 在 3072↔0 之间跳)**重建上下文救不回来**(实测连试 9 次全败,设备固件侧卡死了),只有 USB 复位/重枚举能洗。改动:新增 3 秒停滞看门狗(`STREAM_STALL_TIMEOUT_SECONDS`,首帧 4 秒)——此前整路静默报废没有任何人管;停摆(`rc>0`)走 `uvc_exit`+`uvc_init` 重建上下文;开不起来(`rc<0`)计入 `hard_failures`,**连续 2 次**升级成 USB 复位(`USB_RESET_LIMIT` 3 次封顶——设备真坏了时不设上限会变成每 2 秒复位一次、把同 Hub 的另外两路一直按在地上),而停摆会**清零**该计数,免得几次停摆凑数误触发复位去打扰邻居;**复位要抢在 `uvc_stop_streaming` 之前**(`teardown_failed_open`)——卡死设备上 `uvc_stop_streaming` 会一直等它那批永远回不来的等时传输,实测能把客户端那 2 秒宽限耗光而被 SIGKILL,进程死在这中间、设备就停在激活的 alt setting 上,下一轮启动照样起不来(用户 09:24 的日志正是断在 startup failed 与 usb reset 之间);所有阈值由客户端窗口倒推(`SERVICE_START_TIMEOUT_S = 10.0`:每次失败约 0.3 秒 + 1 秒间隔,第 2 次失败在 t≈2 秒触发复位、重枚举加重开约 1 秒、t≈3 秒就能出帧,10 秒够用;旧的「重开 20 秒零帧才复位」在真实启动场景**永远够不到**——20 > 10,且只挂在零帧分支上,实测到的 `I/O error` 根本不走那条);复位语义实测——打在**健康**设备上是原地端口复位(内核 `reset high-speed USB device number N`,**devnum 不变**),打在**卡死**设备上是掉线再重枚举(`USB disconnect` + `new high-speed USB device`,**devnum 变了**)**这才会好**,而 libusb 在掉线重枚举的窗口里返回 `rc=-4 (No such device)` 是**报错但事办了**、别被它误导;`libusb_reset_device` 用 `dlsym(RTLD_DEFAULT, …)` 取,不新增 NEEDED、不需要 root(设备节点 udev MODE=0666);顺带修每秒 fps 上报基线(`previous_received` 从 0 起算,重开后把进程启动至今的全部帧数当成本窗口增量,算出 164/207/251 的假速率——纯日志问题,但会把人带偏)。真机验证:确定性升级测试(第 1 次失败不复位、第 2 次 `usb reset: rc=0 (Success)`、打满 3 次后停手)、三路 90 秒回归 0 停摆 0 误复位(2694/2683/2684 帧 ≈29.9fps)、SIGTERM 退出 1.16 秒(旧 1.13 秒)不超客户端 2 秒宽限。**源码位置**:`online/` 在 .gitignore:56 里、不入库;本次把这两个程序的源码连同构建配方搬进了 `core/gripper/camera_service_src/`(`./build.sh` 是唯一构建入口——它替我们处理 libusb 的 pkg-config shim、`-DCMAKE_POLICY_VERSION_MINIMUM=3.5`、以及链接后去掉 RUNPATH 里那个空条目,手工 cmake 会在这些地方卡住;产物装到 `core/gripper/native/camera_service/build/`,旧件按 `.pre_rebuild_<时间戳>` 备份),以后不必再从 libusb 头文件、pkg-config、RUNPATH 那一整串摸起。交付副本 `programs/camera_service/src/camera_service.c` 未动、与 `程序清单.txt` 第 18 行一致。**RGB 断联的根因(2026-09-15 查明,本条是用户「还是会断联」的正面回答):服务自愈之后相机仍会断,断的原因是 DECXIN 跑在高带宽等时档 alt7 上时每 68~116 秒静默停摆一次,两块控制器(AMD `1022:43fc`/PCI `0000:0a:00.0` 与 `1022:15b7`/`0000:74:00.4`)上都一样。机制**未查明**:停摆当时实际吞吐只有 1.66 MB/s(峰值 2.63),离 alt7 预留的 10.24 MB/s 差得远,「带宽不够」解释不通——**别把机制写死**。alt6 同样三路下长跑不停,而两档出帧率一模一样(都 30.00 fps),alt7 多出来的每帧余量(327680 对 241664 字节)换不到任何看得见的好处。此前两个结论已推翻、别再引用:「bus 1 上 alt7 是好的」——那条所谓干净腿根本没跑在 alt7 上,旧二进制里 ini 的 `forced_*` 是死的、服务只把 ini 的值原样打进日志,读到的 `alt=7 payload=1280` 是它在**复读**,**判断一条腿真实档位只认 `[LIBUVC-QUIRK] ... alt=N payload=M ... xfers=` 那一行**;以及同源的「停摆是控制器特异的」。改动:libuvc 新增运行时接口 `uvc_set_altsetting_override()`(声明在 `include/libuvc/libuvc.h`、实现在 `src/device.c`,`uvc_device_handle_t` 是 calloc 出来的、新字段自动零初始化),`forced_altsetting`/`forced_payload` 从此**真正生效**——此前这两个 ini 字段只用于校验和打印,改 ini 完全不改变行为,极容易误判;起始档位由 app 决定、取**档位表里最保守的一档**(`uvc_camera_service.py` 的 `_starting_mode` 优先级:上一轮学到的 > 最后一档 > 扫描程序报的首选档),**不按机器/控制器写死**(机架插在哪条总线不固定,用户明说不是永久的),曾经那张「敌意控制器」表已删;降档梯子 `maybe_downgrade_altsetting`:当前档位连着停摆 2 次、或连着开不起来 3 次(后者覆盖 STREAMON 阶段就排不下带宽、流根本起不来的情形,停摆那条路永远等不到)就退一档并把结论**落盘**(键 = `vid:pid × 控制器 PCI 路径 × 相机序列号`,一个键一个文件,放 `native/gripper_version1/camera_modes/`——**不能放服务的 runtime 目录,那里每次租约释放整个删掉**),稳定跑满 `CLEAN_RUN_SECONDS=300` 清零停摆计数;**降档必须同时清掉两个计数**——门槛是拿 `==` 比的,只清一个的话另一条路降完一档就永远不再命中,表里剩下的档位形同不存在(DECXIN 只有两档,正好把这个缺陷盖住了);两条路的日志都在调用**之前**抓计数,否则清零后只能打出「0 停摆」,正好把最该看的那次降档说成没有依据;`tools/discover_uvc_config.c` 如实报**相机描述符里的首选档**(alt7),app 拿它跟服务端档位表对一遍、确认这一对是梯子上的任意一档,对不上就报「扫描程序与服务端档位表已经脱节」(那说明两个程序分开编了,必须一起重编);`./build.sh --test` 从点名跑 `test-frame-integrity` 改成走 `ctest`——`tests/test_altsetting_ladder.c` 虽然在 `CMakeLists.txt` 里注册了 `add_test`,此前却一次也没被执行过,上面那个「降一档就卡死」正好落在它本该覆盖的范围内。真机验证:ini 强制 alt7 → 78 秒停摆 → 116 秒再停 → 服务打出 `2 stalls at alt=7; dropping to alt=6 payload=944` → 重开在 alt6 → 169 秒 30fps 零停摆,整条降档+恢复路径走通;装 app 自己生成的 ini(alt6 默认)跑 **600 秒三路:0 停摆 / 0 重建 / 0 启动失败 / 0 复位**,17513/17496/17487 帧(30.00/30.00/29.80 fps),日志里 `[LIBUVC-QUIRK] … alt=6 payload=944 endpoint=944 xfers=32 (altsetting override)` 证明确实跑在 alt6 上、ini 真的生效了;装机后再做一次 300 秒回归同样全零停摆;装机产物与源码构建逐个 md5 相同、RUNPATH 仍只有 `$ORIGIN/third_party/libuvc`。离线侧新增 `tools/tests/test_camera_altsetting_mode.py`(19 条,覆盖最保守档/学到值优先/表外值忽略/扫描程序与服务端脱节必须先报错,并钉死与 C 测试共用的落盘键串),`test_altsetting_ladder.c` 补上「两个计数都要清零」的断言并**反向验证过不是空跑的**(把清零那行注释掉,该测试当场断言中止)。装机后需重启主程序才能同时拿到新的 `uvc_camera_service.py` 与新服务,否则两边档位要求对不上会像 2026-09-15 09:24 那样整个起不来。扫描侧:移植交付包「设备扫描逻辑与程序_20260914」,夹爪与 UVC/ESP32 的配对从 **USB 根端口/控制器**改走 **NVS 序列号**——旧规则(`_bus_root`/`_root_port`,外加「同一 USB2 总线出现双 rig 就拒扫」)的前提就是错的:Fays 是 USB3/FT602 挂在配套的 5000M 总线上,跟 UVC/ESP32 本来就不共根,只能靠猜。新链路:UVC 组 → 唯一 ESP32(`bus-outer.` 开头)→ 串口发 `QF` 读它 NVS 里绑定的 Fays 序列号 → 与官方 SDK 枚举出的 `device.serial` 比对(`_resolve_fays_group` 三步,任一步不唯一就明确拒绝;`_match_esp` 拒收空序列号,不再按端口或枚举顺序猜)。SDK 探测前先 `validate_fays_superspeed` 预检,再以 `serial_only_fast=True` 快速枚举序列号(`fays_serial_probe.py` 加 `--serial-only-fast`;超时不再只报一句 timeout,解码 stdout/stderr 并附最后 20 行),`_probe_serial` 交叉核对 SDK serial 与 NVS 绑定;双 rig 新增「在用时跳过」——`fays_device_guard(port, timeout=0.0)` 探到另一 rig 正持有该设备就跳过而不是占用。串口侧:`CONNECT_BOOT_DELAY = 2.0` 死等改成 `CONNECT_BOOT_TIMEOUT = 2.0` 轮询 `?` 握手(实际尝试次数按真实值上报,不再报上限),打开加 `exclusive=True`,新增 `query_fays_serial()`/`set_fays_serial()`(`QF` 查询 / `WF:` 写入,值校验 `[A-Za-z0-9._-]{1,64}`);顺带修 `GripperSerial.send()` 只拿首字符去查命令表(`[:1]`)——`"QF"` 因此永远匹配不上自己的期望表,改成先查全命令再退回首字符。UVC 发现程序侧:`_native_env(binary)` 改成优先用二进制自带的 `third_party/libuvc`(不再指望环境里恰好有),`_run_discovery` 加互斥的 `--topology-only`/`--identity-only`/`--skip-flash` 三种扫描深度。**前置条件:ESP32 固件必须认识 `QF`/`WF:`,当前 `online/esp32_proc` 的固件还不认识,会失败关闭并报「查询 Fays 序列号失败: ERR」,需先烧固件。** 新增离线自检 `tools/tests/test_gripper_fays_pairing.py`(假串口 + 假桥接 + 假探针,覆盖 QF/WF 往返、ESP 匹配、按序列号解析、整套 acquire、UVC 关联,并核对部署的原生程序确实内嵌了新参数)。s80c 上色工具修隔帧重复(`tools/s80c_arm_convert/convert_arm_dataset.py`,v1.3.4 之后单独提交的补丁):`pooled_episodes_v1` 这版录制**每帧写两行**(`frame_index` = 0,0,1,1,…,同一帧两行的 `timestamp`/`hardware_ns` 逐值相同)而视频只有一帧,工具把行数当帧数(`n = tbl.num_rows`)、主流程再按视频帧号 1:1 取 `hw_ns[i]`,于是每个时间戳被连送两遍——离线 ISP 对重复时间戳复用上一帧的输出,输出视频就隔帧重复。实测 rec001 无损版 833 帧里 394 帧与前一帧逐字节相同、且 394 个全落在奇数位(每对时间戳的第二个),源视频 0 重复;同一根因还让 IMU 侧车**少一半**(修复前 `hw_ns[:n_frames]` 只够到第 417 个时间戳,其后的 IMU 样本全被「晚于末帧 hw」规则丢掉,输出只剩 416 行 / 13.8 秒,修复后 832 行 / 27.7 秒,与视频时长 27.8 秒对上)。现按 `frame_index` 折叠冗余行,但**只在同一 `frame_index` 名下所有行的 `timestamp` 与 `hardware_ns` 逐值相同时才折**,否则打告警原样不动——全库 142 个带 `frame_index` 的 parquet 里 129 个本就每帧一行(空操作)、1 个真冗余(rec001,1666 行 → 833 帧)、12 个行间时间戳互不相同(折叠会丢时间戳,一律只告警)。上色链路一行未动,同一份 config、同一个离线 ISP、`--sdk-wb-auto` 照旧,灰世界增益与修复前逐位相同。承接 v1.3.4 的新夹爪接入即自动生成运行标定并连接(Fays S80M):此前接入一只新夹爪要人工两步——先在夹爪上位机点 `device_setup`、再在采集机跑 `tools/import_gripper_calibration.py` 导入,漏掉任一步主程序直接拒绝启动(「当前 Fays 缺少运行标定文件…请先在夹爪上位机中运行 device_setup」);现在 `SingleFaysLease.acquire()` 发现 per-serial YAML 缺失时,就在设备锁内调厂商导出程序从**这只夹爪自身**读出厂标定、生成 SDK YAML 与 ORB YAML(鱼眼 `stereoRectify` 求 P1/R1 + IMU 外参 `T_b_c1` + 探针读五项噪声/频率),复核落盘路径后直接连上,已有标定走 `isfile` 快路径(启动零额外开销、不碰设备)——这两个文件是**逐设备**出厂标定不可跨设备复用(实测 098/099 三组全不同),只能现场读;设备面板夹爪条目右键加「重新读取出厂标定」(录制中禁用,标定前自动关该夹爪、完成后开回),`tools/import_gripper_calibration.py` 加 `--generate`(旧文件先备份 `.bak_<时间戳>`)供命令行强制重生成;顺带修掉生成产物第 3 行的出处注释——厂商模板写死指向 `3500000261870088`,照抄会让每只新夹爪的 IMU 外参都被记成「取自另一台设备」,现改写成本机序列号(历史产物不动)。承接 v1.3.3 的力矩阵/触觉力与 RGB 视频的时间戳对齐:**力侧此前完全没有时间戳**——同一行里的 RGB 帧和力样本不是同时刻采集的,RGB 走外部帧源队列取队头最旧帧、力/矩阵走 latest-wins 单槽取当下最新,于是「行号相同」≠「时刻相同」,力恒领先 RGB 且领先量随录制时长增长(RGB 源 30.84fps vs 写线程 30fps,实测约 1 帧/秒,下游观测到的滞后 3 帧就是这么来的),力矩阵走独立泵线程还与 3 向量力各记各的时刻。修法是让每行自描述:`tactile_ready` 加第 5 个载荷 `capture_ns`(在 SDK 回调入口取),`pipeline.write_tactile_force/_force_matrix` 落成独立的 `observation.gripper_{side}_force_ns` / `_force_matrix_ns` 稀疏 int64 列(与 `hardware_ns` 同宿主单调钟时基,features 里声明 `encoding: host_monotonic_ns`),下游按时间取最近邻即可还原真实配对,精度上界=半个力样本间隔;顺带修 `rgb_frame_ready`/`stereo_frame_ready` 的 `pyqtSignal(int)` 把 `time.monotonic_ns()` 按 C++ qint32 静默截断成负数(每 2.147s 翻符号),改 `object` 封送——这也解释了此前用 `hardware_ns` 解回卷时凭空造出上百帧假漂移、把"中位 5.8 帧 / 最大 ±80 帧"报成对齐误差(真值是 ~3 帧,正确规则是**无符号**:单调钟 + FIFO 消费 ⇒ 真步长恒非负);新增 `scripts/align_modalities.py` 处理端最近邻对齐工具,对 v1.3.3 之前录的 episode 明确报「无法对齐(只能重录)」而不用增长率去猜。承接 v1.3.2 的 SLAM 陈旧帧入库前拦截与轨迹显示深拷贝修复。:桥接按「连续回退次数」判定——单帧脏读丢弃、连丢 30 帧才判定时钟真跳变并换基准放行(此前每一帧回退都会让核心库清空 IMU 队并重建地图、位姿停发 0.2–1.34 s,静止时更久),新增 `[TIME_DROP]`/`[TIME_REBASE]` 现场行并**无条件**打进 GUI 日志(此前落进未匹配行被 50 条上限吃掉——实测原生日志 4 次回退、GUI 日志 0 条,真出事时反而看不见),且带 `seq`/`prev_seq` 对比结论以区分「SDK 乱序投递 / 重复投递同一帧 / 帧配了旧时间戳」三种成因(时间戳上三者长得一模一样,对策完全不同);逐秒遥测 `[FPS_DATA]` 改「只在异常时出声」(健康静默、进入异常与恢复各一行、持续异常每 30 s 重复,全量逐秒流仍在原生日志里),并修 `wait_sdk_ready` 就绪门被**粘滞** `state.error` 锁死——任何信息性输出(如 ld.so 的 `cannot be preloaded ... ignored.`)都会让标定明明已完成的这一次返回 False、报出误导的「未等到 [FAYS-CALIB] 标记」(2026-09-10 18:32 假超时事故,文案白名单 + 去掉粘滞判断双管修);原生日志在 runtime 目录 `rmtree` 之前留档到 `logs/slam_native/`(保留最近 20 份),修「一次干净退出的会话其原生日志不可恢复」——排查 SLAM 崩溃时唯一的证据曾随目录一起被删;轨迹显示去掉 Qt 主线程上的整条深拷贝(正是这次拷贝让 `_rendered_trajectory is traj` 判等恒为假、每个位姿都在主线程复制随会话线性增长的点列,即「画一段时间后帧率变低」的直接原因),显示上限 400→6000,并以向量化投影 + 一次 `drawPolyline` 绘制,修「十几秒后轨迹显出折角」(降采样按 stride 翻倍使顶点数恒落 [上限/2, 上限],上限 400 时每段跨 67 ms 且随 stride 每翻一倍继续变粗,观感像 SLAM 出点变慢而数据一直满 30 Hz,是绘制侧丢的);RGB 外部队列在录制开始/结束/中止三个边界排空,修「上一段残留 + 本段启动窗口累积被写成新视频开头」(实测每段开头约 28 帧与上一段 episode 末帧逐帧匹配,队列满时还占 ~110 MB/槽);任务进度只上报后端当前任务列表里存在的任务(本地自建任务平台没这个项目,上报必被拒 400),且后端该项目口径为 `"sessions"`(从没收到过任何上报)时首次送本机**全量**当基线——只送增量会把后端计数从 session 数砸成增量本身(现场:3/3/3 的项目再录一条变 1)。承接 v1.3.1 的力矩阵 5 档落盘与 SLAM 停落 slam_pose 列。 diff --git a/collector/core/gripper/camera_service_src/CMakeLists.txt b/collector/core/gripper/camera_service_src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1d0b3107d53bef2da60245feec1f18d42ad38fa --- /dev/null +++ b/collector/core/gripper/camera_service_src/CMakeLists.txt @@ -0,0 +1,100 @@ +cmake_minimum_required(VERSION 3.16) +project(ksq_camera_service C) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +set(BUILD_EXAMPLE OFF CACHE BOOL "" FORCE) +set(BUILD_TEST OFF CACHE BOOL "" FORCE) +set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE) + +add_subdirectory(third_party/libuvc) + +find_package(Threads REQUIRED) +find_package(PkgConfig REQUIRED) +pkg_check_modules(LIBUSB REQUIRED IMPORTED_TARGET libusb-1.0) + +add_executable(ksq-camera-service + src/camera_service.c +) +target_include_directories(ksq-camera-service PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libuvc/include +) +target_compile_definitions(ksq-camera-service PRIVATE + _GNU_SOURCE +) +target_compile_options(ksq-camera-service PRIVATE + -Wall -Wextra -Wpedantic +) +target_link_libraries(ksq-camera-service PRIVATE + LibUVC::UVC + PkgConfig::LIBUSB + Threads::Threads +) + +add_executable(sonix-flash-probe + tools/sonix_flash_probe.c +) +target_compile_options(sonix-flash-probe PRIVATE + -Wall -Wextra -Wpedantic +) +target_link_libraries(sonix-flash-probe PRIVATE + PkgConfig::LIBUSB +) + +add_executable(discover-uvc-config + tools/discover_uvc_config.c +) +target_include_directories(discover-uvc-config PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libuvc/include +) +target_compile_definitions(discover-uvc-config PRIVATE + _GNU_SOURCE +) +target_compile_options(discover-uvc-config PRIVATE + -Wall -Wextra -Wpedantic +) +target_link_libraries(discover-uvc-config PRIVATE + LibUVC::UVC + PkgConfig::LIBUSB +) + +install(TARGETS ksq-camera-service RUNTIME DESTINATION bin) + +# Hardware-free integrity regression tests for the production callback. +enable_testing() +add_executable(test-frame-integrity tests/test_frame_integrity.c) +target_compile_definitions(test-frame-integrity PRIVATE _GNU_SOURCE) +target_compile_options(test-frame-integrity PRIVATE -Wall -Wextra -Wpedantic) +target_link_libraries(test-frame-integrity PRIVATE + LibUVC::UVC PkgConfig::LIBUSB Threads::Threads) +add_test(NAME frame-integrity COMMAND test-frame-integrity) + +# The altsetting ladder decides which isochronous setting each camera is opened +# with, and its state-file key has to be derived identically in Python. Neither +# is observable without hardware, so pin both here. +add_executable(test-altsetting-ladder tests/test_altsetting_ladder.c) +target_compile_definitions(test-altsetting-ladder PRIVATE _GNU_SOURCE) +target_compile_options(test-altsetting-ladder PRIVATE -Wall -Wextra -Wpedantic) +target_link_libraries(test-altsetting-ladder PRIVATE + LibUVC::UVC PkgConfig::LIBUSB Threads::Threads) +add_test(NAME altsetting-ladder COMMAND test-altsetting-ladder) + +# Checkout deployment keeps the bundled libuvc next to these executables. +# Avoid CMake embedding the build machine's absolute checkout directory. +# +# CMake appends an empty element to this list for ksq-camera-service (it counts +# Threads::Threads as an empty link directory), which would leave the RUNPATH as +# "$ORIGIN/third_party/libuvc:" -- and an empty element means "also search the +# current working directory". build.sh strips that element after the link and +# fails the build if it survives; do not "fix" it here by hand, the per-target +# SKIP_BUILD_RPATH and global CMAKE_SKIP_RPATH routes both make it worse +# (CMake then emits the entire empty list). +foreach(_target ksq-camera-service discover-uvc-config test-frame-integrity + test-altsetting-ladder) + set_target_properties(${_target} PROPERTIES + BUILD_RPATH "$ORIGIN/third_party/libuvc" + INSTALL_RPATH "$ORIGIN/../lib" + BUILD_RPATH_USE_ORIGIN TRUE) +endforeach() diff --git a/collector/core/gripper/camera_service_src/README.md b/collector/core/gripper/camera_service_src/README.md new file mode 100644 index 0000000000000000000000000000000000000000..22eac8aa5e4e74005497feac7cc01b9c34373ecd --- /dev/null +++ b/collector/core/gripper/camera_service_src/README.md @@ -0,0 +1,181 @@ +# 相机服务与 UVC 扫描程序(源码入库版) + +`ksq-camera-service`(libuvc 推流服务,走 IPC 给主程序供帧)与 +`discover-uvc-config`(UVC 相机扫描:拓扑枚举 + Flash 身份读取 + 生成配置)的 +**源码**。用 `./build.sh` 构建,产物安装到 +`core/gripper/native/camera_service/build/`。 + +## 为什么源码在这里 + +这两个程序的源码原先**只存在于 `online/`**(`.gitignore:56` 整个目录不上传), +`core/gripper/native/` 下只有编译好的二进制,重建配方只活在当时那次排查的会话里 +—— 二进制一旦丢失或要改一行,就得从头摸清 libusb 头文件、pkg-config、RUNPATH +这一整串。2026-09-15 把源码连同构建配方搬进 core,让采集程序自己的相机逻辑随包入库。 + +## 目录 + +``` +CMakeLists.txt 与交付包 online/camera_service/CMakeLists.txt **逐字节一致** +src/camera_service.c 推流服务 +tools/discover_uvc_config.c UVC 扫描程序(三档扫描深度) +tools/sonix_flash_probe.c Sonix Flash 读写工具(CMakeLists 里的目标之一) +tests/test_frame_integrity.c 无硬件回归测试(MJPEG 回调完整性) +third_party/libuvc/ vendored libuvc 0.0.7,含本地补丁 ksq_altsetting_quirks + (src/stream.c:DECXIN 3060→1280、Sightac 3072→800) +build.sh 构建脚本(唯一入口) +``` + +## 构建 + +```sh +core/gripper/camera_service_src/build.sh # 构建 + 安装(旧的先备份) +core/gripper/camera_service_src/build.sh --test # 顺带跑 test-frame-integrity +core/gripper/camera_service_src/build.sh --no-install +``` + +依赖:`gcc`、`cmake >= 3.16`、`make`、libusb-1.0 头文件(`libusb-1.0-0-dev`,或退到 +conda 的 `include/libusb-1.0`)。libjpeg 头文件可选,但**缺了 libuvc 会退化成不支持 +MJPEG 解码**,构建脚本会告警 —— 线上产物是带 libjpeg 的,两者不一致。 + +安装会按 `.pre_rebuild_<时间戳>` 备份旧二进制,回退就是覆盖回去。 + +## 三个已踩过的坑(改脚本前先看) + +1. **`*** 目标模式不含有"%"`**:真正的病因是 vendored `FindLibUSB.cmake` 走 + `find_library()` 找不到库(系统只有 `libusb-1.0.so.0`,没有给链接器用的 + `libusb-1.0.so`),把 `LibUSB::LibUSB-NOTFOUND` 写进了依赖表;GNU make 把那条 + 依赖里的第二个冒号当成静态模式规则的分隔符,于是报出这个与病因毫不相干的错。 + 解法是 `-DLibUSB_LIBRARY=...` 预置缓存,让 `find_library` 整个跳过。 +2. **pkg-config 里只能有一个 `-I`**:`FindLibUSB.cmake` 把 `${LibUSB_INCLUDE_DIRS}` + 不 quote 地交给 `set_target_properties`,两个 `-I` 就变成三个实参报错。而 + libuvc 内部用 ``、两个工具用 ``,两种写法都要能 + 解析 —— 所以 shim 目录里同时放 `libusb-1.0/` 与 `libusb.h` 两个软链,只给一个 `-I`。 +3. **`ksq-camera-service` 的 RUNPATH 会多一个空条目**(`$ORIGIN/third_party/libuvc:`): + CMake 把它链的 `Threads::Threads` 在本机算成了空目录。RUNPATH 里的空条目等于让 + 加载器去**当前工作目录**找 `libuvc.so.0`,线上那份手工链的没有这个口子,所以 + 构建脚本会在链接后把这个冒号就地改成字符串终止符(等价 `chrpath -d` 的收缩改写; + 本机没有 chrpath/patchelf)。校验段会断言空条目已消失。 + +## 等时档位(altsetting):ini 说了算,服务会自己降档 + +**`forced_altsetting` / `forced_payload` 是真正生效的**,不是校验用的装饰。服务 +打开设备后立刻把这两个值交给 libuvc 的新 API `uvc_set_altsetting_override()` +(声明在 `include/libuvc/libuvc.h`,实现在 `src/device.c`,`uvc_device_handle_t` +是 `calloc` 出来的,新字段自动零初始化,没设过就退回编译期那张 +`ksq_altsetting_quirks` 表)。**改档位只需要改 ini。** + +在此之前这两个 ini 字段只用于校验和打印,真正决定档位的是编译进 libuvc 的表 +——所以「改 ini」完全不改变行为,这一点极容易误判。**判断一条腿实际跑在哪个档 +位,只认日志里的 `[LIBUVC-QUIRK] ... alt=N payload=M ... xfers=` 那一行**(带 +`(altsetting override)` 后缀表示走的覆盖值);服务自己那行 +`vidpid=... alt=7 payload=1280` 只是 ini 的回声,在旧二进制上与真实档位无关。 + +档位表在 `src/camera_service.c`(`kDecxinModes` / `kSightacModes`),**必须按 +从好到差降序**,降档梯子按表往下走一格、走到最后一项就不再降。两个门槛分开计: +连着停摆 `STALLS_BEFORE_ALTSETTING_DOWNGRADE`(2) 次降档;连着开不起来 +`OPEN_FAILURES_BEFORE_ALTSETTING_DOWNGRADE`(3) 次也降档(覆盖「STREAMON 阶段 +就排不下带宽、流根本起不来」那种,停摆那条路永远等不到)。结论按 +「相机序列号 × 控制器 PCI 路径」落盘到 `state_dir`,下次开机直接读。 + +**降档必须把两个计数都清零**(2026-09-15 修)。门槛是拿 `==` 比的,计数停在 +门槛上就再也不会命中——原来 `maybe_downgrade_altsetting` 只清了 `stalls_at_mode`, +于是「开不起来」那条路**降完一档就永久卡死**,表里剩下的档位形同不存在 +(DECXIN 只有两档,正好被掩盖住;三档机型上就会露出来)。两条路的日志都在 +调用**之前**抓计数,否则清零后只能打出「0 failed opens」,把最该看的那次降档 +说成没有依据。 + +**这套东西能测,而且以前从来没被测过**(2026-09-15 修)。`tests/test_altsetting_ladder.c` +一直在 `CMakeLists.txt` 里注册着 `add_test`,但 `build.sh --test` 是点名跑 +`test-frame-integrity` 的,梯子那个**一次也没执行过**——上面那个「降一档就卡死」 +的 bug 正好落在它本该覆盖的范围内。现在 `--test` 走 `ctest`,新增测试只要 +`add_test` 就自动纳进来。反向验证过:把清零那行注释掉,`altsetting-ladder` +立刻断言中止,不是个空跑的测试。 + +**起始档位由 app 决定,不在这张表里**:`uvc_camera_service.py` 的 +`_starting_mode` 取**表里最保守的一档**(=最后一项)。实测 DECXIN 的 alt7 +(10.24 MB/s)在整机三路一起出流时每 45~130 秒必停摆一次,alt6(7.552 MB/s) +同样三路下长跑不停,而**两档出帧率一模一样(都 30.00fps)**——alt7 多出来的每帧 +余量(327680 对 241664 B)换不到任何看得见的好处,所以默认不用它。想要那点余量 +就把 ini 改回 alt7,服务停两次会自己退回 alt6 并把结论落盘。 + +`tools/discover_uvc_config.c` 报的是**相机描述符里的首选档**(alt7),是如实汇报 +硬件,不是起始档;app 拿它跟服务端档位表对一遍,对不上就报「扫描程序与服务端 +档位表已经脱节」——那说明两个程序分开编了,必须一起重编。 + +## SIGTERM 收尾:join 必须有界(2026-09-15 修) + +**症状**:服务收到 SIGTERM 后退不出来。实测线上二进制卡了 3 分钟以上,只攥着 +DECXIN 的 `/dev/bus/usb/007/032` 一个设备 fd(left/right 都已干净释放),日志 +停在断流那一刻——连 `[SUPERVISION] parent exited` 都没打出来。 + +**病根**:相机线程陷在 `uvc_open` 的同步 libusb 调用里(卡死的设备上它不返回), +永远走不到循环头那个 `g_stop` 判断;而 `main` 堵在 `pthread_join` 上等它。 +`g_stop` 置了也没用——没人去看。 + +**后果**:客户端只等 2 秒(`uvc_camera_service.py` 的 `terminate()` → 等 2 秒 → +`kill()`),超了就是 SIGKILL,进程死在 libusb 调用中间、设备停在激活的 alt +setting 上,下一轮照样起不来——正是 2026-09-15 09:24 那次事故的形状。 +`teardown_failed_open` 里「复位抢在 `uvc_stop_streaming` 之前」只覆盖**失败路径**, +覆盖不到「线程已经卡在 `uvc_open` 里」这一种。 + +**改法**:`pthread_join` → `pthread_timedjoin_np`。整体预算 1.5 秒、单路 0.8 秒, +超时就 `pthread_detach` 掉继续走,`main` 一返回进程即结束(内核替我们释放句柄), +并打一行 `收尾超时:线程未在预算内退出(多半卡在设备调用里),不再等它`。 +跳过超时那一路的统计与 `pthread_mutex_destroy`——线程可能还在用,销毁是 UAF。 + +**一个坑(第一版就踩了)**:这个 join 循环**同时就是服务的主运行循环**——它在 +**启动时**进入、一直跑到 `g_stop`,不是「收尾时才走的一段」。所以截止时间不能在 +进循环前算好:第一版把 `shutdown_deadline` 放在 `for` 之前,结果服务启动 1.5 秒后 +三路一起「收尾超时」、自己退出了(现象:三路 `总帧=0`、日志里三行收尾超时、 +`SIGTERM → pid` 那行根本没机会打)。现在改成**等 `g_stop` 真置位时才开始计时**, +没置位时只用 200ms 短超时轮询(成本可忽略)。 + +**验证**:正常路径真机 45 秒三路 —— left/right 各 1351 帧满帧、decxin 1111 帧, +SIGTERM 退出 **0.71 秒**(改前 0.56 秒,仍在 2 秒宽限内),服务全程不自杀。 +**超时那条分支本身没能在真机上触发**(没法按需把设备弄卡),只做了代码审查。 + +## 与交付包的关系 + +`CMakeLists.txt` 与四个 C 源文件都从交付包 `online/camera_service/` 原样搬来 +(逐字节一致),本仓库只新增 `build.sh` 与这份 README。**改这里的 C 源码时要同步 +回交付包**,否则两边会分叉。 + +构建产物与线上二进制的实测关系(2026-09-15): + +| 产物 | 与线上二进制 | +|---|---| +| `discover-uvc-config` | **逐字节一致**(sha256 `b9d8bba870f60c11…`)——配方忠实 | +| `ksq-camera-service` | **源码已领先线上**(多了下面的 SIGTERM 收尾修复),且编译选项不同:CMake Release 用 `-O3 -DNDEBUG`,线上那份是手工 `-O2`(源码无 `assert()`,`NDEBUG` 无语义影响) | +| `sonix-flash-probe` | 同上,代码同源、编译选项不同 | +| `libuvc.so.0.0.7` | 代码同源、编译选项不同;`ksq_altsetting_quirks` 补丁与 `[LIBUVC-QUIRK]` 日志**都在**,NEEDED 三者一致(libusb-1.0.so.0 / libjpeg.so.8 / libc.so.6) | + +也就是说 `build.sh` 现在是**单一机制**(一套 CMake 配置编全部目标),代价是 +`ksq-camera-service` 与当年手工链的那个二进制不是同一个字节。重新构建后应重新做 +一次三路相机回归,而不是假定等价。 + +**2026-09-15 19:29 已按此装机**(`STAMP=20260915_192940`):`ksq-camera-service` +现在带自适应档位 + 两个计数都清零的修复。装机前三路回归已做(app 生成的 ini、 +alt6 默认,**600 秒三路零停摆零重建,decxin/left 30.00fps、right 29.80fps**, +17513/17496/17487 帧),装机后又做了一次 300 秒回归。 + +**2026-09-15 11:34 曾按此装机**(`STAMP=20260915_113444`): +`core/gripper/native/camera_service/build/` 里的 `ksq-camera-service` 当时是 +`07f1f5a34b569b7b`(带 SIGTERM 收尾修复),旧件 `b64b74d810abe482` 备份在同目录 +`.pre_rebuild_20260915_113444`;`discover-uvc-config` 装前装后同为 +`b9d8bba870f60c11`,装不装等价。装机前三路回归已做(90 秒 ×2 腿 + 45 秒修复腿)。 +**另注意 `build.sh` 的安装段不备份 `third_party/libuvc/`**(`rm -f` 直接覆盖、 +`include/` 还是 `rm -rf`),所以这次装机前手工备份了库文件为 +`libuvc.so.0.0.7.pre_rebuild_20260915_113330` + `include.pre_rebuild_20260915_113330/`。 +改脚本时补上这段备份更稳妥。 + +### glibc 下限:`ksq-camera-service` 2.34 → 2.38(不是新约束) + +新编的 `ksq-camera-service` 引用 `__isoc23_strtol@GLIBC_2.38`(GCC 15 默认 C23, +`strtol` 解析成 C23 语义的符号),最低 glibc 从线上的 2.34 抬到 2.38。看着像门槛 +变高,其实**没有新增约束**:那个**逐字节一致**的 `discover-uvc-config` 本来就要求 +GLIBC_2.38,而它是扫描时每次都要在采集机上跑的 —— 能跑扫描程序就一定能跑这个 +服务。其余产物(`sonix-flash-probe`、libuvc)两边都是 2.34。 + +不要去给 CMake 钉 `-DCMAKE_C_STANDARD=17` 来消掉它:那会连带把 +`discover-uvc-config` 的 `strtol` 换回旧符号,而它正是目前唯一能逐字节复现线上 +二进制的产物,是「配方忠实」的活证据。 diff --git a/collector/core/gripper/camera_service_src/build.sh b/collector/core/gripper/camera_service_src/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..484ece6adffec21bb5baaada96f52ba80a9af736 --- /dev/null +++ b/collector/core/gripper/camera_service_src/build.sh @@ -0,0 +1,244 @@ +#!/usr/bin/env bash +# 构建 libuvc 相机服务(ksq-camera-service)与 UVC 扫描程序(discover-uvc-config), +# 产物安装到 core/gripper/native/camera_service/build/。 +# +# 为什么有这份脚本:这两个程序的源码原先只在 online/(.gitignore 里),core/ 下 +# 只有编译好的二进制,重建配方只活在当时那次会话里 —— 一旦二进制丢了或要改一行 +# 就得从头摸。现在源码随包入库(core/gripper/camera_service_src/),配方固化于此。 +# +# 依赖:gcc、cmake(>=3.16)、make、libusb-1.0 头文件;libjpeg 头文件可选(缺了 +# libuvc 会退化:不支持 MJPEG 解码,实测产物 NEEDED 里就没有 libjpeg.so.8)。 +# +# 用法: +# ./build.sh 构建 + 安装(旧的同名二进制先备份为 .pre_rebuild_<时间戳>) +# ./build.sh --no-install 只构建,不动 core/gripper/native/ +# ./build.sh --test 构建后跑 ctest(全部无硬件回归测试) +# ./build.sh --jobs 4 限制并行度 +set -euo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO="$(cd "$HERE/../../.." && pwd)" +OUT="$REPO/core/gripper/native/camera_service/build" +BUILD="$HERE/build" +SHIM="$BUILD/shim" + +DO_INSTALL=1 +DO_TEST=0 +JOBS="$(nproc 2>/dev/null || echo 4)" + +while [ $# -gt 0 ]; do + case "$1" in + --no-install) DO_INSTALL=0 ;; + --test) DO_TEST=1 ;; + --jobs) JOBS="${2:?--jobs 需要一个数字}"; shift ;; + -h|--help) sed -n '2,18p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit 0 ;; + *) echo "未知参数: $1(-h 看用法)" >&2; exit 2 ;; + esac + shift +done + +die() { echo "错误: $*" >&2; exit 1; } + +# ---------------------------------------------------------------- 依赖定位 + +# libusb 头文件:系统装了 libusb-1.0-0-dev 最省事;否则退到 conda 的 include。 +# 注意头文件父目录要进 -I,因为源码里既有 (sonix_flash_probe) +# 也有 (libuvc 自己),两种写法都得能解析。 +find_libusb_include() { + local candidate + for candidate in \ + "${LIBUSB_INCLUDE_PARENT:-}" \ + /usr/include \ + /usr/local/include \ + "${CONDA_PREFIX:-}/include" \ + "$HOME/miniconda3/include" \ + "$HOME/anaconda3/include" + do + [ -n "$candidate" ] && [ -f "$candidate/libusb-1.0/libusb.h" ] && { + echo "$candidate"; return 0; } + done + return 1 +} + +# libusb 运行库:优先系统 multiarch 的 .so.0(只链 soname,产物不带任何本机 +# RUNPATH 依赖),再退到 conda。 +find_libusb_library() { + local candidate + for candidate in \ + "${LIBUSB_LIBRARY:-}" \ + /usr/lib/x86_64-linux-gnu/libusb-1.0.so.0 \ + /usr/lib/libusb-1.0.so.0 \ + /usr/local/lib/libusb-1.0.so.0 \ + "${CONDA_PREFIX:-}/lib/libusb-1.0.so" \ + "$HOME/miniconda3/lib/libusb-1.0.so" \ + "$HOME/anaconda3/lib/libusb-1.0.so" + do + [ -n "$candidate" ] && [ -e "$candidate" ] && { echo "$candidate"; return 0; } + done + return 1 +} + +LIBUSB_INC_PARENT="$(find_libusb_include)" \ + || die "找不到 libusb-1.0 头文件。装 libusb-1.0-0-dev,或用 LIBUSB_INCLUDE_PARENT=<含 libusb-1.0/ 的目录> 指定。" +LIBUSB_LIB="$(find_libusb_library)" \ + || die "找不到 libusb-1.0 运行库。装 libusb-1.0-0,或用 LIBUSB_LIBRARY=<路径> 指定。" + +# libjpeg:FindJpegPkg 会先走 CMake 自带的 FindJPEG,这里预置缓存值把它钉死在 +# 系统头/库上,免得 cmake 是 conda 装的时候误抓 conda 的 libjpeg。 +JPEG_ARGS=() +if [ -f /usr/include/jpeglib.h ]; then + JPEG_ARGS+=("-DJPEG_INCLUDE_DIR=/usr/include") + for lib in /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/libjpeg.so; do + [ -e "$lib" ] && { JPEG_ARGS+=("-DJPEG_LIBRARY=$lib"); break; } + done +else + echo "警告: 没有 /usr/include/jpeglib.h,libuvc 将编译成不支持 MJPEG 解码" >&2 +fi + +# ---------------------------------------------------------------- 头文件 shim +# +# 顶层的 CMakeLists 用 pkg_check_modules(LIBUSB REQUIRED ... libusb-1.0),而系统 +# 上根本没有 libusb-1.0.pc(那个文件由 -dev 包提供)。这里现造一个,指向真实头 +# 文件和运行库的 soname(-l:libusb-1.0.so.0 不带 -L,所以不会给产物塞 RUNPATH)。 +# +# 只有**一个** -I,而且是 shim 目录而不是真实头目录:vendored 的 +# FindLibUSB.cmake 把 ${LibUSB_INCLUDE_DIRS} 不 quote 地交给 +# set_target_properties,一旦 pkg-config 给出两个 -I,它就会变成三个实参报 +# 「set_target_properties called with incorrect number of arguments」。 +# 而两种 include 写法都得满足 —— libuvc 内部是 ,两个工具是 +# —— 所以 shim 目录里同时放 libusb-1.0/ 和 libusb.h 两个软链。 + +mkdir -p "$SHIM/include" "$SHIM/pkgconfig" +ln -sfn "$LIBUSB_INC_PARENT/libusb-1.0" "$SHIM/include/libusb-1.0" +ln -sfn "$LIBUSB_INC_PARENT/libusb-1.0/libusb.h" "$SHIM/include/libusb.h" + +cat > "$SHIM/pkgconfig/libusb-1.0.pc" </dev/null 2>&1 || return 0 + python3 - "$binary" <<'PY' +import sys +path = sys.argv[1] +needle = b"$ORIGIN/third_party/libuvc:\x00" +fixed = b"$ORIGIN/third_party/libuvc\x00\x00" +with open(path, "rb") as handle: + data = handle.read() +if needle not in data: + sys.exit(0) +with open(path, "wb") as handle: + handle.write(data.replace(needle, fixed)) +print(f" 去掉 RUNPATH 空条目: {path}") +PY +} + +for binary in ksq-camera-service discover-uvc-config sonix-flash-probe; do + strip_empty_rpath_entry "$BUILD/$binary" +done + +# ---------------------------------------------------------------- 校验 +# +# 产物必须链上 libuvc.so.0 且 RUNPATH 为 $ORIGIN/third_party/libuvc —— 部署布局 +# 靠的就是这个相对路径(ksq-camera-service 里 libusb_reset_device 是 dlsym 取的, +# 所以它自己 NEEDED 里没有 libusb,libuvc 带进来就够)。 + +for binary in ksq-camera-service discover-uvc-config; do + [ -x "$BUILD/$binary" ] || die "没有产出 $BUILD/$binary" + if command -v readelf >/dev/null 2>&1; then + readelf -d "$BUILD/$binary" | grep -q 'libuvc.so.0' \ + || die "$binary 没有链接 libuvc.so.0" + readelf -d "$BUILD/$binary" | grep -q '\$ORIGIN/third_party/libuvc' \ + || die "$binary 的 RUNPATH 不是 \$ORIGIN/third_party/libuvc" + readelf -d "$BUILD/$binary" | grep -q 'libuvc:' \ + && die "$binary 的 RUNPATH 里还有空条目(strip_empty_rpath_entry 没生效)" + fi +done +readelf -d "$BUILD/third_party/libuvc/libuvc.so.0.0.7" 2>/dev/null | grep -q libjpeg \ + && echo "libuvc: 带 libjpeg(支持 MJPEG 解码)" \ + || echo "警告: libuvc 没链上 libjpeg —— 不带 MJPEG 解码,与线上产物不一致" >&2 + +if [ "$DO_TEST" = 1 ]; then + # 走 ctest 而不是点名跑某一个:以前这里写死跑 test-frame-integrity, + # 结果 test-altsetting-ladder 虽然在 CMakeLists 里注册了 add_test,却 + # 从来没有被任何入口调起来 —— 降档梯子是真机上最难复现、最该靠测试 + # 兜住的一块,却一直没人跑。新增测试只要 add_test 就自动纳进来。 + echo "--- ctest ---" + ( cd "$BUILD" && ctest --output-on-failure ) +fi + +if [ "$DO_INSTALL" = 0 ]; then + echo "已完成构建(--no-install,未改动 core/gripper/native/)" + exit 0 +fi + +# ---------------------------------------------------------------- 安装 +# +# 旧的同名二进制按 .pre_rebuild_<时间戳> 备份,保留现场可比对(历史上这里存过 +# pre_stall_watchdog / pre_usb_reset_escalation 两份,都是用来回退的)。 + +[ -d "$OUT" ] || die "安装目标不存在: $OUT" + +STAMP="$(date +%Y%m%d_%H%M%S)" +for binary in ksq-camera-service discover-uvc-config sonix-flash-probe; do + [ -f "$BUILD/$binary" ] || continue + if [ -f "$OUT/$binary" ]; then + cp -p "$OUT/$binary" "$OUT/$binary.pre_rebuild_$STAMP" + fi + cp -p "$BUILD/$binary" "$OUT/$binary" + echo "安装 $binary → $OUT/$binary" +done + +mkdir -p "$OUT/third_party/libuvc" +for name in libuvc.so libuvc.so.0 libuvc.so.0.0.7; do + [ -e "$BUILD/third_party/libuvc/$name" ] || continue + rm -f "$OUT/third_party/libuvc/$name" + cp -a "$BUILD/third_party/libuvc/$name" "$OUT/third_party/libuvc/$name" +done +rm -rf "$OUT/third_party/libuvc/include" +cp -a "$BUILD/third_party/libuvc/include" "$OUT/third_party/libuvc/include" +echo "安装 libuvc → $OUT/third_party/libuvc/" + +echo +echo "完成。回退:把 $OUT/<名字>.pre_rebuild_$STAMP 覆盖回去即可。" diff --git a/collector/core/gripper/camera_service_src/src/camera_service.c b/collector/core/gripper/camera_service_src/src/camera_service.c new file mode 100644 index 0000000000000000000000000000000000000000..5755ff78dc32fe0895b16e0fc06235690bf859e9 --- /dev/null +++ b/collector/core/gripper/camera_service_src/src/camera_service.c @@ -0,0 +1,1514 @@ +/* pthread_timedjoin_np 是 GNU 扩展,必须在任何头文件之前打开。 */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define MAX_CAMERAS 8 +#define FRAME_QUEUE_DEPTH 4 +#define MAX_LINE 512 +#define IPC_MAGIC 0x4b535146u /* "KSQF" */ +#define IPC_VERSION 1u +/* 等时流静默停摆看门狗。DECXIN (1bcf:2d4f) 会在 6~82 秒之间无声停止推帧, + * 此后永不恢复,内核也不报任何错误(实测:同一总线同一 Hub 上的两路 + * Sightac 全程 30fps 正常,只有 DECXIN 自己死)。停滞不是「暂时掉帧」: + * libuvc 丢完等时包后不会自愈,必须重开流。停滞超过这个秒数就中断本路, + * 交给 camera_main 的重试循环重开——否则整场会话只剩最后一帧,客户端 + * 重连也只能重连进空气。 */ +#define STREAM_STALL_TIMEOUT_SECONDS 3.0 + +/* 首次启动等首帧的时限(秒)。 */ +#define FIRST_FRAME_TIMEOUT_SECONDS 4.0 +/* 停摆重开时等首帧的时限(秒)。实测 DECXIN 被拆流后不会立刻回来, + * 4 秒内一帧都没有(会被误判成 startup failed 再拆一次,越拆越糟), + * 放宽到 20 秒再判死。 */ +#define RESTART_FIRST_FRAME_TIMEOUT_SECONDS 20.0 + +/* 连着停摆几次才降档。 + * + * 设成 2 而不是 1:单次停摆多半只是设备自己抽了一下——实测停摆 6 次里每次 + * 单靠重建 libusb 上下文就能恢复;一停就降会把 alt7 的带宽白白让出去,而 + * alt6 的单帧上限只有 241664 B(实测最大帧 234148 B,3% 余量),降下去是有 + * 代价的。两次说明当前档位确实撑不住:实测 alt7 在整机三路出流时每 45~130 秒 + * 必停一次(AMD 1022:15b7 / PCI 0000:74:00.4,以及 1022:43fc / PCI + * 0000:0a:00.0,两块都是),两次最多赔 260 秒,且结论会落盘,每台机器只赔这 + * 一回。 */ +#define STALLS_BEFORE_ALTSETTING_DOWNGRADE 2 + +/* 开不起来(rc<0)连着几次才降档。 + * + * 与停摆分开计、门槛也更高:开不起来多半是设备侧卡死,而那有自己的一条恢复 + * 路径(连续 2 次失败升级成 USB 复位,实测 t≈3 秒就能出帧),一开不起来就降 + * 档会在正常恢复路径上白降。门槛 3 意味着复位试过、还是开不起来,档位才是 + * 剩下的嫌疑。要覆盖的是另一种失败:STREAMON 阶段就排不下高带宽等时档 + * (libusb_set_interface_alt_setting 报 -ENOSPC),此时流根本不会启动, + * 光靠停摆那条路永远等不到。 */ +#define OPEN_FAILURES_BEFORE_ALTSETTING_DOWNGRADE 3 + +/* 一段流稳定跑够这么久,就把「本档位停摆计数」清零。 + * 要比实测的停摆间隔(45~130 秒)明显长,否则计数永远清不掉。 */ +#define CLEAN_RUN_SECONDS 300.0 + +/* 复位 USB 设备(等价于拔插一次)。只在一个场合用:重开之后一帧都没有, + * 说明设备侧真的卡住了(典型是上一次服务被 SIGKILL、设备停在激活的等时 + * alt setting 上),只重建上下文救不回来。 + * + * 平时停摆恢复**不要**走这里:复位是 USB 端口级操作,会重新枚举整条链路, + * 连带打扰同一总线同一 Hub 上的另外两路 Sightac(实测每次复位两个 Sightac + * 都掉一批帧)。实测停摆 6 次只用「重建 libusb 上下文」就 6 次全恢复,复位 + * 是白付的代价。 + * + * libusb 是 libuvc 的依赖、进程里必然已加载,所以按符号名取而不是直接链接 + * ——这样不给二进制新增 NEEDED,交付树里 libuvc/libusb 的解析结果不变。 */ +typedef int (*libusb_reset_device_fn)(struct libusb_device_handle *); + +static libusb_reset_device_fn resolve_libusb_reset_device(void) { + static libusb_reset_device_fn cached = NULL; + static int resolved = 0; + if (!resolved) { + cached = (libusb_reset_device_fn)dlsym(RTLD_DEFAULT, + "libusb_reset_device"); + resolved = 1; + } + return cached; +} + +static volatile sig_atomic_t g_stop = 0; +static int g_parent_pid = 0; + +typedef struct { + char name[64]; + int vid; + int pid; + int usb_bus; + char usb_port_path[64]; + int streaming_interface; + /* 实际生效的等时档位。这两项不是「声明」——run_camera_once 打开设备后 + * 会把它们交给 libuvc 的 uvc_set_altsetting_override(),由它同时决定 + * COMMIT 的 payload 和 libusb 的等时传输几何。留空(-1)时退回 libuvc + * 的编译期兜底表。 */ + int forced_altsetting; + int forced_payload; + int width; + int height; + int fps; + char format[16]; + /* 相机的 USB 序列号、所在控制器的 PCI 路径、以及学习结果的存放目录。 + * 三者只用来给「这台相机 × 这条物理路径」的档位选择建一个稳定的键, + * 见 mode_state_key()。控制器只进键、不参与选档。 */ + char usb_serial[64]; + char usb_controller[64]; + char state_dir[PATH_MAX]; + char socket_path[PATH_MAX]; +} camera_config_t; + +typedef struct { + uint32_t magic; + uint16_t version; + uint16_t header_bytes; + uint32_t sequence; + uint32_t width; + uint32_t height; + uint32_t fourcc; + uint32_t payload_bytes; + uint64_t timestamp_ns; +} ipc_frame_header_t; + +typedef struct { + uint8_t *data; + size_t length; + uint32_t sequence; + uint64_t capture_timestamp_ns; +} frame_item_t; + +typedef struct camera_state camera_state_t; + +struct camera_state { + camera_config_t config; + pthread_t thread; + pthread_t writer_thread; + pthread_mutex_t mutex; + pthread_cond_t condition; + frame_item_t queue[FRAME_QUEUE_DEPTH]; + size_t head; + size_t count; + int stopping; + int listen_fd; + int client_fd; + uint64_t frames_received; + uint64_t frames_output; + uint64_t frames_dropped; + uint64_t bad_jpeg_frames; + uint64_t bad_jpeg_logs; + uint64_t bad_jpeg_replaced; + uint64_t write_errors; + uint64_t reconnects; + uint64_t stalls; + /* 当前档位下已经停摆了几次,连着停够 STALLS_BEFORE_ALTSETTING_DOWNGRADE + * 次就降到下一档;中间只要有一段够长的稳定运行就清零(那次停摆是设备 + * 自己抽了一下,不是档位撑不住)。 */ + unsigned stalls_at_mode; + /* 当前档位下连着几次没能把流开起来(rc<0)。任何一次「开起来了」的证据 + * 都会清零它——停摆也算,因为停摆说明设备是开得起来的。 */ + unsigned open_failures_at_mode; + /* 连续「开不起来」的次数(rc<0)。与 stalls 分开计:停摆说明设备能开、 + * 能出帧,只是中途死了;连续开不起来才是设备侧卡死的signature。 */ + unsigned hard_failures; + unsigned usb_resets; + +}; + +static int has_mjpeg_soi(const uint8_t *data, size_t length) { + return length >= 2 && data[0] == 0xff && data[1] == 0xd8; +} + +static int has_mjpeg_eoi(const uint8_t *data, size_t length) { + /* Some firmware variants append padding after the EOI marker, so scan + * backwards instead of requiring the final two bytes to be exactly + * FF D9. A truncated scan will not contain the marker at all. */ + for (size_t index = length; index >= 2; --index) { + if (data[index - 2] == 0xff && data[index - 1] == 0xd9) { + return 1; + } + } + return 0; +} + +static int is_complete_mjpeg_payload(const uint8_t *data, size_t length) { + return has_mjpeg_soi(data, length) && has_mjpeg_eoi(data, length); +} + +static void request_stop(int signal_number) { + (void)signal_number; + g_stop = 1; +} + +static char *trim(char *value) { + char *end; + while (*value == ' ' || *value == '\t' || *value == '\r' || + *value == '\n') { + ++value; + } + end = value + strlen(value); + while (end > value && (end[-1] == ' ' || end[-1] == '\t' || + end[-1] == '\r' || end[-1] == '\n')) { + --end; + } + *end = '\0'; + return value; +} + +static int parse_int(const char *value, int *result) { + char *end = NULL; + long parsed; + errno = 0; + parsed = strtol(value, &end, 0); + if (errno != 0 || end == value || *trim(end) != '\0' || + parsed < INT_MIN || parsed > INT_MAX) { + return -1; + } + *result = (int)parsed; + return 0; +} + +static void set_defaults(camera_config_t *config) { + memset(config, 0, sizeof(*config)); + config->usb_bus = -1; + config->streaming_interface = 1; + config->forced_altsetting = -1; + config->forced_payload = -1; + config->width = 640; + config->height = 480; + config->fps = 30; + snprintf(config->format, sizeof(config->format), "MJPEG"); +} + +static int assign_key(camera_config_t *config, const char *key, + const char *value) { + if (strcmp(key, "vid") == 0) { + return parse_int(value, &config->vid); + } + if (strcmp(key, "pid") == 0) { + return parse_int(value, &config->pid); + } + if (strcmp(key, "usb_bus") == 0) { + return parse_int(value, &config->usb_bus); + } + if (strcmp(key, "streaming_interface") == 0) { + return parse_int(value, &config->streaming_interface); + } + if (strcmp(key, "forced_altsetting") == 0) { + return parse_int(value, &config->forced_altsetting); + } + if (strcmp(key, "forced_payload") == 0) { + return parse_int(value, &config->forced_payload); + } + if (strcmp(key, "width") == 0) { + return parse_int(value, &config->width); + } + if (strcmp(key, "height") == 0) { + return parse_int(value, &config->height); + } + if (strcmp(key, "fps") == 0) { + return parse_int(value, &config->fps); + } + if (strcmp(key, "usb_port_path") == 0) { + snprintf(config->usb_port_path, sizeof(config->usb_port_path), + "%s", value); + return 0; + } + if (strcmp(key, "usb_serial") == 0) { + snprintf(config->usb_serial, sizeof(config->usb_serial), "%s", value); + return 0; + } + if (strcmp(key, "usb_controller") == 0) { + snprintf(config->usb_controller, sizeof(config->usb_controller), + "%s", value); + return 0; + } + if (strcmp(key, "state_dir") == 0) { + snprintf(config->state_dir, sizeof(config->state_dir), "%s", value); + return 0; + } + if (strcmp(key, "socket_path") == 0) { + snprintf(config->socket_path, sizeof(config->socket_path), "%s", value); + return 0; + } + if (strcmp(key, "format") == 0) { + snprintf(config->format, sizeof(config->format), + "%s", value); + return 0; + } + if (strcmp(key, "name") == 0) { + snprintf(config->name, sizeof(config->name), "%s", value); + return 0; + } + return 1; +} + +static int is_supported_device(const camera_config_t *config) { + return (config->vid == 0x0c45 && config->pid == 0x636f) || + (config->vid == 0x1bcf && config->pid == 0x2d4f); +} + +/* 每个机型允许的「档位对」(altsetting, payload),按从好到差的顺序排列。 + * 第 0 项是带宽最好的一档,停摆降级时往后走一格,走到最后一项就不再降 + * ——**降级方向必须是从好到差,表序不能颠倒**。 + * + * 这两张表必须与 libuvc 的编译期兜底表(third_party/libuvc/src/stream.c + * 的 ksq_altsetting_quirks)以及扫描程序(tools/discover_uvc_config.c 的 + * profile_for)保持一致:libuvc 的表决定「没有覆盖值时的默认」,这里决定 + * 「服务愿意接受哪些值」。 + * + * **起始档位不在这张表里定**:起手用哪一档由 uvc_camera_service.py 的 + * _starting_mode 写进 ini(表里最保守的一档,即最后一项),服务只负责接受 + * 表内的值、并在反复停摆时降档。 + * + * DECXIN 两档的账:alt7/1280 是 2 事务/微帧、10.24 MB/s,单帧上限 327680 B; + * alt6/944 是单事务档里最大的一档,8 transfer × 32 包 × 944 B = 241664 B 就是 + * 单帧硬上限,而实测最大帧 234148 B——只剩 3% 余量。也就是说 alt7 的余量更 + * 好看,但实测 alt7 在整机三路一起出流时每 45~130 秒必停摆一次,而 alt6 长跑 + * 不停,**两档的出帧率完全一样(都 30.00fps)**——多出来的余量换不到任何看得 + * 见的好处,所以默认就是 alt6。哪一档真的撑不住不靠推测,靠停摆实测往下走 + * (见 maybe_downgrade_altsetting)。 */ +typedef struct { + int altsetting; + int payload; +} altsetting_mode_t; + +static const altsetting_mode_t kSightacModes[] = { + {3, 800}, +}; +static const altsetting_mode_t kDecxinModes[] = { + {7, 1280}, + {6, 944}, +}; + +static const altsetting_mode_t *mode_table_for(const camera_config_t *config, + size_t *count) { + if (config->vid == 0x0c45 && config->pid == 0x636f) { + *count = sizeof(kSightacModes) / sizeof(kSightacModes[0]); + return kSightacModes; + } + if (config->vid == 0x1bcf && config->pid == 0x2d4f) { + *count = sizeof(kDecxinModes) / sizeof(kDecxinModes[0]); + return kDecxinModes; + } + *count = 0; + return NULL; +} + +static size_t mode_index_for(const camera_config_t *config) { + size_t count = 0; + const altsetting_mode_t *modes = mode_table_for(config, &count); + for (size_t i = 0; i < count; ++i) { + if (modes[i].altsetting == config->forced_altsetting && + modes[i].payload == config->forced_payload) { + return i; + } + } + return count; +} + +/* 「这台相机 × 这条物理路径」的落盘键。 + * + * 刻意不用总线号/端口路径:机架插在哪个口、哪条总线都不是永久的(用户 + * 2026-09-15 明确说过 bus 1 不是永久的),端口一变键就变,要么把上一台 + * 机器的结论套到新拓扑上,要么白学一遍。序列号取自相机描述符、随相机走; + * 控制器取自 PCI 路径、随插槽走。换电脑 / 换 USB 口都会得到新键,也就是 + * 重新学一次——取保守的那一边:结论严格绑在学它的那条物理路径上。控制器 + * 本身是不是变量并无定论(2026-09-15 实测 alt7 在 74:00.4 与 0a:00.0 上都 + * 停摆),所以它只进键、不参与选档。 + * + * Python 侧 core/gripper/devices/uvc_camera_service.py 用同一套规则造键去 + * 查这个目录,两边的清洗规则必须逐字一致。 */ +static void mode_state_key(const camera_config_t *config, char *out, + size_t size) { + char raw[192]; + size_t written = 0; + + snprintf(raw, sizeof(raw), "%04x_%04x_%s_%s", config->vid, config->pid, + config->usb_controller[0] != '\0' ? config->usb_controller + : "unknown", + config->usb_serial[0] != '\0' ? config->usb_serial : "noserial"); + for (const char *cursor = raw; *cursor != '\0' && written + 1 < size; + ++cursor) { + char c = *cursor; + int safe = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c == '-'; + out[written++] = safe ? c : '_'; + } + out[written] = '\0'; +} + +/* 把学到的档位写进 state_dir,下次开机直接用它,不必再赔一次停摆窗口。 + * 尽力而为:目录建不出来、盘写不进去都只记日志,绝不能因此让相机起不来。 */ +static void persist_mode_choice(const camera_state_t *camera) { + char key[200]; + char path[PATH_MAX]; + char temporary[PATH_MAX]; + FILE *file; + + if (camera->config.state_dir[0] == '\0') { + return; + } + mode_state_key(&camera->config, key, sizeof(key)); + if (snprintf(path, sizeof(path), "%s/%s.mode", camera->config.state_dir, + key) >= (int)sizeof(path) || + snprintf(temporary, sizeof(temporary), "%s.tmp.%d", path, + (int)getpid()) >= (int)sizeof(temporary)) { + fprintf(stderr, "[%s] state path too long; not persisting mode\n", + camera->config.name); + return; + } + if (mkdir(camera->config.state_dir, 0755) != 0 && errno != EEXIST) { + fprintf(stderr, "[%s] cannot create state dir %s: %s\n", + camera->config.name, camera->config.state_dir, + strerror(errno)); + return; + } + file = fopen(temporary, "w"); + if (file == NULL) { + fprintf(stderr, "[%s] cannot write %s: %s\n", camera->config.name, + temporary, strerror(errno)); + return; + } + fprintf(file, "altsetting=%d\npayload=%d\n", + camera->config.forced_altsetting, camera->config.forced_payload); + fflush(file); + fsync(fileno(file)); + fclose(file); + if (rename(temporary, path) != 0) { + fprintf(stderr, "[%s] cannot install %s: %s\n", camera->config.name, + path, strerror(errno)); + unlink(temporary); + return; + } + fprintf(stderr, "[%s] remembered altsetting=%d payload=%d for this " + "camera/controller in %s\n", camera->config.name, + camera->config.forced_altsetting, camera->config.forced_payload, + path); +} + +static int validate_config(const camera_config_t *config, size_t index) { + if (config->name[0] == '\0' || config->vid <= 0 || config->pid <= 0 || + config->usb_bus < 0 || config->usb_port_path[0] == '\0' || + config->socket_path[0] == '\0' || config->streaming_interface < 0 || + config->forced_altsetting < 0 || config->forced_payload <= 0 || + config->width <= 0 || config->height <= 0 || config->fps <= 0 || + strcasecmp(config->format, "MJPEG") != 0) { + fprintf(stderr, "invalid camera config at index %zu\n", index); + return -1; + } + if (!is_supported_device(config)) { + fprintf(stderr, "%s: unsupported UVC device %04x:%04x; only Sightac " + "0c45:636f and DECXIN 1bcf:2d4f are supported\n", + config->name, config->vid, config->pid); + return -1; + } + if (config->vid == 0x0c45 && config->pid == 0x636f && + (config->width != 640 || config->height != 480 || config->fps != 30)) { + fprintf(stderr, "%s: unsupported Sightac mode; expected 640x480 " + "MJPEG@30\n", config->name); + return -1; + } + if (config->vid == 0x1bcf && config->pid == 0x2d4f && + (config->width != 1280 || config->height != 960 || config->fps != 30)) { + fprintf(stderr, "%s: unsupported DECXIN mode; expected 1280x960 " + "MJPEG@30\n", config->name); + return -1; + } + /* 档位对必须整体命中表里某一项。只查「alt 在表里」是不够的:alt 和 + * payload 是一个整体(alt7 的端点就是 1280 B/包),把 7 和 944 拼在 + * 一起会让 libuvc 用 alt7 的端点去跑 944 的预算,而 944 只是 COMMIT + * 上写的数——2026-09-15 主程序连不上夹爪就是这两项被拆开配出来的。 */ + { + size_t count = 0; + mode_table_for(config, &count); + if (mode_index_for(config) < count) { + return 0; + } + } + fprintf(stderr, "%s: unsupported altsetting pair alt=%d payload=%d; this " + "camera accepts only the pairs in the service's mode table\n", + config->name, config->forced_altsetting, config->forced_payload); + return -1; +} + +static int configs_conflict(const camera_config_t *left, + const camera_config_t *right) { + if (strcmp(left->socket_path, right->socket_path) == 0) { + return 1; + } + return left->vid == right->vid && left->pid == right->pid && + left->usb_bus == right->usb_bus && + strcmp(left->usb_port_path, right->usb_port_path) == 0; +} + +static int load_config(const char *path, camera_config_t *configs, + size_t *count) { + FILE *file; + char line[MAX_LINE]; + camera_config_t *current = NULL; + size_t index = 0; + + file = fopen(path, "r"); + if (file == NULL) { + fprintf(stderr, "cannot open config %s: %s\n", path, strerror(errno)); + return -1; + } + while (fgets(line, sizeof(line), file) != NULL) { + char *text = trim(line); + char *equals; + if (*text == '\0' || *text == '#' || *text == ';') { + continue; + } + if (*text == '[') { + char *close = strchr(text, ']'); + if (close == NULL || index >= MAX_CAMERAS) { + fclose(file); + return -1; + } + *close = '\0'; + set_defaults(&configs[index]); + snprintf(configs[index].name, sizeof(configs[index].name), + "%s", trim(text + 1)); + current = &configs[index++]; + continue; + } + if (current == NULL || (equals = strchr(text, '=')) == NULL) { + fclose(file); + return -1; + } + *equals = '\0'; + { + char *key = trim(text); + char *value = trim(equals + 1); + char *comment = strchr(value, '#'); + if (comment != NULL) { + *comment = '\0'; + value = trim(value); + } + if (assign_key(current, key, value) < 0) { + fprintf(stderr, "invalid config value %s=%s\n", key, value); + fclose(file); + return -1; + } + } + } + fclose(file); + if (index == 0 || index > MAX_CAMERAS) { + return -1; + } + for (size_t i = 0; i < index; ++i) { + if (validate_config(&configs[i], i) != 0) { + return -1; + } + for (size_t j = 0; j < i; ++j) { + if (configs_conflict(&configs[i], &configs[j])) { + fprintf(stderr, + "camera config conflict between %s and %s " + "(duplicate output or USB identity)\n", + configs[j].name, configs[i].name); + return -1; + } + } + } + *count = index; + return 0; +} + +static int uvc_port_path(uvc_device_t *device, char *buffer, + size_t buffer_size) { + uint8_t ports[8]; + int count; + size_t used = 0; + count = uvc_get_port_numbers(device, ports, sizeof(ports)); + if (count < 0) { + return -1; + } + buffer[0] = '\0'; + for (int i = 0; i < count; ++i) { + int written = snprintf(buffer + used, buffer_size - used, "%s%u", + i == 0 ? "" : ".", ports[i]); + if (written < 0 || (size_t)written >= buffer_size - used) { + return -1; + } + used += (size_t)written; + } + return 0; +} + +static uvc_error_t open_matching_device(uvc_context_t *context, + const camera_config_t *config, + uvc_device_handle_t **result, + char *actual_path, + size_t actual_path_size) { + uvc_device_t **list = NULL; + uvc_error_t error; + *result = NULL; + error = uvc_get_device_list(context, &list); + if (error != UVC_SUCCESS) { + return error; + } + for (size_t i = 0; list[i] != NULL; ++i) { + uvc_device_descriptor_t *descriptor = NULL; + uvc_device_handle_t *candidate = NULL; + error = uvc_get_device_descriptor(list[i], &descriptor); + if (error != UVC_SUCCESS || descriptor == NULL || + descriptor->idVendor != (uint16_t)config->vid || + descriptor->idProduct != (uint16_t)config->pid || + (int)uvc_get_bus_number(list[i]) != config->usb_bus) { + uvc_free_device_descriptor(descriptor); + continue; + } + if (uvc_port_path(list[i], actual_path, actual_path_size) != 0 || + strcmp(actual_path, config->usb_port_path) != 0) { + uvc_free_device_descriptor(descriptor); + continue; + } + error = uvc_open(list[i], &candidate); + uvc_free_device_descriptor(descriptor); + if (error != UVC_SUCCESS || candidate == NULL) { + fprintf(stderr, "[%s] matched bus=%d port=%s open failed: %s (%d)\n", + config->name, config->usb_bus, actual_path, + uvc_strerror(error), error); + uvc_free_device_list(list, 1); + return error == UVC_SUCCESS ? UVC_ERROR_IO : error; + } + *result = candidate; + uvc_free_device_list(list, 1); + return UVC_SUCCESS; + } + uvc_free_device_list(list, 1); + return UVC_ERROR_NO_DEVICE; +} + +static uint64_t timespec_nanoseconds(struct timespec value) { + if (value.tv_sec < 0 || value.tv_nsec < 0 || value.tv_nsec >= 1000000000L) { + return 0; + } + return (uint64_t)value.tv_sec * 1000000000ull + + (uint64_t)value.tv_nsec; +} + +static int configure_ipc(camera_state_t *camera) { + struct sockaddr_un address; + mode_t old_umask; + size_t path_length = strlen(camera->config.socket_path); + + if (path_length >= sizeof(address.sun_path)) { + fprintf(stderr, "[%s] Unix socket path is too long: %s\n", + camera->config.name, camera->config.socket_path); + return -1; + } + /* + * Use a byte-stream Unix socket instead of SOCK_SEQPACKET. A DECXIN + * MJPEG frame can exceed the kernel's AF_UNIX packet-size limit; a + * length-bearing stream header avoids EMSGSIZE while retaining one + * complete frame per read_packet() at the protocol level. + */ + camera->listen_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (camera->listen_fd < 0) { + fprintf(stderr, "[%s] create Unix socket failed: %s\n", + camera->config.name, strerror(errno)); + return -1; + } + memset(&address, 0, sizeof(address)); + address.sun_family = AF_UNIX; + memcpy(address.sun_path, camera->config.socket_path, path_length + 1); + unlink(camera->config.socket_path); + old_umask = umask(0); + if (bind(camera->listen_fd, (struct sockaddr *)&address, + sizeof(address)) < 0) { + umask(old_umask); + fprintf(stderr, "[%s] bind Unix socket %s failed: %s\n", + camera->config.name, camera->config.socket_path, + strerror(errno)); + close(camera->listen_fd); + camera->listen_fd = -1; + return -1; + } + umask(old_umask); + if (chmod(camera->config.socket_path, 0666) != 0 || + listen(camera->listen_fd, 1) != 0) { + fprintf(stderr, "[%s] prepare Unix socket %s failed: %s\n", + camera->config.name, camera->config.socket_path, + strerror(errno)); + close(camera->listen_fd); + camera->listen_fd = -1; + unlink(camera->config.socket_path); + return -1; + } + fprintf(stderr, "[%s] IPC socket=%s format=MJPEG size=%dx%d fps=%d\n", + camera->config.name, camera->config.socket_path, + camera->config.width, camera->config.height, camera->config.fps); + return 0; +} + +static int accept_ipc_client(camera_state_t *camera) { + while (!g_stop && camera->client_fd < 0) { + struct pollfd descriptor = { + .fd = camera->listen_fd, + .events = POLLIN, + .revents = 0, + }; + int ready = poll(&descriptor, 1, 500); + if (ready < 0 && errno == EINTR) { + continue; + } + if (ready <= 0) { + continue; + } + camera->client_fd = accept(camera->listen_fd, NULL, NULL); + if (camera->client_fd < 0 && errno != EINTR) { + return errno; + } + } + return camera->client_fd >= 0 ? 0 : ECANCELED; +} + +static int send_all(int fd, const void *data, size_t length) { + const uint8_t *cursor = (const uint8_t *)data; + while (length > 0) { + ssize_t sent = send(fd, cursor, length, MSG_NOSIGNAL); + if (sent < 0) { + if (errno == EINTR) { + continue; + } + return errno; + } + if (sent == 0) { + return EPIPE; + } + cursor += (size_t)sent; + length -= (size_t)sent; + } + return 0; +} + +static int write_frame(camera_state_t *camera, const frame_item_t *item) { + ipc_frame_header_t header; + int error; + + if (accept_ipc_client(camera) != 0) { + return g_stop ? ECANCELED : ENOTCONN; + } + memset(&header, 0, sizeof(header)); + header.magic = IPC_MAGIC; + header.version = IPC_VERSION; + header.header_bytes = (uint16_t)sizeof(header); + header.sequence = item->sequence; + header.width = (uint32_t)camera->config.width; + header.height = (uint32_t)camera->config.height; + header.fourcc = (uint32_t)('M' | ('J' << 8) | ('P' << 16) | ('G' << 24)); + header.payload_bytes = (uint32_t)item->length; + /* + * Preserve the timestamp assigned by libuvc when the complete UVC frame + * was received. The socket writer can run later (or burst after a + * client connects), so send time would measure IPC scheduling rather than + * camera acquisition cadence. + */ + header.timestamp_ns = item->capture_timestamp_ns; + + error = send_all(camera->client_fd, &header, sizeof(header)); + if (error == 0) { + error = send_all(camera->client_fd, item->data, item->length); + } + /* Any partial write invalidates byte-stream framing, including timeout. */ + if (error != 0) { + close(camera->client_fd); + camera->client_fd = -1; + } + return error; +} + +static void enqueue_frame(uvc_frame_t *frame, camera_state_t *camera) { + uint8_t *copy; + size_t tail; + uint64_t capture_timestamp_ns; + uint8_t *source = NULL; + size_t source_length = 0; + uint32_t source_sequence = 0; + if (frame == NULL || frame->data == NULL || frame->data_bytes == 0 || + frame->frame_format != UVC_FRAME_FORMAT_MJPEG) { + return; + } + if (!is_complete_mjpeg_payload(frame->data, frame->data_bytes)) { + int should_log; + uint64_t bad_count; + pthread_mutex_lock(&camera->mutex); + camera->bad_jpeg_frames++; + camera->bad_jpeg_logs++; + camera->frames_dropped++; + bad_count = camera->bad_jpeg_frames; + should_log = bad_count == 1 || camera->bad_jpeg_logs % 100 == 0; + pthread_mutex_unlock(&camera->mutex); + if (should_log) { + fprintf(stderr, + "[%s] dropped incomplete MJPEG sequence=%u bytes=%zu " + "bad=%llu\n", + camera->config.name, frame->sequence, frame->data_bytes, + (unsigned long long)bad_count); + } + /* Never fabricate a new sample from an older image. The sequence + * gap is intentional and preserves honest acquisition timestamps. */ + return; + } + source = frame->data; + source_length = frame->data_bytes; + source_sequence = frame->sequence; + capture_timestamp_ns = timespec_nanoseconds(frame->capture_time_finished); + if (capture_timestamp_ns == 0) { + pthread_mutex_lock(&camera->mutex); + camera->frames_dropped++; + pthread_mutex_unlock(&camera->mutex); + return; + } + copy = malloc(source_length); + if (copy == NULL) { + pthread_mutex_lock(&camera->mutex); + camera->frames_dropped++; + pthread_mutex_unlock(&camera->mutex); + return; + } + memcpy(copy, source, source_length); + pthread_mutex_lock(&camera->mutex); + if (camera->stopping) { + free(copy); + pthread_mutex_unlock(&camera->mutex); + return; + } + if (camera->count == FRAME_QUEUE_DEPTH) { + free(camera->queue[camera->head].data); + camera->head = (camera->head + 1) % FRAME_QUEUE_DEPTH; + camera->count--; + camera->frames_dropped++; + } + tail = (camera->head + camera->count) % FRAME_QUEUE_DEPTH; + camera->queue[tail].data = copy; + camera->queue[tail].length = source_length; + camera->queue[tail].sequence = source_sequence; + camera->queue[tail].capture_timestamp_ns = capture_timestamp_ns; + camera->count++; + camera->frames_received++; + + pthread_cond_signal(&camera->condition); + pthread_mutex_unlock(&camera->mutex); +} + +static void frame_callback(uvc_frame_t *frame, void *user_ptr) { + enqueue_frame(frame, (camera_state_t *)user_ptr); +} + +static void *writer_main(void *user_ptr) { + camera_state_t *camera = (camera_state_t *)user_ptr; + for (;;) { + frame_item_t item; + memset(&item, 0, sizeof(item)); + pthread_mutex_lock(&camera->mutex); + while (camera->count == 0 && !camera->stopping) { + pthread_cond_wait(&camera->condition, &camera->mutex); + } + if (camera->count == 0 && camera->stopping) { + pthread_mutex_unlock(&camera->mutex); + break; + } + item = camera->queue[camera->head]; + camera->queue[camera->head].data = NULL; + camera->head = (camera->head + 1) % FRAME_QUEUE_DEPTH; + camera->count--; + pthread_mutex_unlock(&camera->mutex); + + int write_error = write_frame(camera, &item); + if (write_error == 0) { + pthread_mutex_lock(&camera->mutex); + camera->frames_output++; + pthread_mutex_unlock(&camera->mutex); + } else if (write_error == ECANCELED && g_stop) { + /* Normal shutdown: do not report queued frames canceled by the + * stop signal as an output failure. */ + } else { + pthread_mutex_lock(&camera->mutex); + camera->write_errors++; + pthread_mutex_unlock(&camera->mutex); + fprintf(stderr, "[%s] output write failed: %s (%d)\n", + camera->config.name, strerror(write_error), write_error); + } + free(item.data); + } + return NULL; +} + +static double monotonic_seconds(void) { + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) { + return 0.0; + } + return (double)now.tv_sec + (double)now.tv_nsec / 1000000000.0; +} + +static void report_stats(camera_state_t *camera, double elapsed, + uint64_t previous_received, + uint64_t previous_output, + uint64_t previous_dropped, + uint64_t previous_bad_jpeg) { + uint64_t received; + uint64_t output; + uint64_t dropped; + uint64_t bad_jpeg; + uint64_t bad_replaced; + uint64_t write_errors; + size_t queued; + + pthread_mutex_lock(&camera->mutex); + received = camera->frames_received; + output = camera->frames_output; + dropped = camera->frames_dropped; + bad_jpeg = camera->bad_jpeg_frames; + bad_replaced = camera->bad_jpeg_replaced; + write_errors = camera->write_errors; + queued = camera->count; + pthread_mutex_unlock(&camera->mutex); + if (elapsed <= 0.0) { + return; + } + fprintf(stderr, + "[%s] fps_in=%.2f fps_out=%.2f received=%llu output=%llu " + "dropped=%llu (+%llu) bad_jpeg=%llu (+%llu) " + "bad_replaced=%llu write_errors=%llu queue=%zu\n", + camera->config.name, + (double)(received - previous_received) / elapsed, + (double)(output - previous_output) / elapsed, + (unsigned long long)received, (unsigned long long)output, + (unsigned long long)dropped, + (unsigned long long)(dropped - previous_dropped), + (unsigned long long)bad_jpeg, + (unsigned long long)(bad_jpeg - previous_bad_jpeg), + (unsigned long long)bad_replaced, + (unsigned long long)write_errors, queued); +} + +static void close_ipc(camera_state_t *camera) { + pthread_mutex_lock(&camera->mutex); + camera->stopping = 1; + pthread_cond_broadcast(&camera->condition); + pthread_mutex_unlock(&camera->mutex); + if (camera->writer_thread != 0) { + pthread_join(camera->writer_thread, NULL); + camera->writer_thread = 0; + } + for (size_t i = 0; i < FRAME_QUEUE_DEPTH; ++i) { + free(camera->queue[i].data); + camera->queue[i].data = NULL; + } + camera->head = 0; + camera->count = 0; + if (camera->client_fd >= 0) { + close(camera->client_fd); + camera->client_fd = -1; + } + if (camera->listen_fd >= 0) { + close(camera->listen_fd); + camera->listen_fd = -1; + } + unlink(camera->config.socket_path); +} + +static void reset_usb_device(camera_state_t *camera, + uvc_device_handle_t *device) { + struct libusb_device_handle *usb_handle = uvc_get_libusb_handle(device); + libusb_reset_device_fn reset_device = resolve_libusb_reset_device(); + if (usb_handle == NULL || reset_device == NULL) { + fprintf(stderr, + "[%s] cannot reset device (handle=%p symbol=%p)\n", + camera->config.name, (void *)usb_handle, (void *)reset_device); + return; + } + int reset_rc = reset_device(usb_handle); + fprintf(stderr, "[%s] usb reset: rc=%d (%s)\n", camera->config.name, + reset_rc, uvc_strerror(reset_rc)); +} + +/* 上一次复位之后留给客户端的余量:客户端只等 10 秒就把服务收掉,所以 + * 「第几次失败才升级成复位」是拿这个窗口倒推出来的,不是拍的。 + * 实测卡死设备的失败很快(每次约 0.3 秒 + 1 秒间隔),第 2 次失败触发 + * 复位的时刻在 t≈2 秒,重枚举加重开约 1 秒,t≈3 秒就能出帧——10 秒够用。 + * 门槛设成「连续 2 次」而不是「1 次」:单次失败往往只是设备还没缓过来 + * (那种情况重建上下文就够,实测 6/6 全恢复),一失败就复位会白白打扰 + * 同 Hub 的另外两路。 + * + * 上限 USB_RESET_LIMIT 次:设备真坏了的时候,不设上限会变成每 2 秒复位 + * 一次、把另外两路一直按在地上。打满就不再复位,退回普通重试。 */ +#define HARD_FAILURES_BEFORE_RESET 1 +#define USB_RESET_LIMIT 3 + +/* 停摆够次数就退一档,并记住这次选择。 + * + * 为什么要有这条路(而不是起手就用最保守档、或者按机器写死):起手档已经 + * 是最保守的那一档了,这条路是给**操作者手动把 ini 改成高带宽档**兜底的 + * ——想要 alt7 那点每帧余量就改,真撑不住时服务停两次自己退回 alt6 并把结论 + * 落盘,下次开机直接用,不用人去记哪台机器该用哪档。按机器写死则是另一回事: + * 机架插在哪条总线、哪台机器都不固定,写死要每台各配一份,而且写死的那个 + * 判断(「这台控制器扛不扛得住」)本身就没被测准过——试错要便宜得多。 + * + * 返回 1 表示已降档。 */ +static int maybe_downgrade_altsetting(camera_state_t *camera) { + size_t count = 0; + const altsetting_mode_t *modes = mode_table_for(&camera->config, &count); + size_t index = mode_index_for(&camera->config); + + if (modes == NULL || index + 1 >= count) { + return 0; + } + camera->config.forced_altsetting = modes[index + 1].altsetting; + camera->config.forced_payload = modes[index + 1].payload; + /* 两个计数都要归零,各自对应一条降档触发路径。漏掉哪个,那条路就 + * 只能降一次:stalls 由本函数清零,open_failures 若不清零,判等 + * (== 门槛)在降档后永远不再成立,梯子在「开不起来」那条路上走 + * 完一格就卡死,后两档形同不存在。 */ + camera->stalls_at_mode = 0; + camera->open_failures_at_mode = 0; + persist_mode_choice(camera); + return 1; +} + +static void escalate_to_usb_reset(camera_state_t *camera, + uvc_device_handle_t *device) { + if (camera->hard_failures < HARD_FAILURES_BEFORE_RESET) { + return; + } + if (camera->usb_resets >= USB_RESET_LIMIT) { + return; + } + camera->usb_resets++; + reset_usb_device(camera, device); +} + +/* 失败路径的收尾。复位要抢在 uvc_stop_streaming 之前: + * 卡死的设备上 uvc_stop_streaming 会一直等它那批永远回不来的等时传输, + * 实测能卡满客户端那 2 秒宽限期、被 SIGKILL 打断——进程死在这中间, + * 设备就停在激活的 alt setting 上,下一轮启动照样起不来(用户 09:24 + * 的日志正是断在 startup failed 与 usb reset 之间)。复位会取消在途 + * 传输,先复位再停流,这条路径才走得完。 */ +static void teardown_failed_open(camera_state_t *camera, + uvc_device_handle_t *device) { + escalate_to_usb_reset(camera, device); + uvc_stop_streaming(device); + uvc_close(device); + close_ipc(camera); +} + +static int run_camera_once(camera_state_t *camera, uvc_context_t *context) { + uvc_device_handle_t *device = NULL; + uvc_stream_ctrl_t control; + char actual_path[64] = {0}; + uvc_error_t error; + double previous_report = monotonic_seconds(); + uint64_t previous_received = 0; + uint64_t previous_output = 0; + uint64_t previous_dropped = 0; + uint64_t previous_bad_jpeg = 0; + + pthread_mutex_lock(&camera->mutex); + uint64_t initial_received = camera->frames_received; + /* 每次重开都要把上报基线对齐到当前累计值。留在 0 会让重开后的第一次 + * 上报把「进程启动至今的全部帧数」当成本窗口的增量,算出 200+fps 这种 + * 假速率(纯日志问题,不影响出帧,但会把人带偏)。 */ + previous_received = camera->frames_received; + previous_output = camera->frames_output; + previous_dropped = camera->frames_dropped; + previous_bad_jpeg = camera->bad_jpeg_frames; + camera->stopping = 0; + pthread_mutex_unlock(&camera->mutex); + error = open_matching_device(context, &camera->config, &device, + actual_path, sizeof(actual_path)); + if (error != UVC_SUCCESS) { + fprintf(stderr, "[%s] device %04x:%04x bus=%d port=%s unavailable: %s\n", + camera->config.name, camera->config.vid, camera->config.pid, + camera->config.usb_bus, camera->config.usb_port_path, + uvc_strerror(error)); + close_ipc(camera); + return -1; + } + /* 在协商之前把 ini 里的档位钉到设备句柄上。libuvc 自己的编译期表只是 + * 兜底:真正决定用哪一档的是这份 ini,而 ini 里的值来自扫描程序实测的 + * 端点描述符、或者上一轮学到的结论。 */ + error = uvc_set_altsetting_override(device, camera->config.forced_altsetting, + (unsigned int)camera->config.forced_payload); + if (error != UVC_SUCCESS) { + fprintf(stderr, "[%s] cannot apply altsetting override alt=%d payload=%d: %s\n", + camera->config.name, camera->config.forced_altsetting, + camera->config.forced_payload, uvc_strerror(error)); + teardown_failed_open(camera, device); + return -1; + } + memset(&control, 0, sizeof(control)); + error = uvc_get_stream_ctrl_format_size( + device, &control, UVC_FRAME_FORMAT_MJPEG, + camera->config.width, camera->config.height, camera->config.fps); + if (error != UVC_SUCCESS || + control.bInterfaceNumber != camera->config.streaming_interface) { + fprintf(stderr, "[%s] UVC format/interface negotiation failed: %s interface=%u expected=%d\n", + camera->config.name, uvc_strerror(error), + control.bInterfaceNumber, camera->config.streaming_interface); + teardown_failed_open(camera, device); + return -1; + } + fprintf(stderr, + "[%s] vidpid=%04x:%04x bus=%d port=%s interface=%u alt=%d payload=%d " + "format=MJPEG size=%dx%d fps=%d socket=%s negotiated_payload=%u\n", + camera->config.name, camera->config.vid, camera->config.pid, + camera->config.usb_bus, actual_path, control.bInterfaceNumber, + camera->config.forced_altsetting, camera->config.forced_payload, + camera->config.width, camera->config.height, camera->config.fps, + camera->config.socket_path, control.dwMaxPayloadTransferSize); + error = uvc_start_streaming(device, &control, frame_callback, camera, 0); + if (error != UVC_SUCCESS) { + fprintf(stderr, "[%s] uvc_start_streaming failed: %s\n", + camera->config.name, uvc_strerror(error)); + teardown_failed_open(camera, device); + return -1; + } + /* Publish IPC only once MJPG negotiation, STREAMON and a valid frame + * have succeeded. Socket existence is a readiness promise to the parent. */ + int first_frame = 0; + int restarting = camera->reconnects > 0; + double first_frame_timeout = restarting + ? RESTART_FIRST_FRAME_TIMEOUT_SECONDS : FIRST_FRAME_TIMEOUT_SECONDS; + double deadline = monotonic_seconds() + first_frame_timeout; + while (!g_stop && monotonic_seconds() < deadline) { + pthread_mutex_lock(&camera->mutex); + first_frame = camera->frames_received > initial_received; + pthread_mutex_unlock(&camera->mutex); + if (first_frame) break; + usleep(10000); + } + if (!first_frame || configure_ipc(camera) != 0) { + fprintf(stderr, "[%s] startup failed: no valid MJPG frame or IPC unavailable\n", camera->config.name); + teardown_failed_open(camera, device); + return -1; + } + if (pthread_create(&camera->writer_thread, NULL, writer_main, camera) != 0) { + fprintf(stderr, "[%s] writer thread creation failed\n", camera->config.name); + uvc_stop_streaming(device); + uvc_close(device); + close_ipc(camera); + return -1; + } + int stalled = 0; + double last_progress = monotonic_seconds(); + double stream_started = last_progress; + int clean_run_credited = 0; + uint64_t last_received = 0; + pthread_mutex_lock(&camera->mutex); + last_received = camera->frames_received; + pthread_mutex_unlock(&camera->mutex); + + while (!g_stop) { + sleep(1); + if (g_parent_pid > 1 && getppid() != g_parent_pid) { + fprintf(stderr, + "[%s] parent %d exited; stopping stream\n", + camera->config.name, g_parent_pid); + g_stop = 1; + break; + } + double now = monotonic_seconds(); + if (now - previous_report >= 5.0) { + report_stats(camera, now - previous_report, + previous_received, previous_output, + previous_dropped, previous_bad_jpeg); + pthread_mutex_lock(&camera->mutex); + previous_received = camera->frames_received; + previous_output = camera->frames_output; + previous_dropped = camera->frames_dropped; + previous_bad_jpeg = camera->bad_jpeg_frames; + pthread_mutex_unlock(&camera->mutex); + previous_report = now; + } + /* 停滞看门狗:见 STREAM_STALL_TIMEOUT_SECONDS 的注释。这里不能 + * 只等 g_stop——流死了 g_stop 永远不会置位,重试循环也就永远 + * 轮不到,整路相机就此静默报废。 */ + pthread_mutex_lock(&camera->mutex); + uint64_t received_now = camera->frames_received; + pthread_mutex_unlock(&camera->mutex); + /* 稳定跑够 CLEAN_RUN_SECONDS 就把本档位的停摆计数清零:说明这个档位 + * 是撑得住的,之前那次停摆是设备自己抽了一下。 */ + if (!clean_run_credited && now - stream_started >= CLEAN_RUN_SECONDS) { + clean_run_credited = 1; + camera->stalls_at_mode = 0; + } + if (received_now != last_received) { + last_received = received_now; + last_progress = now; + } else if (now - last_progress >= STREAM_STALL_TIMEOUT_SECONDS) { + pthread_mutex_lock(&camera->mutex); + camera->stalls++; + pthread_mutex_unlock(&camera->mutex); + fprintf(stderr, + "[%s] stream stalled: no frame for %.1fs " + "(received=%llu); restarting UVC stream\n", + camera->config.name, now - last_progress, + (unsigned long long)received_now); + stalled = 1; + break; + } + } + uvc_stop_streaming(device); + uvc_close(device); + close_ipc(camera); + /* 返回 0 会被 camera_main 当成正常收尾而退出重试循环;停摆用 +1 单独 + * 标记,让 camera_main 知道还要重建 libusb 上下文。 */ + return stalled ? 1 : 0; +} + +static void *camera_main(void *user_ptr) { + camera_state_t *camera = (camera_state_t *)user_ptr; + uvc_context_t *context = NULL; + uvc_error_t error = uvc_init(&context, NULL); + if (error != UVC_SUCCESS) { + fprintf(stderr, "[%s] uvc_init failed: %s\n", camera->config.name, + uvc_strerror(error)); + return NULL; + } + while (!g_stop) { + if (g_parent_pid > 1 && getppid() != g_parent_pid) { + fprintf(stderr, + "[SUPERVISION] parent %d exited; stopping service\n", + g_parent_pid); + g_stop = 1; + break; + } + int rc = run_camera_once(camera, context); + if (rc == 0) { + break; + } + camera->reconnects++; + if (rc > 0) { + /* 停摆那次是开得起来、出过帧的,设备侧没卡死;把连续失败清零, + * 免得几次停摆的失败凑够数、误触发 USB 复位去打扰另外两路。 */ + camera->hard_failures = 0; + /* 开得起来 ⇒ 这个档位至少被控制器接受了,清掉开不起来的计数。 */ + camera->open_failures_at_mode = 0; + /* 当前档位连着停够次数就退一档(并落盘)。降档要在重建上下文 + * 之前生效——重开的流才会用新的 alt/payload。 */ + camera->stalls_at_mode++; + if (camera->stalls_at_mode == STALLS_BEFORE_ALTSETTING_DOWNGRADE) { + /* 计数要在降档之前抓下来:maybe_downgrade_altsetting 成功时 + * 会把它清零,之后再读就只能打出「0 stalls」,正好把最该 + * 看的那次降级说成没有依据。 */ + unsigned stalls = camera->stalls_at_mode; + int previous_alt = camera->config.forced_altsetting; + if (maybe_downgrade_altsetting(camera)) { + fprintf(stderr, + "[%s] %u stalls at alt=%d; dropping to alt=%d " + "payload=%d\n", + camera->config.name, stalls, previous_alt, + camera->config.forced_altsetting, + camera->config.forced_payload); + } else { + fprintf(stderr, + "[%s] %u stalls but alt=%d is already the lowest " + "setting for this camera; staying put\n", + camera->config.name, stalls, + camera->config.forced_altsetting); + } + } + /* 停摆:同一个 libusb 上下文里的设备对象在复位后已经失效, + * 用它重开只会拿到一个永远不出帧的死句柄(表现为 + * 「negotiated OK 但 20 秒一帧没有」)。新进程能恢复、同进程 + * 重开不能,差别就在这里——重建上下文=拿到与「新进程」等价 + * 的干净枚举。 */ + fprintf(stderr, "[%s] rebuilding libusb context after stall\n", + camera->config.name); + uvc_exit(context); + context = NULL; + if (uvc_init(&context, NULL) != UVC_SUCCESS) { + fprintf(stderr, "[%s] uvc_init failed after stall; " + "camera thread exiting\n", camera->config.name); + return NULL; + } + } else { + /* 开不起来(rc<0):计数到第 2 次就升级成 USB 复位,见 + * escalate_to_usb_reset。 */ + camera->hard_failures++; + /* 复位也救不回来时,档位是剩下的嫌疑——可能在 STREAMON 阶段就 + * 排不下这个等时档,那样流根本不会启动,停摆那条路永远等不到。 */ + camera->open_failures_at_mode++; + if (camera->open_failures_at_mode == + OPEN_FAILURES_BEFORE_ALTSETTING_DOWNGRADE) { + /* 和停摆那条路一样,计数要在降档之前抓下来:成功降档会把 + * 它清零,之后再读就打不出触发这次降级的次数。 */ + unsigned failed = camera->open_failures_at_mode; + int previous_alt = camera->config.forced_altsetting; + if (maybe_downgrade_altsetting(camera)) { + fprintf(stderr, + "[%s] %u failed opens at alt=%d; dropping to " + "alt=%d payload=%d\n", + camera->config.name, failed, previous_alt, + camera->config.forced_altsetting, + camera->config.forced_payload); + } else { + fprintf(stderr, + "[%s] %u failed opens but alt=%d is already the " + "lowest setting for this camera; staying put\n", + camera->config.name, failed, + camera->config.forced_altsetting); + } + } + } + if (!g_stop) { + sleep(1); + } + } + uvc_exit(context); + return NULL; +} + +static void print_usage(const char *program) { + fprintf(stderr, + "usage: %s --config FILE [--validate-only] " + "[--parent-pid PID]\n", + program); +} + +/* SIGTERM 之后必须退得掉。客户端(uvc_camera_service.py)只给 2 秒宽限: + * terminate() → 等 2 秒 → kill()。超了就是 SIGKILL,进程死在 libusb 调用 + * 中间、设备停在激活的 alt setting 上,下一轮照样起不来——正是 2026-09-15 + * 09:24 那次事故的形状。 + * + * 光置 g_stop 不够:相机线程可能正陷在 uvc_open 的同步 libusb 调用里(卡死 + * 的设备上它不返回),永远走不到循环头那个 g_stop 判断,pthread_join 于是 + * 永远等下去。实测:生产二进制收到 SIGTERM 后 3 分钟不退,只攥着 DECXIN 的 + * fd,left/right 都已干净释放,日志停在断流那一刻——连 + * [SUPERVISION] parent exited 都没打出来。 + * + * 所以 join 必须有界:整体 1.5 秒、单路 0.8 秒(健康时三路是并行收尾的, + * 实测全程 0.56 秒,留足余量)。超时就 detach、继续走,main 一返回进程即 + * 结束——至少把能收的收干净了,跟客户端硬杀不是一回事。 + * + * 注意 join 循环同时就是主运行循环,所以正常运行时不能套这个截止时间, + * 只能短超时轮询着等 g_stop(见 main 里那段说明)。 */ +#define SHUTDOWN_JOIN_TOTAL_MS 1500 +#define SHUTDOWN_JOIN_PER_CAMERA_MS 800 +#define SHUTDOWN_JOIN_POLL_MS 200 + +/* 距 deadline 还有多少毫秒(≤0 表示已过期)。 */ +static long ms_until(const struct timespec *deadline) { + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + return (long)(deadline->tv_sec - now.tv_sec) * 1000L + + (long)(deadline->tv_nsec - now.tv_nsec) / 1000000L; +} + +/* 现在起 ms 毫秒之后的时刻。pthread_timedjoin_np 按 CLOCK_REALTIME 算。 */ +static struct timespec deadline_after_ms(long ms) { + struct timespec t; + clock_gettime(CLOCK_REALTIME, &t); + t.tv_sec += ms / 1000; + t.tv_nsec += (ms % 1000) * 1000000L; + if (t.tv_nsec >= 1000000000L) { + t.tv_sec += 1; + t.tv_nsec -= 1000000000L; + } + return t; +} + +int main(int argc, char **argv) { + const char *config_path = NULL; + int validate_only = 0; + camera_config_t configs[MAX_CAMERAS]; + camera_state_t cameras[MAX_CAMERAS]; + size_t camera_count = 0; + size_t started = 0; + struct sigaction action; + + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--config") == 0 && i + 1 < argc) { + config_path = argv[++i]; + } else if (strcmp(argv[i], "--validate-only") == 0) { + validate_only = 1; + } else if (strcmp(argv[i], "--parent-pid") == 0 && + i + 1 < argc) { + if (parse_int(argv[++i], &g_parent_pid) != 0 || + g_parent_pid <= 1) { + fprintf(stderr, "invalid --parent-pid\n"); + return 2; + } + } else { + print_usage(argv[0]); + return 2; + } + } + if (config_path == NULL || load_config(config_path, configs, + &camera_count) != 0) { + print_usage(argv[0]); + return 2; + } + if (validate_only) { + for (size_t i = 0; i < camera_count; ++i) { + fprintf(stdout, + "valid[%zu] name=%s vidpid=%04x:%04x bus=%d port=%s " + "interface=%d alt=%d payload=%d mode=%dx%d MJPEG@%d " + "socket=%s\n", + i, configs[i].name, configs[i].vid, configs[i].pid, + configs[i].usb_bus, configs[i].usb_port_path, + configs[i].streaming_interface, + configs[i].forced_altsetting, configs[i].forced_payload, + configs[i].width, configs[i].height, configs[i].fps, + configs[i].socket_path); + } + return 0; + } + memset(&action, 0, sizeof(action)); + action.sa_handler = request_stop; + sigemptyset(&action.sa_mask); + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); + + memset(cameras, 0, sizeof(cameras)); + for (size_t i = 0; i < camera_count; ++i) { + cameras[i].config = configs[i]; + cameras[i].listen_fd = -1; + cameras[i].client_fd = -1; + pthread_mutex_init(&cameras[i].mutex, NULL); + pthread_cond_init(&cameras[i].condition, NULL); + if (pthread_create(&cameras[i].thread, NULL, camera_main, + &cameras[i]) != 0) { + fprintf(stderr, "[%s] capture thread creation failed\n", + cameras[i].config.name); + g_stop = 1; + break; + } + started++; + } + /* 这个 join 循环**就是服务的主运行循环**——它在启动时进入、一直跑到 + * g_stop,不是「收尾时才走的一段」。所以截止时间不能在进循环前就算好 + * (那样正常运行时也会到点超时、服务自己退出),要等 g_stop 真置位时 + * 才开始计时。没置位时只用 200ms 短超时轮询,成本可忽略。 */ + int shutdown_started = 0; + struct timespec shutdown_deadline = {0, 0}; + for (size_t i = 0; i < started; ++i) { + int join_rc; + for (;;) { + long budget = SHUTDOWN_JOIN_POLL_MS; + if (g_stop) { + if (!shutdown_started) { + shutdown_deadline = + deadline_after_ms(SHUTDOWN_JOIN_TOTAL_MS); + shutdown_started = 1; + } + long left = ms_until(&shutdown_deadline); + budget = left < SHUTDOWN_JOIN_PER_CAMERA_MS + ? left : SHUTDOWN_JOIN_PER_CAMERA_MS; + /* 总预算已用尽:不再等,但还是要问一次——线程可能早就退了 + * (健康的那几路是并行收尾的),0 超时的 join 会立刻返回。 */ + if (budget < 0) { + budget = 0; + } + } + struct timespec limit = deadline_after_ms(budget); + join_rc = pthread_timedjoin_np(cameras[i].thread, NULL, &limit); + if (join_rc != ETIMEDOUT) { + break; + } + if (!g_stop) { + continue; /* 正常运行中的轮询到期,接着等 */ + } + if (budget == 0) { + break; /* 预算已尽,放弃这一路 */ + } + } + if (join_rc == ETIMEDOUT) { + /* 线程没在预算内退出——多半还陷在设备调用里。不能为它把整个 + * 进程陪进去,否则客户端 2 秒宽限一到就是 SIGKILL、设备留脏。 + * detach 后 main 一返回进程即结束,内核会替我们释放设备句柄。 + * 跳过下面的统计与销毁:那些结构线程可能还在用,销毁它们是 + * use-after-free。 */ + fprintf(stderr, + "[%s] 收尾超时:线程未在预算内退出(多半卡在设备调用里)," + "不再等它\n", cameras[i].config.name); + pthread_detach(cameras[i].thread); + continue; + } + pthread_mutex_lock(&cameras[i].mutex); + fprintf(stderr, "[%s] received=%llu output=%llu dropped=%llu " + "bad_jpeg=%llu bad_replaced=%llu write_errors=%llu " + "retries=%llu stalls=%llu usb_resets=%u\n", + cameras[i].config.name, + (unsigned long long)cameras[i].frames_received, + (unsigned long long)cameras[i].frames_output, + (unsigned long long)cameras[i].frames_dropped, + (unsigned long long)cameras[i].bad_jpeg_frames, + (unsigned long long)cameras[i].bad_jpeg_replaced, + (unsigned long long)cameras[i].write_errors, + (unsigned long long)cameras[i].reconnects, + (unsigned long long)cameras[i].stalls, + cameras[i].usb_resets); + pthread_mutex_unlock(&cameras[i].mutex); + pthread_cond_destroy(&cameras[i].condition); + pthread_mutex_destroy(&cameras[i].mutex); + } + return started == camera_count ? 0 : 1; +} diff --git a/collector/core/gripper/camera_service_src/tests/test_altsetting_ladder.c b/collector/core/gripper/camera_service_src/tests/test_altsetting_ladder.c new file mode 100644 index 0000000000000000000000000000000000000000..aea6b7937bb50c1e3a4ccad23df9d474e87db7ee --- /dev/null +++ b/collector/core/gripper/camera_service_src/tests/test_altsetting_ladder.c @@ -0,0 +1,202 @@ +/* Deterministic tests for the altsetting ladder. No USB devices involved. + * + * The ladder is the thing that lets one binary work both on controllers that + * can carry DECXIN's high-bandwidth isochronous setting and on those that + * cannot, so its two failure modes are worth pinning down: + * + * - silently accepting a pair the camera cannot do. alt and payload are one + * unit (alt7's endpoint *is* 1280 B/packet); pairing 7 with 944 is exactly + * the configuration that took the whole gripper down on 2026-09-15 with + * "unsupported DECXIN mode" -> rc=2. + * - silently refusing to step down, which leaves the camera wedged at a + * setting its controller cannot carry. + * - stepping down once and then jamming, because the counter that triggered + * the step is never cleared back below its threshold: the comparison is an + * equality against the threshold, so a counter left standing on it never + * fires again and every rung below the second is unreachable. + * + * The state-file name is also pinned, because uvc_camera_service.py has to + * derive the same key in Python to read the result back; the two are only kept + * in step by this assertion and its Python counterpart. + */ +#undef NDEBUG +#include +#include +#include +#include + +#define main camera_service_main +#include "../src/camera_service.c" +#undef main + +static camera_config_t make_camera(int vid, int pid, int width, int height) { + camera_config_t config; + set_defaults(&config); + snprintf(config.name, sizeof(config.name), "unit_1_test"); + config.vid = vid; + config.pid = pid; + config.usb_bus = 1; + snprintf(config.usb_port_path, sizeof(config.usb_port_path), "2.2.2"); + config.width = width; + config.height = height; + config.fps = 30; + snprintf(config.format, sizeof(config.format), "MJPEG"); + snprintf(config.socket_path, sizeof(config.socket_path), "/tmp/x.sock"); + snprintf(config.usb_serial, sizeof(config.usb_serial), "DECXIN-01"); + snprintf(config.usb_controller, sizeof(config.usb_controller), + "0000:74:00.4"); + return config; +} + +static camera_config_t make_decxin(void) { + camera_config_t config = make_camera(0x1bcf, 0x2d4f, 1280, 960); + config.forced_altsetting = 7; + config.forced_payload = 1280; + return config; +} + +static void test_accepts_every_rung_and_nothing_else(void) { + camera_config_t config = make_decxin(); + + assert(validate_config(&config, 0) == 0); /* alt7/1280, the preferred rung */ + config.forced_altsetting = 6; + config.forced_payload = 944; + assert(validate_config(&config, 0) == 0); /* alt6/944, the fallback rung */ + + /* Alt and payload are a matched pair, so a mixed pair must be refused even + * though both numbers appear in the table on their own. */ + config.forced_altsetting = 7; + config.forced_payload = 944; + assert(validate_config(&config, 0) == -1); + config.forced_altsetting = 6; + config.forced_payload = 1280; + assert(validate_config(&config, 0) == -1); + /* A pair nobody has measured must not be accepted on faith either. */ + config.forced_altsetting = 5; + config.forced_payload = 800; + assert(validate_config(&config, 0) == -1); + + config = make_camera(0x0c45, 0x636f, 640, 480); + config.forced_altsetting = 3; + config.forced_payload = 800; + assert(validate_config(&config, 0) == 0); + config.forced_altsetting = 4; /* the pre-2026-08-28 1600 B setting */ + config.forced_payload = 1600; + assert(validate_config(&config, 0) == -1); +} + +static void test_steps_down_one_rung_and_then_stops(void) { + camera_state_t camera; + memset(&camera, 0, sizeof(camera)); + camera.config = make_decxin(); + + assert(mode_index_for(&camera.config) == 0); + /* Both counters are driven to non-zero first: stepping down has to clear + * *each* of them. The thresholds are tested with ==, so a counter left + * standing at the threshold never fires again and that whole trigger path + * gets one step and then jams -- the rungs below it might as well not + * exist. Stalls and failed opens are separate paths and each clears its + * own; a downgrade is a fresh start for both. */ + camera.stalls_at_mode = 99; + camera.open_failures_at_mode = 99; + assert(maybe_downgrade_altsetting(&camera) == 1); + assert(camera.config.forced_altsetting == 6); + assert(camera.config.forced_payload == 944); + assert(mode_index_for(&camera.config) == 1); + assert(camera.stalls_at_mode == 0); + assert(camera.open_failures_at_mode == 0); + + /* alt6 is the last rung: a further stall must not invent a worse one. */ + assert(maybe_downgrade_altsetting(&camera) == 0); + assert(camera.config.forced_altsetting == 6); + assert(camera.config.forced_payload == 944); + + /* Sightac has a single rung, so it never steps anywhere. */ + camera.config = make_camera(0x0c45, 0x636f, 640, 480); + camera.config.forced_altsetting = 3; + camera.config.forced_payload = 800; + assert(maybe_downgrade_altsetting(&camera) == 0); + assert(camera.config.forced_altsetting == 3); + + /* A pair that is in no table at all must not be walked off the end. */ + camera.config = make_decxin(); + camera.config.forced_payload = 944; /* 7/944: refused by validate_config */ + assert(mode_index_for(&camera.config) == 2); + assert(maybe_downgrade_altsetting(&camera) == 0); +} + +static void test_downgrade_is_remembered_under_a_stable_key(void) { + char parent[] = "/tmp/ksq-ladder-test-XXXXXX"; + char state_dir[PATH_MAX]; + char expected[PATH_MAX]; + char contents[128]; + camera_state_t camera; + FILE *file; + size_t read_bytes; + + assert(mkdtemp(parent) != NULL); + /* A subdirectory that does not exist yet: persist_mode_choice creates it. */ + snprintf(state_dir, sizeof(state_dir), "%s/camera_modes", parent); + memset(&camera, 0, sizeof(camera)); + camera.config = make_decxin(); + snprintf(camera.config.state_dir, sizeof(camera.config.state_dir), "%s", + state_dir); + + assert(maybe_downgrade_altsetting(&camera) == 1); + + /* Key = vid_pid_controller_serial with everything outside [A-Za-z0-9-] + * replaced by '_'. uvc_camera_service._mode_state_key must produce this + * exact string for the learned value to be read back. */ + snprintf(expected, sizeof(expected), "%s/1bcf_2d4f_0000_74_00_4_DECXIN-01.mode", + state_dir); + file = fopen(expected, "r"); + assert(file != NULL); + read_bytes = fread(contents, 1, sizeof(contents) - 1, file); + contents[read_bytes] = '\0'; + fclose(file); + assert(strcmp(contents, "altsetting=6\npayload=944\n") == 0); + + /* No temp file may be left behind next to the result. */ + { + DIR *dir = opendir(state_dir); + struct dirent *entry; + int seen = 0; + assert(dir != NULL); + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] == '.') { + continue; + } + ++seen; + assert(strstr(entry->d_name, ".tmp.") == NULL); + } + closedir(dir); + assert(seen == 1); + } + + unlink(expected); + rmdir(state_dir); + rmdir(parent); +} + +static void test_missing_state_dir_is_not_fatal(void) { + camera_state_t camera; + memset(&camera, 0, sizeof(camera)); + camera.config = make_decxin(); + /* Empty state_dir means "do not remember anything" and must still step + * down in memory for the rest of this session. */ + assert(camera.config.state_dir[0] == '\0'); + assert(maybe_downgrade_altsetting(&camera) == 1); + assert(camera.config.forced_altsetting == 6); +} + +int main(void) { + /* validate_config reports refusals on stderr; that is the production + * behaviour and is expected here, so keep the test output readable. */ + freopen("/dev/null", "w", stderr); + test_accepts_every_rung_and_nothing_else(); + test_steps_down_one_rung_and_then_stops(); + test_downgrade_is_remembered_under_a_stable_key(); + test_missing_state_dir_is_not_fatal(); + printf("altsetting ladder: all assertions passed\n"); + return 0; +} diff --git a/collector/core/gripper/camera_service_src/tests/test_frame_integrity.c b/collector/core/gripper/camera_service_src/tests/test_frame_integrity.c new file mode 100644 index 0000000000000000000000000000000000000000..f8e76136a805f5a09f03c20439f5bf49b1ca5fe2 --- /dev/null +++ b/collector/core/gripper/camera_service_src/tests/test_frame_integrity.c @@ -0,0 +1,45 @@ +/* Test the actual callback and queue without opening USB devices. */ +#undef NDEBUG +#include +#define main camera_service_main +#include "../src/camera_service.c" +#undef main + +int main(void) { + camera_state_t camera = {0}; + uint8_t good[] = {0xff, 0xd8, 0x01, 0x02, 0xff, 0xd9}; + uint8_t short_frame[] = {0xff}; + uvc_frame_t frame = {0}; + pthread_mutex_init(&camera.mutex, NULL); + pthread_cond_init(&camera.condition, NULL); + frame.frame_format = UVC_FRAME_FORMAT_MJPEG; + frame.data = good; + frame.data_bytes = sizeof(good); + frame.sequence = 1; + frame.capture_time_finished.tv_sec = 2; + enqueue_frame(&frame, &camera); + assert(camera.count == 1); + assert(camera.queue[0].sequence == 1); + assert(camera.queue[0].capture_timestamp_ns == 2000000000ull); + frame.data = short_frame; + frame.data_bytes = sizeof(short_frame); + frame.sequence = 2; + frame.capture_time_finished.tv_sec = 3; + enqueue_frame(&frame, &camera); + assert(camera.count == 1); /* No old image under a new timestamp. */ + assert(camera.bad_jpeg_frames == 1); + assert(camera.frames_dropped == 1); + assert(camera.bad_jpeg_replaced == 0); + assert(camera.queue[0].capture_timestamp_ns == 2000000000ull); + frame.data = good; + frame.data_bytes = sizeof(good); + frame.sequence = 3; + enqueue_frame(&frame, &camera); + assert(camera.count == 2); + assert(camera.queue[1].sequence == 3); + assert(camera.queue[1].capture_timestamp_ns == 3000000000ull); + for (size_t i = 0; i < FRAME_QUEUE_DEPTH; ++i) free(camera.queue[i].data); + pthread_mutex_destroy(&camera.mutex); + pthread_cond_destroy(&camera.condition); + return 0; +} diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/CMakeLists.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b765ebe2be80bb08ddb99b20311f25d007dea5c4 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/CMakeLists.txt @@ -0,0 +1,230 @@ +cmake_minimum_required(VERSION 3.1) +project(libuvc + VERSION 0.0.7 + LANGUAGES C +) + +# Additional search scripts path for libusb-1.0, libjpeg, OpenCV +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) + +# Xcode and Visual Studio do not using CMAKE_BUILD_TYPE cache variable +# so we use Release build type only with single configuration generators. +if (NOT CMAKE_CONFIGURATION_TYPES) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, default to Release") + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) + endif() +endif() + +if(NOT CMAKE_BUILD_TARGET) + message(STATUS "No target type selected, default to both shared and static library") + set(CMAKE_BUILD_TARGET "Both" CACHE STRING "" FORCE) +endif() + +option(BUILD_EXAMPLE "Build example program" ON) +option(BUILD_TEST "Build test program" OFF) +option(ENABLE_UVC_DEBUGGING "Enable UVC debugging" OFF) + +set(libuvc_DESCRIPTION "A cross-platform library for USB video devices") +set(libuvc_URL "https://github.com/libuvc/libuvc") + +set(SOURCES + src/ctrl.c + src/ctrl-gen.c + src/device.c + src/diag.c + src/frame.c + src/init.c + src/stream.c + src/misc.c +) + +find_package(LibUSB) + +# JpegPkg name to differ from shipped with CMake +find_package(JpegPkg QUIET) +if(JPEG_FOUND) + message(STATUS "Building libuvc with JPEG support.") + set(LIBUVC_HAS_JPEG TRUE) + list(APPEND SOURCES src/frame-mjpeg.c) +else() + message(WARNING "JPEG not found. libuvc will not support JPEG decoding.") +endif() + +if((UNIX AND NOT APPLE) OR MINGW OR WIN32) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) + set(threads Threads::Threads) +endif() + +if(${CMAKE_BUILD_TARGET} MATCHES "Shared") + set(BUILD_UVC_SHARED TRUE) +elseif(${CMAKE_BUILD_TARGET} MATCHES "Static") + set(BUILD_UVC_STATIC TRUE) +elseif(${CMAKE_BUILD_TARGET} MATCHES "Both") + set(BUILD_UVC_SHARED TRUE) + set(BUILD_UVC_STATIC TRUE) +else() + message(FATAL_ERROR "Invalid build type ${CMAKE_BUILD_TARGET}" ) +endif() + +if(BUILD_UVC_SHARED) + add_library(uvc SHARED ${SOURCES}) + set_target_properties(uvc PROPERTIES + VERSION ${libuvc_VERSION} + SOVERSION ${libuvc_VERSION_MAJOR} + # Exported name of target within namespace LibUVC + EXPORT_NAME UVCShared + ) + list(APPEND UVC_TARGETS uvc) + if(NOT LibUVC_STATIC) + add_library(LibUVC::UVC ALIAS uvc) + endif() + # Aliases defined here available only if project included + # via addsubdirectory + add_library(LibUVC::UVCShared ALIAS uvc) +endif() + +if(BUILD_UVC_STATIC) + add_library(uvc_static STATIC ${SOURCES}) + set_target_properties(uvc_static PROPERTIES + OUTPUT_NAME uvc + # Exported name of target within namespace LibUVC + EXPORT_NAME UVCStatic + ) + list(APPEND UVC_TARGETS uvc_static) + add_library(LibUVC::UVCStatic ALIAS uvc_static) + if(LibUVC_STATIC) + add_library(LibUVC::UVC ALIAS uvc_static) + endif() +endif() + +configure_file(include/libuvc/libuvc_config.h.in + include/libuvc/libuvc_config.h + @ONLY +) + +foreach(target_name IN LISTS UVC_TARGETS) + target_include_directories(${target_name} + PUBLIC + # Different paths for includes for build and install phase supported + # via INSTALL_INTERFACE and BUILD_INTERFACE generator expressions. + $ + $ + $ + ) + target_link_libraries(${target_name} + # libusb-1.0 used internally so we link to it privately. + PRIVATE LibUSB::LibUSB ${threads} + ) + if(JPEG_FOUND) + target_link_libraries(${target_name} + PRIVATE JPEG::JPEG + ) + endif() + set_target_properties(${target_name} PROPERTIES + PUBLIC_HEADER "include/libuvc/libuvc.h;${CMAKE_CURRENT_BINARY_DIR}/include/libuvc/libuvc_config.h" + ) + if(ENABLE_UVC_DEBUGGING) + target_compile_definitions(${target_name} + PRIVATE + UVC_DEBUGGING + ) + find_library( + log-lib + log + ) + target_link_libraries( + ${target_name} + PRIVATE + ${log-lib} + ) + endif() +endforeach() + +if(BUILD_EXAMPLE) + add_executable(example src/example.c) + find_package(Threads) + target_link_libraries(example + PRIVATE + LibUVC::UVC + Threads::Threads + ) +endif() + +if(BUILD_TEST) + # OpenCV defines targets with transitive dependencies not with namespaces but using opencv_ prefix. + # This targets provide necessary include directories and linked flags. + find_package(OpenCVPkg REQUIRED + COMPONENTS + opencv_core + opencv_highgui + ) + + add_executable(uvc_test src/test.c) + target_link_libraries(uvc_test + PRIVATE + LibUVC::UVC + opencv_core + opencv_highgui + ) +endif() + + +include(GNUInstallDirs) +set(CMAKE_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/libuvc) + +install( + TARGETS ${UVC_TARGETS} + EXPORT libuvcTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libuvc +) + +install(EXPORT libuvcTargets + FILE libuvcTargets.cmake + NAMESPACE LibUVC:: + DESTINATION ${CMAKE_INSTALL_CMAKEDIR} +) + +install(FILES + cmake/FindLibUSB.cmake + cmake/FindJpegPkg.cmake + DESTINATION ${CMAKE_INSTALL_CMAKEDIR} +) + +include(CMakePackageConfigHelpers) +write_basic_package_version_file(libuvcConfigVersion.cmake + COMPATIBILITY AnyNewerVersion +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/libuvcConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_CMAKEDIR} +) + +if(JPEG_FOUND) + # If we have used JPEG library we need to + # add linker flag for it in config file for pkgconfig + set(PKGCONFIG_JPEG_LDFLAG "-ljpeg") +endif() + +configure_file(libuvc.pc.in + ${PROJECT_BINARY_DIR}/libuvc.pc + @ONLY +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/libuvc.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig +) + +install(FILES libuvcConfig.cmake + DESTINATION ${CMAKE_INSTALL_CMAKEDIR} +) + + diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/LICENSE.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..4acc5ddeaffa636e6c31c3545d497c2e1f3f407b --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/LICENSE.txt @@ -0,0 +1,31 @@ +Software License Agreement (BSD License) + +Copyright (C) 2010-2015 Ken Tossell +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the author nor other contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/README.md b/collector/core/gripper/camera_service_src/third_party/libuvc/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9cdaa35c32d284704f52c21c55357cc5b37037f8 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/README.md @@ -0,0 +1,29 @@ +`libuvc` is a cross-platform library for USB video devices, built atop `libusb`. +It enables fine-grained control over USB video devices exporting the standard USB Video Class +(UVC) interface, enabling developers to write drivers for previously unsupported devices, +or just access UVC devices in a generic fashion. + +## Getting and Building libuvc + +Prerequisites: You will need `libusb` and [CMake](http://www.cmake.org/) installed. + +To build, you can just run these shell commands: + + git clone https://github.com/libuvc/libuvc + cd libuvc + mkdir build + cd build + cmake .. + make && sudo make install + +and you're set! If you want to change the build configuration, you can edit `CMakeCache.txt` +in the build directory, or use a CMake GUI to make the desired changes. + +There is also `BUILD_EXAMPLE` and `BUILD_TEST` options to enable the compilation of `example` and `uvc_test` programs. To use them, replace the `cmake ..` command above with `cmake .. -DBUILD_TEST=ON -DBUILD_EXAMPLE=ON`. +Then you can start them with `./example` and `./uvc_test` respectively. Note that you need OpenCV to build the later (for displaying image). + +## Developing with libuvc + +The documentation for `libuvc` can currently be found at https://libuvc.github.io/. + +Happy hacking! diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_imac.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_imac.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3670256970c3258742cc674eb9fac1dd2c1a495 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_imac.txt @@ -0,0 +1,228 @@ + +Bus 001 Device 007: ID 05ac:8501 Apple, Inc. Built-in iSight [Micron] +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x05ac Apple, Inc. + idProduct 0x8501 Built-in iSight [Micron] + bcdDevice 1.89 + iManufacturer 1 Micron + iProduct 2 Built-in iSight + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 267 + bNumInterfaces 2 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 14 Video + bFunctionSubClass 3 Video Interface Collection + bFunctionProtocol 0 + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 1 Video Control + bInterfaceProtocol 0 + iInterface 0 + VideoControl Interface Descriptor: + bLength 13 + bDescriptorType 36 + bDescriptorSubtype 1 (HEADER) + bcdUVC 1.00 + wTotalLength 49 + dwClockFrequency 13.500000MHz + bInCollection 1 + baInterfaceNr( 0) 1 + VideoControl Interface Descriptor: + bLength 16 + bDescriptorType 36 + bDescriptorSubtype 2 (INPUT_TERMINAL) + bTerminalID 1 + wTerminalType 0x0201 Camera Sensor + bAssocTerminal 0 + iTerminal 0 + wObjectiveFocalLengthMin 0 + wObjectiveFocalLengthMax 0 + wOcularFocalLength 0 + bControlSize 1 + bmControls 0x00000000 + VideoControl Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 5 (PROCESSING_UNIT) + Warning: Descriptor too short + bUnitID 2 + bSourceID 1 + wMaxMultiplier 0 + bControlSize 2 + bmControls 0x00000039 + Brightness + Saturation + Sharpness + Gamma + iProcessing 0 + bmVideoStandards 0x 9 + None + SECAM - 625/50 + VideoControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 3 + wTerminalType 0x0101 USB Streaming + bAssocTerminal 0 + bSourceID 2 + iTerminal 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 10 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + VideoStreaming Interface Descriptor: + bLength 14 + bDescriptorType 36 + bDescriptorSubtype 1 (INPUT_HEADER) + bNumFormats 1 + wTotalLength 155 + bEndPointAddress 130 + bmInfo 0 + bTerminalLink 3 + bStillCaptureMethod 0 + bTriggerSupport 0 + bTriggerUsage 0 + bControlSize 1 + bmaControls( 0) 27 + VideoStreaming Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED) + bFormatIndex 1 + bNumFrameDescriptors 3 + guidFormat {55595659-0000-1000-8000-00aa00389b71} + bBitsPerPixel 16 + bDefaultFrameIndex 1 + bAspectRatioX 0 + bAspectRatioY 0 + bmInterlaceFlags 0x00 + Interlaced stream or variable: No + Fields per frame: 1 fields + Field 1 first: No + Field pattern: Field 1 only + bCopyProtect 0 + VideoStreaming Interface Descriptor: + bLength 38 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 1 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 480 + dwMinBitRate 383976960 + dwMaxBitRate 383976960 + dwMaxVideoFrameBufferSize 614400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 0 + dwMinFrameInterval 333333 + dwMaxFrameInterval 333333 + dwFrameIntervalStep 0 + VideoStreaming Interface Descriptor: + bLength 38 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 2 + bmCapabilities 0x00 + Still image unsupported + wWidth 352 + wHeight 288 + dwMinBitRate 383976960 + dwMaxBitRate 383976960 + dwMaxVideoFrameBufferSize 202752 + dwDefaultFrameInterval 333333 + bFrameIntervalType 0 + dwMinFrameInterval 333333 + dwMaxFrameInterval 333333 + dwFrameIntervalStep 0 + VideoStreaming Interface Descriptor: + bLength 38 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 3 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 240 + dwMinBitRate 383976960 + dwMaxBitRate 383976960 + dwMaxVideoFrameBufferSize 153600 + dwDefaultFrameInterval 333333 + bFrameIntervalType 0 + dwMinFrameInterval 333333 + dwMaxFrameInterval 333333 + dwFrameIntervalStep 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 1 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x1400 3x 1024 bytes + bInterval 1 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 14 Video + bDeviceSubClass 2 Video Streaming + bDeviceProtocol 0 + bMaxPacketSize0 8 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_macbook.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_macbook.txt new file mode 100644 index 0000000000000000000000000000000000000000..62d03376f98d62fcbd6e3e0bf71e788e30da883a --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/isight_macbook.txt @@ -0,0 +1,228 @@ + +Bus 001 Device 010: ID 05ac:8501 Apple, Inc. Built-in iSight [Micron] +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x05ac Apple, Inc. + idProduct 0x8501 Built-in iSight [Micron] + bcdDevice 1.89 + iManufacturer 1 Micron + iProduct 2 Built-in iSight + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 267 + bNumInterfaces 2 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 14 Video + bFunctionSubClass 3 Video Interface Collection + bFunctionProtocol 0 + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 1 Video Control + bInterfaceProtocol 0 + iInterface 0 + VideoControl Interface Descriptor: + bLength 13 + bDescriptorType 36 + bDescriptorSubtype 1 (HEADER) + bcdUVC 1.00 + wTotalLength 49 + dwClockFrequency 13.500000MHz + bInCollection 1 + baInterfaceNr( 0) 1 + VideoControl Interface Descriptor: + bLength 16 + bDescriptorType 36 + bDescriptorSubtype 2 (INPUT_TERMINAL) + bTerminalID 1 + wTerminalType 0x0201 Camera Sensor + bAssocTerminal 0 + iTerminal 0 + wObjectiveFocalLengthMin 0 + wObjectiveFocalLengthMax 0 + wOcularFocalLength 0 + bControlSize 1 + bmControls 0x00000000 + VideoControl Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 5 (PROCESSING_UNIT) + Warning: Descriptor too short + bUnitID 2 + bSourceID 1 + wMaxMultiplier 0 + bControlSize 2 + bmControls 0x00000039 + Brightness + Saturation + Sharpness + Gamma + iProcessing 0 + bmVideoStandards 0x 9 + None + SECAM - 625/50 + VideoControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 3 + wTerminalType 0x0101 USB Streaming + bAssocTerminal 0 + bSourceID 2 + iTerminal 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 10 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + VideoStreaming Interface Descriptor: + bLength 14 + bDescriptorType 36 + bDescriptorSubtype 1 (INPUT_HEADER) + bNumFormats 1 + wTotalLength 155 + bEndPointAddress 130 + bmInfo 0 + bTerminalLink 3 + bStillCaptureMethod 0 + bTriggerSupport 0 + bTriggerUsage 0 + bControlSize 1 + bmaControls( 0) 27 + VideoStreaming Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED) + bFormatIndex 1 + bNumFrameDescriptors 3 + guidFormat {55595659-0000-1000-8000-00aa00389b71} + bBitsPerPixel 16 + bDefaultFrameIndex 1 + bAspectRatioX 0 + bAspectRatioY 0 + bmInterlaceFlags 0x00 + Interlaced stream or variable: No + Fields per frame: 1 fields + Field 1 first: No + Field pattern: Field 1 only + bCopyProtect 0 + VideoStreaming Interface Descriptor: + bLength 38 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 1 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 480 + dwMinBitRate 383976960 + dwMaxBitRate 383976960 + dwMaxVideoFrameBufferSize 614400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 0 + dwMinFrameInterval 333333 + dwMaxFrameInterval 333333 + dwFrameIntervalStep 0 + VideoStreaming Interface Descriptor: + bLength 38 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 2 + bmCapabilities 0x00 + Still image unsupported + wWidth 352 + wHeight 288 + dwMinBitRate 383976960 + dwMaxBitRate 383976960 + dwMaxVideoFrameBufferSize 202752 + dwDefaultFrameInterval 333333 + bFrameIntervalType 0 + dwMinFrameInterval 333333 + dwMaxFrameInterval 333333 + dwFrameIntervalStep 0 + VideoStreaming Interface Descriptor: + bLength 38 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 3 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 240 + dwMinBitRate 383976960 + dwMaxBitRate 383976960 + dwMaxVideoFrameBufferSize 153600 + dwDefaultFrameInterval 333333 + bFrameIntervalType 0 + dwMinFrameInterval 333333 + dwMaxFrameInterval 333333 + dwFrameIntervalStep 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 1 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x1400 3x 1024 bytes + bInterval 1 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 14 Video + bDeviceSubClass 2 Video Streaming + bDeviceProtocol 0 + bMaxPacketSize0 8 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/logitech_hd_pro_920.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/logitech_hd_pro_920.txt new file mode 100644 index 0000000000000000000000000000000000000000..2fbe69c6534d8f91e4ce113c1d113f9e783cf5d4 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/logitech_hd_pro_920.txt @@ -0,0 +1,1817 @@ + +Bus 001 Device 018: ID 046d:082d Logitech, Inc. HD Pro Webcam C920 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x046d Logitech, Inc. + idProduct 0x082d HD Pro Webcam C920 + bcdDevice 0.11 + iManufacturer 0 + iProduct 2 HD Pro Webcam C920 + iSerial 1 E1CA2A7F + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 3452 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 14 Video + bFunctionSubClass 3 Video Interface Collection + bFunctionProtocol 0 + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 1 Video Control + bInterfaceProtocol 0 + iInterface 0 + VideoControl Interface Descriptor: + bLength 13 + bDescriptorType 36 + bDescriptorSubtype 1 (HEADER) + bcdUVC 1.00 + wTotalLength 214 + dwClockFrequency 300.000000MHz + bInCollection 1 + baInterfaceNr( 0) 1 + VideoControl Interface Descriptor: + bLength 18 + bDescriptorType 36 + bDescriptorSubtype 2 (INPUT_TERMINAL) + bTerminalID 1 + wTerminalType 0x0201 Camera Sensor + bAssocTerminal 0 + iTerminal 0 + wObjectiveFocalLengthMin 0 + wObjectiveFocalLengthMax 0 + wOcularFocalLength 0 + bControlSize 3 + bmControls 0x00020a2e + Auto-Exposure Mode + Auto-Exposure Priority + Exposure Time (Absolute) + Focus (Absolute) + Zoom (Absolute) + PanTilt (Absolute) + Focus, Auto + VideoControl Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 5 (PROCESSING_UNIT) + Warning: Descriptor too short + bUnitID 3 + bSourceID 1 + wMaxMultiplier 16384 + bControlSize 2 + bmControls 0x0000175b + Brightness + Contrast + Saturation + Sharpness + White Balance Temperature + Backlight Compensation + Gain + Power Line Frequency + White Balance Temperature, Auto + iProcessing 0 + bmVideoStandards 0x1b + None + NTSC - 525/60 + SECAM - 625/50 + NTSC - 625/50 + VideoControl Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 6 + guidExtensionCode {d09ee423-7811-314f-ae52-d2fb8a8d3b48} + bNumControl 10 + bNrPins 1 + baSourceID( 0) 3 + bControlSize 2 + bmControls( 0) 0xff + bmControls( 1) 0x03 + iExtension 0 + VideoControl Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 8 + guidExtensionCode {e48e6769-0f41-db40-a850-7420d7d8240e} + bNumControl 7 + bNrPins 1 + baSourceID( 0) 1 + bControlSize 2 + bmControls( 0) 0x3b + bmControls( 1) 0x03 + iExtension 0 + VideoControl Interface Descriptor: + bLength 28 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 9 + guidExtensionCode {a94c5d1f-11de-8744-840d-50933c8ec8d1} + bNumControl 17 + bNrPins 1 + baSourceID( 0) 1 + bControlSize 3 + bmControls( 0) 0xf3 + bmControls( 1) 0xff + bmControls( 2) 0x23 + iExtension 0 + VideoControl Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 10 + guidExtensionCode {1502e449-34f4-fe47-b158-0e885023e51b} + bNumControl 7 + bNrPins 1 + baSourceID( 0) 1 + bControlSize 2 + bmControls( 0) 0xaa + bmControls( 1) 0x07 + iExtension 0 + VideoControl Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 11 + guidExtensionCode {212de5ff-3080-2c4e-82d9-f587d00540bd} + bNumControl 2 + bNrPins 1 + baSourceID( 0) 1 + bControlSize 2 + bmControls( 0) 0x00 + bmControls( 1) 0x41 + iExtension 0 + VideoControl Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 12 + guidExtensionCode {41769ea2-04de-e347-8b2b-f4341aff003b} + bNumControl 11 + bNrPins 1 + baSourceID( 0) 3 + bControlSize 2 + bmControls( 0) 0x07 + bmControls( 1) 0x7f + iExtension 0 + VideoControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 4 + wTerminalType 0x0101 USB Streaming + bAssocTerminal 0 + bSourceID 3 + iTerminal 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 8 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + VideoStreaming Interface Descriptor: + bLength 16 + bDescriptorType 36 + bDescriptorSubtype 1 (INPUT_HEADER) + bNumFormats 3 + wTotalLength 2822 + bEndPointAddress 129 + bmInfo 0 + bTerminalLink 4 + bStillCaptureMethod 0 + bTriggerSupport 0 + bTriggerUsage 0 + bControlSize 1 + bmaControls( 0) 27 + bmaControls( 1) 27 + bmaControls( 2) 27 + VideoStreaming Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED) + bFormatIndex 1 + bNumFrameDescriptors 19 + guidFormat {59555932-0000-1000-8000-00aa00389b71} + bBitsPerPixel 16 + bDefaultFrameIndex 1 + bAspectRatioX 0 + bAspectRatioY 0 + bmInterlaceFlags 0x00 + Interlaced stream or variable: No + Fields per frame: 2 fields + Field 1 first: No + Field pattern: Field 1 only + bCopyProtect 0 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 1 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 480 + dwMinBitRate 24576000 + dwMaxBitRate 147456000 + dwMaxVideoFrameBufferSize 614400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 2 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 90 + dwMinBitRate 1152000 + dwMaxBitRate 6912000 + dwMaxVideoFrameBufferSize 28800 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 3 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 120 + dwMinBitRate 1536000 + dwMaxBitRate 9216000 + dwMaxVideoFrameBufferSize 38400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 4 + bmCapabilities 0x00 + Still image unsupported + wWidth 176 + wHeight 144 + dwMinBitRate 2027520 + dwMaxBitRate 12165120 + dwMaxVideoFrameBufferSize 50688 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 5 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 180 + dwMinBitRate 4608000 + dwMaxBitRate 27648000 + dwMaxVideoFrameBufferSize 115200 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 6 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 240 + dwMinBitRate 6144000 + dwMaxBitRate 36864000 + dwMaxVideoFrameBufferSize 153600 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 7 + bmCapabilities 0x00 + Still image unsupported + wWidth 352 + wHeight 288 + dwMinBitRate 8110080 + dwMaxBitRate 48660480 + dwMaxVideoFrameBufferSize 202752 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 8 + bmCapabilities 0x00 + Still image unsupported + wWidth 432 + wHeight 240 + dwMinBitRate 8294400 + dwMaxBitRate 49766400 + dwMaxVideoFrameBufferSize 207360 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 9 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 360 + dwMinBitRate 18432000 + dwMaxBitRate 110592000 + dwMaxVideoFrameBufferSize 460800 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 10 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 448 + dwMinBitRate 28672000 + dwMaxBitRate 172032000 + dwMaxVideoFrameBufferSize 716800 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 11 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 600 + dwMinBitRate 38400000 + dwMaxBitRate 184320000 + dwMaxVideoFrameBufferSize 960000 + dwDefaultFrameInterval 416666 + bFrameIntervalType 6 + dwFrameInterval( 0) 416666 + dwFrameInterval( 1) 500000 + dwFrameInterval( 2) 666666 + dwFrameInterval( 3) 1000000 + dwFrameInterval( 4) 1333333 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 12 + bmCapabilities 0x00 + Still image unsupported + wWidth 864 + wHeight 480 + dwMinBitRate 33177600 + dwMaxBitRate 159252480 + dwMaxVideoFrameBufferSize 829440 + dwDefaultFrameInterval 416666 + bFrameIntervalType 6 + dwFrameInterval( 0) 416666 + dwFrameInterval( 1) 500000 + dwFrameInterval( 2) 666666 + dwFrameInterval( 3) 1000000 + dwFrameInterval( 4) 1333333 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 42 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 13 + bmCapabilities 0x00 + Still image unsupported + wWidth 960 + wHeight 720 + dwMinBitRate 55296000 + dwMaxBitRate 165888000 + dwMaxVideoFrameBufferSize 1382400 + dwDefaultFrameInterval 666666 + bFrameIntervalType 4 + dwFrameInterval( 0) 666666 + dwFrameInterval( 1) 1000000 + dwFrameInterval( 2) 1333333 + dwFrameInterval( 3) 2000000 + VideoStreaming Interface Descriptor: + bLength 42 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 14 + bmCapabilities 0x00 + Still image unsupported + wWidth 1024 + wHeight 576 + dwMinBitRate 47185920 + dwMaxBitRate 141557760 + dwMaxVideoFrameBufferSize 1179648 + dwDefaultFrameInterval 666666 + bFrameIntervalType 4 + dwFrameInterval( 0) 666666 + dwFrameInterval( 1) 1000000 + dwFrameInterval( 2) 1333333 + dwFrameInterval( 3) 2000000 + VideoStreaming Interface Descriptor: + bLength 38 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 15 + bmCapabilities 0x00 + Still image unsupported + wWidth 1280 + wHeight 720 + dwMinBitRate 73728000 + dwMaxBitRate 147456000 + dwMaxVideoFrameBufferSize 1843200 + dwDefaultFrameInterval 1000000 + bFrameIntervalType 3 + dwFrameInterval( 0) 1000000 + dwFrameInterval( 1) 1333333 + dwFrameInterval( 2) 2000000 + VideoStreaming Interface Descriptor: + bLength 34 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 16 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 896 + dwMinBitRate 114688000 + dwMaxBitRate 172032000 + dwMaxVideoFrameBufferSize 2867200 + dwDefaultFrameInterval 1333333 + bFrameIntervalType 2 + dwFrameInterval( 0) 1333333 + dwFrameInterval( 1) 2000000 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 17 + bmCapabilities 0x00 + Still image unsupported + wWidth 1920 + wHeight 1080 + dwMinBitRate 165888000 + dwMaxBitRate 165888000 + dwMaxVideoFrameBufferSize 4147200 + dwDefaultFrameInterval 2000000 + bFrameIntervalType 1 + dwFrameInterval( 0) 2000000 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 18 + bmCapabilities 0x00 + Still image unsupported + wWidth 2304 + wHeight 1296 + dwMinBitRate 238878720 + dwMaxBitRate 238878720 + dwMaxVideoFrameBufferSize 5971968 + dwDefaultFrameInterval 4999998 + bFrameIntervalType 1 + dwFrameInterval( 0) 4999998 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 19 + bmCapabilities 0x00 + Still image unsupported + wWidth 2304 + wHeight 1536 + dwMinBitRate 283115520 + dwMaxBitRate 283115520 + dwMaxVideoFrameBufferSize 7077888 + dwDefaultFrameInterval 4999998 + bFrameIntervalType 1 + dwFrameInterval( 0) 4999998 + VideoStreaming Interface Descriptor: + bLength 6 + bDescriptorType 36 + bDescriptorSubtype 13 (COLORFORMAT) + bColorPrimaries 1 (BT.709,sRGB) + bTransferCharacteristics 1 (BT.709) + bMatrixCoefficients 4 (SMPTE 170M (BT.601)) + VideoStreaming Interface Descriptor: + bLength 28 + bDescriptorType 36 + bDescriptorSubtype 16 (FORMAT_FRAME_BASED) + bFormatIndex 2 + bNumFrameDescriptors 17 + guidFormat {48323634-0000-1000-8000-00aa00389b71} + bBitsPerPixel 16 + bDefaultFrameIndex 1 + bAspectRatioX 0 + bAspectRatioY 0 + bmInterlaceFlags 0x00 + Interlaced stream or variable: No + Fields per frame: 2 fields + Field 1 first: No + Field pattern: Field 1 only + bCopyProtect 0 + bVariableSize 1 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 1 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 480 + dwMinBitRate 24576000 + dwMaxBitRate 147456000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 2 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 90 + dwMinBitRate 1152000 + dwMaxBitRate 6912000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 3 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 120 + dwMinBitRate 1536000 + dwMaxBitRate 9216000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 4 + bmCapabilities 0x00 + Still image unsupported + wWidth 176 + wHeight 144 + dwMinBitRate 2027520 + dwMaxBitRate 12165120 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 5 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 180 + dwMinBitRate 4608000 + dwMaxBitRate 27648000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 6 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 240 + dwMinBitRate 6144000 + dwMaxBitRate 36864000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 7 + bmCapabilities 0x00 + Still image unsupported + wWidth 352 + wHeight 288 + dwMinBitRate 8110080 + dwMaxBitRate 48660480 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 8 + bmCapabilities 0x00 + Still image unsupported + wWidth 432 + wHeight 240 + dwMinBitRate 8294400 + dwMaxBitRate 49766400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 9 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 360 + dwMinBitRate 18432000 + dwMaxBitRate 110592000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 10 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 448 + dwMinBitRate 28672000 + dwMaxBitRate 172032000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 11 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 600 + dwMinBitRate 38400000 + dwMaxBitRate 230400000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 12 + bmCapabilities 0x00 + Still image unsupported + wWidth 864 + wHeight 480 + dwMinBitRate 33177600 + dwMaxBitRate 199065600 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 13 + bmCapabilities 0x00 + Still image unsupported + wWidth 960 + wHeight 720 + dwMinBitRate 55296000 + dwMaxBitRate 331776000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 14 + bmCapabilities 0x00 + Still image unsupported + wWidth 1024 + wHeight 576 + dwMinBitRate 47185920 + dwMaxBitRate 283115520 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 15 + bmCapabilities 0x00 + Still image unsupported + wWidth 1280 + wHeight 720 + dwMinBitRate 73728000 + dwMaxBitRate 442368000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 16 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 896 + dwMinBitRate 114688000 + dwMaxBitRate 688128000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 17 (FRAME_FRAME_BASED) + bFrameIndex 17 + bmCapabilities 0x00 + Still image unsupported + wWidth 1920 + wHeight 1080 + dwMinBitRate 165888000 + dwMaxBitRate 995328000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwBytesPerLine 0 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 6 + bDescriptorType 36 + bDescriptorSubtype 13 (COLORFORMAT) + bColorPrimaries 1 (BT.709,sRGB) + bTransferCharacteristics 1 (BT.709) + bMatrixCoefficients 4 (SMPTE 170M (BT.601)) + VideoStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 6 (FORMAT_MJPEG) + bFormatIndex 3 + bNumFrameDescriptors 17 + bFlags 1 + Fixed-size samples: Yes + bDefaultFrameIndex 1 + bAspectRatioX 0 + bAspectRatioY 0 + bmInterlaceFlags 0x00 + Interlaced stream or variable: No + Fields per frame: 1 fields + Field 1 first: No + Field pattern: Field 1 only + bCopyProtect 0 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 1 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 480 + dwMinBitRate 24576000 + dwMaxBitRate 147456000 + dwMaxVideoFrameBufferSize 614400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 2 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 90 + dwMinBitRate 1152000 + dwMaxBitRate 6912000 + dwMaxVideoFrameBufferSize 28800 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 3 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 120 + dwMinBitRate 1536000 + dwMaxBitRate 9216000 + dwMaxVideoFrameBufferSize 38400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 4 + bmCapabilities 0x00 + Still image unsupported + wWidth 176 + wHeight 144 + dwMinBitRate 2027520 + dwMaxBitRate 12165120 + dwMaxVideoFrameBufferSize 50688 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 5 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 180 + dwMinBitRate 4608000 + dwMaxBitRate 27648000 + dwMaxVideoFrameBufferSize 115200 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 6 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 240 + dwMinBitRate 6144000 + dwMaxBitRate 36864000 + dwMaxVideoFrameBufferSize 153600 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 7 + bmCapabilities 0x00 + Still image unsupported + wWidth 352 + wHeight 288 + dwMinBitRate 8110080 + dwMaxBitRate 48660480 + dwMaxVideoFrameBufferSize 202752 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 8 + bmCapabilities 0x00 + Still image unsupported + wWidth 432 + wHeight 240 + dwMinBitRate 8294400 + dwMaxBitRate 49766400 + dwMaxVideoFrameBufferSize 207360 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 9 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 360 + dwMinBitRate 18432000 + dwMaxBitRate 110592000 + dwMaxVideoFrameBufferSize 460800 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 10 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 448 + dwMinBitRate 28672000 + dwMaxBitRate 172032000 + dwMaxVideoFrameBufferSize 716800 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 11 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 600 + dwMinBitRate 38400000 + dwMaxBitRate 230400000 + dwMaxVideoFrameBufferSize 960000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 12 + bmCapabilities 0x00 + Still image unsupported + wWidth 864 + wHeight 480 + dwMinBitRate 33177600 + dwMaxBitRate 199065600 + dwMaxVideoFrameBufferSize 829440 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 13 + bmCapabilities 0x00 + Still image unsupported + wWidth 960 + wHeight 720 + dwMinBitRate 55296000 + dwMaxBitRate 331776000 + dwMaxVideoFrameBufferSize 1382400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 14 + bmCapabilities 0x00 + Still image unsupported + wWidth 1024 + wHeight 576 + dwMinBitRate 47185920 + dwMaxBitRate 283115520 + dwMaxVideoFrameBufferSize 1179648 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 15 + bmCapabilities 0x00 + Still image unsupported + wWidth 1280 + wHeight 720 + dwMinBitRate 73728000 + dwMaxBitRate 442368000 + dwMaxVideoFrameBufferSize 1843200 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 16 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 896 + dwMinBitRate 114688000 + dwMaxBitRate 688128000 + dwMaxVideoFrameBufferSize 2867200 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 54 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 17 + bmCapabilities 0x00 + Still image unsupported + wWidth 1920 + wHeight 1080 + dwMinBitRate 165888000 + dwMaxBitRate 995328000 + dwMaxVideoFrameBufferSize 4147200 + dwDefaultFrameInterval 333333 + bFrameIntervalType 7 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 416666 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 1333333 + dwFrameInterval( 6) 2000000 + VideoStreaming Interface Descriptor: + bLength 6 + bDescriptorType 36 + bDescriptorSubtype 13 (COLORFORMAT) + bColorPrimaries 1 (BT.709,sRGB) + bTransferCharacteristics 1 (BT.709) + bMatrixCoefficients 4 (SMPTE 170M (BT.601)) + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 1 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x00c0 1x 192 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 2 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0180 1x 384 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 3 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 4 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0280 1x 640 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 5 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0320 1x 800 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 6 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x03b0 1x 944 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 7 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0a80 2x 640 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 8 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0b20 2x 800 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 9 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0be0 2x 992 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 10 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x1380 3x 896 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 11 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x13fc 3x 1020 bytes + bInterval 1 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 2 + bInterfaceCount 2 + bFunctionClass 1 Audio + bFunctionSubClass 2 Streaming + bFunctionProtocol 0 + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 1 Audio + bInterfaceSubClass 1 Control Device + bInterfaceProtocol 0 + iInterface 0 + AudioControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 1 (HEADER) + bcdADC 1.00 + wTotalLength 38 + bInCollection 1 + baInterfaceNr( 0) 3 + AudioControl Interface Descriptor: + bLength 12 + bDescriptorType 36 + bDescriptorSubtype 2 (INPUT_TERMINAL) + bTerminalID 1 + wTerminalType 0x0201 Microphone + bAssocTerminal 0 + bNrChannels 1 + wChannelConfig 0x0003 + Left Front (L) + Right Front (R) + iChannelNames 0 + iTerminal 0 + AudioControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 3 + wTerminalType 0x0101 USB Streaming + bAssocTerminal 0 + bSourceID 5 + iTerminal 0 + AudioControl Interface Descriptor: + bLength 8 + bDescriptorType 36 + bDescriptorSubtype 6 (FEATURE_UNIT) + bUnitID 5 + bSourceID 1 + bControlSize 1 + bmaControls( 0) 0x03 + Mute Control + Volume Control + iFeature 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 1 + bNumEndpoints 1 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + AudioStreaming Interface Descriptor: + bLength 7 + bDescriptorType 36 + bDescriptorSubtype 1 (AS_GENERAL) + bTerminalLink 3 + bDelay 255 frames + wFormatTag 1 PCM + AudioStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 2 (FORMAT_TYPE) + bFormatType 1 (FORMAT_TYPE_I) + bNrChannels 2 + bSubframeSize 2 + bBitResolution 16 + bSamFreqType 1 Discrete + tSamFreq[ 0] 16000 + Endpoint Descriptor: + bLength 9 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0044 1x 68 bytes + bInterval 4 + bRefresh 0 + bSynchAddress 0 + AudioControl Endpoint Descriptor: + bLength 7 + bDescriptorType 37 + bDescriptorSubtype 1 (EP_GENERAL) + bmAttributes 0x01 + Sampling Frequency + bLockDelayUnits 0 Undefined + wLockDelay 0 Undefined + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 2 + bNumEndpoints 1 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + AudioStreaming Interface Descriptor: + bLength 7 + bDescriptorType 36 + bDescriptorSubtype 1 (AS_GENERAL) + bTerminalLink 3 + bDelay 255 frames + wFormatTag 1 PCM + AudioStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 2 (FORMAT_TYPE) + bFormatType 1 (FORMAT_TYPE_I) + bNrChannels 2 + bSubframeSize 2 + bBitResolution 16 + bSamFreqType 1 Discrete + tSamFreq[ 0] 24000 + Endpoint Descriptor: + bLength 9 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0064 1x 100 bytes + bInterval 4 + bRefresh 0 + bSynchAddress 0 + AudioControl Endpoint Descriptor: + bLength 7 + bDescriptorType 37 + bDescriptorSubtype 1 (EP_GENERAL) + bmAttributes 0x01 + Sampling Frequency + bLockDelayUnits 0 Undefined + wLockDelay 0 Undefined + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 3 + bNumEndpoints 1 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + AudioStreaming Interface Descriptor: + bLength 7 + bDescriptorType 36 + bDescriptorSubtype 1 (AS_GENERAL) + bTerminalLink 3 + bDelay 255 frames + wFormatTag 1 PCM + AudioStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 2 (FORMAT_TYPE) + bFormatType 1 (FORMAT_TYPE_I) + bNrChannels 2 + bSubframeSize 2 + bBitResolution 16 + bSamFreqType 1 Discrete + tSamFreq[ 0] 32000 + Endpoint Descriptor: + bLength 9 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0084 1x 132 bytes + bInterval 4 + bRefresh 0 + bSynchAddress 0 + AudioControl Endpoint Descriptor: + bLength 7 + bDescriptorType 37 + bDescriptorSubtype 1 (EP_GENERAL) + bmAttributes 0x01 + Sampling Frequency + bLockDelayUnits 0 Undefined + wLockDelay 0 Undefined +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/ms_lifecam_show.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/ms_lifecam_show.txt new file mode 100644 index 0000000000000000000000000000000000000000..d8f96501c2def4255330a84187a84316a0e21145 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/ms_lifecam_show.txt @@ -0,0 +1,767 @@ + +Bus 001 Device 010: ID 045e:0729 Microsoft Corp. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x045e Microsoft Corp. + idProduct 0x0729 + bcdDevice 1.00 + iManufacturer 1 Microsoft + iProduct 2 Microsoft® LifeCam Show(TM) + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 961 + bNumInterfaces 5 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 320mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 14 Video + bFunctionSubClass 3 Video Interface Collection + bFunctionProtocol 0 + iFunction 2 Microsoft® LifeCam Show(TM) + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 1 Video Control + bInterfaceProtocol 0 + iInterface 2 Microsoft® LifeCam Show(TM) + VideoControl Interface Descriptor: + bLength 13 + bDescriptorType 36 + bDescriptorSubtype 1 (HEADER) + bcdUVC 1.00 + wTotalLength 79 + dwClockFrequency 24.000000MHz + bInCollection 1 + baInterfaceNr( 0) 1 + VideoControl Interface Descriptor: + bLength 18 + bDescriptorType 36 + bDescriptorSubtype 2 (INPUT_TERMINAL) + bTerminalID 1 + wTerminalType 0x0201 Camera Sensor + bAssocTerminal 0 + iTerminal 0 + wObjectiveFocalLengthMin 0 + wObjectiveFocalLengthMax 0 + wOcularFocalLength 0 + bControlSize 3 + bmControls 0x00000a0a + Auto-Exposure Mode + Exposure Time (Absolute) + Zoom (Absolute) + PanTilt (Absolute) + VideoControl Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 5 (PROCESSING_UNIT) + Warning: Descriptor too short + bUnitID 2 + bSourceID 1 + wMaxMultiplier 0 + bControlSize 2 + bmControls 0x0000073b + Brightness + Contrast + Saturation + Sharpness + Gamma + Backlight Compensation + Gain + Power Line Frequency + iProcessing 0 + bmVideoStandards 0x 9 + None + SECAM - 625/50 + VideoControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 3 + wTerminalType 0x0101 USB Streaming + bAssocTerminal 0 + bSourceID 2 + iTerminal 0 + VideoControl Interface Descriptor: + bLength 28 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 4 + guidExtensionCode {5dc717a9-1941-da11-ae0e-000d56ac7b4c} + bNumControl 8 + bNrPins 1 + baSourceID( 0) 1 + bControlSize 3 + bmControls( 0) 0xf9 + bmControls( 1) 0x01 + bmControls( 2) 0xc0 + iExtension 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x000a 1x 10 bytes + bInterval 5 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + VideoStreaming Interface Descriptor: + bLength 15 + bDescriptorType 36 + bDescriptorSubtype 1 (INPUT_HEADER) + bNumFormats 2 + wTotalLength 587 + bEndPointAddress 130 + bmInfo 0 + bTerminalLink 3 + bStillCaptureMethod 2 + bTriggerSupport 1 + bTriggerUsage 1 + bControlSize 1 + bmaControls( 0) 27 + bmaControls( 1) 27 + VideoStreaming Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED) + bFormatIndex 1 + bNumFrameDescriptors 6 + guidFormat {59555932-0000-1000-8000-00aa00389b71} + bBitsPerPixel 16 + bDefaultFrameIndex 1 + bAspectRatioX 0 + bAspectRatioY 0 + bmInterlaceFlags 0x00 + Interlaced stream or variable: No + Fields per frame: 1 fields + Field 1 first: No + Field pattern: Field 1 only + bCopyProtect 0 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 1 + bmCapabilities 0x00 + Still image unsupported + wWidth 352 + wHeight 288 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 2 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 480 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 3 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 240 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 4 + bmCapabilities 0x00 + Still image unsupported + wWidth 176 + wHeight 144 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 5 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 120 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 6 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 600 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 3 (STILL_IMAGE_FRAME) + bEndpointAddress 0 + bNumImageSizePatterns 6 + wWidth( 0) 352 + wHeight( 0) 288 + wWidth( 1) 640 + wHeight( 1) 480 + wWidth( 2) 320 + wHeight( 2) 240 + wWidth( 3) 176 + wHeight( 3) 144 + wWidth( 4) 160 + wHeight( 4) 120 + wWidth( 5) 800 + wHeight( 5) 600 + bNumCompressionPatterns 6 + VideoStreaming Interface Descriptor: + bLength 6 + bDescriptorType 36 + bDescriptorSubtype 13 (COLORFORMAT) + bColorPrimaries 0 (Unspecified) + bTransferCharacteristics 0 (Unspecified) + bMatrixCoefficients 0 (Unspecified) + VideoStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 6 (FORMAT_MJPEG) + bFormatIndex 2 + bNumFrameDescriptors 9 + bFlags 1 + Fixed-size samples: Yes + bDefaultFrameIndex 1 + bAspectRatioX 0 + bAspectRatioY 0 + bmInterlaceFlags 0x00 + Interlaced stream or variable: No + Fields per frame: 1 fields + Field 1 first: No + Field pattern: Field 1 only + bCopyProtect 0 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 1 + bmCapabilities 0x00 + Still image unsupported + wWidth 352 + wHeight 288 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 2 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 480 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 3 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 240 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 4 + bmCapabilities 0x00 + Still image unsupported + wWidth 176 + wHeight 144 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 5 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 120 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 6 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 600 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 666667 + bFrameIntervalType 1 + dwFrameInterval( 0) 666667 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 7 + bmCapabilities 0x00 + Still image unsupported + wWidth 1024 + wHeight 768 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 1333333 + bFrameIntervalType 1 + dwFrameInterval( 0) 1333333 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 8 + bmCapabilities 0x00 + Still image unsupported + wWidth 1280 + wHeight 960 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 1333333 + bFrameIntervalType 1 + dwFrameInterval( 0) 1333333 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 9 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 1200 + dwMinBitRate 196608000 + dwMaxBitRate 196608000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 1333333 + bFrameIntervalType 1 + dwFrameInterval( 0) 1333333 + VideoStreaming Interface Descriptor: + bLength 42 + bDescriptorType 36 + bDescriptorSubtype 3 (STILL_IMAGE_FRAME) + bEndpointAddress 0 + bNumImageSizePatterns 9 + wWidth( 0) 352 + wHeight( 0) 288 + wWidth( 1) 640 + wHeight( 1) 480 + wWidth( 2) 320 + wHeight( 2) 240 + wWidth( 3) 176 + wHeight( 3) 144 + wWidth( 4) 160 + wHeight( 4) 120 + wWidth( 5) 800 + wHeight( 5) 600 + wWidth( 6) 1024 + wHeight( 6) 768 + wWidth( 7) 1280 + wHeight( 7) 960 + wWidth( 8) 1600 + wHeight( 8) 1200 + bNumCompressionPatterns 9 + VideoStreaming Interface Descriptor: + bLength 6 + bDescriptorType 36 + bDescriptorSubtype 13 (COLORFORMAT) + bColorPrimaries 0 (Unspecified) + bTransferCharacteristics 0 (Unspecified) + bMatrixCoefficients 0 (Unspecified) + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 1 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0080 1x 128 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 2 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 3 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0400 1x 1024 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 4 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0b00 2x 768 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 5 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0c00 2x 1024 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 6 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x1380 3x 896 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 7 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x1400 3x 1024 bytes + bInterval 1 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 2 + bInterfaceCount 2 + bFunctionClass 1 Audio + bFunctionSubClass 2 Streaming + bFunctionProtocol 0 + iFunction 2 Microsoft® LifeCam Show(TM) + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 1 Audio + bInterfaceSubClass 1 Control Device + bInterfaceProtocol 0 + iInterface 2 Microsoft® LifeCam Show(TM) + AudioControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 1 (HEADER) + bcdADC 1.00 + wTotalLength 39 + bInCollection 1 + baInterfaceNr( 0) 3 + AudioControl Interface Descriptor: + bLength 12 + bDescriptorType 36 + bDescriptorSubtype 2 (INPUT_TERMINAL) + bTerminalID 1 + wTerminalType 0x0201 Microphone + bAssocTerminal 0 + bNrChannels 1 + wChannelConfig 0x0000 + iChannelNames 0 + iTerminal 0 + AudioControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 6 (FEATURE_UNIT) + bUnitID 2 + bSourceID 1 + bControlSize 1 + bmaControls( 0) 0x00 + bmaControls( 1) 0x03 + Mute + Volume + iFeature 0 + AudioControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 3 + wTerminalType 0x0101 USB Streaming + bAssocTerminal 1 + bSourceID 2 + iTerminal 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 1 + bNumEndpoints 1 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + AudioStreaming Interface Descriptor: + bLength 7 + bDescriptorType 36 + bDescriptorSubtype 1 (AS_GENERAL) + bTerminalLink 3 + bDelay 1 frames + wFormatTag 1 PCM + AudioStreaming Interface Descriptor: + bLength 14 + bDescriptorType 36 + bDescriptorSubtype 2 (FORMAT_TYPE) + bFormatType 1 (FORMAT_TYPE_I) + bNrChannels 1 + bSubframeSize 2 + bBitResolution 16 + bSamFreqType 2 Discrete + tSamFreq[ 0] 44100 + tSamFreq[ 1] 48000 + Endpoint Descriptor: + bLength 9 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0062 1x 98 bytes + bInterval 4 + bRefresh 0 + bSynchAddress 0 + AudioControl Endpoint Descriptor: + bLength 7 + bDescriptorType 37 + bDescriptorSubtype 1 (EP_GENERAL) + bmAttributes 0x01 + Sampling Frequency + bLockDelayUnits 0 Undefined + wLockDelay 0 Undefined + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 4 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 1 Boot Interface Subclass + bInterfaceProtocol 1 Keyboard + iInterface 0 + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.10 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 24 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0001 1x 1 bytes + bInterval 10 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000.txt new file mode 100644 index 0000000000000000000000000000000000000000..5b859b39422ac91c26868f95a03ab3231a899131 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000.txt @@ -0,0 +1,1543 @@ + +Bus 001 Device 009: ID 046d:0809 Logitech, Inc. Webcam Pro 9000 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x046d Logitech, Inc. + idProduct 0x0809 Webcam Pro 9000 + bcdDevice 0.10 + iManufacturer 0 + iProduct 0 + iSerial 2 XXXXXXXX + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 2589 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 14 Video + bFunctionSubClass 3 Video Interface Collection + bFunctionProtocol 0 + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 1 Video Control + bInterfaceProtocol 0 + iInterface 0 + VideoControl Interface Descriptor: + bLength 13 + bDescriptorType 36 + bDescriptorSubtype 1 (HEADER) + bcdUVC 1.00 + wTotalLength 245 + dwClockFrequency 48.000000MHz + bInCollection 1 + baInterfaceNr( 0) 1 + VideoControl Interface Descriptor: + bLength 18 + bDescriptorType 36 + bDescriptorSubtype 2 (INPUT_TERMINAL) + bTerminalID 1 + wTerminalType 0x0201 Camera Sensor + bAssocTerminal 0 + iTerminal 0 + wObjectiveFocalLengthMin 0 + wObjectiveFocalLengthMax 0 + wOcularFocalLength 0 + bControlSize 3 + bmControls 0x0000080e + Auto-Exposure Mode + Auto-Exposure Priority + Exposure Time (Absolute) + PanTilt (Absolute) + VideoControl Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 5 (PROCESSING_UNIT) + Warning: Descriptor too short + bUnitID 2 + bSourceID 1 + wMaxMultiplier 16384 + bControlSize 2 + bmControls 0x0000175b + Brightness + Contrast + Saturation + Sharpness + White Balance Temperature + Backlight Compensation + Gain + Power Line Frequency + White Balance Temperature, Auto + iProcessing 0 + bmVideoStandards 0x1b + None + NTSC - 525/60 + SECAM - 625/50 + NTSC - 625/50 + VideoControl Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 4 + guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d221e} + bNumControl 10 + bNrPins 1 + baSourceID( 0) 2 + bControlSize 2 + bmControls( 0) 0xff + bmControls( 1) 0x03 + iExtension 0 + VideoControl Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 13 + guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d221f} + bNumControl 7 + bNrPins 1 + baSourceID( 0) 2 + bControlSize 2 + bmControls( 0) 0x6f + bmControls( 1) 0x01 + iExtension 0 + VideoControl Interface Descriptor: + bLength 28 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 8 + guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d2251} + bNumControl 3 + bNrPins 1 + baSourceID( 0) 4 + bControlSize 3 + bmControls( 0) 0x19 + bmControls( 1) 0x00 + bmControls( 2) 0x00 + iExtension 0 + VideoControl Interface Descriptor: + bLength 28 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 10 + guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d2252} + bNumControl 24 + bNrPins 1 + baSourceID( 0) 4 + bControlSize 3 + bmControls( 0) 0xff + bmControls( 1) 0xff + bmControls( 2) 0xff + iExtension 0 + VideoControl Interface Descriptor: + bLength 28 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 14 + guidExtensionCode {b7935ba4-15c7-0245-90f4-532a3b311365} + bNumControl 4 + bNrPins 1 + baSourceID( 0) 1 + bControlSize 3 + bmControls( 0) 0x0f + bmControls( 1) 0x00 + bmControls( 2) 0x00 + iExtension 0 + VideoControl Interface Descriptor: + bLength 28 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 9 + guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d2256} + bNumControl 5 + bNrPins 1 + baSourceID( 0) 4 + bControlSize 3 + bmControls( 0) 0x0c + bmControls( 1) 0x00 + bmControls( 2) 0x00 + iExtension 0 + VideoControl Interface Descriptor: + bLength 28 + bDescriptorType 36 + bDescriptorSubtype 6 (EXTENSION_UNIT) + bUnitID 12 + guidExtensionCode {82066163-7050-ab49-b8cc-b3855e8d2250} + bNumControl 17 + bNrPins 1 + baSourceID( 0) 4 + bControlSize 3 + bmControls( 0) 0xfe + bmControls( 1) 0x7f + bmControls( 2) 0x70 + iExtension 0 + VideoControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 5 + wTerminalType 0x0101 USB Streaming + bAssocTerminal 0 + bSourceID 4 + iTerminal 0 + ** UNRECOGNIZED: 20 41 01 0b 82 06 61 63 70 50 ab 49 b8 cc b3 85 5e 8d 22 55 01 01 04 03 01 00 00 00 00 00 00 00 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x87 EP 7 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 8 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + VideoStreaming Interface Descriptor: + bLength 16 + bDescriptorType 36 + bDescriptorSubtype 1 (INPUT_HEADER) + bNumFormats 3 + wTotalLength 1852 + bEndPointAddress 129 + bmInfo 0 + bTerminalLink 5 + bStillCaptureMethod 2 + bTriggerSupport 1 + bTriggerUsage 0 + bControlSize 1 + bmaControls( 0) 27 + bmaControls( 1) 27 + bmaControls( 2) 27 + VideoStreaming Interface Descriptor: + bLength 27 + bDescriptorType 36 + bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED) + bFormatIndex 1 + bNumFrameDescriptors 18 + guidFormat {59555932-0000-1000-8000-00aa00389b71} + bBitsPerPixel 16 + bDefaultFrameIndex 1 + bAspectRatioX 0 + bAspectRatioY 0 + bmInterlaceFlags 0x00 + Interlaced stream or variable: No + Fields per frame: 1 fields + Field 1 first: No + Field pattern: Field 1 only + bCopyProtect 0 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 1 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 480 + dwMinBitRate 24576000 + dwMaxBitRate 147456000 + dwMaxVideoFrameBufferSize 614400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 2 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 120 + dwMinBitRate 1536000 + dwMaxBitRate 9216000 + dwMaxVideoFrameBufferSize 38400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 3 + bmCapabilities 0x00 + Still image unsupported + wWidth 176 + wHeight 144 + dwMinBitRate 2027520 + dwMaxBitRate 12165120 + dwMaxVideoFrameBufferSize 50688 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 4 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 240 + dwMinBitRate 6144000 + dwMaxBitRate 36864000 + dwMaxVideoFrameBufferSize 153600 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 5 + bmCapabilities 0x00 + Still image unsupported + wWidth 352 + wHeight 288 + dwMinBitRate 8110080 + dwMaxBitRate 48660480 + dwMaxVideoFrameBufferSize 202752 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 6 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 360 + dwMinBitRate 18432000 + dwMaxBitRate 110592000 + dwMaxVideoFrameBufferSize 460800 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 7 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 400 + dwMinBitRate 20480000 + dwMaxBitRate 122880000 + dwMaxVideoFrameBufferSize 512000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 46 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 8 + bmCapabilities 0x00 + Still image unsupported + wWidth 768 + wHeight 480 + dwMinBitRate 29491200 + dwMaxBitRate 147456000 + dwMaxVideoFrameBufferSize 737280 + dwDefaultFrameInterval 400000 + bFrameIntervalType 5 + dwFrameInterval( 0) 400000 + dwFrameInterval( 1) 500000 + dwFrameInterval( 2) 666666 + dwFrameInterval( 3) 1000000 + dwFrameInterval( 4) 2000000 + VideoStreaming Interface Descriptor: + bLength 46 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 9 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 456 + dwMinBitRate 29184000 + dwMaxBitRate 145920000 + dwMaxVideoFrameBufferSize 729600 + dwDefaultFrameInterval 400000 + bFrameIntervalType 5 + dwFrameInterval( 0) 400000 + dwFrameInterval( 1) 500000 + dwFrameInterval( 2) 666666 + dwFrameInterval( 3) 1000000 + dwFrameInterval( 4) 2000000 + VideoStreaming Interface Descriptor: + bLength 46 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 10 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 504 + dwMinBitRate 32256000 + dwMaxBitRate 161280000 + dwMaxVideoFrameBufferSize 806400 + dwDefaultFrameInterval 400000 + bFrameIntervalType 5 + dwFrameInterval( 0) 400000 + dwFrameInterval( 1) 500000 + dwFrameInterval( 2) 666666 + dwFrameInterval( 3) 1000000 + dwFrameInterval( 4) 2000000 + VideoStreaming Interface Descriptor: + bLength 46 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 11 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 600 + dwMinBitRate 38400000 + dwMaxBitRate 192000000 + dwMaxVideoFrameBufferSize 960000 + dwDefaultFrameInterval 400000 + bFrameIntervalType 5 + dwFrameInterval( 0) 400000 + dwFrameInterval( 1) 500000 + dwFrameInterval( 2) 666666 + dwFrameInterval( 3) 1000000 + dwFrameInterval( 4) 2000000 + VideoStreaming Interface Descriptor: + bLength 46 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 12 + bmCapabilities 0x00 + Still image unsupported + wWidth 864 + wHeight 480 + dwMinBitRate 33177600 + dwMaxBitRate 165888000 + dwMaxVideoFrameBufferSize 829440 + dwDefaultFrameInterval 400000 + bFrameIntervalType 5 + dwFrameInterval( 0) 400000 + dwFrameInterval( 1) 500000 + dwFrameInterval( 2) 666666 + dwFrameInterval( 3) 1000000 + dwFrameInterval( 4) 2000000 + VideoStreaming Interface Descriptor: + bLength 38 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 13 + bmCapabilities 0x00 + Still image unsupported + wWidth 960 + wHeight 720 + dwMinBitRate 55296000 + dwMaxBitRate 165888000 + dwMaxVideoFrameBufferSize 1382400 + dwDefaultFrameInterval 1000000 + bFrameIntervalType 3 + dwFrameInterval( 0) 666666 + dwFrameInterval( 1) 1000000 + dwFrameInterval( 2) 2000000 + VideoStreaming Interface Descriptor: + bLength 34 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 14 + bmCapabilities 0x00 + Still image unsupported + wWidth 1280 + wHeight 720 + dwMinBitRate 73728000 + dwMaxBitRate 147456000 + dwMaxVideoFrameBufferSize 1843200 + dwDefaultFrameInterval 2000000 + bFrameIntervalType 2 + dwFrameInterval( 0) 1333333 + dwFrameInterval( 1) 2000000 + VideoStreaming Interface Descriptor: + bLength 34 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 15 + bmCapabilities 0x00 + Still image unsupported + wWidth 1280 + wHeight 800 + dwMinBitRate 81920000 + dwMaxBitRate 163840000 + dwMaxVideoFrameBufferSize 2048000 + dwDefaultFrameInterval 2000000 + bFrameIntervalType 2 + dwFrameInterval( 0) 1333333 + dwFrameInterval( 1) 2000000 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 16 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 904 + dwMinBitRate 115712000 + dwMaxBitRate 115712000 + dwMaxVideoFrameBufferSize 2892800 + dwDefaultFrameInterval 2000000 + bFrameIntervalType 1 + dwFrameInterval( 0) 2000000 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 17 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 1000 + dwMinBitRate 128000000 + dwMaxBitRate 128000000 + dwMaxVideoFrameBufferSize 3200000 + dwDefaultFrameInterval 2000000 + bFrameIntervalType 1 + dwFrameInterval( 0) 2000000 + VideoStreaming Interface Descriptor: + bLength 30 + bDescriptorType 36 + bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) + bFrameIndex 18 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 1200 + dwMinBitRate 153600000 + dwMaxBitRate 153600000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 2000000 + bFrameIntervalType 1 + dwFrameInterval( 0) 2000000 + VideoStreaming Interface Descriptor: + bLength 79 + bDescriptorType 36 + bDescriptorSubtype 3 (STILL_IMAGE_FRAME) + bEndpointAddress 0 + bNumImageSizePatterns 18 + wWidth( 0) 640 + wHeight( 0) 480 + wWidth( 1) 160 + wHeight( 1) 120 + wWidth( 2) 176 + wHeight( 2) 144 + wWidth( 3) 320 + wHeight( 3) 240 + wWidth( 4) 352 + wHeight( 4) 288 + wWidth( 5) 640 + wHeight( 5) 360 + wWidth( 6) 640 + wHeight( 6) 400 + wWidth( 7) 768 + wHeight( 7) 480 + wWidth( 8) 800 + wHeight( 8) 456 + wWidth( 9) 800 + wHeight( 9) 504 + wWidth(10) 800 + wHeight(10) 600 + wWidth(11) 864 + wHeight(11) 480 + wWidth(12) 960 + wHeight(12) 720 + wWidth(13) 1280 + wHeight(13) 720 + wWidth(14) 1280 + wHeight(14) 800 + wWidth(15) 1600 + wHeight(15) 904 + wWidth(16) 1600 + wHeight(16) 1000 + wWidth(17) 1600 + wHeight(17) 1200 + bNumCompressionPatterns 18 + bCompression( 0) 5 + VideoStreaming Interface Descriptor: + bLength 6 + bDescriptorType 36 + bDescriptorSubtype 13 (COLORFORMAT) + bColorPrimaries 1 (BT.709,sRGB) + bTransferCharacteristics 1 (BT.709) + bMatrixCoefficients 4 (SMPTE 170M (BT.601)) + VideoStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 6 (FORMAT_MJPEG) + bFormatIndex 2 + bNumFrameDescriptors 18 + bFlags 1 + Fixed-size samples: Yes + bDefaultFrameIndex 1 + bAspectRatioX 0 + bAspectRatioY 0 + bmInterlaceFlags 0x00 + Interlaced stream or variable: No + Fields per frame: 1 fields + Field 1 first: No + Field pattern: Field 1 only + bCopyProtect 0 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 1 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 480 + dwMinBitRate 24576000 + dwMaxBitRate 147456000 + dwMaxVideoFrameBufferSize 614400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 2 + bmCapabilities 0x00 + Still image unsupported + wWidth 160 + wHeight 120 + dwMinBitRate 1536000 + dwMaxBitRate 9216000 + dwMaxVideoFrameBufferSize 38400 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 3 + bmCapabilities 0x00 + Still image unsupported + wWidth 176 + wHeight 144 + dwMinBitRate 2027520 + dwMaxBitRate 12165120 + dwMaxVideoFrameBufferSize 50688 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 4 + bmCapabilities 0x00 + Still image unsupported + wWidth 320 + wHeight 240 + dwMinBitRate 6144000 + dwMaxBitRate 36864000 + dwMaxVideoFrameBufferSize 153600 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 5 + bmCapabilities 0x00 + Still image unsupported + wWidth 352 + wHeight 288 + dwMinBitRate 8110080 + dwMaxBitRate 48660480 + dwMaxVideoFrameBufferSize 202752 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 6 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 360 + dwMinBitRate 18432000 + dwMaxBitRate 110592000 + dwMaxVideoFrameBufferSize 460800 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 7 + bmCapabilities 0x00 + Still image unsupported + wWidth 640 + wHeight 400 + dwMinBitRate 20480000 + dwMaxBitRate 122880000 + dwMaxVideoFrameBufferSize 512000 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 8 + bmCapabilities 0x00 + Still image unsupported + wWidth 768 + wHeight 480 + dwMinBitRate 29491200 + dwMaxBitRate 176947200 + dwMaxVideoFrameBufferSize 737280 + dwDefaultFrameInterval 333333 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 9 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 456 + dwMinBitRate 29184000 + dwMaxBitRate 175104000 + dwMaxVideoFrameBufferSize 729600 + dwDefaultFrameInterval 666666 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 10 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 504 + dwMinBitRate 32256000 + dwMaxBitRate 193536000 + dwMaxVideoFrameBufferSize 806400 + dwDefaultFrameInterval 666666 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 11 + bmCapabilities 0x00 + Still image unsupported + wWidth 800 + wHeight 600 + dwMinBitRate 38400000 + dwMaxBitRate 230400000 + dwMaxVideoFrameBufferSize 960000 + dwDefaultFrameInterval 666666 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 12 + bmCapabilities 0x00 + Still image unsupported + wWidth 864 + wHeight 480 + dwMinBitRate 33177600 + dwMaxBitRate 199065600 + dwMaxVideoFrameBufferSize 829440 + dwDefaultFrameInterval 666666 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 13 + bmCapabilities 0x00 + Still image unsupported + wWidth 960 + wHeight 720 + dwMinBitRate 55296000 + dwMaxBitRate 331776000 + dwMaxVideoFrameBufferSize 1382400 + dwDefaultFrameInterval 1000000 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 50 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 14 + bmCapabilities 0x00 + Still image unsupported + wWidth 1280 + wHeight 720 + dwMinBitRate 73728000 + dwMaxBitRate 442368000 + dwMaxVideoFrameBufferSize 1843200 + dwDefaultFrameInterval 1000000 + bFrameIntervalType 6 + dwFrameInterval( 0) 333333 + dwFrameInterval( 1) 400000 + dwFrameInterval( 2) 500000 + dwFrameInterval( 3) 666666 + dwFrameInterval( 4) 1000000 + dwFrameInterval( 5) 2000000 + VideoStreaming Interface Descriptor: + bLength 46 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 15 + bmCapabilities 0x00 + Still image unsupported + wWidth 1280 + wHeight 800 + dwMinBitRate 81920000 + dwMaxBitRate 409600000 + dwMaxVideoFrameBufferSize 2048000 + dwDefaultFrameInterval 1000000 + bFrameIntervalType 5 + dwFrameInterval( 0) 400000 + dwFrameInterval( 1) 500000 + dwFrameInterval( 2) 666666 + dwFrameInterval( 3) 1000000 + dwFrameInterval( 4) 2000000 + VideoStreaming Interface Descriptor: + bLength 34 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 16 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 904 + dwMinBitRate 115712000 + dwMaxBitRate 231424000 + dwMaxVideoFrameBufferSize 2892800 + dwDefaultFrameInterval 1000000 + bFrameIntervalType 2 + dwFrameInterval( 0) 1000000 + dwFrameInterval( 1) 2000000 + VideoStreaming Interface Descriptor: + bLength 34 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 17 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 1000 + dwMinBitRate 128000000 + dwMaxBitRate 256000000 + dwMaxVideoFrameBufferSize 3200000 + dwDefaultFrameInterval 1000000 + bFrameIntervalType 2 + dwFrameInterval( 0) 1000000 + dwFrameInterval( 1) 2000000 + VideoStreaming Interface Descriptor: + bLength 34 + bDescriptorType 36 + bDescriptorSubtype 7 (FRAME_MJPEG) + bFrameIndex 18 + bmCapabilities 0x00 + Still image unsupported + wWidth 1600 + wHeight 1200 + dwMinBitRate 153600000 + dwMaxBitRate 307200000 + dwMaxVideoFrameBufferSize 3840000 + dwDefaultFrameInterval 2000000 + bFrameIntervalType 2 + dwFrameInterval( 0) 1000000 + dwFrameInterval( 1) 2000000 + VideoStreaming Interface Descriptor: + bLength 83 + bDescriptorType 36 + bDescriptorSubtype 3 (STILL_IMAGE_FRAME) + bEndpointAddress 0 + bNumImageSizePatterns 18 + wWidth( 0) 640 + wHeight( 0) 480 + wWidth( 1) 160 + wHeight( 1) 120 + wWidth( 2) 176 + wHeight( 2) 144 + wWidth( 3) 320 + wHeight( 3) 240 + wWidth( 4) 352 + wHeight( 4) 288 + wWidth( 5) 640 + wHeight( 5) 360 + wWidth( 6) 640 + wHeight( 6) 400 + wWidth( 7) 768 + wHeight( 7) 480 + wWidth( 8) 800 + wHeight( 8) 456 + wWidth( 9) 800 + wHeight( 9) 504 + wWidth(10) 800 + wHeight(10) 600 + wWidth(11) 864 + wHeight(11) 480 + wWidth(12) 960 + wHeight(12) 720 + wWidth(13) 1280 + wHeight(13) 720 + wWidth(14) 1280 + wHeight(14) 800 + wWidth(15) 1600 + wHeight(15) 904 + wWidth(16) 1600 + wHeight(16) 1000 + wWidth(17) 1600 + wHeight(17) 1200 + bNumCompressionPatterns 18 + bCompression( 0) 5 + bCompression( 1) 10 + bCompression( 2) 15 + bCompression( 3) 20 + bCompression( 4) 25 + VideoStreaming Interface Descriptor: + bLength 6 + bDescriptorType 36 + bDescriptorSubtype 13 (COLORFORMAT) + bColorPrimaries 1 (BT.709,sRGB) + bTransferCharacteristics 1 (BT.709) + bMatrixCoefficients 4 (SMPTE 170M (BT.601)) + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 1 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x00c0 1x 192 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 2 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0180 1x 384 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 3 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 4 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0280 1x 640 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 5 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0320 1x 800 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 6 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x03b0 1x 944 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 7 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0a80 2x 640 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 8 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0b20 2x 800 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 9 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0be0 2x 992 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 10 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x1380 3x 896 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 11 + bNumEndpoints 1 + bInterfaceClass 14 Video + bInterfaceSubClass 2 Video Streaming + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x13fc 3x 1020 bytes + bInterval 1 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 2 + bInterfaceCount 2 + bFunctionClass 1 Audio + bFunctionSubClass 2 Streaming + bFunctionProtocol 0 + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 1 Audio + bInterfaceSubClass 1 Control Device + bInterfaceProtocol 0 + iInterface 0 + AudioControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 1 (HEADER) + bcdADC 1.00 + wTotalLength 38 + bInCollection 1 + baInterfaceNr( 0) 3 + AudioControl Interface Descriptor: + bLength 12 + bDescriptorType 36 + bDescriptorSubtype 2 (INPUT_TERMINAL) + bTerminalID 1 + wTerminalType 0x0201 Microphone + bAssocTerminal 0 + bNrChannels 1 + wChannelConfig 0x0000 + iChannelNames 0 + iTerminal 0 + AudioControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 3 + wTerminalType 0x0101 USB Streaming + bAssocTerminal 1 + bSourceID 5 + iTerminal 0 + AudioControl Interface Descriptor: + bLength 9 + bDescriptorType 36 + bDescriptorSubtype 6 (FEATURE_UNIT) + bUnitID 5 + bSourceID 1 + bControlSize 1 + bmaControls( 0) 0x03 + Mute + Volume + bmaControls( 1) 0x00 + iFeature 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 1 + bNumEndpoints 1 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + AudioStreaming Interface Descriptor: + bLength 7 + bDescriptorType 36 + bDescriptorSubtype 1 (AS_GENERAL) + bTerminalLink 3 + bDelay 1 frames + wFormatTag 1 PCM + AudioStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 2 (FORMAT_TYPE) + bFormatType 1 (FORMAT_TYPE_I) + bNrChannels 1 + bSubframeSize 2 + bBitResolution 16 + bSamFreqType 1 Discrete + tSamFreq[ 0] 16000 + Endpoint Descriptor: + bLength 9 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0044 1x 68 bytes + bInterval 4 + bRefresh 0 + bSynchAddress 0 + AudioControl Endpoint Descriptor: + bLength 7 + bDescriptorType 37 + bDescriptorSubtype 1 (EP_GENERAL) + bmAttributes 0x01 + Sampling Frequency + bLockDelayUnits 0 Undefined + wLockDelay 0 Undefined + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 2 + bNumEndpoints 1 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + AudioStreaming Interface Descriptor: + bLength 7 + bDescriptorType 36 + bDescriptorSubtype 1 (AS_GENERAL) + bTerminalLink 3 + bDelay 1 frames + wFormatTag 1 PCM + AudioStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 2 (FORMAT_TYPE) + bFormatType 1 (FORMAT_TYPE_I) + bNrChannels 1 + bSubframeSize 2 + bBitResolution 16 + bSamFreqType 1 Discrete + tSamFreq[ 0] 24000 + Endpoint Descriptor: + bLength 9 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0064 1x 100 bytes + bInterval 4 + bRefresh 0 + bSynchAddress 0 + AudioControl Endpoint Descriptor: + bLength 7 + bDescriptorType 37 + bDescriptorSubtype 1 (EP_GENERAL) + bmAttributes 0x01 + Sampling Frequency + bLockDelayUnits 0 Undefined + wLockDelay 0 Undefined + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 3 + bNumEndpoints 1 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + AudioStreaming Interface Descriptor: + bLength 7 + bDescriptorType 36 + bDescriptorSubtype 1 (AS_GENERAL) + bTerminalLink 3 + bDelay 1 frames + wFormatTag 1 PCM + AudioStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 2 (FORMAT_TYPE) + bFormatType 1 (FORMAT_TYPE_I) + bNrChannels 1 + bSubframeSize 2 + bBitResolution 16 + bSamFreqType 1 Discrete + tSamFreq[ 0] 32000 + Endpoint Descriptor: + bLength 9 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x0084 1x 132 bytes + bInterval 4 + bRefresh 0 + bSynchAddress 0 + AudioControl Endpoint Descriptor: + bLength 7 + bDescriptorType 37 + bDescriptorSubtype 1 (EP_GENERAL) + bmAttributes 0x01 + Sampling Frequency + bLockDelayUnits 0 Undefined + wLockDelay 0 Undefined + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 4 + bNumEndpoints 1 + bInterfaceClass 1 Audio + bInterfaceSubClass 2 Streaming + bInterfaceProtocol 0 + iInterface 0 + AudioStreaming Interface Descriptor: + bLength 7 + bDescriptorType 36 + bDescriptorSubtype 1 (AS_GENERAL) + bTerminalLink 3 + bDelay 1 frames + wFormatTag 1 PCM + AudioStreaming Interface Descriptor: + bLength 11 + bDescriptorType 36 + bDescriptorSubtype 2 (FORMAT_TYPE) + bFormatType 1 (FORMAT_TYPE_I) + bNrChannels 1 + bSubframeSize 2 + bBitResolution 16 + bSamFreqType 1 Discrete + tSamFreq[ 0] 48000 + Endpoint Descriptor: + bLength 9 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 5 + Transfer Type Isochronous + Synch Type Asynchronous + Usage Type Data + wMaxPacketSize 0x00c4 1x 196 bytes + bInterval 4 + bRefresh 0 + bSynchAddress 0 + AudioControl Endpoint Descriptor: + bLength 7 + bDescriptorType 37 + bDescriptorSubtype 1 (EP_GENERAL) + bmAttributes 0x01 + Sampling Frequency + bLockDelayUnits 0 Undefined + wLockDelay 0 Undefined +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_builtin_ctrls.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_builtin_ctrls.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b2969e930f35ebee23c00a9b7ddb1f50cde68d5 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_builtin_ctrls.txt @@ -0,0 +1,13 @@ +Listing available controls for device video0: + Exposure, Auto Priority + Exposure (Absolute) + Exposure, Auto + Backlight Compensation + Sharpness + White Balance Temperature + Power Line Frequency + Gain + White Balance Temperature, Auto + Saturation + Contrast + Brightness diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_extra_ctrls.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_extra_ctrls.txt new file mode 100644 index 0000000000000000000000000000000000000000..205aaf6520de99b6c2fe4b1f0db1c10eea5037f3 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cameras/quickcampro9000_extra_ctrls.txt @@ -0,0 +1,18 @@ +Listing available controls for device video0: + Raw bits per pixel + Disable video processing + LED1 Frequency + LED1 Mode + Focus + Exposure, Auto Priority + Exposure (Absolute) + Exposure, Auto + Backlight Compensation + Sharpness + White Balance Temperature + Power Line Frequency + Gain + White Balance Temperature, Auto + Saturation + Contrast + Brightness diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/changelog.txt b/collector/core/gripper/camera_service_src/third_party/libuvc/changelog.txt new file mode 100644 index 0000000000000000000000000000000000000000..807dbed8f0f36c2b828cb84027fb31e71cd133d7 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/changelog.txt @@ -0,0 +1,140 @@ +Changes in 0.0.7 (2023-03-31) +---------------- + +New features: + - USB 3 support + - Several image/stream formats (incl. NV12, H264, BGR, RGB, P010) + - Format conversion functions + - Accept pre-opened libusb handles (used on Android) + - Library filename versioning (libuvc.0.0.7.dylib) + - Store system time upon receipt of new frame + - In-stream still-image-capture support + - Ensure successful stream parameter negotiation + - Improved build scripts + - Better logging on Android + +Bug fixes: + - Many build issues + - Log spam in production builds + - A situation where libuvc could hang during shutdown + - A deadlock in get_frame() + - An issue that could cause the first frame to fail + - Incorrect settings usage in example code + - Unnecessary device reopening + - Excessive number of transfer buffers affecting Mac builds + - Freeing of transfers that may still be in progress + +Changes in 0.0.6 (2017-09-21) +---------------- + +New features: + - Added support for pkg-config. + - Silence pkg-config when searching for libjpeg + - Resolve pkg-config conflict, update CONF_LIBRARY #11 + - Actually use pkg-config to find libjpeg, and set cflags and ldflags for it. #78 + - Add a pkg-config file to allow build systems to identify the flags needed for compiling and linking against this library #77 + - Add support for 16-bit greyscale image format (Y16) #77 + - Add support for 8-bit raw colour formats, specifically: BA81, GRBG, GBRG, RGGB and BGGR #77 + - Improve detection of The Imaging Source Cameras that implement the UVC protocols but don't announce themselves as UVC cameras (and ignore similar cameras that appear to be UVC but are not). #77 + - add routine for listing frame configs #76 + - New Travis configuration + - Add uvc_find_devices function to support libuvc_ros index selection #36 + - VideoStreaming status processing #30 + - Add conversion from YUYV to Y (GRAY8) and UV (GRAY8) #27 + - Add LICENSE.txt. + - Add Dw_clock_frequency field and populate acording to UVC1.0 or 1.1 spec. #19 + - Changes to enable compilation with Windows MSVC #13 + - Modify ABS_FMT macro to function correctly with MSVC. + - Implement gettimeofday for MSVC. + - Use portable memset instead of bzero for MSVC compatibility. + - Annotate libusb callback methods with LIBUSB_CALL for MSVC. + + - Merge of bulk mode transfer support from Tridge, Mauricio and James (#8) + - Support for BY8 frames + - (Very basic) support for UVC1.1 camera data structures + - Support for frame-based video streams + - Support for TIS astro CCD cameras + - Squashed a few possible bugs + - Added section descriptions and control getter/setter documentation + +Bug fixes: + - update CMakeLists.txt + - Add missing include (for ${CMAKE_INSTALL_LIBDIR}), fix static-/shared-only build #15 + - Allow both static and dynamic versions of library to be built to work more neatly when building into runtime and development packages #77 + + - Update device.c, reduce salience of the alert which end user perceives as more important than it actually is. #79 + - Clean up transfer buffers when an error occurs #77 + - Fixed the issue that camera control functions can not work well with some cameras #41 + UVC specification says that low byte of wIndex (for camera control) is interface number for camera control interface but current implementation of libuvc expects it is always zero and sometimes cause trouble. + Fixed camera control issue when using uvc_get_ctrl_len/uvc_get_ctrl/uvc_set_ctrl with camera that interface number of camera control interface is not zero. + - In some (as yet unidentified) circumstances it is possible for an interface to be claimed more than once. This can cause an error. #77 + - A race allows queued transfers to arrive and be viable for resubmission even when a stream is no longer running. #77 + - Querying stream controls before claiming the interface can fail, so claim the interface first, then do the query. #77 + - Show error code in error message to help debugging #77 + - Add specific error messages for unsupported frame formats to make failures clearer #77 + - Clean up compiler warnings #77 + - Remove libusb.h from the public header #62 + - Fix the first captured image being dropped #51 + The first frame generated by any camera was always lost in the libuvc layer, and not passed on to the listening application. + The start value of seq (thus hold_seq) could be arbitrary, but it must be non-zero. Both the callback listener and the polling function's last_seq / last_polled_seq start initialised to zero, which causes any image with hold_seq zero to be ignored. + - Build fix for Chromium #48, #58 + Some platforms use different version of libusb. For instance, Chromium compiles libusb by itself. So hard coding of libuse version (i.e. ) causes compile failure. + Remove libusb.h from the public header, This should fix the include path problems seen when including libuvc.h into other programs + - pthread_cond_timedwait nanoseconds shouldn't be greater than 1 billion #47 + While using the library and testing the timed poll with 500000 us wait time, I noticed that it often happened that the timedwait returned EINVAL. +According to http://stackoverflow.com/questions/11319063/pthread-cond-timedwait-root-causes-of-einval +this might happen for several reasons, and one of them is when the number of nanoseconds in the timespec is greater than 1 billion (1 billion = 1 second). + Thus, I added a check that correctly updates the seconds and nanoseconds, bringing the nanosecond values in the range 0-999999999. + In Issue #16 it is mentioned that code sometimes crashes on uvc_stream_get_frame with some specific timeout values, this might have been the cause. + Fix for wrong setting of pthread_cond_timedwait nanoseconds + - Fix control functions for processors and other devices #32 + When using a control function that is pertinent to a particular device (such as a processing device), the id of that device needs to be passed to the camera, or the call will fail + - Added docs for some more controls and switched to yaml doc file + - Updated documentation index + - Enable uvc_mjpeg2rgb function, if JPEG is supported + +Changes in 0.0.5 (2014-07-19) +---------------- + +New features: + - Added support for all of the camera terminal and processing unit controls, including the controls + that appeared in UVC 1.1 and 1.5. + - Added LIBUVC_VERSION_GTE(major, minor, patch) macro. + +Bug fixes: + - Switching to explicit kernel driver detachment since auto_detach isn't available in libusb < 1.0.16. + - The cmake module now looks for libuvc.dylib instead of libuvc.so on OS X. + + +Changes in 0.0.4 (2014-06-26) +---------------- + +New features: + - Support devices with multiple streaming interfaces and multiple concurrent streams. + A new uvc_stream* API is added, along with a uvc_stream_handle type to encapsulate the + state of a single UVC stream. Multiple streams can run alongside each other, provided + your USB connection has enough bandwidth. Streams can be individually stopped and + resumed; the old uvc_start/stop_streaming API is still provided as a convenient way + to interact with the usual one-stream devices. + - Added support for MJPEG streams. + - Added functions for checking/setting autofocus mode. + - Added an interface to set/get arbitrary controls on units and terminals. + - Made the input, output, processing and extension units public. + - Implemented uvc_get_device and uvc_get_libusb_handle. + - Add a library-owned flag to uvc_frame_t so that users may allocate their own frame buffers. + +Bug fixes: + - Send frames as soon as they're received, not when the following frame arrives + - Fixed call to NULL when no status callback is provided. + - Fixed crash that occurred during shutdown if the USB device was disconnected during streaming. + +Miscellaneous improvements: + - Hid the transfer method (isochronous vs bulk) from the user. This was never really + selectable; the camera's streaming interface supports either bulk or isochronous + transfers, so now libuvc will figure out which one is appropriate. The `isochronous` + parameter has been converted to a `flags` parameter, which is currently unused but + could be used to convey up to 7 bits of stream mode information in the future. + - Improved the method for claiming the camera's interfaces. + - Renamed UVC_COLOR_FORMAT_* to UVC_FRAME_FORMAT_*. The old #defines are still available. + - Simplified format definition and lookup. + - Improved transfer status (error) handling. diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindJpegPkg.cmake b/collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindJpegPkg.cmake new file mode 100644 index 0000000000000000000000000000000000000000..b533d9c237f21606b2f57c1fd77081b53feca6be --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindJpegPkg.cmake @@ -0,0 +1,82 @@ +#[==============================================[ +FindJpegPkg +----------- + +Searching jpeg library library and creating imported +target JPEG::JPEG (this is different from shipped one with CMake) + +#]==============================================] + +# TODO Append parts for Version compasion and REQUIRED support +if (MSVC OR MINGW) + return() +endif() + +# Try to find JPEG using a module or pkg-config. If that doesn't work, search for the header. +if (NOT TARGET JPEG::JPEG) + find_package(JPEG) + if (JPEG_FOUND) + message(STATUS "Found JPEG library using standard module") + set(IMPORTED_JPEG_INCLUDE_DIRS ${JPEG_INCLUDE_DIR}) + set(IMPORTED_JPEG_LIBRARIES ${JPEG_LIBRARIES}) + else() + find_package(PkgConfig) + pkg_check_modules(JPEG libjpeg) + if(JPEG_FOUND) + message(STATUS "JPEG found by pkgconfig") + + if (DEFINED JPEG_INCLUDE_DIRS) + set(IMPORTED_JPEG_INCLUDE_DIRS ${JPEG_INCLUDE_DIRS}) + endif() + + if(JPEG_LIBRARIES) + find_library(JPEG_LIBRARY + NAMES ${JPEG_LIBRARIES} + PATHS ${JPEG_LIBDIR} ${JPEG_LIBRARY_DIRS} + ) + if(JPEG_LIBRARY) + set(IMPORTED_JPEG_LIBRARIES ${JPEG_LIBRARY}) + else() + message(WARNING "Could not found libjpeg library file") + endif() + endif() + else() + message(STATUS "Searching library manually") + find_path(IMPORTED_JPEG_INCLUDE_DIRS + NAMES jpeglib.h + ) + + if (NOT IMPORTED_JPEG_LIBRARIES) + find_library(IMPORTED_JPEG_LIBRARIES + NAMES jpeg + ) + endif() + endif() + endif() + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(JPEG + REQUIRED_VARS IMPORTED_JPEG_LIBRARIES IMPORTED_JPEG_INCLUDE_DIRS + ) + + if(JPEG_FOUND) + set(JpegPkg_FOUND TRUE) + if (NOT TARGET JPEG::JPEG) + add_library(JPEG::JPEG + UNKNOWN IMPORTED + ) + if(IMPORTED_JPEG_INCLUDE_DIRS) + set_target_properties(JPEG::JPEG PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${IMPORTED_JPEG_INCLUDE_DIRS} + ) + endif() + if(IMPORTED_JPEG_LIBRARIES) + set_target_properties(JPEG::JPEG PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION ${IMPORTED_JPEG_LIBRARIES} + ) + endif() + endif() + endif() + +endif() diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindLibUSB.cmake b/collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindLibUSB.cmake new file mode 100644 index 0000000000000000000000000000000000000000..43f3201fb710c3884ca6acae19d1c0da818d60e3 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindLibUSB.cmake @@ -0,0 +1,51 @@ +#[==============================================[ +FindLibUSB +----------- + +Searching libusb-1.0 library and creating imported +target LibUSB::LibUSB + +#]==============================================] + +# TODO Append parts for Version compasion and REQUIRED support + +if (MSVC OR MINGW) + return() +endif() + +if (NOT TARGET LibUSB::LibUSB) + find_package(PkgConfig) + pkg_check_modules(LibUSB REQUIRED + libusb-1.0 + ) + + if(LibUSB_FOUND) + message(STATUS "libusb-1.0 found using pkgconfig") + + add_library(LibUSB::LibUSB + UNKNOWN IMPORTED + ) + if (DEFINED LibUSB_INCLUDE_DIRS AND NOT LibUSB_INCLUDE_DIRS STREQUAL "") + set_target_properties(LibUSB::LibUSB PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${LibUSB_INCLUDE_DIRS} + ) + endif() + + if(LibUSB_LIBRARIES) + find_library(LibUSB_LIBRARY + NAMES ${LibUSB_LIBRARIES} + PATHS ${LibUSB_LIBDIR} ${LibUSB_LIBRARY_DIRS} + ) + if(LibUSB_LIBRARY) + set_target_properties(LibUSB::LibUSB PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION ${LibUSB_LIBRARY} + ) + else() + message(WARNING "Could not found libusb-1.0 library file") + endif() + endif() + endif() +else() + message(WARNING "libusb-1.0 could not be found using pkgconfig") +endif() diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindOpenCVPkg.cmake b/collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindOpenCVPkg.cmake new file mode 100644 index 0000000000000000000000000000000000000000..9d12f8bdb58cd3134838a4378363047dc979c8c9 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/cmake/FindOpenCVPkg.cmake @@ -0,0 +1,86 @@ +#[==============================================[ +FindOpenCVPkg +----------- + +Searching OpenCV components on systems which does not have fully installed OpenCV. +Such systems does not include OpenCVConfig.cmake and OpenCVConfigVersion.cmake files. +Example of such system is Ubuntu 18.04. +This package try to use OpenCV config file first if it exists. + +#]==============================================] + +if (${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS) + set(comps ${${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS}) +else() + set(comps) +endif() + +list(LENGTH comps comps_count) +message(STATUS "Components requested: ${comps}") + +# Try to find components using standard OpenCV config package +if(comps_count GREATER 0) + find_package(OpenCV QUIET + COMPONENTS ${comps} + ) + if(OpenCV_FOUND) + set(OpenCVPkg_FOUND TRUE) + return() + endif() +else() + find_package(OpenCV QUIET) + if(OpenCV_FOUND) + set(OpenCVPkg_FOUND TRUE) + return() + endif() +endif() + +if(comps_count EQUAL 0) + set(err_level) + if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED) + set(err_level FATAL_ERROR) + endif() + if (${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY) + set(err_level STATUS) + endif() + message(${err_level} "Without standart OpenCV config file you must list components you want") + return() +endif() + +unset(required_comps_not_found) +foreach(comp IN LISTS comps) + string(REPLACE "opencv_" "" comp_name ${comp}) + set(include_rel_path "opencv2/${comp_name}.hpp" "opencv2/${comp_name}/${comp_name}.hpp") + find_path(OpenCV_${comp}_INCLUDE_DIR + NAMES ${include_rel_path} + ) + find_library(OpenCV_${comp}_LIBRARY + NAMES ${comp} + ) + if (${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED_${comp} AND + (NOT OpenCV_${comp}_INCLUDE_DIR OR NOT OpenCV_${comp}_LIBRARY)) + list(APPEND required_comps_not_found ${comp}) + else() + message(STATUS "Found component ${comp}: ${OpenCV_${comp}_LIBRARY}") + endif() +endforeach() + +if(required_comps_not_found) + message(FATAL_ERROR "Following required components not found: ${required_comps_not_found}") + return() +endif() + +foreach(comp IN LISTS comps) + if(NOT TARGET ${comp}) + message(STATUS "No target ${comp} yet. Creating it") + add_library(${comp} + UNKNOWN IMPORTED + ) + set_target_properties(${comp} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${OpenCV_${comp}_INCLUDE_DIR} + IMPORTED_LOCATION ${OpenCV_${comp}_LIBRARY} + ) + endif() +endforeach() + +set(OpenCVPkg_FOUND TRUE) diff --git a/collector/core/gripper/camera_service_src/third_party/libuvc/doxygen.conf b/collector/core/gripper/camera_service_src/third_party/libuvc/doxygen.conf new file mode 100644 index 0000000000000000000000000000000000000000..226134a27926e63dfd37fee9069e9072425e0902 --- /dev/null +++ b/collector/core/gripper/camera_service_src/third_party/libuvc/doxygen.conf @@ -0,0 +1,2284 @@ +# Doxyfile 1.8.5 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = libuvc + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese- +# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en, +# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, +# Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = YES + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = src \ + include/libuvc + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = include/libuvc/libuvc_internal.h \ + include/utlist.h + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = src + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = doc + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /