mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-09-13 02:54:26 +08:00
fix: 为 RKCIF/RK628 选择受支持的视频格式 (#292)
RK628 通过 RKCIF 接入时,如果 One-KVM 启动时 HDMI 信号尚未锁定, SourceFollowing 路径可能回退到默认 MJPEG。由于 RKCIF 不支持 MJPEG, 后续 S_FMT 无法建立有效的采集链路。 解决方案: 在解析 SourceFollowing 配置后,根据设备的 VIDIOC_ENUM_FMT 枚举结果 校验最终格式。如果该格式不受支持且格式列表非空,则选择按优先级排序 的首个可用格式,对于 RKCIF/RK628 通常为 NV12。 该方法只替换 FourCC,保留 HDMI DV timings 提供的分辨率和帧率。 同时覆盖无信号启动和当前格式已失效两种场景。
This commit is contained in:
@@ -125,6 +125,12 @@ pub fn resolve_video_input_config(
|
||||
requested_resolution: Resolution,
|
||||
requested_fps: u32,
|
||||
) -> ResolvedVideoInputConfig {
|
||||
let mut resolved = ResolvedVideoInputConfig {
|
||||
format: requested_format,
|
||||
resolution: requested_resolution,
|
||||
fps: requested_fps,
|
||||
};
|
||||
|
||||
if device.control_mode == VideoControlMode::SourceFollowing {
|
||||
if let VideoInputStatus {
|
||||
state: VideoInputState::Locked,
|
||||
@@ -135,26 +141,39 @@ pub fn resolve_video_input_config(
|
||||
} = &device.input_status
|
||||
{
|
||||
if let Ok(format) = format.parse::<PixelFormat>() {
|
||||
return ResolvedVideoInputConfig {
|
||||
resolved = ResolvedVideoInputConfig {
|
||||
format,
|
||||
resolution: Resolution::new(*width, *height),
|
||||
fps: fps.round().clamp(1.0, 120.0) as u32,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Source-following devices do not allow One-KVM to choose the HDMI
|
||||
// resolution or frame rate, but their pixel format still has to be one
|
||||
// of the formats enumerated by the capture node. In particular, rkcif
|
||||
// commonly exposes NV12 but One-KVM's default is MJPEG. Passing that
|
||||
// unsupported default to S_FMT leaves the pipeline in an invalid state.
|
||||
if !device.formats.is_empty()
|
||||
&& !device
|
||||
.formats
|
||||
.iter()
|
||||
.any(|format| format.format == resolved.format)
|
||||
{
|
||||
resolved.format = device.formats[0].format;
|
||||
}
|
||||
}
|
||||
|
||||
ResolvedVideoInputConfig {
|
||||
format: requested_format,
|
||||
resolution: requested_resolution,
|
||||
fps: requested_fps,
|
||||
}
|
||||
resolved
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(unix)]
|
||||
use super::linux::FormatInfo;
|
||||
|
||||
#[cfg(unix)]
|
||||
fn device(control_mode: VideoControlMode, input_status: VideoInputStatus) -> VideoDeviceInfo {
|
||||
VideoDeviceInfo {
|
||||
@@ -175,6 +194,15 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn format(format: PixelFormat) -> FormatInfo {
|
||||
FormatInfo {
|
||||
format,
|
||||
resolutions: Vec::new(),
|
||||
description: format.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recognizes_vendor_and_upstream_native_hdmirx_names() {
|
||||
assert!(is_rk_hdmirx_driver("rk_hdmirx", "rk_hdmirx"));
|
||||
@@ -246,6 +274,48 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn source_following_replaces_unenumerated_default_format_without_signal() {
|
||||
let mut device = device(
|
||||
VideoControlMode::SourceFollowing,
|
||||
VideoInputStatus::no_signal(),
|
||||
);
|
||||
device.formats = vec![format(PixelFormat::Nv12), format(PixelFormat::Yuyv)];
|
||||
|
||||
let resolved = resolve_video_input_config(
|
||||
&device,
|
||||
PixelFormat::Mjpeg,
|
||||
Resolution::new(1920, 1080),
|
||||
30,
|
||||
);
|
||||
|
||||
assert_eq!(resolved.format, PixelFormat::Nv12);
|
||||
assert_eq!(resolved.resolution, Resolution::new(1920, 1080));
|
||||
assert_eq!(resolved.fps, 30);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn source_following_replaces_stale_active_format_but_keeps_input_mode() {
|
||||
let mut device = device(
|
||||
VideoControlMode::SourceFollowing,
|
||||
VideoInputStatus::locked(PixelFormat::Mjpeg, 1280, 720, 59.94),
|
||||
);
|
||||
device.formats = vec![format(PixelFormat::Nv12), format(PixelFormat::Yuyv)];
|
||||
|
||||
let resolved = resolve_video_input_config(
|
||||
&device,
|
||||
PixelFormat::Mjpeg,
|
||||
Resolution::new(1920, 1080),
|
||||
30,
|
||||
);
|
||||
|
||||
assert_eq!(resolved.format, PixelFormat::Nv12);
|
||||
assert_eq!(resolved.resolution, Resolution::new(1280, 720));
|
||||
assert_eq!(resolved.fps, 60);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_signal_and_unavailable_never_expose_stale_mode_fields() {
|
||||
for status in [
|
||||
|
||||
Reference in New Issue
Block a user