feat: v4l2 buffer 由2改为4

This commit is contained in:
mofeng-git
2026-07-05 21:15:44 +08:00
parent bb2691fe8f
commit 16a65289f2
4 changed files with 11 additions and 24 deletions

View File

@@ -3,6 +3,8 @@
pub(crate) mod runtime;
pub(crate) mod status;
pub const DEFAULT_CAPTURE_BUFFER_COUNT: u32 = 4;
#[cfg(unix)]
mod linux;
#[cfg(windows)]

View File

@@ -38,7 +38,6 @@ const CSI_BRIDGE_NOSIGNAL_INTERVAL_MS: u64 = 500;
const NOSIGNAL_POLL_MAX: Duration = Duration::from_secs(20);
/// Throttle repeated encoding errors to avoid log flooding
const ENCODE_ERROR_THROTTLE_SECS: u64 = 5;
const INVALID_MJPEG_LOG_THROTTLE_SECS: u64 = 5;
static PROCESS_START: std::sync::OnceLock<Instant> = std::sync::OnceLock::new();
@@ -61,6 +60,7 @@ use crate::video::frame::{FrameBuffer, FrameBufferPool, VideoFrame};
use crate::video::signal::SignalStatus;
const MIN_CAPTURE_FRAME_SIZE: usize = 128;
#[cfg(all(
any(target_arch = "aarch64", target_arch = "arm"),
not(target_os = "android")
@@ -870,8 +870,6 @@ impl SharedVideoPipeline {
let mut sequence: u64 = 0;
let mut consecutive_timeouts: u32 = 0;
let capture_error_throttler = LogThrottler::with_secs(5);
let invalid_mjpeg_throttler =
LogThrottler::with_secs(INVALID_MJPEG_LOG_THROTTLE_SECS);
let mut suppressed_capture_errors: HashMap<String, u64> = HashMap::new();
while pipeline.running_flag.load(Ordering::Acquire) {
@@ -1232,24 +1230,8 @@ impl SharedVideoPipeline {
}
owned.truncate(frame_size);
if pixel_format.is_compressed() && !VideoFrame::is_valid_jpeg_bytes(&owned) {
if invalid_mjpeg_throttler.should_log("invalid_mjpeg_capture_frame") {
let b0 = owned.first().copied().unwrap_or_default();
let b1 = owned.get(1).copied().unwrap_or_default();
warn!(
"Dropping invalid MJPEG capture frame: size={}, starts with 0x{:02x} 0x{:02x}",
owned.len(),
b0,
b1
);
}
continue;
}
// Notify streaming only after frame validation passes
// stale/warm-up frames from V4L2 kernel queues can cause
// DQBUF Ok with invalid data, which would prematurely
// clear the frontend error overlay.
// Notify streaming only after the short-frame guard passes.
pipeline.notify_state(PipelineStateNotification::streaming());
let frame = Arc::new(VideoFrame::from_pooled(
Arc::new(FrameBuffer::new(owned, Some(buffer_pool.clone()))),

View File

@@ -27,7 +27,9 @@ use crate::video::capture::status::{
capture_error_log_key, classify_capture_io_error, signal_status_from_capture_kind,
CaptureIoErrorKind,
};
use crate::video::capture::{is_source_changed_error, BridgeContext, CaptureStream};
use crate::video::capture::{
is_source_changed_error, BridgeContext, CaptureStream, DEFAULT_CAPTURE_BUFFER_COUNT,
};
const MIN_CAPTURE_FRAME_SIZE: usize = 128;
@@ -769,7 +771,7 @@ impl Streamer {
const MAX_RETRIES: u32 = 5;
const RETRY_DELAY_MS: u64 = 200;
const IDLE_STOP_DELAY_SECS: u64 = 5;
const BUFFER_COUNT: u32 = 2;
const BUFFER_COUNT: u32 = DEFAULT_CAPTURE_BUFFER_COUNT;
/// Initial back-off after signal loss before the first soft restart.
///
/// PiKVM/ustreamer drops to sub-second recovery because it subscribes to

View File

@@ -12,6 +12,7 @@ use crate::audio::{AudioController, OpusFrame};
use crate::error::{AppError, Result};
use crate::events::{EventBus, StreamDeviceLostKind, SystemEvent};
use crate::hid::HidController;
use crate::video::capture::DEFAULT_CAPTURE_BUFFER_COUNT;
use crate::video::codec::h264_bitstream;
use crate::video::device::{
enumerate_devices, select_recovery_device, VideoDevice, VideoDeviceRecoveryHint,
@@ -319,7 +320,7 @@ impl WebRtcStreamer {
current_capture
.as_ref()
.map(|capture| capture.buffer_count)
.unwrap_or(2),
.unwrap_or(DEFAULT_CAPTURE_BUFFER_COUNT),
)
};
@@ -745,7 +746,7 @@ impl WebRtcStreamer {
});
*self.capture_device.write().await = Some(CaptureDeviceConfig {
device_path,
buffer_count: 2,
buffer_count: DEFAULT_CAPTURE_BUFFER_COUNT,
jpeg_quality,
subdev_path,
bridge_kind,