install: keep UVC output on MJPEG helper

This commit is contained in:
Brad Stein 2026-05-12 11:13:47 -03:00
parent 59d5f0cc0d
commit 38df734d42
9 changed files with 74 additions and 17 deletions

6
Cargo.lock generated
View File

@ -1652,7 +1652,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]] [[package]]
name = "lesavka_client" name = "lesavka_client"
version = "0.22.11" version = "0.22.12"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
@ -1686,7 +1686,7 @@ dependencies = [
[[package]] [[package]]
name = "lesavka_common" name = "lesavka_common"
version = "0.22.11" version = "0.22.12"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64", "base64",
@ -1698,7 +1698,7 @@ dependencies = [
[[package]] [[package]]
name = "lesavka_server" name = "lesavka_server"
version = "0.22.11" version = "0.22.12"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64", "base64",

View File

@ -4,7 +4,7 @@ path = "src/main.rs"
[package] [package]
name = "lesavka_client" name = "lesavka_client"
version = "0.22.11" version = "0.22.12"
edition = "2024" edition = "2024"
[dependencies] [dependencies]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "lesavka_common" name = "lesavka_common"
version = "0.22.11" version = "0.22.12"
edition = "2024" edition = "2024"
build = "build.rs" build = "build.rs"

View File

@ -174,7 +174,16 @@ UVC_HEIGHT=${LESAVKA_UVC_HEIGHT:-720}
UVC_FPS=${LESAVKA_UVC_FPS:-30} UVC_FPS=${LESAVKA_UVC_FPS:-30}
UVC_DISABLE_IRQ=${LESAVKA_UVC_DISABLE_IRQ:-} UVC_DISABLE_IRQ=${LESAVKA_UVC_DISABLE_IRQ:-}
UVC_BULK=${LESAVKA_UVC_BULK:-} UVC_BULK=${LESAVKA_UVC_BULK:-}
UVC_CODEC=${LESAVKA_UVC_CODEC:-yuyv} UVC_CODEC=${LESAVKA_UVC_CODEC:-mjpeg}
case "${UVC_CODEC,,}" in
mjpeg|mjpg|jpeg)
UVC_CODEC=mjpeg
;;
*)
log "UVC codec '$UVC_CODEC' is not supported by the MJPEG UVC helper; using mjpeg"
UVC_CODEC=mjpeg
;;
esac
uvc_fifo_min() { uvc_fifo_min() {
local path="$1" local path="$1"

View File

@ -27,6 +27,18 @@ persisted_uvc_value() {
persisted_env_value /etc/lesavka/uvc.env "$1" persisted_env_value /etc/lesavka/uvc.env "$1"
} }
normalize_uvc_codec() {
local raw=${1:-mjpeg}
case "${raw,,}" in
mjpeg|mjpg|jpeg|"")
echo "mjpeg"
;;
*)
echo "mjpeg"
;;
esac
}
uvc_env_value() { uvc_env_value() {
local key=$1 local key=$1
local default=$2 local default=$2
@ -43,7 +55,12 @@ REPO_URL=${LESAVKA_REPO_URL:-}
INSTALL_SOURCE=${LESAVKA_INSTALL_SOURCE:-auto} INSTALL_SOURCE=${LESAVKA_INSTALL_SOURCE:-auto}
USER_HOME=$(getent passwd "$ORIG_USER" | cut -d: -f6) USER_HOME=$(getent passwd "$ORIG_USER" | cut -d: -f6)
PERSISTED_UVC_CODEC=$(persisted_uvc_value LESAVKA_UVC_CODEC || true) PERSISTED_UVC_CODEC=$(persisted_uvc_value LESAVKA_UVC_CODEC || true)
INSTALL_UVC_CODEC=${LESAVKA_INSTALL_UVC_CODEC:-${PERSISTED_UVC_CODEC:-mjpeg}} REQUESTED_UVC_CODEC=${LESAVKA_INSTALL_UVC_CODEC:-${PERSISTED_UVC_CODEC:-mjpeg}}
INSTALL_UVC_CODEC=$(normalize_uvc_codec "$REQUESTED_UVC_CODEC")
if [[ "${REQUESTED_UVC_CODEC,,}" != "${INSTALL_UVC_CODEC}" ]]; then
echo "⚠️ UVC gadget output codec '${REQUESTED_UVC_CODEC}' is not supported by the MJPEG UVC helper; using '${INSTALL_UVC_CODEC}' for the host-facing gadget."
echo " Use LESAVKA_INSTALL_CAM_CODEC=hevc to choose HEVC for the client-to-server upstream transport."
fi
INSTALL_CAM_CODEC=${LESAVKA_INSTALL_CAM_CODEC:-${LESAVKA_CAM_CODEC:-hevc}} INSTALL_CAM_CODEC=${LESAVKA_INSTALL_CAM_CODEC:-${LESAVKA_CAM_CODEC:-hevc}}
INSTALL_UPLINK_AUDIO_CODEC=${LESAVKA_INSTALL_UPLINK_AUDIO_CODEC:-${LESAVKA_UPLINK_AUDIO_CODEC:-pcm}} INSTALL_UPLINK_AUDIO_CODEC=${LESAVKA_INSTALL_UPLINK_AUDIO_CODEC:-${LESAVKA_UPLINK_AUDIO_CODEC:-pcm}}
INSTALL_UVC_FRAME_META=${LESAVKA_INSTALL_UVC_FRAME_META:-${LESAVKA_UVC_FRAME_META:-0}} INSTALL_UVC_FRAME_META=${LESAVKA_INSTALL_UVC_FRAME_META:-${LESAVKA_UVC_FRAME_META:-0}}
@ -507,7 +524,7 @@ live_uvc_descriptor_codec() {
return 0 return 0
fi fi
if [[ -e "$function_root/streaming/header/h/yuyv" ]]; then if [[ -e "$function_root/streaming/header/h/yuyv" ]]; then
echo "hevc" echo "yuyv"
return 0 return 0
fi fi
if [[ -d "$function_root/streaming/mjpeg/m" ]]; then if [[ -d "$function_root/streaming/mjpeg/m" ]]; then
@ -515,7 +532,7 @@ live_uvc_descriptor_codec() {
return 0 return 0
fi fi
if [[ -d "$function_root/streaming/uncompressed/yuyv" ]]; then if [[ -d "$function_root/streaming/uncompressed/yuyv" ]]; then
echo "hevc" echo "yuyv"
return 0 return 0
fi fi
echo "unknown" echo "unknown"
@ -529,8 +546,8 @@ live_uvc_descriptor_matches_request() {
[[ "$INSTALL_UVC_CODEC" == "mjpeg" ]] || return 1 [[ "$INSTALL_UVC_CODEC" == "mjpeg" ]] || return 1
frame_root="$function_root/streaming/mjpeg/m/720p" frame_root="$function_root/streaming/mjpeg/m/720p"
;; ;;
hevc) yuyv)
[[ "$INSTALL_UVC_CODEC" != "mjpeg" ]] || return 1 [[ "$INSTALL_UVC_CODEC" == "yuyv" ]] || return 1
frame_root="$function_root/streaming/uncompressed/yuyv/480p" frame_root="$function_root/streaming/uncompressed/yuyv/480p"
;; ;;
*) *)

View File

@ -10,7 +10,7 @@ bench = false
[package] [package]
name = "lesavka_server" name = "lesavka_server"
version = "0.22.11" version = "0.22.12"
edition = "2024" edition = "2024"
autobins = false autobins = false

View File

@ -89,3 +89,18 @@ fn core_script_treats_uvc_env_as_defaults_not_overrides() {
); );
} }
} }
#[test]
fn core_script_keeps_uvc_output_on_supported_mjpeg_descriptor() {
for expected in [
"UVC_CODEC=${LESAVKA_UVC_CODEC:-mjpeg}",
"UVC codec '$UVC_CODEC' is not supported by the MJPEG UVC helper; using mjpeg",
"UVC_CODEC=mjpeg",
"streaming/mjpeg/m/720p",
] {
assert!(
CORE_SCRIPT.contains(expected),
"lesavka-core should keep UVC output on the supported MJPEG helper path: {expected}"
);
}
}

