From 42c7c5982c977181306928772568e729ee05a6c6 Mon Sep 17 00:00:00 2001 From: 21pages Date: Thu, 9 Jun 2022 19:46:41 +0800 Subject: [PATCH] scrap: check hwconfig in another process Signed-off-by: 21pages --- Cargo.lock | 2 +- Cargo.toml | 1 + libs/hbb_common/src/config.rs | 38 ++++++++++++++ libs/scrap/src/common/codec.rs | 6 +-- libs/scrap/src/common/hwcodec.rs | 88 +++++++++++++++++++++----------- src/ipc.rs | 29 ++++++++++- src/main.rs | 13 +++++ 7 files changed, 141 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a42715628..7decf58f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2236,7 +2236,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hwcodec" version = "0.1.0" -source = "git+https://github.com/21pages/hwcodec#6bb387828c9aa69861b707b0f71472b21b5b1711" +source = "git+https://github.com/21pages/hwcodec#3ef5b674d3721699daba1f78569eb9c706cb206c" dependencies = [ "bindgen", "cc", diff --git a/Cargo.toml b/Cargo.toml index 4b5b5dd29..7c0946754 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ cli = [] use_samplerate = ["samplerate"] use_rubato = ["rubato"] use_dasp = ["dasp"] +hwcodec = ["scrap/hwcodec"] default = ["use_dasp"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index ce0fc509a..6bfef1f97 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -35,6 +35,7 @@ lazy_static::lazy_static! { static ref CONFIG: Arc> = Arc::new(RwLock::new(Config::load())); static ref CONFIG2: Arc> = Arc::new(RwLock::new(Config2::load())); static ref LOCAL_CONFIG: Arc> = Arc::new(RwLock::new(LocalConfig::load())); + static ref HWCODEC_CONFIG: Arc> = Arc::new(RwLock::new(HwCodecConfig::load())); pub static ref ONLINE: Arc>> = Default::default(); pub static ref PROD_RENDEZVOUS_SERVER: Arc> = Default::default(); pub static ref APP_NAME: Arc> = Arc::new(RwLock::new("RustDesk".to_owned())); @@ -871,6 +872,43 @@ impl LanPeers { } } +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct HwCodecConfig { + #[serde(default)] + options: HashMap, +} + +impl HwCodecConfig { + fn load() -> HwCodecConfig { + Config::load_::("_hwcodec") + } + + fn store(&self) { + Config::store_(self, "_hwcodec"); + } + + pub fn get_option(k: &str) -> String { + if let Some(v) = HWCODEC_CONFIG.read().unwrap().options.get(k) { + v.clone() + } else { + "".to_owned() + } + } + + pub fn set_option(k: String, v: String) { + let mut config = HWCODEC_CONFIG.write().unwrap(); + let v2 = if v.is_empty() { None } else { Some(&v) }; + if v2 != config.options.get(&k) { + if v2.is_none() { + config.options.remove(&k); + } else { + config.options.insert(k, v); + } + config.store(); + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/libs/scrap/src/common/codec.rs b/libs/scrap/src/common/codec.rs index 9e9a824dd..bfc93fabc 100644 --- a/libs/scrap/src/common/codec.rs +++ b/libs/scrap/src/common/codec.rs @@ -103,7 +103,7 @@ impl Encoder { codec: Box::new(hw), }), Err(e) => { - HwEncoder::best(true); + HwEncoder::best(true, true); Err(e) } }, @@ -114,7 +114,7 @@ impl Encoder { // TODO pub fn update_video_encoder(id: i32, update: EncoderUpdate) { - log::info!("update video encoder:{:?}", update); + log::info!("encoder update: {:?}", update); #[cfg(feature = "hwcodec")] { let mut states = PEER_DECODER_STATES.lock().unwrap(); @@ -133,7 +133,7 @@ impl Encoder { } let current_encoder_name = HwEncoder::current_name(); if states.len() > 0 { - let best = HwEncoder::best(false); + let (best, _) = HwEncoder::best(false, true); let enabled_h264 = best.h264.is_some() && states.len() > 0 && states.iter().all(|(_, s)| s.H264); let enabled_h265 = diff --git a/libs/scrap/src/common/hwcodec.rs b/libs/scrap/src/common/hwcodec.rs index 2d7b6b138..ec4e7082c 100644 --- a/libs/scrap/src/common/hwcodec.rs +++ b/libs/scrap/src/common/hwcodec.rs @@ -4,7 +4,7 @@ use crate::{ }; use hbb_common::{ anyhow::{anyhow, Context}, - config::LocalConfig, + config::HwCodecConfig, lazy_static, log, message_proto::{H264s, H265s, Message, VideoFrame, H264, H265}, ResultType, @@ -17,12 +17,18 @@ use hwcodec::{ Quality::{self, *}, RateContorl::{self, *}, }; -use std::sync::{Arc, Mutex}; +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; lazy_static::lazy_static! { static ref HW_ENCODER_NAME: Arc>> = Default::default(); } +const CFG_KEY_ENCODER: &str = "bestHwEncoders"; +const CFG_KEY_DECODER: &str = "bestHwDecoders"; + const DEFAULT_PIXFMT: AVPixelFormat = AVPixelFormat::AV_PIX_FMT_YUV420P; const DEFAULT_TIME_BASE: [i32; 2] = [1, 30]; const DEFAULT_GOP: i32 = 60; @@ -137,12 +143,19 @@ impl EncoderApi for HwEncoder { } impl HwEncoder { - pub fn best(force_reset: bool) -> CodecInfos { - let key = "bestHwEncoders"; - - let config = get_config(key); + /// Get best encoders. + /// + /// # Parameter + /// `force_reset`: force to refresh config. + /// `write`: write to config file. + /// + /// # Return + /// `CodecInfos`: infos. + /// `bool`: whether the config is refreshed. + pub fn best(force_reset: bool, write: bool) -> (CodecInfos, bool) { + let config = get_config(CFG_KEY_ENCODER); if !force_reset && config.is_ok() { - config.unwrap() + (config.unwrap(), false) } else { let ctx = EncodeContext { name: String::from(""), @@ -157,10 +170,12 @@ impl HwEncoder { rc: DEFAULT_RC, }; let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx)); - let _ = set_config(key, &encoders) - .map_err(|e| log::error!("{:?}", e)) - .ok(); - encoders + if write { + let _ = set_config(CFG_KEY_ENCODER, &encoders) + .map_err(|e| log::error!("{:?}", e)) + .ok(); + } + (encoders, true) } } @@ -234,23 +249,24 @@ pub struct HwDecoders { } impl HwDecoder { - /// H264, H265 decoder info with the highest score. - fn best(force_reset: bool) -> CodecInfos { - let key = "bestHwDecoders"; - let config = get_config(key); + /// See HwEncoder::best + fn best(force_reset: bool, write: bool) -> (CodecInfos, bool) { + let config = get_config(CFG_KEY_DECODER); if !force_reset && config.is_ok() { - config.unwrap() + (config.unwrap(), false) } else { let decoders = CodecInfo::score(Decoder::avaliable_decoders()); - set_config(key, &decoders) - .map_err(|e| log::error!("{:?}", e)) - .ok(); - decoders + if write { + set_config(CFG_KEY_DECODER, &decoders) + .map_err(|e| log::error!("{:?}", e)) + .ok(); + } + (decoders, true) } } pub fn new_decoders() -> HwDecoders { - let best = HwDecoder::best(false); + let (best, _) = HwDecoder::best(false, true); let mut h264: Option = None; let mut h265: Option = None; let mut fail = false; @@ -268,14 +284,7 @@ impl HwDecoder { } } if fail { - HwDecoder::best(true); - } - - if h264.is_some() { - log::info!("h264 decoder:{:?}", h264.as_ref().unwrap().info); - } - if h265.is_some() { - log::info!("h265 decoder:{:?}", h265.as_ref().unwrap().info); + HwDecoder::best(true, true); } HwDecoders { h264, h265 } } @@ -336,7 +345,7 @@ impl HwDecoderImage<'_> { } fn get_config(k: &str) -> ResultType { - let v = LocalConfig::get_option(k); + let v = HwCodecConfig::get_option(k); match CodecInfos::deserialize(&v) { Ok(v) => Ok(v), Err(_) => Err(anyhow!("Failed to get config:{}", k)), @@ -346,9 +355,26 @@ fn get_config(k: &str) -> ResultType { fn set_config(k: &str, v: &CodecInfos) -> ResultType<()> { match v.serialize() { Ok(v) => { - LocalConfig::set_option(k.to_owned(), v); + HwCodecConfig::set_option(k.to_owned(), v); Ok(()) } Err(_) => Err(anyhow!("Failed to set config:{}", k)), } } + +pub fn check_config() -> Option> { + let (encoders, update_encoders) = HwEncoder::best(false, false); + let (decoders, update_decoders) = HwDecoder::best(false, false); + if update_encoders || update_decoders { + if let Ok(encoders) = encoders.serialize() { + if let Ok(decoders) = decoders.serialize() { + return Some(HashMap::from([ + (CFG_KEY_ENCODER.to_owned(), encoders), + (CFG_KEY_DECODER.to_owned(), decoders), + ])); + } + } + log::error!("Failed to serialize codec info"); + } + None +} diff --git a/src/ipc.rs b/src/ipc.rs index 2388a7d9c..be9f6d87f 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,6 +1,8 @@ use crate::rendezvous_mediator::RendezvousMediator; #[cfg(not(any(target_os = "android", target_os = "ios")))] pub use clipboard::ClipbaordFile; +#[cfg(feature = "hwcodec")] +use hbb_common::config::HwCodecConfig; use hbb_common::{ allow_err, bail, bytes, bytes_codec::BytesCodec, @@ -63,7 +65,7 @@ pub enum FS { WriteOffset { id: i32, file_num: i32, - offset_blk: u32 + offset_blk: u32, }, CheckDigest { id: i32, @@ -116,6 +118,8 @@ pub enum Data { #[cfg(not(any(target_os = "android", target_os = "ios")))] ClipbaordFile(ClipbaordFile), ClipboardFileEnabled(bool), + #[cfg(feature = "hwcodec")] + HwCodecConfig(Option>), } #[tokio::main(flavor = "current_thread")] @@ -325,6 +329,12 @@ async fn handle(data: Data, stream: &mut Connection) { .await ); } + #[cfg(feature = "hwcodec")] + Data::HwCodecConfig(Some(config)) => { + for (k, v) in config { + HwCodecConfig::set_option(k, v); + } + } _ => {} } } @@ -624,3 +634,20 @@ pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> { .await?; Ok(()) } + +#[cfg(feature = "hwcodec")] +#[tokio::main] +pub async fn check_hwcodec_config() { + if let Some(config) = scrap::hwcodec::check_config() { + match connect(1000, "").await { + Ok(mut conn) => { + if conn.send(&Data::HwCodecConfig(Some(config))).await.is_err() { + log::error!("Failed to send hwcodec config by ipc"); + } + } + Err(err) => { + log::info!("Failed to connect ipc: {:?}", err); + } + } + } +} diff --git a/src/main.rs b/src/main.rs index d802b8ae9..16c365f5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,6 +70,15 @@ fn main() { } if args.is_empty() { std::thread::spawn(move || start_server(false)); + #[cfg(feature = "hwcodec")] + if let Ok(exe) = std::env::current_exe() { + std::thread::spawn(move || { + std::process::Command::new(exe) + .arg("--check-hwcodec-config") + .status() + .ok() + }); + } } else { #[cfg(windows)] { @@ -104,6 +113,10 @@ fn main() { "".to_owned() )); return; + } else if args[0] == "--check-hwcodec-config" { + #[cfg(feature = "hwcodec")] + ipc::check_hwcodec_config(); + return; } } if args[0] == "--remove" {