mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-02-01 02:21:53 +08:00
feat(rustdesk): 完整实现RustDesk协议和P2P连接
重大变更: - 从prost切换到protobuf 3.4实现完整的RustDesk协议栈 - 新增P2P打洞模块(punch.rs)支持直连和中继回退 - 重构加密系统:临时Curve25519密钥对+Ed25519签名 - 完善HID适配器:支持CapsLock状态同步和修饰键映射 - 添加音频流支持:Opus编码+音频帧适配器 - 优化视频流:改进帧适配器和编码器协商 - 移除pacer.rs简化视频管道 扩展系统: - 在设置向导中添加扩展步骤(ttyd/rustdesk切换) - 扩展可用性检测和自动启动 - 新增WebConfig handler用于Web服务器配置 前端改进: - SetupView增加第4步扩展配置 - 音频设备列表和配置界面 - 新增多语言支持(en-US/zh-CN) - TypeScript类型生成更新 文档: - 更新系统架构文档 - 完善config/hid/rustdesk/video/webrtc模块文档
This commit is contained in:
@@ -10,7 +10,6 @@ pub mod encoder;
|
||||
pub mod format;
|
||||
pub mod frame;
|
||||
pub mod h264_pipeline;
|
||||
pub mod pacer;
|
||||
pub mod shared_video_pipeline;
|
||||
pub mod stream_manager;
|
||||
pub mod streamer;
|
||||
@@ -19,7 +18,6 @@ pub mod video_session;
|
||||
pub use capture::VideoCapturer;
|
||||
pub use convert::{MjpegDecoder, MjpegToYuv420Converter, PixelConverter, Yuv420pBuffer};
|
||||
pub use decoder::{MjpegVaapiDecoder, MjpegVaapiDecoderConfig};
|
||||
pub use pacer::{EncoderPacer, PacerStats};
|
||||
pub use device::{VideoDevice, VideoDeviceInfo};
|
||||
pub use encoder::{JpegEncoder, H264Encoder, H264EncoderType};
|
||||
pub use format::PixelFormat;
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
//! Encoder Pacer - Placeholder for future backpressure control
|
||||
//!
|
||||
//! Currently a pass-through that allows all frames.
|
||||
//! TODO: Implement effective backpressure control.
|
||||
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use tracing::debug;
|
||||
|
||||
/// Encoder pacing statistics
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PacerStats {
|
||||
/// Total frames processed
|
||||
pub frames_processed: u64,
|
||||
/// Frames skipped (currently always 0)
|
||||
pub frames_skipped: u64,
|
||||
/// Keyframes processed
|
||||
pub keyframes_processed: u64,
|
||||
}
|
||||
|
||||
/// Encoder pacer (currently pass-through)
|
||||
///
|
||||
/// This is a placeholder for future backpressure control.
|
||||
/// Currently allows all frames through without throttling.
|
||||
pub struct EncoderPacer {
|
||||
frames_processed: AtomicU64,
|
||||
keyframes_processed: AtomicU64,
|
||||
}
|
||||
|
||||
impl EncoderPacer {
|
||||
/// Create a new encoder pacer
|
||||
pub fn new(_max_in_flight: usize) -> Self {
|
||||
debug!("Creating encoder pacer (pass-through mode)");
|
||||
Self {
|
||||
frames_processed: AtomicU64::new(0),
|
||||
keyframes_processed: AtomicU64::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if encoding should proceed (always returns true)
|
||||
pub async fn should_encode(&self, is_keyframe: bool) -> bool {
|
||||
self.frames_processed.fetch_add(1, Ordering::Relaxed);
|
||||
if is_keyframe {
|
||||
self.keyframes_processed.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
true // Always allow encoding
|
||||
}
|
||||
|
||||
/// Report lag from receiver (currently no-op)
|
||||
pub async fn report_lag(&self, _frames_lagged: u64) {
|
||||
// TODO: Implement effective backpressure control
|
||||
// Currently this is a no-op
|
||||
}
|
||||
|
||||
/// Check if throttling (always false)
|
||||
pub fn is_throttling(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Get pacer statistics
|
||||
pub fn stats(&self) -> PacerStats {
|
||||
PacerStats {
|
||||
frames_processed: self.frames_processed.load(Ordering::Relaxed),
|
||||
frames_skipped: 0,
|
||||
keyframes_processed: self.keyframes_processed.load(Ordering::Relaxed),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get in-flight count (always 0)
|
||||
pub fn in_flight(&self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,6 @@ use crate::video::encoder::vp8::{VP8Config, VP8Encoder};
|
||||
use crate::video::encoder::vp9::{VP9Config, VP9Encoder};
|
||||
use crate::video::format::{PixelFormat, Resolution};
|
||||
use crate::video::frame::VideoFrame;
|
||||
use crate::video::pacer::EncoderPacer;
|
||||
|
||||
/// Encoded video frame for distribution
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -71,8 +70,6 @@ pub struct SharedVideoPipelineConfig {
|
||||
pub fps: u32,
|
||||
/// Encoder backend (None = auto select best available)
|
||||
pub encoder_backend: Option<EncoderBackend>,
|
||||
/// Maximum in-flight frames for backpressure control
|
||||
pub max_in_flight_frames: usize,
|
||||
}
|
||||
|
||||
impl Default for SharedVideoPipelineConfig {
|
||||
@@ -84,7 +81,6 @@ impl Default for SharedVideoPipelineConfig {
|
||||
bitrate_preset: crate::video::encoder::BitratePreset::Balanced,
|
||||
fps: 30,
|
||||
encoder_backend: None,
|
||||
max_in_flight_frames: 8, // Default: allow 8 frames in flight
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,7 +149,6 @@ pub struct SharedVideoPipelineStats {
|
||||
pub frames_captured: u64,
|
||||
pub frames_encoded: u64,
|
||||
pub frames_dropped: u64,
|
||||
/// Frames skipped due to backpressure (pacer)
|
||||
pub frames_skipped: u64,
|
||||
pub bytes_encoded: u64,
|
||||
pub keyframes_encoded: u64,
|
||||
@@ -161,8 +156,6 @@ pub struct SharedVideoPipelineStats {
|
||||
pub current_fps: f32,
|
||||
pub errors: u64,
|
||||
pub subscribers: u64,
|
||||
/// Current number of frames in-flight (waiting to be sent)
|
||||
pub pending_frames: usize,
|
||||
}
|
||||
|
||||
|
||||
@@ -326,21 +319,18 @@ pub struct SharedVideoPipeline {
|
||||
/// Pipeline start time for PTS calculation (epoch millis, 0 = not set)
|
||||
/// Uses AtomicI64 instead of Mutex for lock-free access
|
||||
pipeline_start_time_ms: AtomicI64,
|
||||
/// Encoder pacer for backpressure control
|
||||
pacer: EncoderPacer,
|
||||
}
|
||||
|
||||
impl SharedVideoPipeline {
|
||||
/// Create a new shared video pipeline
|
||||
pub fn new(config: SharedVideoPipelineConfig) -> Result<Arc<Self>> {
|
||||
info!(
|
||||
"Creating shared video pipeline: {} {}x{} @ {} (input: {}, max_in_flight: {})",
|
||||
"Creating shared video pipeline: {} {}x{} @ {} (input: {})",
|
||||
config.output_codec,
|
||||
config.resolution.width,
|
||||
config.resolution.height,
|
||||
config.bitrate_preset,
|
||||
config.input_format,
|
||||
config.max_in_flight_frames
|
||||
config.input_format
|
||||
);
|
||||
|
||||
let (frame_tx, _) = broadcast::channel(16); // Reduced from 64 for lower latency
|
||||
@@ -348,9 +338,6 @@ impl SharedVideoPipeline {
|
||||
let nv12_size = (config.resolution.width * config.resolution.height * 3 / 2) as usize;
|
||||
let yuv420p_size = nv12_size; // Same size as NV12
|
||||
|
||||
// Create pacer for backpressure control
|
||||
let pacer = EncoderPacer::new(config.max_in_flight_frames);
|
||||
|
||||
let pipeline = Arc::new(Self {
|
||||
config: RwLock::new(config),
|
||||
encoder: Mutex::new(None),
|
||||
@@ -369,7 +356,6 @@ impl SharedVideoPipeline {
|
||||
sequence: AtomicU64::new(0),
|
||||
keyframe_requested: AtomicBool::new(false),
|
||||
pipeline_start_time_ms: AtomicI64::new(0),
|
||||
pacer,
|
||||
});
|
||||
|
||||
Ok(pipeline)
|
||||
@@ -620,14 +606,13 @@ impl SharedVideoPipeline {
|
||||
/// Report that a receiver has lagged behind
|
||||
///
|
||||
/// Call this when a broadcast receiver detects it has fallen behind
|
||||
/// (e.g., when RecvError::Lagged is received). This triggers throttle
|
||||
/// mode in the encoder to reduce encoding rate.
|
||||
/// (e.g., when RecvError::Lagged is received).
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `frames_lagged` - Number of frames the receiver has lagged
|
||||
pub async fn report_lag(&self, frames_lagged: u64) {
|
||||
self.pacer.report_lag(frames_lagged).await;
|
||||
/// * `_frames_lagged` - Number of frames the receiver has lagged (currently unused)
|
||||
pub async fn report_lag(&self, _frames_lagged: u64) {
|
||||
// No-op: backpressure control removed as it was not effective
|
||||
}
|
||||
|
||||
/// Request encoder to produce a keyframe on next encode
|
||||
@@ -645,15 +630,9 @@ impl SharedVideoPipeline {
|
||||
pub async fn stats(&self) -> SharedVideoPipelineStats {
|
||||
let mut stats = self.stats.lock().await.clone();
|
||||
stats.subscribers = self.frame_tx.receiver_count() as u64;
|
||||
stats.pending_frames = if self.pacer.is_throttling() { 1 } else { 0 };
|
||||
stats
|
||||
}
|
||||
|
||||
/// Get pacer statistics for debugging
|
||||
pub fn pacer_stats(&self) -> crate::video::pacer::PacerStats {
|
||||
self.pacer.stats()
|
||||
}
|
||||
|
||||
/// Check if running
|
||||
pub fn is_running(&self) -> bool {
|
||||
*self.running_rx.borrow()
|
||||
@@ -777,14 +756,6 @@ impl SharedVideoPipeline {
|
||||
}
|
||||
}
|
||||
|
||||
// === Lag-feedback based flow control ===
|
||||
// Check if this is a keyframe interval
|
||||
let is_keyframe_interval = frame_count % gop_size as u64 == 0;
|
||||
|
||||
// Note: pacer.should_encode() currently always returns true
|
||||
// TODO: Implement effective backpressure control
|
||||
let _ = pipeline.pacer.should_encode(is_keyframe_interval).await;
|
||||
|
||||
match pipeline.encode_frame(&video_frame, frame_count).await {
|
||||
Ok(Some(encoded_frame)) => {
|
||||
// Send frame to all subscribers
|
||||
@@ -822,7 +793,6 @@ impl SharedVideoPipeline {
|
||||
s.errors += local_errors;
|
||||
s.frames_dropped += local_dropped;
|
||||
s.frames_skipped += local_skipped;
|
||||
s.pending_frames = if pipeline.pacer.is_throttling() { 1 } else { 0 };
|
||||
s.current_fps = current_fps;
|
||||
|
||||
// Reset local counters
|
||||
|
||||
Reference in New Issue
Block a user