mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-11-23 19:49:05 +08:00
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none. when start check process: ipc server process start or option changed from disable to enable when get config: main window start or option changed from disable to enable, start_video_audio_threads. Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file. Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
parent
0f10a88b23
commit
610009528b
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -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",
|
||||
|
@ -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_::<HwCodecConfig>("_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_::<T>(suffix)
|
||||
}
|
||||
|
||||
pub fn common_store<T: serde::Serialize>(config: &T, suffix: &str) {
|
||||
Config::store_(config, suffix);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -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)
|
||||
|
@ -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<std::sync::Mutex<Option<HwCodecConfig>>> = Default::default();
|
||||
static ref CONFIG_SET_BY_IPC: std::sync::Arc<std::sync::Mutex<bool>> = 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<CodecInfo> {
|
||||
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<CodecInfo>,
|
||||
d: Vec<CodecInfo>,
|
||||
}
|
||||
|
||||
fn get_config() -> ResultType<Available> {
|
||||
#[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<CodecInfo>,
|
||||
#[serde(default)]
|
||||
pub ram_decode: Vec<CodecInfo>,
|
||||
#[cfg(feature = "vram")]
|
||||
#[serde(default)]
|
||||
pub vram_encode: Vec<hwcodec::vram::FeatureContext>,
|
||||
#[cfg(feature = "vram")]
|
||||
#[serde(default)]
|
||||
pub vram_decode: Vec<hwcodec::vram::DecodeContext>,
|
||||
}
|
||||
|
||||
// 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::<HwCodecConfig>("_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<HwCodecConfig> {
|
||||
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);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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<Available> {
|
||||
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<FeatureContext>, Vec<DecodeContext>, 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(),
|
||||
)
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -412,7 +412,7 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
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
|
||||
|
104
src/ipc.rs
104
src/ipc.rs
@ -239,6 +239,7 @@ pub enum Data {
|
||||
VideoConnCount(Option<usize>),
|
||||
// Although the key is not neccessary, it is used to avoid hardcoding the key.
|
||||
WaylandScreencastRestoreToken((String, String)),
|
||||
HwCodecConfig(Option<String>),
|
||||
}
|
||||
|
||||
#[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<u64> = 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<String> {
|
||||
let v = handle_wayland_screencast_restore_token(key, "get".to_owned()).await?;
|
||||
|
@ -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);
|
||||
|
@ -172,15 +172,13 @@ pub fn get_option<T: AsRef<str>>(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();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user