uvc: default to 720p gadget settings
This commit is contained in:
parent
54c2367c8c
commit
368319af63
@ -11,6 +11,21 @@ cleanup() { echo "" >"$G/UDC" 2>/dev/null || true; }
|
|||||||
DISABLE_UAC=${LESAVKA_DISABLE_UAC:-}
|
DISABLE_UAC=${LESAVKA_DISABLE_UAC:-}
|
||||||
DISABLE_UVC=${LESAVKA_DISABLE_UVC:-}
|
DISABLE_UVC=${LESAVKA_DISABLE_UVC:-}
|
||||||
UVC_FALLBACK=${LESAVKA_UVC_FALLBACK:-1}
|
UVC_FALLBACK=${LESAVKA_UVC_FALLBACK:-1}
|
||||||
|
UVC_STREAMING_INTERVAL=${LESAVKA_UVC_STREAMING_INTERVAL:-1}
|
||||||
|
UVC_MAXPACKET=${LESAVKA_UVC_MAXPACKET:-1024}
|
||||||
|
UVC_MAXBURST=${LESAVKA_UVC_MAXBURST:-1}
|
||||||
|
UVC_INTERVAL=${LESAVKA_UVC_INTERVAL:-}
|
||||||
|
UVC_WIDTH=${LESAVKA_UVC_WIDTH:-1280}
|
||||||
|
UVC_HEIGHT=${LESAVKA_UVC_HEIGHT:-720}
|
||||||
|
UVC_FPS=${LESAVKA_UVC_FPS:-30}
|
||||||
|
UVC_DISABLE_IRQ=${LESAVKA_UVC_DISABLE_IRQ:-}
|
||||||
|
UVC_BULK=${LESAVKA_UVC_BULK:-}
|
||||||
|
MAX_SPEED=${LESAVKA_MAX_SPEED:-high-speed}
|
||||||
|
|
||||||
|
if [[ -z $UVC_INTERVAL ]]; then
|
||||||
|
UVC_INTERVAL=$((10000000 / UVC_FPS))
|
||||||
|
fi
|
||||||
|
UVC_FRAME_SIZE=$((UVC_WIDTH * UVC_HEIGHT * 2))
|
||||||
|
|
||||||
wait_for_enum() {
|
wait_for_enum() {
|
||||||
local tries=${1:-50} # 50 x 100ms = 5s
|
local tries=${1:-50} # 50 x 100ms = 5s
|
||||||
@ -86,15 +101,19 @@ G=/sys/kernel/config/usb_gadget/lesavka
|
|||||||
if [[ -d $G ]]; then
|
if [[ -d $G ]]; then
|
||||||
echo '' >"$G/UDC" 2>/dev/null || true
|
echo '' >"$G/UDC" 2>/dev/null || true
|
||||||
sleep 0.2
|
sleep 0.2
|
||||||
find "$G/configs" -type l -delete 2>/dev/null || true
|
# configfs doesn't allow unlinking attribute files; remove links then rmdir.
|
||||||
rm -rf "$G" 2>/dev/null || true
|
find "$G" -type l -delete 2>/dev/null || true
|
||||||
|
for dir in "$G/functions" "$G/configs" "$G/strings" "$G/os_desc" "$G/webusb"; do
|
||||||
|
[[ -d $dir ]] || continue
|
||||||
|
find "$dir" -mindepth 1 -depth -type d -exec rmdir {} \; 2>/dev/null || true
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$G"
|
mkdir -p "$G"
|
||||||
echo 0x1d6b >"$G/idVendor" # Linux Foundation
|
echo 0x1d6b >"$G/idVendor" # Linux Foundation
|
||||||
echo 0x0104 >"$G/idProduct" # Multifunction Composite Gadget
|
echo 0x0104 >"$G/idProduct" # Multifunction Composite Gadget
|
||||||
echo 0x0200 >"$G/bcdUSB"
|
echo 0x0200 >"$G/bcdUSB"
|
||||||
echo high-speed >"$G/max_speed"
|
echo "$MAX_SPEED" >"$G/max_speed"
|
||||||
|
|
||||||
mkdir -p "$G/strings/0x409"
|
mkdir -p "$G/strings/0x409"
|
||||||
echo "$(cat /proc/sys/kernel/random/uuid)" >"$G/strings/0x409/serialnumber"
|
echo "$(cat /proc/sys/kernel/random/uuid)" >"$G/strings/0x409/serialnumber"
|
||||||
@ -145,6 +164,12 @@ if [[ -z $DISABLE_UVC ]]; then
|
|||||||
# ----------------------- UVC function (usb‑video) ------------------
|
# ----------------------- UVC function (usb‑video) ------------------
|
||||||
mkdir -p "$G/functions/uvc.usb0"
|
mkdir -p "$G/functions/uvc.usb0"
|
||||||
F="$G/functions/uvc.usb0"
|
F="$G/functions/uvc.usb0"
|
||||||
|
echo "$UVC_STREAMING_INTERVAL" >"$F/streaming_interval"
|
||||||
|
echo "$UVC_MAXPACKET" >"$F/streaming_maxpacket"
|
||||||
|
echo "$UVC_MAXBURST" >"$F/streaming_maxburst"
|
||||||
|
if [[ -n $UVC_BULK ]]; then
|
||||||
|
echo 1 >"$F/streaming_bulk" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
# ── 1. FORMAT DESCRIPTOR (uncompressed YUY2, 16 bpp) ──────────────
|
# ── 1. FORMAT DESCRIPTOR (uncompressed YUY2, 16 bpp) ──────────────
|
||||||
mkdir -p "$F/streaming/uncompressed/yuyv"
|
mkdir -p "$F/streaming/uncompressed/yuyv"
|
||||||
@ -153,14 +178,15 @@ if [[ -z $DISABLE_UVC ]]; then
|
|||||||
>"$F/streaming/uncompressed/yuyv/guidFormat"
|
>"$F/streaming/uncompressed/yuyv/guidFormat"
|
||||||
echo 16 >"$F/streaming/uncompressed/yuyv/bBitsPerPixel"
|
echo 16 >"$F/streaming/uncompressed/yuyv/bBitsPerPixel"
|
||||||
|
|
||||||
# ── 2. FRAME DESCRIPTOR (720p @ 30 fps) ───────────────────────────
|
# ── 2. FRAME DESCRIPTOR (480p @ 30 fps) ───────────────────────────
|
||||||
mkdir -p "$F/streaming/uncompressed/yuyv/720p"
|
mkdir -p "$F/streaming/uncompressed/yuyv/480p"
|
||||||
echo 1280 >"$F/streaming/uncompressed/yuyv/720p/wWidth"
|
echo "$UVC_WIDTH" >"$F/streaming/uncompressed/yuyv/480p/wWidth"
|
||||||
echo 720 >"$F/streaming/uncompressed/yuyv/720p/wHeight"
|
echo "$UVC_HEIGHT" >"$F/streaming/uncompressed/yuyv/480p/wHeight"
|
||||||
echo 1843200 >"$F/streaming/uncompressed/yuyv/720p/dwMaxVideoFrameBufferSize"
|
echo "$UVC_FRAME_SIZE" >"$F/streaming/uncompressed/yuyv/480p/dwMaxVideoFrameBufferSize"
|
||||||
echo 333333 >"$F/streaming/uncompressed/yuyv/720p/dwDefaultFrameInterval"
|
echo "$UVC_INTERVAL" >"$F/streaming/uncompressed/yuyv/480p/dwDefaultFrameInterval"
|
||||||
cat <<'EOF' >"$F/streaming/uncompressed/yuyv/720p/dwFrameInterval"
|
cat <<EOF >"$F/streaming/uncompressed/yuyv/480p/dwFrameInterval"
|
||||||
333333
|
${UVC_INTERVAL}
|
||||||
|
$((UVC_INTERVAL * 2))
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# ── 3. REQUIRED HEADER LINKS (per UVC gadget docs) ────────────────
|
# ── 3. REQUIRED HEADER LINKS (per UVC gadget docs) ────────────────
|
||||||
@ -187,6 +213,10 @@ EOF
|
|||||||
done
|
done
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
if [[ -n $UVC_DISABLE_IRQ ]]; then
|
||||||
|
echo 0 >"$F/control/enable_interrupt_ep" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
# optional: hide unsupported controls
|
# optional: hide unsupported controls
|
||||||
echo 0 >"$F/control/terminal/camera/default/bmControls" 2>/dev/null || true
|
echo 0 >"$F/control/terminal/camera/default/bmControls" 2>/dev/null || true
|
||||||
echo 0 >"$F/control/processing/default/bmControls" 2>/dev/null || true
|
echo 0 >"$F/control/processing/default/bmControls" 2>/dev/null || true
|
||||||
|
|||||||
@ -229,11 +229,11 @@ fn parse_args() -> Result<(String, UvcConfig)> {
|
|||||||
|
|
||||||
impl UvcConfig {
|
impl UvcConfig {
|
||||||
fn from_env() -> Self {
|
fn from_env() -> Self {
|
||||||
let width = env_u32("LESAVKA_UVC_WIDTH", 640);
|
let width = env_u32("LESAVKA_UVC_WIDTH", 1280);
|
||||||
let height = env_u32("LESAVKA_UVC_HEIGHT", 480);
|
let height = env_u32("LESAVKA_UVC_HEIGHT", 720);
|
||||||
let fps = env_u32("LESAVKA_UVC_FPS", 30).max(1);
|
let fps = env_u32("LESAVKA_UVC_FPS", 30).max(1);
|
||||||
let interval = env_u32("LESAVKA_UVC_INTERVAL", 0);
|
let interval = env_u32("LESAVKA_UVC_INTERVAL", 0);
|
||||||
let mut max_packet = env_u32("LESAVKA_UVC_MAXPACKET", 3072);
|
let mut max_packet = env_u32("LESAVKA_UVC_MAXPACKET", 1024);
|
||||||
if env::var("LESAVKA_UVC_BULK").is_ok() {
|
if env::var("LESAVKA_UVC_BULK").is_ok() {
|
||||||
max_packet = max_packet.min(512);
|
max_packet = max_packet.min(512);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -16,6 +16,13 @@ const EYE_ID: [&str; 2] = ["l", "r"];
|
|||||||
static START: std::sync::OnceLock<gst::ClockTime> = std::sync::OnceLock::new();
|
static START: std::sync::OnceLock<gst::ClockTime> = std::sync::OnceLock::new();
|
||||||
static DEV_MODE: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
static DEV_MODE: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||||
|
|
||||||
|
fn env_u32(name: &str, default: u32) -> u32 {
|
||||||
|
std::env::var(name)
|
||||||
|
.ok()
|
||||||
|
.and_then(|v| v.parse::<u32>().ok())
|
||||||
|
.unwrap_or(default)
|
||||||
|
}
|
||||||
|
|
||||||
fn dev_mode_enabled() -> bool {
|
fn dev_mode_enabled() -> bool {
|
||||||
*DEV_MODE
|
*DEV_MODE
|
||||||
.get_or_init(|| std::env::var("LESAVKA_DEV_MODE").is_ok())
|
.get_or_init(|| std::env::var("LESAVKA_DEV_MODE").is_ok())
|
||||||
@ -271,15 +278,19 @@ impl WebcamSink {
|
|||||||
|
|
||||||
let pipeline = gst::Pipeline::new();
|
let pipeline = gst::Pipeline::new();
|
||||||
|
|
||||||
|
let width = env_u32("LESAVKA_UVC_WIDTH", 1280) as i32;
|
||||||
|
let height = env_u32("LESAVKA_UVC_HEIGHT", 720) as i32;
|
||||||
|
let fps = env_u32("LESAVKA_UVC_FPS", 30).max(1) as i32;
|
||||||
|
|
||||||
let caps_h264 = gst::Caps::builder("video/x-h264")
|
let caps_h264 = gst::Caps::builder("video/x-h264")
|
||||||
.field("stream-format", "byte-stream")
|
.field("stream-format", "byte-stream")
|
||||||
.field("alignment", "au")
|
.field("alignment", "au")
|
||||||
.build();
|
.build();
|
||||||
let raw_caps = gst::Caps::builder("video/x-raw")
|
let raw_caps = gst::Caps::builder("video/x-raw")
|
||||||
.field("format", "YUY2")
|
.field("format", "YUY2")
|
||||||
.field("width", 1280i32)
|
.field("width", width)
|
||||||
.field("height", 720i32)
|
.field("height", height)
|
||||||
.field("framerate", gst::Fraction::new(30, 1))
|
.field("framerate", gst::Fraction::new(fps, 1))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let src = gst::ElementFactory::make("appsrc")
|
let src = gst::ElementFactory::make("appsrc")
|
||||||
@ -297,6 +308,7 @@ impl WebcamSink {
|
|||||||
.build()
|
.build()
|
||||||
.with_context(|| format!("building decoder element {decoder_name}"))?;
|
.with_context(|| format!("building decoder element {decoder_name}"))?;
|
||||||
let convert = gst::ElementFactory::make("videoconvert").build()?;
|
let convert = gst::ElementFactory::make("videoconvert").build()?;
|
||||||
|
let scale = gst::ElementFactory::make("videoscale").build()?;
|
||||||
let caps = gst::ElementFactory::make("capsfilter")
|
let caps = gst::ElementFactory::make("capsfilter")
|
||||||
.property("caps", &raw_caps)
|
.property("caps", &raw_caps)
|
||||||
.build()?;
|
.build()?;
|
||||||
@ -311,6 +323,7 @@ impl WebcamSink {
|
|||||||
&h264parse,
|
&h264parse,
|
||||||
&decoder,
|
&decoder,
|
||||||
&convert,
|
&convert,
|
||||||
|
&scale,
|
||||||
&caps,
|
&caps,
|
||||||
&sink,
|
&sink,
|
||||||
])?;
|
])?;
|
||||||
@ -319,6 +332,7 @@ impl WebcamSink {
|
|||||||
&h264parse,
|
&h264parse,
|
||||||
&decoder,
|
&decoder,
|
||||||
&convert,
|
&convert,
|
||||||
|
&scale,
|
||||||
&caps,
|
&caps,
|
||||||
&sink,
|
&sink,
|
||||||
])?;
|
])?;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user