View File

@ -64,10 +64,14 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
.contains("${LESAVKA_INSTALL_UPLINK_AUDIO_CODEC:-${LESAVKA_UPLINK_AUDIO_CODEC:-pcm}}") .contains("${LESAVKA_INSTALL_UPLINK_AUDIO_CODEC:-${LESAVKA_UPLINK_AUDIO_CODEC:-pcm}}")
); );
assert!( assert!(
SERVER_INSTALL.contains( SERVER_INSTALL
"INSTALL_UVC_CODEC=${LESAVKA_INSTALL_UVC_CODEC:-${PERSISTED_UVC_CODEC:-mjpeg}}" .contains("PERSISTED_UVC_CODEC=$(persisted_uvc_value LESAVKA_UVC_CODEC || true)")
), && SERVER_INSTALL.contains(
"plain upgrade installs should preserve the already-installed UVC codec" "REQUESTED_UVC_CODEC=${LESAVKA_INSTALL_UVC_CODEC:-${PERSISTED_UVC_CODEC:-mjpeg}}"
)
&& SERVER_INSTALL
.contains("INSTALL_UVC_CODEC=$(normalize_uvc_codec \"$REQUESTED_UVC_CODEC\")"),
"plain upgrade installs should normalize persisted UVC output to the supported MJPEG helper path"
); );
assert!( assert!(
SERVER_INSTALL.contains("${LESAVKA_INSTALL_UVC_FRAME_META:-${LESAVKA_UVC_FRAME_META:-0}}") SERVER_INSTALL.contains("${LESAVKA_INSTALL_UVC_FRAME_META:-${LESAVKA_UVC_FRAME_META:-0}}")
@ -167,6 +171,11 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
!SERVER_INSTALL.contains("LESAVKA_UVC_CODEC=${LESAVKA_UVC_CODEC:-mjpeg}"), !SERVER_INSTALL.contains("LESAVKA_UVC_CODEC=${LESAVKA_UVC_CODEC:-mjpeg}"),
"install script should not let ambient LESAVKA_UVC_CODEC leak into persisted defaults" "install script should not let ambient LESAVKA_UVC_CODEC leak into persisted defaults"
); );
assert!(
SERVER_INSTALL
.contains("UVC gadget output codec '${REQUESTED_UVC_CODEC}' is not supported"),
"install script should not keep creating YUYV descriptors under the misleading HEVC UVC label"
);
assert!( assert!(
SERVER_INSTALL.contains("ensure_hevc_decode_support"), SERVER_INSTALL.contains("ensure_hevc_decode_support"),
"install script should prepare HEVC decode dependencies for the default uplink codec" "install script should prepare HEVC decode dependencies for the default uplink codec"

View File

@ -19,7 +19,9 @@ const CLIENT_CAMERA: &str = include_str!(concat!(
fn server_install_defaults_to_hevc_ingress_and_mjpeg_uvc_output() { fn server_install_defaults_to_hevc_ingress_and_mjpeg_uvc_output() {
for marker in [ for marker in [
"PERSISTED_UVC_CODEC=$(persisted_uvc_value LESAVKA_UVC_CODEC || true)", "PERSISTED_UVC_CODEC=$(persisted_uvc_value LESAVKA_UVC_CODEC || true)",
"INSTALL_UVC_CODEC=${LESAVKA_INSTALL_UVC_CODEC:-${PERSISTED_UVC_CODEC:-mjpeg}}", "normalize_uvc_codec()",
"REQUESTED_UVC_CODEC=${LESAVKA_INSTALL_UVC_CODEC:-${PERSISTED_UVC_CODEC:-mjpeg}}",
"INSTALL_UVC_CODEC=$(normalize_uvc_codec \"$REQUESTED_UVC_CODEC\")",
"INSTALL_CAM_CODEC=${LESAVKA_INSTALL_CAM_CODEC:-${LESAVKA_CAM_CODEC:-hevc}}", "INSTALL_CAM_CODEC=${LESAVKA_INSTALL_CAM_CODEC:-${LESAVKA_CAM_CODEC:-hevc}}",
"printf 'LESAVKA_CAM_CODEC=%s\\n' \"${INSTALL_CAM_CODEC}\"", "printf 'LESAVKA_CAM_CODEC=%s\\n' \"${INSTALL_CAM_CODEC}\"",
"printf 'LESAVKA_UVC_CODEC=%s\\n' \"${INSTALL_UVC_CODEC}\"", "printf 'LESAVKA_UVC_CODEC=%s\\n' \"${INSTALL_UVC_CODEC}\"",
@ -43,6 +45,11 @@ fn server_install_does_not_let_ambient_uvc_codec_override_persisted_default() {
SERVER_INSTALL.contains("LESAVKA_INSTALL_UVC_CODEC"), SERVER_INSTALL.contains("LESAVKA_INSTALL_UVC_CODEC"),
"operator install override should remain available" "operator install override should remain available"
); );
assert!(
SERVER_INSTALL
.contains("UVC gadget output codec '${REQUESTED_UVC_CODEC}' is not supported"),
"unsupported host-facing UVC codecs should be downgraded loudly instead of creating a stale YUYV descriptor"
);
} }
#[test] #[test]