diff --git a/Cargo.lock b/Cargo.lock index 06763278a..48d488151 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3037,8 +3037,8 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hwcodec" -version = "0.4.15" -source = "git+https://github.com/21pages/hwcodec#1d504ee590c15472813fecc22cee4b8149b2b8cd" +version = "0.4.16" +source = "git+https://github.com/21pages/hwcodec#0973290faddc4e22936859dd10f05610eb8d1619" dependencies = [ "bindgen 0.59.2", "cc", diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index d2f568fd4..b9533407a 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -1553,40 +1553,6 @@ impl LanPeers { } } -#[derive(Debug, Default, Serialize, Deserialize, Clone)] -pub struct HwCodecConfig { - #[serde(default, deserialize_with = "deserialize_string")] - pub ram: String, - #[serde(default, deserialize_with = "deserialize_string")] - pub vram: String, -} - -impl HwCodecConfig { - pub fn load() -> HwCodecConfig { - Config::load_::("_hwcodec") - } - - pub fn store(&self) { - Config::store_(self, "_hwcodec"); - } - - pub fn clear() { - HwCodecConfig::default().store(); - } - - pub fn clear_ram() { - let mut c = Self::load(); - c.ram = Default::default(); - c.store(); - } - - pub fn clear_vram() { - let mut c = Self::load(); - c.vram = Default::default(); - c.store(); - } -} - #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct UserDefaultConfig { #[serde(default, deserialize_with = "deserialize_hashmap_string_string")] @@ -2238,6 +2204,18 @@ pub mod keys { ]; } +pub fn common_load< + T: serde::Serialize + serde::de::DeserializeOwned + Default + std::fmt::Debug, +>( + suffix: &str, +) -> T { + Config::load_::(suffix) +} + +pub fn common_store(config: &T, suffix: &str) { + Config::store_(config, suffix); +} + #[cfg(test)] mod tests { use super::*; diff --git a/libs/scrap/src/common/codec.rs b/libs/scrap/src/common/codec.rs index 098daa998..343b1997b 100644 --- a/libs/scrap/src/common/codec.rs +++ b/libs/scrap/src/common/codec.rs @@ -144,10 +144,7 @@ impl Encoder { }), Err(e) => { log::error!("new hw encoder failed: {e:?}, clear config"); - #[cfg(target_os = "android")] - crate::android::ffi::clear_codec_info(); - #[cfg(not(target_os = "android"))] - hbb_common::config::HwCodecConfig::clear_ram(); + HwCodecConfig::clear(false, true); Self::update(EncodingUpdate::Check); *ENCODE_CODEC_FORMAT.lock().unwrap() = CodecFormat::VP9; Err(e) @@ -160,7 +157,7 @@ impl Encoder { }), Err(e) => { log::error!("new vram encoder failed: {e:?}, clear config"); - hbb_common::config::HwCodecConfig::clear_vram(); + HwCodecConfig::clear(true, true); Self::update(EncodingUpdate::Check); *ENCODE_CODEC_FORMAT.lock().unwrap() = CodecFormat::VP9; Err(e) diff --git a/libs/scrap/src/common/hwcodec.rs b/libs/scrap/src/common/hwcodec.rs index 8c50d12c7..ed713887a 100644 --- a/libs/scrap/src/common/hwcodec.rs +++ b/libs/scrap/src/common/hwcodec.rs @@ -8,7 +8,6 @@ use crate::{ use hbb_common::{ anyhow::{anyhow, bail, Context}, bytes::Bytes, - config::HwCodecConfig, log, message_proto::{EncodedVideoFrame, EncodedVideoFrames, VideoFrame}, serde_derive::{Deserialize, Serialize}, @@ -16,7 +15,7 @@ use hbb_common::{ }; use hwcodec::{ common::{ - DataFormat, + get_gpu_signature, DataFormat, Quality::{self, *}, RateControl::{self, *}, }, @@ -35,6 +34,12 @@ const DEFAULT_HW_QUALITY: Quality = Quality_Default; crate::generate_call_macro!(call_yuv, false); +#[cfg(not(target_os = "android"))] +lazy_static::lazy_static! { + static ref CONFIG: std::sync::Arc>> = Default::default(); + static ref CONFIG_SET_BY_IPC: std::sync::Arc> = Default::default(); +} + #[derive(Debug, Clone)] pub struct HwRamEncoderConfig { pub name: String, @@ -210,21 +215,19 @@ impl EncoderApi for HwRamEncoder { impl HwRamEncoder { pub fn try_get(format: CodecFormat) -> Option { let mut info = None; - if let Ok(hw) = get_config().map(|c| c.e) { - let best = CodecInfo::prioritized(hw); - match format { - CodecFormat::H264 => { - if let Some(v) = best.h264 { - info = Some(v); - } + let best = CodecInfo::prioritized(HwCodecConfig::get().ram_encode); + match format { + CodecFormat::H264 => { + if let Some(v) = best.h264 { + info = Some(v); } - CodecFormat::H265 => { - if let Some(v) = best.h265 { - info = Some(v); - } - } - _ => {} } + CodecFormat::H265 => { + if let Some(v) = best.h265 { + info = Some(v); + } + } + _ => {} } info } @@ -313,21 +316,19 @@ impl HwRamDecoder { _ => {} } if enable_hwcodec_option() { - if let Ok(hw) = get_config().map(|c| c.d) { - let best = CodecInfo::prioritized(hw); - match format { - CodecFormat::H264 => { - if let Some(v) = best.h264 { - info = Some(v); - } + let best = CodecInfo::prioritized(HwCodecConfig::get().ram_decode); + match format { + CodecFormat::H264 => { + if let Some(v) = best.h264 { + info = Some(v); } - CodecFormat::H265 => { - if let Some(v) = best.h265 { - info = Some(v); - } - } - _ => {} } + CodecFormat::H265 => { + if let Some(v) = best.h265 { + info = Some(v); + } + } + _ => {} } } info @@ -347,10 +348,7 @@ impl HwRamDecoder { match Decoder::new(ctx) { Ok(decoder) => Ok(HwRamDecoder { decoder, info }), Err(_) => { - #[cfg(target_os = "android")] - crate::android::ffi::clear_codec_info(); - #[cfg(not(target_os = "android"))] - hbb_common::config::HwCodecConfig::clear_ram(); + HwCodecConfig::clear(false, false); Err(anyhow!(format!("Failed to create decoder"))) } } @@ -467,85 +465,6 @@ impl HwRamDecoderImage<'_> { } } -#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)] -struct Available { - e: Vec, - d: Vec, -} - -fn get_config() -> ResultType { - #[cfg(target_os = "android")] - { - let info = crate::android::ffi::get_codec_info(); - log::info!("all codec info: {info:?}"); - struct T { - name_prefix: &'static str, - data_format: DataFormat, - } - let ts = vec![ - T { - name_prefix: "h264", - data_format: DataFormat::H264, - }, - T { - name_prefix: "hevc", - data_format: DataFormat::H265, - }, - ]; - let mut e = vec![]; - if let Some(info) = info { - ts.iter().for_each(|t| { - let codecs: Vec<_> = info - .codecs - .iter() - .filter(|c| { - c.is_encoder - && c.mime_type.as_str() == get_mime_type(t.data_format) - && c.nv12 - && c.hw == Some(true) //only use hardware codec - }) - .collect(); - log::debug!("available {:?} encoders: {codecs:?}", t.data_format); - let screen_wh = std::cmp::max(info.w, info.h); - let mut best = None; - if let Some(codec) = codecs - .iter() - .find(|c| c.max_width >= screen_wh && c.max_height >= screen_wh) - { - best = Some(codec.name.clone()); - } else { - // find the max resolution - let mut max_area = 0; - for codec in codecs.iter() { - if codec.max_width * codec.max_height > max_area { - best = Some(codec.name.clone()); - max_area = codec.max_width * codec.max_height; - } - } - } - if let Some(best) = best { - e.push(CodecInfo { - name: format!("{}_mediacodec", t.name_prefix), - mc_name: Some(best), - format: t.data_format, - hwdevice: hwcodec::ffmpeg::AVHWDeviceType::AV_HWDEVICE_TYPE_NONE, - priority: 0, - }); - } - }); - } - log::debug!("e: {e:?}"); - Ok(Available { e, d: vec![] }) - } - #[cfg(not(target_os = "android"))] - { - match serde_json::from_str(&HwCodecConfig::load().ram) { - Ok(v) => Ok(v), - Err(e) => Err(anyhow!("Failed to get config:{e:?}")), - } - } -} - #[cfg(target_os = "android")] fn get_mime_type(codec: DataFormat) -> &'static str { match codec { @@ -557,7 +476,181 @@ fn get_mime_type(codec: DataFormat) -> &'static str { } } -pub fn check_available_hwcodec() { +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct HwCodecConfig { + #[serde(default)] + pub signature: u64, + #[serde(default)] + pub ram_encode: Vec, + #[serde(default)] + pub ram_decode: Vec, + #[cfg(feature = "vram")] + #[serde(default)] + pub vram_encode: Vec, + #[cfg(feature = "vram")] + #[serde(default)] + pub vram_decode: Vec, +} + +// ipc server process start check process once, other process get from ipc server once +// install: --server start check process, check process send to --server, ui get from --server +// portable: ui start check process, check process send to ui +// sciter and unilink: get from ipc server +impl HwCodecConfig { + #[cfg(any(target_os = "windows", target_os = "linux"))] + pub fn set(config: String) { + let config = serde_json::from_str(&config).unwrap_or_default(); + log::info!("set hwcodec config"); + log::debug!("{config:?}"); + #[cfg(windows)] + hbb_common::config::common_store(&config, "_hwcodec"); + *CONFIG.lock().unwrap() = Some(config); + *CONFIG_SET_BY_IPC.lock().unwrap() = true; + } + + pub fn get() -> HwCodecConfig { + #[cfg(target_os = "android")] + { + let info = crate::android::ffi::get_codec_info(); + log::info!("all codec info: {info:?}"); + struct T { + name_prefix: &'static str, + data_format: DataFormat, + } + let ts = vec![ + T { + name_prefix: "h264", + data_format: DataFormat::H264, + }, + T { + name_prefix: "hevc", + data_format: DataFormat::H265, + }, + ]; + let mut e = vec![]; + if let Some(info) = info { + ts.iter().for_each(|t| { + let codecs: Vec<_> = info + .codecs + .iter() + .filter(|c| { + c.is_encoder + && c.mime_type.as_str() == get_mime_type(t.data_format) + && c.nv12 + && c.hw == Some(true) //only use hardware codec + }) + .collect(); + let screen_wh = std::cmp::max(info.w, info.h); + let mut best = None; + if let Some(codec) = codecs + .iter() + .find(|c| c.max_width >= screen_wh && c.max_height >= screen_wh) + { + best = Some(codec.name.clone()); + } else { + // find the max resolution + let mut max_area = 0; + for codec in codecs.iter() { + if codec.max_width * codec.max_height > max_area { + best = Some(codec.name.clone()); + max_area = codec.max_width * codec.max_height; + } + } + } + if let Some(best) = best { + e.push(CodecInfo { + name: format!("{}_mediacodec", t.name_prefix), + mc_name: Some(best), + format: t.data_format, + hwdevice: hwcodec::ffmpeg::AVHWDeviceType::AV_HWDEVICE_TYPE_NONE, + priority: 0, + }); + } + }); + } + log::debug!("e: {e:?}"); + HwCodecConfig { + ram_encode: e, + ..Default::default() + } + } + #[cfg(windows)] + { + let config = CONFIG.lock().unwrap().clone(); + match config { + Some(c) => c, + None => { + log::info!("try load cached hwcodec config"); + let c = hbb_common::config::common_load::("_hwcodec"); + let new_signature = get_gpu_signature(); + if c.signature == new_signature { + log::debug!("load cached hwcodec config: {c:?}"); + *CONFIG.lock().unwrap() = Some(c.clone()); + c + } else { + log::info!( + "gpu signature changed, {} -> {}", + c.signature, + new_signature + ); + HwCodecConfig::default() + } + } + } + } + #[cfg(target_os = "linux")] + { + CONFIG.lock().unwrap().clone().unwrap_or_default() + } + #[cfg(any(target_os = "macos", target_os = "ios"))] + { + HwCodecConfig::default() + } + } + + #[cfg(any(target_os = "windows", target_os = "linux"))] + pub fn get_set_value() -> Option { + let set = CONFIG_SET_BY_IPC.lock().unwrap().clone(); + if set { + CONFIG.lock().unwrap().clone() + } else { + None + } + } + + #[cfg(any(target_os = "windows", target_os = "linux"))] + pub fn already_set() -> bool { + CONFIG_SET_BY_IPC.lock().unwrap().clone() + } + + pub fn clear(vram: bool, encode: bool) { + log::info!("clear hwcodec config, vram: {vram}, encode: {encode}"); + #[cfg(target_os = "android")] + crate::android::ffi::clear_codec_info(); + #[cfg(not(target_os = "android"))] + { + let mut c = CONFIG.lock().unwrap(); + if let Some(c) = c.as_mut() { + if vram { + #[cfg(feature = "vram")] + if encode { + c.vram_encode = vec![]; + } else { + c.vram_decode = vec![]; + } + } else { + if encode { + c.ram_encode = vec![]; + } else { + c.ram_decode = vec![]; + } + } + } + } + } +} + +pub fn check_available_hwcodec() -> String { let ctx = EncodeContext { name: String::from(""), mc_name: None, @@ -575,29 +668,31 @@ pub fn check_available_hwcodec() { }; #[cfg(feature = "vram")] let vram = crate::vram::check_available_vram(); + #[cfg(feature = "vram")] + let vram_string = vram.2; #[cfg(not(feature = "vram"))] - let vram = "".to_owned(); - let ram = Available { - e: Encoder::available_encoders(ctx, Some(vram.clone())), - d: Decoder::available_decoders(Some(vram.clone())), + let vram_string = "".to_owned(); + let c = HwCodecConfig { + ram_encode: Encoder::available_encoders(ctx, Some(vram_string.clone())), + ram_decode: Decoder::available_decoders(Some(vram_string)), + #[cfg(feature = "vram")] + vram_encode: vram.0, + #[cfg(feature = "vram")] + vram_decode: vram.1, + signature: get_gpu_signature(), }; - if let Ok(ram) = serde_json::to_string_pretty(&ram) { - HwCodecConfig { ram, vram }.store(); - } + log::debug!("{c:?}"); + serde_json::to_string(&c).unwrap_or_default() } #[cfg(any(target_os = "windows", target_os = "linux"))] -pub fn start_check_process(force: bool) { - if !force && !enable_hwcodec_option() { +pub fn start_check_process() { + if !enable_hwcodec_option() || HwCodecConfig::already_set() { return; } use hbb_common::allow_err; use std::sync::Once; let f = || { - // Clear to avoid checking process errors - // But when the program is just started, the configuration file has not been updated, and the new connection will read an empty configuration - // TODO: --server start multi times on windows startup, which will clear the last config and cause concurrent file writing - HwCodecConfig::clear(); if let Ok(exe) = std::env::current_exe() { if let Some(_) = exe.file_name().to_owned() { let arg = "--check-hwcodec-config"; @@ -631,11 +726,7 @@ pub fn start_check_process(force: bool) { }; }; static ONCE: Once = Once::new(); - if force && ONCE.is_completed() { + ONCE.call_once(|| { std::thread::spawn(f); - } else { - ONCE.call_once(|| { - std::thread::spawn(f); - }); - } + }); } diff --git a/libs/scrap/src/common/vram.rs b/libs/scrap/src/common/vram.rs index d99a6bc59..8baf6ea69 100644 --- a/libs/scrap/src/common/vram.rs +++ b/libs/scrap/src/common/vram.rs @@ -6,6 +6,7 @@ use std::{ use crate::{ codec::{base_bitrate, enable_vram_option, EncoderApi, EncoderCfg, Quality}, + hwcodec::HwCodecConfig, AdapterDevice, CodecFormat, EncodeInput, EncodeYuvFormat, Pixfmt, }; use hbb_common::{ @@ -228,9 +229,8 @@ impl VRamEncoder { CodecFormat::H265 => DataFormat::H265, _ => return vec![], }; - let v: Vec<_> = get_available_config() - .map(|c| c.e) - .unwrap_or_default() + let v: Vec<_> = crate::hwcodec::HwCodecConfig::get() + .vram_encode .drain(..) .filter(|c| c.data_format == data_format) .collect(); @@ -339,9 +339,8 @@ impl VRamDecoder { CodecFormat::H265 => DataFormat::H265, _ => return vec![], }; - get_available_config() - .map(|c| c.d) - .unwrap_or_default() + crate::hwcodec::HwCodecConfig::get() + .vram_decode .drain(..) .filter(|c| c.data_format == data_format && c.luid == luid && luid != 0) .collect() @@ -351,7 +350,7 @@ impl VRamDecoder { if !enable_vram_option() { return (false, false); } - let v = get_available_config().map(|c| c.d).unwrap_or_default(); + let v = crate::hwcodec::HwCodecConfig::get().vram_decode; ( v.iter().any(|d| d.data_format == DataFormat::H264), v.iter().any(|d| d.data_format == DataFormat::H265), @@ -364,7 +363,7 @@ impl VRamDecoder { match Decoder::new(ctx) { Ok(decoder) => Ok(Self { decoder }), Err(_) => { - hbb_common::config::HwCodecConfig::clear_vram(); + HwCodecConfig::clear(true, false); Err(anyhow!(format!( "Failed to create decoder, format: {:?}", format @@ -386,15 +385,7 @@ pub struct VRamDecoderImage<'a> { impl VRamDecoderImage<'_> {} -fn get_available_config() -> ResultType { - let available = hbb_common::config::HwCodecConfig::load().vram; - match Available::deserialize(&available) { - Ok(v) => Ok(v), - Err(_) => Err(anyhow!("Failed to deserialize:{}", available)), - } -} - -pub(crate) fn check_available_vram() -> String { +pub(crate) fn check_available_vram() -> (Vec, Vec, String) { let d = DynamicContext { device: None, width: 1280, @@ -406,8 +397,12 @@ pub(crate) fn check_available_vram() -> String { let encoders = encode::available(d); let decoders = decode::available(); let available = Available { - e: encoders, - d: decoders, + e: encoders.clone(), + d: decoders.clone(), }; - available.serialize().unwrap_or_default() + ( + encoders, + decoders, + available.serialize().unwrap_or_default(), + ) } diff --git a/src/client.rs b/src/client.rs index b3f790d67..41f290bf0 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2132,6 +2132,7 @@ where std::thread::spawn(move || { #[cfg(windows)] sync_cpu_usage(); + get_hwcodec_config(); let mut handler_controller_map = HashMap::new(); // let mut count = Vec::new(); // let mut duration = std::time::Duration::ZERO; @@ -2333,6 +2334,27 @@ pub fn start_audio_thread() -> MediaSender { audio_sender } +fn get_hwcodec_config() { + // for sciter and unilink + #[cfg(feature = "hwcodec")] + #[cfg(any(target_os = "windows", target_os = "linux"))] + { + use std::sync::Once; + static ONCE: Once = Once::new(); + ONCE.call_once(|| { + let start = std::time::Instant::now(); + if let Err(e) = crate::ipc::get_hwcodec_config_from_server() { + log::error!( + "failed to get hwcodec config: {e:?}, elapsed: {:?}", + start.elapsed() + ); + } else { + log::info!("{:?} used to get hwcodec config", start.elapsed()); + } + }); + } +} + #[cfg(windows)] fn sync_cpu_usage() { use std::sync::Once; diff --git a/src/core_main.rs b/src/core_main.rs index e91b55710..bf7e536f6 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -412,7 +412,7 @@ pub fn core_main() -> Option> { return None; } else if args[0] == "--check-hwcodec-config" { #[cfg(feature = "hwcodec")] - scrap::hwcodec::check_available_hwcodec(); + crate::ipc::hwcodec_process(); return None; } else if args[0] == "--cm" { // call connection manager to establish connections diff --git a/src/ipc.rs b/src/ipc.rs index a10a8f955..47cac05a6 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -239,6 +239,7 @@ pub enum Data { VideoConnCount(Option), // Although the key is not neccessary, it is used to avoid hardcoding the key. WaylandScreencastRestoreToken((String, String)), + HwCodecConfig(Option), } #[tokio::main(flavor = "current_thread")] @@ -523,12 +524,26 @@ async fn handle(data: Data, stream: &mut Connection) { .await ); } - Data::CheckHwcodec => - { - #[cfg(feature = "hwcodec")] - #[cfg(any(target_os = "windows", target_os = "linux"))] - if crate::platform::is_root() { - scrap::hwcodec::start_check_process(true); + #[cfg(feature = "hwcodec")] + #[cfg(any(target_os = "windows", target_os = "linux"))] + Data::CheckHwcodec => { + scrap::hwcodec::start_check_process(); + } + #[cfg(feature = "hwcodec")] + #[cfg(any(target_os = "windows", target_os = "linux"))] + Data::HwCodecConfig(c) => { + match c { + None => { + let v = match scrap::hwcodec::HwCodecConfig::get_set_value() { + Some(v) => Some(serde_json::to_string(&v).unwrap_or_default()), + None => None, + }; + allow_err!(stream.send(&Data::HwCodecConfig(v)).await); + } + Some(v) => { + // --server and portable + scrap::hwcodec::HwCodecConfig::set(v); + } } } Data::WaylandScreencastRestoreToken((key, value)) => { @@ -1025,6 +1040,83 @@ pub async fn notify_server_to_check_hwcodec() -> ResultType<()> { Ok(()) } +#[cfg(feature = "hwcodec")] +#[cfg(any(target_os = "windows", target_os = "linux"))] +#[tokio::main(flavor = "current_thread")] +pub async fn get_hwcodec_config_from_server() -> ResultType<()> { + if !scrap::codec::enable_hwcodec_option() || scrap::hwcodec::HwCodecConfig::already_set() { + return Ok(()); + } + let mut c = connect(50, "").await?; + c.send(&Data::HwCodecConfig(None)).await?; + if let Some(Data::HwCodecConfig(v)) = c.next_timeout(50).await? { + match v { + Some(v) => { + scrap::hwcodec::HwCodecConfig::set(v); + return Ok(()); + } + None => { + bail!("hwcodec config is none"); + } + } + } + bail!("failed to get hwcodec config"); +} + +#[cfg(feature = "hwcodec")] +#[cfg(any(target_os = "windows", target_os = "linux"))] +pub fn client_get_hwcodec_config_thread(wait_sec: u64) { + static ONCE: std::sync::Once = std::sync::Once::new(); + if !crate::platform::is_installed() + || !scrap::codec::enable_hwcodec_option() + || scrap::hwcodec::HwCodecConfig::already_set() + { + return; + } + ONCE.call_once(move || { + std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_secs(1)); + let mut intervals: Vec = vec![wait_sec, 3, 3, 6, 9]; + for i in intervals.drain(..) { + if i > 0 { + std::thread::sleep(std::time::Duration::from_secs(i)); + } + if get_hwcodec_config_from_server().is_ok() { + break; + } + } + }); + }); +} + +#[cfg(feature = "hwcodec")] +#[tokio::main(flavor = "current_thread")] +pub async fn hwcodec_process() { + let s = scrap::hwcodec::check_available_hwcodec(); + for _ in 0..5 { + match crate::ipc::connect(1000, "").await { + Ok(mut conn) => { + match conn + .send(&crate::ipc::Data::HwCodecConfig(Some(s.clone()))) + .await + { + Ok(()) => { + log::info!("send ok"); + break; + } + Err(e) => { + log::error!("send failed: {e:?}"); + } + } + } + Err(e) => { + log::error!("connect failed: {e:?}"); + } + } + std::thread::sleep(std::time::Duration::from_secs(1)); + } +} + #[tokio::main(flavor = "current_thread")] pub async fn get_wayland_screencast_restore_token(key: String) -> ResultType { let v = handle_wayland_screencast_restore_token(key, "get".to_owned()).await?; diff --git a/src/server.rs b/src/server.rs index 81b509034..43edaea0e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -459,9 +459,6 @@ pub async fn start_server(is_server: bool) { log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); } - #[cfg(feature = "hwcodec")] - #[cfg(any(target_os = "windows", target_os = "linux"))] - scrap::hwcodec::start_check_process(false); #[cfg(windows)] hbb_common::platform::windows::start_cpu_performance_monitor(); @@ -489,6 +486,9 @@ pub async fn start_server(is_server: bool) { tokio::spawn(async { sync_and_watch_config_dir().await }); #[cfg(target_os = "windows")] crate::platform::try_kill_broker(); + #[cfg(feature = "hwcodec")] + #[cfg(any(target_os = "windows", target_os = "linux"))] + scrap::hwcodec::start_check_process(); crate::RendezvousMediator::start_all().await; } else { match crate::ipc::connect(1000, "").await { @@ -509,6 +509,9 @@ pub async fn start_server(is_server: bool) { } } } + #[cfg(feature = "hwcodec")] + #[cfg(any(target_os = "windows", target_os = "linux"))] + crate::ipc::client_get_hwcodec_config_thread(0); } Err(err) => { log::info!("server not started (will try to start): {}", err); diff --git a/src/ui_interface.rs b/src/ui_interface.rs index b58ed6bb3..6c95d4c4a 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -172,15 +172,13 @@ pub fn get_option>(key: T) -> String { #[inline] #[cfg(target_os = "macos")] pub fn use_texture_render() -> bool { - cfg!(feature = "flutter") - && LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) == "Y" + cfg!(feature = "flutter") && LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) == "Y" } #[inline] #[cfg(any(target_os = "windows", target_os = "linux"))] pub fn use_texture_render() -> bool { - cfg!(feature = "flutter") - && LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) != "N" + cfg!(feature = "flutter") && LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) != "N" } #[inline] @@ -1398,9 +1396,16 @@ pub fn check_hwcodec() { #[cfg(feature = "hwcodec")] #[cfg(any(target_os = "windows", target_os = "linux"))] { - scrap::hwcodec::start_check_process(true); - if crate::platform::is_installed() { - ipc::notify_server_to_check_hwcodec().ok(); - } + use std::sync::Once; + static ONCE: Once = Once::new(); + + ONCE.call_once(|| { + if crate::platform::is_installed() { + ipc::notify_server_to_check_hwcodec().ok(); + ipc::client_get_hwcodec_config_thread(3); + } else { + scrap::hwcodec::start_check_process(); + } + }) } }