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_UVC=${LESAVKA_DISABLE_UVC:-}
|
||||
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() {
|
||||
local tries=${1:-50} # 50 x 100ms = 5s
|
||||
@ -86,15 +101,19 @@ G=/sys/kernel/config/usb_gadget/lesavka
|
||||
if [[ -d $G ]]; then
|
||||
echo '' >"$G/UDC" 2>/dev/null || true
|
||||
sleep 0.2
|
||||
find "$G/configs" -type l -delete 2>/dev/null || true
|
||||
rm -rf "$G" 2>/dev/null || true
|
||||
# configfs doesn't allow unlinking attribute files; remove links then rmdir.
|
||||
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
|
||||
|
||||
mkdir -p "$G"
|
||||
echo 0x1d6b >"$G/idVendor" # Linux Foundation
|
||||
echo 0x0104 >"$G/idProduct" # Multifunction Composite Gadget
|
||||
echo 0x0200 >"$G/bcdUSB"
|
||||
echo high-speed >"$G/max_speed"
|
||||
echo "$MAX_SPEED" >"$G/max_speed"
|
||||
|
||||
mkdir -p "$G/strings/0x409"
|
||||
echo "$(cat /proc/sys/kernel/random/uuid)" >"$G/strings/0x409/serialnumber"
|
||||
@ -145,6 +164,12 @@ if [[ -z $DISABLE_UVC ]]; then
|
||||
# ----------------------- UVC function (usb‑video) ------------------
|
||||
mkdir -p "$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) ──────────────
|
||||
mkdir -p "$F/streaming/uncompressed/yuyv"
|
||||
@ -153,14 +178,15 @@ if [[ -z $DISABLE_UVC ]]; then
|
||||
>"$F/streaming/uncompressed/yuyv/guidFormat"
|
||||
echo 16 >"$F/streaming/uncompressed/yuyv/bBitsPerPixel"
|
||||
|
||||
# ── 2. FRAME DESCRIPTOR (720p @ 30 fps) ───────────────────────────
|
||||
mkdir -p "$F/streaming/uncompressed/yuyv/720p"
|
||||
echo 1280 >"$F/streaming/uncompressed/yuyv/720p/wWidth"
|
||||
echo 720 >"$F/streaming/uncompressed/yuyv/720p/wHeight"
|
||||
echo 1843200 >"$F/streaming/uncompressed/yuyv/720p/dwMaxVideoFrameBufferSize"
|
||||
echo 333333 >"$F/streaming/uncompressed/yuyv/720p/dwDefaultFrameInterval"
|
||||
cat <<'EOF' >"$F/streaming/uncompressed/yuyv/720p/dwFrameInterval"
|
||||
333333
|
||||
# ── 2. FRAME DESCRIPTOR (480p @ 30 fps) ───────────────────────────
|
||||
mkdir -p "$F/streaming/uncompressed/yuyv/480p"
|
||||
echo "$UVC_WIDTH" >"$F/streaming/uncompressed/yuyv/480p/wWidth"
|
||||
echo "$UVC_HEIGHT" >"$F/streaming/uncompressed/yuyv/480p/wHeight"
|
||||
echo "$UVC_FRAME_SIZE" >"$F/streaming/uncompressed/yuyv/480p/dwMaxVideoFrameBufferSize"
|
||||
echo "$UVC_INTERVAL" >"$F/streaming/uncompressed/yuyv/480p/dwDefaultFrameInterval"
|
||||
cat <<EOF >"$F/streaming/uncompressed/yuyv/480p/dwFrameInterval"
|
||||
${UVC_INTERVAL}
|
||||
$((UVC_INTERVAL * 2))
|
||||
EOF
|
||||
|
||||
# ── 3. REQUIRED HEADER LINKS (per UVC gadget docs) ────────────────
|
||||
@ -187,6 +213,10 @@ EOF
|
||||
done
|
||||
set -e
|
||||
|
||||
if [[ -n $UVC_DISABLE_IRQ ]]; then
|
||||
echo 0 >"$F/control/enable_interrupt_ep" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# optional: hide unsupported controls
|
||||
echo 0 >"$F/control/terminal/camera/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 {
|
||||
fn from_env() -> Self {
|
||||
let width = env_u32("LESAVKA_UVC_WIDTH", 640);
|
||||
let height = env_u32("LESAVKA_UVC_HEIGHT", 480);
|
||||
let width = env_u32("LESAVKA_UVC_WIDTH", 1280);
|
||||
let height = env_u32("LESAVKA_UVC_HEIGHT", 720);
|
||||
let fps = env_u32("LESAVKA_UVC_FPS", 30).max(1);
|
||||
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() {
|
||||
max_packet = max_packet.min(512);
|
||||
} else {
|
||||
|
||||
@ -16,6 +16,13 @@ const EYE_ID: [&str; 2] = ["l", "r"];
|
||||
static START: std::sync::OnceLock<gst::ClockTime> = 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 {
|
||||
*DEV_MODE
|
||||
.get_or_init(|| std::env::var("LESAVKA_DEV_MODE").is_ok())
|
||||
@ -271,15 +278,19 @@ impl WebcamSink {
|
||||
|
||||
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")
|
||||
.field("stream-format", "byte-stream")
|
||||
.field("alignment", "au")
|
||||
.build();
|
||||
let raw_caps = gst::Caps::builder("video/x-raw")
|
||||
.field("format", "YUY2")
|
||||
.field("width", 1280i32)
|
||||
.field("height", 720i32)
|
||||
.field("framerate", gst::Fraction::new(30, 1))
|
||||
.field("width", width)
|
||||
.field("height", height)
|
||||
.field("framerate", gst::Fraction::new(fps, 1))
|
||||
.build();
|
||||
|
||||
let src = gst::ElementFactory::make("appsrc")
|
||||
@ -297,6 +308,7 @@ impl WebcamSink {
|
||||
.build()
|
||||
.with_context(|| format!("building decoder element {decoder_name}"))?;
|
||||
let convert = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let scale = gst::ElementFactory::make("videoscale").build()?;
|
||||
let caps = gst::ElementFactory::make("capsfilter")
|
||||
.property("caps", &raw_caps)
|
||||
.build()?;
|
||||
@ -311,6 +323,7 @@ impl WebcamSink {
|
||||
&h264parse,
|
||||
&decoder,
|
||||
&convert,
|
||||
&scale,
|
||||
&caps,
|
||||
&sink,
|
||||
])?;
|
||||
@ -319,6 +332,7 @@ impl WebcamSink {
|
||||
&h264parse,
|
||||
&decoder,
|
||||
&convert,
|
||||
&scale,
|
||||
&caps,
|
||||
&sink,
|
||||
])?;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user