This commit is contained in:
Asura 2022-07-23 06:33:15 -07:00
commit a46df491e5
43 changed files with 637 additions and 464 deletions

10
Cargo.lock generated
View File

@ -378,9 +378,12 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e"
dependencies = [
"serde 1.0.139",
]
[[package]]
name = "cache-padded"
@ -2230,7 +2233,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hwcodec"
version = "0.1.0"
source = "git+https://github.com/21pages/hwcodec#91d1cd327c88490f917457072aeef0676ddb2be7"
source = "git+https://github.com/21pages/hwcodec#890204e0703a3d361fc7a45f035fe75c0575bb1d"
dependencies = [
"bindgen",
"cc",
@ -3986,6 +3989,7 @@ dependencies = [
"async-process",
"async-trait",
"base64",
"bytes",
"cc",
"cfg-if 1.0.0",
"clap 3.2.12",

View File

@ -55,6 +55,7 @@ rpassword = "7.0"
base64 = "0.13"
sysinfo = "0.24"
num_cpus = "1.13"
bytes = { version = "1.2", features = ["serde"] }
default-net = "0.11.0"
wol-rs = "0.9.1"

32
build.py Normal file → Executable file
View File

@ -22,7 +22,7 @@ def get_version():
return ''
def get_features(feature):
def parse_rc_features(feature):
available_features = {
'IddDriver': {
'zip_url': 'https://github.com/fufesou/RustDeskIddDriver/releases/download/v0.1/RustDeskIddDriver_x64.zip',
@ -94,8 +94,8 @@ def download_extract_features(features, res_dir):
print(f'{feat} extract end')
def build_windows(args):
features = get_features(args.feature)
def get_rc_features(args):
features = parse_rc_features(args.feature)
if features:
print(f'Build with features {list(features.keys())}')
res_dir = 'resources'
@ -105,12 +105,17 @@ def build_windows(args):
raise Exception(f'Find file {res_dir}, not a directory')
os.makedirs(res_dir, exist_ok=True)
download_extract_features(features, res_dir)
return ['with_rc'] if features else []
with_rc = ',with_rc' if features else ''
hwcodec = ',hwcodec' if args.hwcodec else ''
cmd = 'cargo build --release --features inline' + with_rc + hwcodec
print(cmd)
os.system(cmd)
def get_features(args):
features = ['inline']
if windows:
features.extend(get_rc_features(args))
if args.hwcodec:
features.append('hwcodec')
print("features:", features)
return features
def main():
parser = make_parser()
@ -129,8 +134,9 @@ def main():
if os.path.isfile('/usr/bin/pacman'):
os.system('git checkout src/ui/common.tis')
version = get_version()
features = ",".join(get_features(args))
if windows:
build_windows(args)
os.system('cargo build --release --features ' + features)
# os.system('upx.exe target/release/rustdesk.exe')
os.system('mv target/release/rustdesk.exe target/release/RustDesk.exe')
pa = os.environ.get('P')
@ -141,7 +147,7 @@ def main():
print('Not signed')
os.system(f'cp -rf target/release/RustDesk.exe rustdesk-{version}-setdown.exe')
elif os.path.isfile('/usr/bin/pacman'):
os.system('cargo build --release --features inline')
os.system('cargo build --release --features ' + features)
os.system('git checkout src/ui/common.tis')
os.system('strip target/release/rustdesk')
os.system("sed -i 's/pkgver=.*/pkgver=%s/g' PKGBUILD" % version)
@ -150,7 +156,7 @@ def main():
os.system('mv rustdesk-%s-0-x86_64.pkg.tar.zst rustdesk-%s-manjaro-arch.pkg.tar.zst' % (version, version))
# pacman -U ./rustdesk.pkg.tar.zst
elif os.path.isfile('/usr/bin/yum'):
os.system('cargo build --release --features inline')
os.system('cargo build --release --features ' + features)
os.system('strip target/release/rustdesk')
os.system("sed -i 's/Version: .*/Version: %s/g' rpm.spec" % version)
os.system('HBB=`pwd` rpmbuild -ba rpm.spec')
@ -158,14 +164,14 @@ def main():
version, version))
# yum localinstall rustdesk.rpm
elif os.path.isfile('/usr/bin/zypper'):
os.system('cargo build --release --features inline')
os.system('cargo build --release --features ' + features)
os.system('strip target/release/rustdesk')
os.system("sed -i 's/Version: .*/Version: %s/g' rpm-suse.spec" % version)
os.system('HBB=`pwd` rpmbuild -ba rpm-suse.spec')
os.system('mv $HOME/rpmbuild/RPMS/x86_64/rustdesk-%s-0.x86_64.rpm ./rustdesk-%s-suse.rpm' % (version, version))
# yum localinstall rustdesk.rpm
else:
os.system('cargo bundle --release --features inline')
os.system('cargo bundle --release --features ' + features)
if osx:
os.system(
'strip target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk')

View File

@ -11,7 +11,7 @@ protobuf = { version = "3.1", features = ["with-bytes"] }
tokio = { version = "1.20", features = ["full"] }
tokio-util = { version = "0.7", features = ["full"] }
futures = "0.3"
bytes = "1.1"
bytes = { version = "1.2", features = ["serde"] }
log = "0.4"
env_logger = "0.9"
socket2 = { version = "0.3", features = ["reuseport"] }

View File

@ -5,6 +5,10 @@ fn main() {
.out_dir("src/protos")
.inputs(&["protos/rendezvous.proto", "protos/message.proto"])
.include("protos")
.customize(
protobuf_codegen::Customize::default()
.tokio_bytes(true)
)
.run()
.expect("Codegen failed.");
}

View File

@ -72,6 +72,11 @@ message Features {
bool privacy_mode = 1;
}
message SupportedEncoding {
bool h264 = 1;
bool h265 = 2;
}
message PeerInfo {
string username = 1;
string hostname = 2;
@ -82,6 +87,7 @@ message PeerInfo {
string version = 7;
int32 conn_id = 8;
Features features = 9;
SupportedEncoding encoding = 10;
}
message LoginResponse {
@ -442,9 +448,17 @@ enum ImageQuality {
}
message VideoCodecState {
int32 ScoreVpx = 1;
int32 ScoreH264 = 2;
int32 ScoreH265 = 3;
enum PerferCodec {
Auto = 0;
VPX = 1;
H264 = 2;
H265 = 3;
}
int32 score_vpx = 1;
int32 score_h264 = 2;
int32 score_h265 = 3;
PerferCodec perfer = 4;
}
message OptionMessage {

View File

@ -978,6 +978,10 @@ impl HwCodecConfig {
pub fn store(&self) {
Config::store_(self, "_hwcodec");
}
pub fn remove() {
std::fs::remove_file(Config::file_("_hwcodec")).ok();
}
}
#[cfg(test)]

View File

@ -50,5 +50,5 @@ gstreamer = { version = "0.16", optional = true }
gstreamer-app = { version = "0.16", features = ["v1_10"], optional = true }
gstreamer-video = { version = "0.16", optional = true }
[target.'cfg(target_os = "windows")'.dependencies]
[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dependencies]
hwcodec = { git = "https://github.com/21pages/hwcodec", optional = true }

View File

@ -4,7 +4,7 @@ extern crate scrap;
use std::fs::File;
#[cfg(windows)]
use scrap::CapturerMag;
use scrap::{CapturerMag, TraitCapturer};
use scrap::{i420_to_rgb, Display};
fn main() {

View File

@ -3,7 +3,7 @@ use std::time::Duration;
extern crate scrap;
fn main() {
use scrap::{Capturer, Display};
use scrap::{Capturer, Display, TraitCapturer};
use std::io::ErrorKind::WouldBlock;
use std::io::Write;
use std::process::{Command, Stdio};

View File

@ -18,7 +18,7 @@ use webm::mux;
use webm::mux::Track;
use scrap::vpxcodec as vpx_encode;
use scrap::{Capturer, Display, STRIDE_ALIGN};
use scrap::{TraitCapturer, Capturer, Display, STRIDE_ALIGN};
const USAGE: &'static str = "
Simple WebM screen capture.

View File

@ -6,7 +6,7 @@ use std::io::ErrorKind::WouldBlock;
use std::thread;
use std::time::Duration;
use scrap::{i420_to_rgb, Capturer, Display};
use scrap::{i420_to_rgb, Capturer, Display, TraitCapturer};
fn main() {
let n = Display::all().unwrap().len();

View File

@ -32,8 +32,12 @@ impl Capturer {
pub fn height(&self) -> usize {
self.display.height() as usize
}
}
pub fn frame<'a>(&'a mut self, _timeout: Duration) -> io::Result<Frame<'a>> {
impl crate::TraitCapturer for Capturer {
fn set_use_yuv(&mut self, _use_yuv: bool) {}
fn frame<'a>(&'a mut self, _timeout: Duration) -> io::Result<Frame<'a>> {
if let Some(buf) = get_video_raw() {
crate::would_block_if_equal(&mut self.saved_raw_data, buf)?;
rgba_to_i420(self.width(), self.height(), buf, &mut self.bgra);

View File

@ -16,12 +16,15 @@ use hbb_common::{
ResultType,
};
#[cfg(feature = "hwcodec")]
use hbb_common::{config::Config2, lazy_static};
use hbb_common::{
config::{Config2, PeerConfig},
lazy_static,
message_proto::video_codec_state::PerferCodec,
};
#[cfg(feature = "hwcodec")]
lazy_static::lazy_static! {
static ref PEER_DECODER_STATES: Arc<Mutex<HashMap<i32, VideoCodecState>>> = Default::default();
static ref MY_DECODER_STATE: Arc<Mutex<VideoCodecState>> = Default::default();
}
const SCORE_VPX: i32 = 90;
@ -102,7 +105,7 @@ impl Encoder {
codec: Box::new(hw),
}),
Err(e) => {
HwEncoder::best(true, true);
check_config_process(true);
Err(e)
}
},
@ -113,7 +116,6 @@ impl Encoder {
// TODO
pub fn update_video_encoder(id: i32, update: EncoderUpdate) {
log::info!("encoder update: {:?}", update);
#[cfg(feature = "hwcodec")]
{
let mut states = PEER_DECODER_STATES.lock().unwrap();
@ -130,49 +132,75 @@ impl Encoder {
}
}
}
let current_encoder_name = HwEncoder::current_name();
let name = HwEncoder::current_name();
if states.len() > 0 {
let (best, _) = HwEncoder::best(false, true);
let best = HwEncoder::best();
let enabled_h264 = best.h264.is_some()
&& states.len() > 0
&& states.iter().all(|(_, s)| s.ScoreH264 > 0);
&& states.iter().all(|(_, s)| s.score_h264 > 0);
let enabled_h265 = best.h265.is_some()
&& states.len() > 0
&& states.iter().all(|(_, s)| s.ScoreH265 > 0);
&& states.iter().all(|(_, s)| s.score_h265 > 0);
// score encoder
let mut score_vpx = SCORE_VPX;
let mut score_h264 = best.h264.as_ref().map_or(0, |c| c.score);
let mut score_h265 = best.h265.as_ref().map_or(0, |c| c.score);
// score decoder
score_vpx += states.iter().map(|s| s.1.ScoreVpx).sum::<i32>();
if enabled_h264 {
score_h264 += states.iter().map(|s| s.1.ScoreH264).sum::<i32>();
}
if enabled_h265 {
score_h265 += states.iter().map(|s| s.1.ScoreH265).sum::<i32>();
// Preference first
let mut preference = PerferCodec::Auto;
let preferences: Vec<_> = states
.iter()
.filter(|(_, s)| {
s.perfer == PerferCodec::VPX.into()
|| s.perfer == PerferCodec::H264.into() && enabled_h264
|| s.perfer == PerferCodec::H265.into() && enabled_h265
})
.map(|(_, s)| s.perfer)
.collect();
if preferences.len() > 0 && preferences.iter().all(|&p| p == preferences[0]) {
preference = preferences[0].enum_value_or(PerferCodec::Auto);
}
if enabled_h265 && score_h265 >= score_vpx && score_h265 >= score_h264 {
*current_encoder_name.lock().unwrap() = Some(best.h265.unwrap().name);
} else if enabled_h264 && score_h264 >= score_vpx && score_h264 >= score_h265 {
*current_encoder_name.lock().unwrap() = Some(best.h264.unwrap().name);
} else {
*current_encoder_name.lock().unwrap() = None;
match preference {
PerferCodec::VPX => *name.lock().unwrap() = None,
PerferCodec::H264 => {
*name.lock().unwrap() = best.h264.map_or(None, |c| Some(c.name))
}
PerferCodec::H265 => {
*name.lock().unwrap() = best.h265.map_or(None, |c| Some(c.name))
}
PerferCodec::Auto => {
// score encoder
let mut score_vpx = SCORE_VPX;
let mut score_h264 = best.h264.as_ref().map_or(0, |c| c.score);
let mut score_h265 = best.h265.as_ref().map_or(0, |c| c.score);
// score decoder
score_vpx += states.iter().map(|s| s.1.score_vpx).sum::<i32>();
if enabled_h264 {
score_h264 += states.iter().map(|s| s.1.score_h264).sum::<i32>();
}
if enabled_h265 {
score_h265 += states.iter().map(|s| s.1.score_h265).sum::<i32>();
}
if enabled_h265 && score_h265 >= score_vpx && score_h265 >= score_h264 {
*name.lock().unwrap() = best.h265.map_or(None, |c| Some(c.name));
} else if enabled_h264
&& score_h264 >= score_vpx
&& score_h264 >= score_h265
{
*name.lock().unwrap() = best.h264.map_or(None, |c| Some(c.name));
} else {
*name.lock().unwrap() = None;
}
}
}
log::info!(
"connection count:{}, h264:{}, h265:{}, score: vpx({}), h264({}), h265({}), set current encoder name {:?}",
"connection count:{}, used preference:{:?}, encoder:{:?}",
states.len(),
enabled_h264,
enabled_h265,
score_vpx,
score_h264,
score_h265,
current_encoder_name.lock().unwrap()
)
preference,
name.lock().unwrap()
)
} else {
*current_encoder_name.lock().unwrap() = None;
*name.lock().unwrap() = None;
}
}
#[cfg(not(feature = "hwcodec"))]
@ -192,57 +220,57 @@ impl Encoder {
#[cfg(not(feature = "hwcodec"))]
return None;
}
}
#[cfg(feature = "hwcodec")]
impl Drop for Decoder {
fn drop(&mut self) {
*MY_DECODER_STATE.lock().unwrap() = VideoCodecState {
ScoreVpx: SCORE_VPX,
..Default::default()
};
pub fn supported_encoding() -> (bool, bool) {
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
let best = HwEncoder::best();
(
best.h264.as_ref().map_or(false, |c| c.score > 0),
best.h265.as_ref().map_or(false, |c| c.score > 0),
)
} else {
(false, false)
}
#[cfg(not(feature = "hwcodec"))]
(false, false)
}
}
impl Decoder {
pub fn video_codec_state() -> VideoCodecState {
// video_codec_state is mainted by creation and destruction of Decoder.
// It has been ensured to use after Decoder's creation.
pub fn video_codec_state(_id: &str) -> VideoCodecState {
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
return MY_DECODER_STATE.lock().unwrap().clone();
let best = HwDecoder::best();
VideoCodecState {
score_vpx: SCORE_VPX,
score_h264: best.h264.map_or(0, |c| c.score),
score_h265: best.h265.map_or(0, |c| c.score),
perfer: Self::codec_preference(_id).into(),
..Default::default()
}
} else {
return VideoCodecState {
ScoreVpx: SCORE_VPX,
score_vpx: SCORE_VPX,
..Default::default()
};
}
#[cfg(not(feature = "hwcodec"))]
VideoCodecState {
ScoreVpx: SCORE_VPX,
score_vpx: SCORE_VPX,
..Default::default()
}
}
pub fn new(config: DecoderCfg) -> Decoder {
let vpx = VpxDecoder::new(config.vpx).unwrap();
let decoder = Decoder {
Decoder {
vpx,
#[cfg(feature = "hwcodec")]
hw: HwDecoder::new_decoders(),
#[cfg(feature = "hwcodec")]
i420: vec![],
};
#[cfg(feature = "hwcodec")]
{
let mut state = MY_DECODER_STATE.lock().unwrap();
state.ScoreVpx = SCORE_VPX;
state.ScoreH264 = decoder.hw.h264.as_ref().map_or(0, |d| d.info.score);
state.ScoreH265 = decoder.hw.h265.as_ref().map_or(0, |d| d.info.score);
}
decoder
}
pub fn handle_video_frame(
@ -316,6 +344,23 @@ impl Decoder {
}
return Ok(ret);
}
#[cfg(feature = "hwcodec")]
fn codec_preference(id: &str) -> PerferCodec {
let codec = PeerConfig::load(id)
.options
.get("codec-preference")
.map_or("".to_owned(), |c| c.to_owned());
if codec == "vp9" {
PerferCodec::VPX
} else if codec == "h264" {
PerferCodec::H264
} else if codec == "h265" {
PerferCodec::H265
} else {
PerferCodec::Auto
}
}
}
#[cfg(feature = "hwcodec")]

View File

@ -246,6 +246,7 @@ pub unsafe fn nv12_to_i420(
#[cfg(feature = "hwcodec")]
pub mod hw {
use hbb_common::{anyhow::anyhow, ResultType};
#[cfg(target_os = "windows")]
use hwcodec::{ffmpeg::ffmpeg_linesize_offset_length, AVPixelFormat};
pub fn hw_bgra_to_i420(
@ -381,6 +382,8 @@ pub mod hw {
src_stride_y: usize,
src_stride_uv: usize,
dst: &mut Vec<u8>,
_i420: &mut Vec<u8>,
_align: usize,
) -> ResultType<()> {
dst.resize(width * height * 4, 0);
unsafe {

View File

@ -1,7 +1,12 @@
use crate::dxgi;
use std::io::ErrorKind::{NotFound, TimedOut, WouldBlock};
use std::time::Duration;
use std::{io, ops};
use crate::{common::TraitCapturer, dxgi};
use std::{
io::{
self,
ErrorKind::{NotFound, TimedOut, WouldBlock},
},
ops,
time::Duration,
};
pub struct Capturer {
inner: dxgi::Capturer,
@ -21,18 +26,6 @@ impl Capturer {
})
}
pub fn set_use_yuv(&mut self, use_yuv: bool) {
self.inner.set_use_yuv(use_yuv);
}
pub fn is_gdi(&self) -> bool {
self.inner.is_gdi()
}
pub fn set_gdi(&mut self) -> bool {
self.inner.set_gdi()
}
pub fn cancel_gdi(&mut self) {
self.inner.cancel_gdi()
}
@ -44,14 +37,28 @@ impl Capturer {
pub fn height(&self) -> usize {
self.height
}
}
pub fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
impl TraitCapturer for Capturer {
fn set_use_yuv(&mut self, use_yuv: bool) {
self.inner.set_use_yuv(use_yuv);
}
fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
match self.inner.frame(timeout.as_millis() as _) {
Ok(frame) => Ok(Frame(frame)),
Err(ref error) if error.kind() == TimedOut => Err(WouldBlock.into()),
Err(error) => Err(error),
}
}
fn is_gdi(&self) -> bool {
self.inner.is_gdi()
}
fn set_gdi(&mut self) -> bool {
self.inner.set_gdi()
}
}
pub struct Frame<'a>(&'a [u8]);
@ -134,10 +141,6 @@ impl CapturerMag {
})
}
pub fn set_use_yuv(&mut self, use_yuv: bool) {
self.inner.set_use_yuv(use_yuv)
}
pub fn exclude(&mut self, cls: &str, name: &str) -> io::Result<bool> {
self.inner.exclude(cls, name)
}
@ -145,8 +148,23 @@ impl CapturerMag {
pub fn get_rect(&self) -> ((i32, i32), usize, usize) {
self.inner.get_rect()
}
pub fn frame<'a>(&'a mut self, _timeout_ms: Duration) -> io::Result<Frame<'a>> {
}
impl TraitCapturer for CapturerMag {
fn set_use_yuv(&mut self, use_yuv: bool) {
self.inner.set_use_yuv(use_yuv)
}
fn frame<'a>(&'a mut self, _timeout_ms: Duration) -> io::Result<Frame<'a>> {
self.inner.frame(&mut self.data)?;
Ok(Frame(&self.data))
}
fn is_gdi(&self) -> bool {
false
}
fn set_gdi(&mut self) -> bool {
false
}
}

View File

@ -7,7 +7,7 @@ use hbb_common::{
config::HwCodecConfig,
lazy_static, log,
message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame},
ResultType,
ResultType, bytes::Bytes,
};
use hwcodec::{
decode::{DecodeContext, DecodeFrame, Decoder},
@ -91,7 +91,7 @@ impl EncoderApi for HwEncoder {
let mut frames = Vec::new();
for frame in self.encode(frame).with_context(|| "Failed to encode")? {
frames.push(EncodedVideoFrame {
data: frame.data,
data: Bytes::from(frame.data),
pts: frame.pts as _,
..Default::default()
});
@ -123,40 +123,11 @@ impl EncoderApi for HwEncoder {
}
impl HwEncoder {
/// 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(), false)
} else {
let ctx = EncodeContext {
name: String::from(""),
width: 1920,
height: 1080,
pixfmt: DEFAULT_PIXFMT,
align: HW_STRIDE_ALIGN as _,
bitrate: 0,
timebase: DEFAULT_TIME_BASE,
gop: DEFAULT_GOP,
quality: DEFAULT_HW_QUALITY,
rc: DEFAULT_RC,
};
let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx));
if write {
set_config(CFG_KEY_ENCODER, &encoders)
.map_err(|e| log::error!("{:?}", e))
.ok();
}
(encoders, true)
}
pub fn best() -> CodecInfos {
get_config(CFG_KEY_ENCODER).unwrap_or(CodecInfos {
h264: None,
h265: None,
})
}
pub fn current_name() -> Arc<Mutex<Option<String>>> {
@ -207,24 +178,15 @@ pub struct HwDecoders {
}
impl HwDecoder {
/// 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(), false)
} else {
let decoders = CodecInfo::score(Decoder::avaliable_decoders());
if write {
set_config(CFG_KEY_DECODER, &decoders)
.map_err(|e| log::error!("{:?}", e))
.ok();
}
(decoders, true)
}
pub fn best() -> CodecInfos {
get_config(CFG_KEY_DECODER).unwrap_or(CodecInfos {
h264: None,
h265: None,
})
}
pub fn new_decoders() -> HwDecoders {
let (best, _) = HwDecoder::best(false, true);
let best = HwDecoder::best();
let mut h264: Option<HwDecoder> = None;
let mut h265: Option<HwDecoder> = None;
let mut fail = false;
@ -242,7 +204,7 @@ impl HwDecoder {
}
}
if fail {
HwDecoder::best(true, true);
check_config_process(true);
}
HwDecoders { h264, h265 }
}
@ -314,31 +276,52 @@ fn get_config(k: &str) -> ResultType<CodecInfos> {
}
}
fn set_config(k: &str, v: &CodecInfos) -> ResultType<()> {
match v.serialize() {
Ok(v) => {
let mut config = HwCodecConfig::load();
config.options.insert(k.to_owned(), v);
config.store();
Ok(())
}
Err(_) => Err(anyhow!("Failed to set config:{}", k)),
}
}
pub fn check_config() {
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() {
let mut config = HwCodecConfig::load();
config.options.insert(CFG_KEY_ENCODER.to_owned(), encoders);
config.options.insert(CFG_KEY_DECODER.to_owned(), decoders);
config.store();
let ctx = EncodeContext {
name: String::from(""),
width: 1920,
height: 1080,
pixfmt: DEFAULT_PIXFMT,
align: HW_STRIDE_ALIGN as _,
bitrate: 0,
timebase: DEFAULT_TIME_BASE,
gop: DEFAULT_GOP,
quality: DEFAULT_HW_QUALITY,
rc: DEFAULT_RC,
};
let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx));
let decoders = CodecInfo::score(Decoder::avaliable_decoders());
if let Ok(old_encoders) = get_config(CFG_KEY_ENCODER) {
if let Ok(old_decoders) = get_config(CFG_KEY_DECODER) {
if encoders == old_encoders && decoders == old_decoders {
return;
}
}
log::error!("Failed to serialize codec info");
}
if let Ok(encoders) = encoders.serialize() {
if let Ok(decoders) = decoders.serialize() {
let mut config = HwCodecConfig::load();
config.options.insert(CFG_KEY_ENCODER.to_owned(), encoders);
config.options.insert(CFG_KEY_DECODER.to_owned(), decoders);
config.store();
return;
}
}
log::error!("Failed to serialize codec info");
}
pub fn check_config_process(force_reset: bool) {
if force_reset {
HwCodecConfig::remove();
}
if let Ok(exe) = std::env::current_exe() {
std::thread::spawn(move || {
std::process::Command::new(exe)
.arg("--check-hwcodec-config")
.status()
.ok()
});
};
}

View File

@ -1,6 +1,7 @@
use crate::common::{
wayland,
x11::{self, Frame},
TraitCapturer,
};
use std::{io, time::Duration};
@ -17,13 +18,6 @@ impl Capturer {
})
}
pub fn set_use_yuv(&mut self, use_yuv: bool) {
match self {
Capturer::X11(d) => d.set_use_yuv(use_yuv),
Capturer::WAYLAND(d) => d.set_use_yuv(use_yuv),
}
}
pub fn width(&self) -> usize {
match self {
Capturer::X11(d) => d.width(),
@ -37,8 +31,17 @@ impl Capturer {
Capturer::WAYLAND(d) => d.height(),
}
}
}
pub fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
impl TraitCapturer for Capturer {
fn set_use_yuv(&mut self, use_yuv: bool) {
match self {
Capturer::X11(d) => d.set_use_yuv(use_yuv),
Capturer::WAYLAND(d) => d.set_use_yuv(use_yuv),
}
}
fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
match self {
Capturer::X11(d) => d.frame(timeout),
Capturer::WAYLAND(d) => d.frame(timeout),

View File

@ -49,3 +49,13 @@ pub fn would_block_if_equal(old: &mut Vec<u128>, b: &[u8]) -> std::io::Result<()
old.copy_from_slice(b);
Ok(())
}
pub trait TraitCapturer {
fn set_use_yuv(&mut self, use_yuv: bool);
fn frame<'a>(&'a mut self, timeout: std::time::Duration) -> std::io::Result<Frame<'a>>;
#[cfg(windows)]
fn is_gdi(&self) -> bool;
#[cfg(windows)]
fn set_gdi(&mut self) -> bool;
}

View File

@ -50,8 +50,14 @@ impl Capturer {
pub fn height(&self) -> usize {
self.inner.height()
}
}
pub fn frame<'a>(&'a mut self, _timeout_ms: std::time::Duration) -> io::Result<Frame<'a>> {
impl crate::TraitCapturer for Capturer {
fn set_use_yuv(&mut self, use_yuv: bool) {
self.use_yuv = use_yuv;
}
fn frame<'a>(&'a mut self, _timeout_ms: std::time::Duration) -> io::Result<Frame<'a>> {
match self.frame.try_lock() {
Ok(mut handle) => {
let mut frame = None;

View File

@ -12,6 +12,7 @@ use crate::STRIDE_ALIGN;
use super::vpx::{vp8e_enc_control_id::*, vpx_codec_err_t::*, *};
use std::os::raw::{c_int, c_uint};
use std::{ptr, slice};
use hbb_common::bytes::Bytes;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum VpxVideoCodecId {
@ -291,7 +292,7 @@ impl VpxEncoder {
#[inline]
fn create_frame(frame: &EncodeFrame) -> EncodedVideoFrame {
EncodedVideoFrame {
data: frame.data.to_vec(),
data: Bytes::from(frame.data.to_vec()),
key: frame.key,
pts: frame.pts,
..Default::default()

View File

@ -1,4 +1,4 @@
use crate::common::x11::Frame;
use crate::common::{x11::Frame, TraitCapturer};
use crate::wayland::{capturable::*, *};
use std::{io, time::Duration};
@ -14,10 +14,6 @@ impl Capturer {
Ok(Capturer(display, r, yuv, Default::default()))
}
pub fn set_use_yuv(&mut self, use_yuv: bool) {
self.2 = use_yuv;
}
pub fn width(&self) -> usize {
self.0.width()
}
@ -25,8 +21,14 @@ impl Capturer {
pub fn height(&self) -> usize {
self.0.height()
}
}
pub fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
impl TraitCapturer for Capturer {
fn set_use_yuv(&mut self, use_yuv: bool) {
self.2 = use_yuv;
}
fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
match self.1.capture(timeout.as_millis() as _).map_err(map_err)? {
PixelProvider::BGR0(w, h, x) => Ok(Frame(if self.2 {
crate::common::bgra_to_i420(w as _, h as _, &x, &mut self.3);

View File

@ -1,4 +1,4 @@
use crate::x11;
use crate::{x11, common::TraitCapturer};
use std::{io, ops, time::Duration};
pub struct Capturer(x11::Capturer);
@ -8,10 +8,6 @@ impl Capturer {
x11::Capturer::new(display.0, yuv).map(Capturer)
}
pub fn set_use_yuv(&mut self, use_yuv: bool) {
self.0.set_use_yuv(use_yuv);
}
pub fn width(&self) -> usize {
self.0.display().rect().w as usize
}
@ -19,8 +15,14 @@ impl Capturer {
pub fn height(&self) -> usize {
self.0.display().rect().h as usize
}
}
pub fn frame<'a>(&'a mut self, _timeout: Duration) -> io::Result<Frame<'a>> {
impl TraitCapturer for Capturer {
fn set_use_yuv(&mut self, use_yuv: bool) {
self.0.set_use_yuv(use_yuv);
}
fn frame<'a>(&'a mut self, _timeout: Duration) -> io::Result<Frame<'a>> {
Ok(Frame(self.0.frame()?))
}
}

View File

@ -216,7 +216,7 @@ impl Client {
} else {
peer_nat_type = ph.nat_type();
is_local = ph.is_local();
signed_id_pk = ph.pk;
signed_id_pk = ph.pk.into();
relay_server = ph.relay_server;
peer_addr = AddrMangle::decode(&ph.socket_addr);
log::info!("Hole Punched {} = {}", peer, peer_addr);
@ -408,8 +408,8 @@ impl Client {
let sealed_key = box_::seal(&key.0, &nonce, &their_pk_b, &out_sk_b);
let mut msg_out = Message::new();
msg_out.set_public_key(PublicKey {
asymmetric_value: our_pk_b.0.into(),
symmetric_value: sealed_key,
asymmetric_value: Vec::from(our_pk_b.0).into(),
symmetric_value: sealed_key.into(),
..Default::default()
});
timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??;
@ -784,6 +784,7 @@ pub struct LoginConfigHandler {
pub conn_id: i32,
features: Option<Features>,
session_id: u64,
pub supported_encoding: Option<(bool, bool)>,
}
impl Deref for LoginConfigHandler {
@ -808,6 +809,7 @@ impl LoginConfigHandler {
self.remember = !config.password.is_empty();
self.config = config;
self.session_id = rand::random();
self.supported_encoding = None;
}
pub fn should_auto_login(&self) -> String {
@ -958,8 +960,7 @@ impl LoginConfigHandler {
msg.disable_clipboard = BoolOption::Yes.into();
n += 1;
}
// TODO: add option
let state = Decoder::video_codec_state();
let state = Decoder::video_codec_state(&self.id);
msg.video_codec_state = hbb_common::protobuf::MessageField::some(state);
n += 1;
@ -1111,6 +1112,10 @@ impl LoginConfigHandler {
self.conn_id = pi.conn_id;
// no matter if change, for update file time
self.save_config(config);
#[cfg(feature = "hwcodec")]
{
self.supported_encoding = Some((pi.encoding.h264, pi.encoding.h265));
}
}
pub fn get_remote_dir(&self) -> String {
@ -1139,7 +1144,7 @@ impl LoginConfigHandler {
let my_id = Config::get_id();
let mut lr = LoginRequest {
username: self.id.clone(),
password,
password:password.into(),
my_id,
my_name: crate::username(),
option: self.get_option_message(true).into(),
@ -1163,6 +1168,18 @@ impl LoginConfigHandler {
msg_out.set_login_request(lr);
msg_out
}
pub fn change_prefer_codec(&self) -> Message {
let state = scrap::codec::Decoder::video_codec_state(&self.id);
let mut misc = Misc::new();
misc.set_option(OptionMessage {
video_codec_state: hbb_common::protobuf::MessageField::some(state),
..Default::default()
});
let mut msg_out = Message::new();
msg_out.set_misc(misc);
msg_out
}
}
pub enum MediaData {

View File

@ -67,7 +67,7 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
CliprdrServerFormatDataResponse {
conn_id,
msg_flags,
format_data,
format_data: format_data.into(),
..Default::default()
},
)),
@ -117,7 +117,7 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
conn_id,
msg_flags,
stream_id,
requested_data,
requested_data: requested_data.into(),
..Default::default()
},
)),
@ -156,7 +156,7 @@ pub fn msg_2_clip(msg: Cliprdr) -> Option<ClipbaordFile> {
Some(ClipbaordFile::ServerFormatDataResponse {
conn_id: data.conn_id,
msg_flags: data.msg_flags,
format_data: data.format_data,
format_data: data.format_data.into(),
})
}
Some(cliprdr::Union::FileContentsRequest(data)) => {
@ -177,7 +177,7 @@ pub fn msg_2_clip(msg: Cliprdr) -> Option<ClipbaordFile> {
conn_id: data.conn_id,
msg_flags: data.msg_flags,
stream_id: data.stream_id,
requested_data: data.requested_data,
requested_data: data.requested_data.into(),
})
}
_ => None,

View File

@ -48,7 +48,7 @@ pub fn create_clipboard_msg(content: String) -> Message {
let mut msg = Message::new();
msg.set_clipboard(Clipboard {
compress,
content,
content:content.into(),
..Default::default()
});
msg
@ -79,7 +79,7 @@ pub fn update_clipboard(clipboard: Clipboard, old: Option<&Arc<Mutex<String>>>)
let content = if clipboard.compress {
decompress(&clipboard.content)
} else {
clipboard.content
clipboard.content.into()
};
if let Ok(content) = String::from_utf8(content) {
if content.is_empty() {

View File

@ -19,6 +19,7 @@ use parity_tokio_ipc::{
};
use serde_derive::{Deserialize, Serialize};
use std::{collections::HashMap, sync::atomic::Ordering};
use bytes::Bytes;
#[cfg(not(windows))]
use std::{fs::File, io::prelude::*};
@ -75,7 +76,7 @@ pub enum FS {
WriteBlock {
id: i32,
file_num: i32,
data: Vec<u8>,
data: Bytes,
compressed: bool,
},
WriteDone {
@ -562,8 +563,8 @@ where
}
}
pub async fn send_raw(&mut self, data: Vec<u8>) -> ResultType<()> {
self.inner.send(bytes::Bytes::from(data)).await?;
pub async fn send_raw(&mut self, data: Bytes) -> ResultType<()> {
self.inner.send(data).await?;
Ok(())
}

View File

@ -6,14 +6,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("desk_tip", "Mit dieser ID und diesem Passwort können Sie auf Ihren Desktop zugreifen."),
("Password", "Passwort"),
("Ready", "Bereit"),
("Established", "Etabliert"),
("Established", "Verbunden"),
("connecting_status", "Verbinden mit dem RustDesk-Netzwerk..."),
("Enable Service", "Verbindungsserver einschalten"),
("Start Service", "Starte Verbindungsserver"),
("Service is running", "Dienst läuft"),
("Service is not running", "Der Verbindungsserver läuft nicht"),
("Enable Service", "Verbindungsserver aktivieren"),
("Start Service", "Starte Vermittlungsdienst"),
("Service is running", "Vermittlungsdienst aktiv"),
("Service is not running", "Vermittlungsdienst deaktiviert"),
("not_ready_status", "Nicht bereit. Bitte überprüfen Sie Ihre Verbindung"),
("Control Remote Desktop", "Entfernten Desktop steuern"),
("Control Remote Desktop", "Entfernten PC steuern"),
("Transfer File", "Datei übertragen"),
("Connect", "Verbinden"),
("Recent Sessions", "Letzte Sitzungen"),
@ -21,49 +21,49 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Confirmation", "Bestätigung"),
("TCP Tunneling", "TCP Tunneln"),
("Remove", "Entfernen"),
("Refresh random password", "Zufälliges Passwort aktualisieren"),
("Set your own password", "Legen Sie Ihr eigenes Passwort fest"),
("Enable Keyboard/Mouse", "Tastatur/Maus einschalten"),
("Enable Clipboard", "Zwischenablage einschalten"),
("Refresh random password", "Neues zufälliges Passwort"),
("Set your own password", "Eigenes Passwort setzen"),
("Enable Keyboard/Mouse", "Tastatur/Maus aktivieren"),
("Enable Clipboard", "Zwischenablage aktivieren"),
("Enable File Transfer", "Dateiübertragung aktivieren"),
("Enable TCP Tunneling", "TCP-Tunneling einschalten"),
("IP Whitelisting", "IP Freigabeliste"),
("ID/Relay Server", "ID/Verbindungsserver"),
("Stop service", "Verbindungsserver ausschalten"),
("Change ID", "ID wechseln"),
("Enable TCP Tunneling", "TCP-Tunneln aktivieren"),
("IP Whitelisting", "IP-Whitelist"),
("ID/Relay Server", "ID/Vermittlungsserver"),
("Stop service", "Vermittlungsdienst deaktivieren"),
("Change ID", "ID ändern"),
("Website", "Webseite"),
("About", "Über"),
("Mute", "Stummschalten"),
("Audio Input", "Audio-Eingang"),
("Enhancements", ""),
("Hardware Codec", ""),
("Adaptive Bitrate", ""),
("Enhancements", "Verbesserungen"),
("Hardware Codec", "Hardware-Codec"),
("Adaptive Bitrate", "Adaptive Bitrate"),
("ID Server", "ID Server"),
("Relay Server", "Verbindungsserver Server"),
("API Server", "API Server"),
("Relay Server", "Vermittlungsserver"),
("API Server", "API-Server"),
("invalid_http", "Muss mit http:// oder https:// beginnen"),
("Invalid IP", "Ungültige IP-Adresse"),
("id_change_tip", "Nur die Zeichen a-z, A-Z, 0-9 und _ (Unterstrich) sind erlaubt. Der erste Buchstabe muss a-z, A-Z sein. Länge zwischen 6 und 16."),
("id_change_tip", "Nur die Zeichen a-z, A-Z, 0-9 und _ (Unterstrich) sind erlaubt. Der erste Buchstabe muss a-z, A-Z sein, Länge zwischen 6 und 16."),
("Invalid format", "Ungültiges Format"),
("server_not_support", "Noch nicht vom Server unterstützt"),
("server_not_support", "Diese Funktion wird noch nicht vom Server unterstützt"),
("Not available", "Nicht verfügbar"),
("Too frequent", "Zu häufig"),
("Cancel", "Abbrechen"),
("Skip", "Überspringen"),
("Close", "Schließen"),
("Retry", "Nochmal versuchen"),
("Retry", "Erneut versuchen"),
("OK", "OK"),
("Password Required", "Passwort erforderlich"),
("Please enter your password", "Bitte geben Sie Ihr Passwort ein"),
("Please enter your password", "Bitte geben Sie das Passwort des entfernten PCs ein."),
("Remember password", "Passwort merken"),
("Wrong Password", "Falsches Passwort"),
("Do you want to enter again?", "Möchten Sie erneut teilnehmen?"),
("Do you want to enter again?", "Erneut verbinden?"),
("Connection Error", "Verbindungsfehler"),
("Error", "Fehler"),
("Reset by the peer", "Zurücksetzen durch die Gegenstelle"),
("Reset by the peer", "Verbindung wurde von der Gegenstelle zurückgesetzt"),
("Connecting...", "Verbinden..."),
("Connection in progress. Please wait.", "Die Verbindung wird hergestellt. Bitte warten Sie."),
("Please try 1 minute later", "Bitte versuchen Sie es 1 Minute später"),
("Please try 1 minute later", "Bitte versuchen Sie es später erneut"),
("Login Error", "Anmeldefehler"),
("Successful", "Erfolgreich"),
("Connected, waiting for image...", "Verbunden, warten auf Bild..."),
@ -75,92 +75,92 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Receive", "Empfangen"),
("Send", "Senden"),
("Refresh File", "Datei aktualisieren"),
("Local", "Lokaler"),
("Remote", "Entfernter"),
("Local", "Lokal"),
("Remote", "Entfernt"),
("Remote Computer", "Entfernter Computer"),
("Local Computer", "Lokaler Computer"),
("Local Computer", "Dieser Computer"),
("Confirm Delete", "Löschen bestätigen"),
("Delete", "Löschen"),
("Properties", "Eigenschaften"),
("Multi Select", "Mehrfachauswahl"),
("Empty Directory", "Leeres Verzeichnis"),
("Not an empty directory", "Kein leeres Verzeichnis"),
("Empty Directory", "Leerer Ordner"),
("Not an empty directory", "Ordner nicht leer"),
("Are you sure you want to delete this file?", "Sind Sie sicher, dass Sie diese Datei löschen wollen?"),
("Are you sure you want to delete this empty directory?", "Sind Sie sicher, dass Sie dieses leere Verzeichnis löschen möchten?"),
("Are you sure you want to delete the file of this directory?", "Sind Sie sicher, dass Sie die Datei dieses Verzeichnisses löschen möchten?"),
("Do this for all conflicts", "Dies gilt für alle Konflikte"),
("Are you sure you want to delete this empty directory?", "Sind Sie sicher, dass Sie diesen leeren Ordner löschen möchten?"),
("Are you sure you want to delete the file of this directory?", "Sind Sie sicher, dass Sie die Datei dieses Ordners löschen möchten?"),
("Do this for all conflicts", "Für alle Konflikte merken"),
("This is irreversible!", "Dies ist irreversibel!"),
("Deleting", "Löschen"),
("files", "Dateien"),
("Waiting", "Warten"),
("Finished", "Fertiggestellt"),
("Speed", "Geschwindigkeit"),
("Custom Image Quality", "Individuelle Bildqualität"),
("Custom Image Quality", "Benutzerdefinierte Bildqualität"),
("Privacy mode", "Datenschutz-Modus"),
("Block user input", "Benutzereingaben blockieren"),
("Unblock user input", "Benutzereingaben freigeben"),
("Adjust Window", "Fenster anpassen"),
("Original", "Original"),
("Shrink", "Geschrumpft"),
("Stretch", "Gestreckt"),
("Good image quality", "Gute Bildqualität"),
("Shrink", "Verkleinern"),
("Stretch", "Strecken"),
("Good image quality", "Schöner"),
("Balanced", "Ausgeglichen"),
("Optimize reaction time", "Optimierte Reaktionszeit"),
("Optimize reaction time", "Schneller"),
("Custom", "Benutzerdefiniert"),
("Show remote cursor", "Ferngesteuerten Cursor anzeigen"),
("Show quality monitor", ""),
("Show remote cursor", "Entfernten Cursor anzeigen"),
("Show quality monitor", "Qualitätsüberwachung anzeigen"),
("Disable clipboard", "Zwischenablage deaktivieren"),
("Lock after session end", "Sperren nach Sitzungsende"),
("Insert", "Einfügen"),
("Insert Lock", "Sperre einfügen"),
("Insert Lock", "Win+L (Sperren) senden"),
("Refresh", "Aktualisieren"),
("ID does not exist", "Die ID existiert nicht"),
("Failed to connect to rendezvous server", "Verbindung zum Verbindungsserver fehlgeschlagen"),
("Please try later", "Bitte versuchen Sie es später"),
("Remote desktop is offline", "Entfernter Desktop ist offline"),
("Key mismatch", "Schlüssel nicht übereinstimmend"),
("ID does not exist", "Diese ID existiert nicht"),
("Failed to connect to rendezvous server", "Verbindung zum Vermittlungsserver fehlgeschlagen"),
("Please try later", "Bitte versuchen Sie es später erneut"),
("Remote desktop is offline", "Entfernter PC ist offline"),
("Key mismatch", "Schlüssel stimmt nicht mit Serverschlüssel überein"),
("Timeout", "Zeitüberschreitung"),
("Failed to connect to relay server", "Verbindung zum Verbindungsserver fehlgeschlagen"),
("Failed to connect via rendezvous server", "Verbindung über rendezvous server fehlgeschlagen"),
("Failed to connect via relay server", "Verbindung über den Verbindungsserver ist fehlgeschlagen"),
("Failed to make direct connection to remote desktop", "Direkte Verbindung zum Entfernten-Desktop konnte nicht hergestellt werden"),
("Failed to connect to relay server", "Verbindung zum Vermittlungsserver fehlgeschlagen"),
("Failed to connect via rendezvous server", "Verbindung über Vermittlungsserver ist fehlgeschlagen"),
("Failed to connect via relay server", "Verbindung über Relay-Server ist fehlgeschlagen"),
("Failed to make direct connection to remote desktop", "Direkte Verbindung zum entfernten PC fehlgeschlagen"),
("Set Password", "Passwort festlegen"),
("OS Password", "Betriebssystem-Passwort"),
("install_tip", "Aufgrund der UAC kann RustDesk in manchen Fällen nicht ordnungsgemäß auf der Gegenseite funktionieren. Um UAC zu vermeiden, klicken Sie bitte auf die Schaltfläche unten, um RustDesk auf dem System zu installieren"),
("Click to upgrade", "Zum Upgrade anklicken"),
("Click to upgrade", "Zum Aktualisieren anklicken"),
("Click to download", "Zum Herunterladen klicken"),
("Click to update", "Zum Aktualisieren klicken"),
("Configure", "Konfigurieren"),
("config_acc", "Um Ihren Desktop aus der Ferne zu steuern, müssen Sie RustDesk \"Zugangs\" Rechte erteilen."),
("config_screen", "Um aus der Ferne auf Ihren Desktop zugreifen zu können, müssen Sie RustDesk \"Bildschirm-Aufnahme\" Berechtigungen erteilen."),
("config_acc", "Um Ihren PC aus der Ferne zu steuern, müssen Sie RustDesk Zugriffsrechte erteilen."),
("config_screen", "Um aus der Ferne auf Ihren PC zugreifen zu können, müssen Sie RustDesk \"Bildschirm-Aufnahme\"-Berechtigung erteilen."),
("Installing ...", "Installiere ..."),
("Install", "Installieren"),
("Installation", "Einrichtung"),
("Installation Path", "Einrichtungs Pfad"),
("Create start menu shortcuts", "Startmenü Verknüpfungen erstellen"),
("Create desktop icon", "Desktop Symbol erstellen"),
("agreement_tip", "Wenn Sie die Einrichtung starten, akzeptieren Sie die Lizenzvereinbarung"),
("Accept and Install", "Akzeptieren und installieren"),
("Installation", "Installation"),
("Installation Path", "Installationspfad"),
("Create start menu shortcuts", "Verknüpfung im Startmenü erstellen"),
("Create desktop icon", "Desktop-Verknüpfung erstellen"),
("agreement_tip", "Durch die Installation akzeptieren Sie die Lizenzvereinbarung"),
("Accept and Install", "Akzeptieren und Installieren"),
("End-user license agreement", "Lizenzvereinbarung für Endbenutzer"),
("Generating ...", "Generierung ..."),
("Your installation is lower version.", "Ihre Installation ist eine niedrigere Version."),
("not_close_tcp_tip", "Schließen Sie dieses Fenster nicht, während Sie den Tunnel benutzen."),
("Listening ...", "Hören ..."),
("Remote Host", "Entfernter Rechner"),
("Generating ...", "Generiere..."),
("Your installation is lower version.", "Ihre Installation ist älter."),
("not_close_tcp_tip", "Schließen Sie dieses Fenster nicht, solange Sie den Tunnel benutzen."),
("Listening ...", "Höre..."),
("Remote Host", "Entfernter PC"),
("Remote Port", "Entfernter Port"),
("Action", "Aktion"),
("Add", "Hinzufügen"),
("Local Port", "Lokaler Port"),
("setup_server_tip", "Für eine schnellere Verbindung, richten Sie bitte Ihren eigenen Verbindungsserver ein"),
("setup_server_tip", "Für eine schnellere Verbindung richten Sie bitte Ihren eigenen Verbindungsserver ein"),
("Too short, at least 6 characters.", "Zu kurz, mindestens 6 Zeichen."),
("The confirmation is not identical.", "Die Bestätigung ist nicht identisch."),
("The confirmation is not identical.", "Die Passwörter sind nicht identisch."),
("Permissions", "Berechtigungen"),
("Accept", "Akzeptieren"),
("Dismiss", "Ablehnen"),
("Disconnect", "Verbindung trennen"),
("Allow using keyboard and mouse", "Erlaubt die Verwendung von Tastatur und Maus"),
("Allow using keyboard and mouse", "Verwendung von Maus und Tastatur zulassen"),
("Allow using clipboard", "Verwendung der Zwischenablage zulassen"),
("Allow hearing sound", "Erlaubt das Hören von Sound"),
("Allow hearing sound", "System-Audio übertragen"),
("Allow file copy and paste", "Kopieren und Einfügen von Dateien zulassen"),
("Connected", "Verbunden"),
("Direct and encrypted connection", "Direkte und verschlüsselte Verbindung"),
@ -171,17 +171,17 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Enter your password", "Geben Sie Ihr Passwort ein"),
("Logging in...", "Anmeldung..."),
("Enable RDP session sharing", "RDP-Sitzungsfreigabe aktivieren"),
("Auto Login", "Automatisches Login (nur gültig, wenn Sie \"Sperren nach Sitzungsende\" eingestellt haben)"),
("Auto Login", "Automatisch anmelden (nur gültig, wenn Sie \"Sperren nach Sitzungsende\" aktiviert haben)"),
("Enable Direct IP Access", "Direkten IP-Zugang aktivieren"),
("Rename", "Umbenennen"),
("Space", "Platz"),
("Space", "Speicherplatz"),
("Create Desktop Shortcut", "Desktop-Verknüpfung erstellen"),
("Change Path", "Pfad ändern"),
("Create Folder", "Ordner erstellen"),
("Please enter the folder name", "Bitte geben Sie den Ordnernamen ein"),
("Fix it", "Reparieren"),
("Warning", "Warnung"),
("Login screen using Wayland is not supported", "Anmeldebildschirm mit Wayland wird nicht unterstützt"),
("Login screen using Wayland is not supported", "Anmeldebildschirm wird mit Wayland nicht unterstützt"),
("Reboot required", "Neustart erforderlich"),
("Unsupported display server ", "Nicht unterstützter Display-Server"),
("x11 expected", "X11 erwartet"),
@ -189,14 +189,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Settings", "Einstellungen"),
("Username", " Benutzername"),
("Invalid port", "Ungültiger Port"),
("Closed manually by the peer", "Vom Peer manuell geschlossen"),
("Enable remote configuration modification", "Änderung der Fernkonfiguration zulassen"),
("Closed manually by the peer", "Von der Gegenstelle manuell geschlossen"),
("Enable remote configuration modification", "Änderung der Konfiguration aus der Ferne zulassen"),
("Run without install", "Ohne Installation ausführen"),
("Always connected via relay", "Immer über Verbindungsserver verbunden"),
("Always connect via relay", "Verbindung immer über Verbindungsserver"),
("whitelist_tip", "Nur IPs auf der Freigabeliste können auf mich zugreifen"),
("Login", "Anmeldung"),
("Logout", "Abmeldung"),
("Always connected via relay", "Immer über Relay-Server verbunden"),
("Always connect via relay", "Immer über Relay-Server verbinden"),
("whitelist_tip", "Nur IPs auf der Whitelist können zugreifen"),
("Login", "Anmelden"),
("Logout", "Abmelden"),
("Tags", "Stichworte"),
("Search ID", "Suche ID"),
("Current Wayland display server is not supported", "Der aktuelle Wayland-Anzeigeserver wird nicht unterstützt"),
@ -205,100 +205,100 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Add Tag", "Stichwort hinzufügen"),
("Unselect all tags", "Alle Stichworte abwählen"),
("Network error", "Netzwerkfehler"),
("Username missed", "Benutzername fehlt"),
("Username missed", "Benutzername vergessen"),
("Password missed", "Passwort vergessen"),
("Wrong credentials", "Falsche Anmeldedaten"),
("Edit Tag", "Stichwort bearbeiten"),
("Unremember Password", "Passwort nicht merken"),
("Unremember Password", "Passwort vergessen"),
("Favorites", "Favoriten"),
("Add to Favorites", "Zu Favoriten hinzufügen"),
("Remove from Favorites", "Entferne von Favoriten"),
("Remove from Favorites", "Aus Favoriten entfernen"),
("Empty", "Leer"),
("Invalid folder name", "Ungültiger Ordnername"),
("Socks5 Proxy", "Socks5 Proxy"),
("Hostname", "Rechnername"),
("Discovered", "Gefunden"),
("install_daemon_tip", "Um beim Booten zu starten, müssen Sie den Systemdienst installieren"),
("install_daemon_tip", "Um mit System zu starten, muss der Systemdienst installiert sein"),
("Remote ID", "Entfernte ID"),
("Paste", "Einfügen"),
("Paste here?", "Hier einfügen?"),
("Are you sure to close the connection?", "Sind Sie sicher, dass Sie die Verbindung schließen wollen?"),
("Are you sure to close the connection?", "Möchten Sie diese Verbindung wirklich trennen?"),
("Download new version", "Neue Version herunterladen"),
("Touch mode", "Touch-Modus"),
("Mouse mode", "Mouse-Modus"),
("One-Finger Tap", "Ein Fingertipp"),
("Left Mouse", "Linke Maus"),
("One-Long Tap", "Tippen Sie mit einem Finger lang"),
("Two-Finger Tap", "Zwei Finger tippen"),
("Right Mouse", "Rechte Maus"),
("One-Finger Move", "Eine Fingerbewegung"),
("Double Tap & Move", "Doppeltippen und verschieben"),
("Mouse Drag", "Maus ziehen"),
("Three-Finger vertically", "Drei Finger vertikal"),
("Mouse mode", "Maus-Modus"),
("One-Finger Tap", "1-Finger-Tipp"),
("Left Mouse", "Linksklick"),
("One-Long Tap", "1-Finger-Halten"),
("Two-Finger Tap", "2-Finger-Tipp"),
("Right Mouse", "Rechtsklick"),
("One-Finger Move", "Einen Finger bewegen"),
("Double Tap & Move", "Doppeltippen und bewegen"),
("Mouse Drag", "Maus bewegen"),
("Three-Finger vertically", "Drei Finger vertikal bewegen"),
("Mouse Wheel", "Mausrad"),
("Two-Finger Move", "Zwei Finger Bewegung"),
("Canvas Move", "Leinwand bewegen"),
("Pinch to Zoom", "Zum Zoomen kneifen"),
("Canvas Zoom", "Leinwand Zoom"),
("Reset canvas", "Anzeige zurücksetzen"),
("No permission of file transfer", "Keine Erlaubnis zur Dateiübertragung"),
("Note", "Notiz"),
("Two-Finger Move", "Zwei Finger bewegen"),
("Canvas Move", "Sichtfeld bewegen"),
("Pinch to Zoom", "2-Finger-Zoom"),
("Canvas Zoom", "Sichtfeld-Zoom"),
("Reset canvas", "Sichtfeld zurücksetzen"),
("No permission of file transfer", "Keine Dateizugriff-Berechtigung"),
("Note", "Anmerkung"),
("Connection", "Verbindung"),
("Share Screen", "Bildschirm freigeben"),
("CLOSE", "NAH DRAN"),
("OPEN", "OFFEN"),
("Chat", "Plaudern"),
("CLOSE", "DEAKTIV."),
("OPEN", "AKTIVIER."),
("Chat", "Chat"),
("Total", "Gesamt"),
("items", "Artikel"),
("items", "Einträge"),
("Selected", "Ausgewählt"),
("Screen Capture", "Bildschirmaufnahme"),
("Input Control", "Eingabesteuerung"),
("Audio Capture", "Audioaufnahme"),
("File Connection", "Dateiverbindung"),
("Screen Capture", "Bildschirmzugr."),
("Input Control", "Eingabezugriff"),
("Audio Capture", "Audiozugriff"),
("File Connection", "Dateizugriff"),
("Screen Connection", "Bildschirmanschluss"),
("Do you accept?", "Akzeptieren Sie?"),
("Do you accept?", "Verbindung zulassen?"),
("Open System Setting", "Systemeinstellung öffnen"),
("How to get Android input permission?", "Wie erhalte ich eine Android-Eingabeberechtigung?"),
("android_input_permission_tip1", "Damit ein Remote-Gerät Ihr Android-Gerät per Maus oder Berührung steuern kann, müssen Sie RustDesk erlauben, den Dienst \"Barrierefreiheit\" zu verwenden."),
("android_input_permission_tip1", "Damit ein Remote-Gerät Ihr Android-Gerät steuern kann, müssen Sie RustDesk erlauben, den Dienst \"Barrierefreiheit\" zu verwenden."),
("android_input_permission_tip2", "Bitte gehen Sie zur nächsten Systemeinstellungsseite, suchen und geben Sie [Installierte Dienste] ein, schalten Sie den Dienst [RustDesk Input] ein."),
("android_new_connection_tip", "Es wurde eine neue Steuerungsanforderung empfangen, die Ihr aktuelles Gerät steuern möchte."),
("android_service_will_start_tip", "Durch das Einschalten der Bildschirmaufnahme wird der Dienst automatisch gestartet, sodass andere Geräte eine Verbindung von diesem Gerät anfordern können."),
("android_stop_service_tip", "Durch das Schließen des Dienstes werden automatisch alle hergestellten Verbindungen geschlossen."),
("android_version_audio_tip", "Die aktuelle Android-Version unterstützt keine Audioaufnahme, bitte aktualisieren Sie auf Android 10 oder höher."),
("android_start_service_tip", "Tippen Sie auf [Dienst starten] oder ÖFFNEN Sie die Berechtigung [Bildschirmaufnahme], um den Bildschirmfreigabedienst zu starten."),
("android_new_connection_tip", "möchte ihr Gerät steuern."),
("android_service_will_start_tip", "Durch das Aktivieren der Bildschirmfreigabe wird der Dienst automatisch gestartet, sodass andere Geräte dieses Android-Gerät steuern können."),
("android_stop_service_tip", "Durch das Deaktivieren des Dienstes werden automatisch alle hergestellten Verbindungen getrennt."),
("android_version_audio_tip", "Ihre Android-Version unterstützt keine Audioaufnahme, bitte aktualisieren Sie auf Android 10 oder höher, falls möglich."),
("android_start_service_tip", "Tippen Sie auf [Dienst aktivieren] oder aktivieren Sie die Berechtigung [Bildschirmzugr.], um den Bildschirmfreigabedienst zu starten."),
("Account", "Konto"),
("Overwrite", "Überschreiben"),
("This file exists, skip or overwrite this file?", "Diese Datei existiert, diese Datei überspringen oder überschreiben?"),
("Quit", "Aufhören"),
("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"),
("This file exists, skip or overwrite this file?", "Diese Datei existiert; überspringen oder überschreiben?"),
("Quit", "Beenden"),
("doc_mac_permission", "https://rustdesk.com/docs/de/manual/mac/#berechtigungen-aktivieren"),
("Help", "Hilfe"),
("Failed", "Gescheitert"),
("Failed", "Fehlgeschlagen"),
("Succeeded", "Erfolgreich"),
("Someone turns on privacy mode, exit", "Jemand aktiviert den Datenschutzmodus, beenden"),
("Someone turns on privacy mode, exit", "Jemand hat den Datenschutzmodus aktiviert, beende..."),
("Unsupported", "Nicht unterstützt"),
("Peer denied", "Peer verweigert"),
("Peer denied", "Die Gegenstelle hat die Verbindung abgelehnt"),
("Please install plugins", "Bitte installieren Sie Plugins"),
("Peer exit", "Peer-Ausgang"),
("Peer exit", "Die Gegenstelle hat die Verbindung getrennt"),
("Failed to turn off", "Ausschalten fehlgeschlagen"),
("Turned off", "Ausgeschaltet"),
("In privacy mode", "im Datenschutzmodus"),
("Out privacy mode", "Datenschutzmodus aus"),
("In privacy mode", "Datenschutzmodus aktivieren"),
("Out privacy mode", "Datenschutzmodus deaktivieren"),
("Language", "Sprache"),
("Keep RustDesk background service", ""),
("Ignore Battery Optimizations", ""),
("android_open_battery_optimizations_tip", ""),
("Random Password After Session", ""),
("Keep", ""),
("Update", ""),
("Disable", ""),
("Onetime Password", ""),
("Verification Method", ""),
("Enable security password", ""),
("Enable random password", ""),
("Enable onetime password", ""),
("Disable onetime password", ""),
("Activate onetime password", ""),
("Set security password", ""),
("Connection not allowed", ""),
("Keep RustDesk background service", "RustDesk im Hintergrund ausführen"),
("Ignore Battery Optimizations", "Batterieoptimierung ignorieren"),
("android_open_battery_optimizations_tip", "Möchten Sie die Batterieopimierungs-Einstellungen öffnen?"),
("Random Password After Session", "Neues zufälliges Passwort nach jeder Sitzung"),
("Keep", "Behalten"),
("Update", "Aktualisieren"),
("Disable", "Deaktivieren"),
("Onetime Password", "Einmal-Passwort"),
("Verification Method", "Überprüfungsmethode"),
("Enable security password", "Sicheres Passwort aktivieren"),
("Enable random password", "Zufälliges Passwort aktivieren"),
("Enable onetime password", "Einmal-Passwort aktivieren"),
("Disable onetime password", "Einmal-Passwort deaktivieren"),
("Activate onetime password", "Einmal-Passwort aktivieren"),
("Set security password", "Sicheres Passwort setzen"),
("Connection not allowed", "Verbindung abgelehnt"),
].iter().cloned().collect();
}

View File

@ -111,7 +111,8 @@ pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
cd.id = (*img).cursor_serial as _;
let pixels =
std::slice::from_raw_parts((*img).pixels, (cd.width * cd.height) as _);
cd.colors.resize(pixels.len() * 4, 0);
// cd.colors.resize(pixels.len() * 4, 0);
let mut cd_colors = vec![0_u8; pixels.len() * 4];
for y in 0..cd.height {
for x in 0..cd.width {
let pos = (y * cd.width + x) as usize;
@ -124,12 +125,13 @@ pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
continue;
}
let pos = pos * 4;
cd.colors[pos] = r as _;
cd.colors[pos + 1] = g as _;
cd.colors[pos + 2] = b as _;
cd.colors[pos + 3] = a as _;
cd_colors[pos] = r as _;
cd_colors[pos + 1] = g as _;
cd_colors[pos + 2] = b as _;
cd_colors[pos + 3] = a as _;
}
}
cd.colors = cd_colors.into();
res = Some(cd);
}
if !img.is_null() {

View File

@ -342,7 +342,7 @@ pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
}
Ok(CursorData {
id: hcursor,
colors,
colors: colors.into(),
hotx: hotspot.x as _,
hoty: hotspot.y as _,
width: size.width as _,

View File

@ -164,7 +164,7 @@ pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
Ok(CursorData {
id: hcursor,
colors: cbits,
colors: cbits.into(),
hotx: ii.0.xHotspot as _,
hoty: ii.0.yHotspot as _,
width: width as _,

View File

@ -266,7 +266,7 @@ impl RendezvousMediator {
async fn handle_request_relay(&self, rr: RequestRelay, server: ServerPtr) -> ResultType<()> {
self.create_relay(
rr.socket_addr,
rr.socket_addr.into(),
rr.relay_server,
rr.uuid,
server,
@ -303,7 +303,7 @@ impl RendezvousMediator {
let mut msg_out = Message::new();
let mut rr = RelayResponse {
socket_addr,
socket_addr: socket_addr.into(),
version: crate::VERSION.to_owned(),
..Default::default()
};
@ -334,8 +334,8 @@ impl RendezvousMediator {
let relay_server = self.get_relay_server(fla.relay_server);
msg_out.set_local_addr(LocalAddr {
id: Config::get_id(),
socket_addr: AddrMangle::encode(peer_addr),
local_addr: AddrMangle::encode(local_addr),
socket_addr: AddrMangle::encode(peer_addr).into(),
local_addr: AddrMangle::encode(local_addr).into(),
relay_server,
version: crate::VERSION.to_owned(),
..Default::default()
@ -353,7 +353,7 @@ impl RendezvousMediator {
{
let uuid = Uuid::new_v4().to_string();
return self
.create_relay(ph.socket_addr, relay_server, uuid, server, true, true)
.create_relay(ph.socket_addr.into(), relay_server, uuid, server, true, true)
.await;
}
let peer_addr = AddrMangle::decode(&ph.socket_addr);
@ -394,8 +394,8 @@ impl RendezvousMediator {
self.last_id_pk_registry = id.clone();
msg_out.set_register_pk(RegisterPk {
id,
uuid,
pk,
uuid: uuid.into(),
pk: pk.into(),
..Default::default()
});
socket.send(&msg_out, self.addr.to_owned()).await?;

View File

@ -20,6 +20,8 @@ use std::{
sync::{Arc, Mutex, RwLock, Weak},
time::Duration,
};
use bytes::Bytes;
pub mod audio_service;
cfg_if::cfg_if! {
if #[cfg(not(any(target_os = "android", target_os = "ios")))] {
@ -130,13 +132,13 @@ pub async fn create_tcp_connection(
id: sign::sign(
&IdPk {
id: Config::get_id(),
pk: our_pk_b.0.to_vec(),
pk: Bytes::from(our_pk_b.0.to_vec()),
..Default::default()
}
.write_to_bytes()
.unwrap_or_default(),
&sk,
),
).into(),
..Default::default()
});
timeout(CONNECT_TIMEOUT, stream.send(&msg_out)).await??;
@ -319,6 +321,14 @@ 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")]
{
use std::sync::Once;
static ONCE: Once = Once::new();
ONCE.call_once(|| {
scrap::hwcodec::check_config_process(false);
})
}
if is_server {
std::thread::spawn(move || {
@ -327,15 +337,6 @@ pub async fn start_server(is_server: bool) {
std::process::exit(-1);
}
});
#[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()
});
}
#[cfg(windows)]
crate::platform::windows::bootstrap();
input_service::fix_key_down_timeout_loop();

View File

@ -367,7 +367,7 @@ fn send_f32(data: &[f32], encoder: &mut Encoder, sp: &GenericService) {
Ok(data) => {
let mut msg_out = Message::new();
msg_out.set_audio_frame(AudioFrame {
data,
data: data.into(),
timestamp: crate::common::get_time(),
..Default::default()
});

View File

@ -636,6 +636,16 @@ impl Connection {
pi.hostname = MOBILE_INFO2.lock().unwrap().clone();
pi.platform = "Android".into();
}
#[cfg(feature = "hwcodec")]
{
let (h264, h265) = scrap::codec::Encoder::supported_encoding();
pi.encoding = Some(SupportedEncoding {
h264,
h265,
..Default::default()
})
.into();
}
if self.port_forward_socket.is_some() {
let mut msg_out = Message::new();
@ -1352,6 +1362,12 @@ impl Connection {
}
}
}
if let Some(q) = o.video_codec_state.clone().take() {
scrap::codec::Encoder::update_video_encoder(
self.inner.id(),
scrap::codec::EncoderUpdate::State(q),
);
}
}
async fn on_close(&mut self, reason: &str, lock: bool) {
@ -1460,7 +1476,7 @@ async fn start_ipc(
file_num,
data,
compressed}) = data {
stream.send(&Data::FS(ipc::FS::WriteBlock{id, file_num, data: Vec::new(), compressed})).await?;
stream.send(&Data::FS(ipc::FS::WriteBlock{id, file_num, data: Bytes::new(), compressed})).await?;
stream.send_raw(data).await?;
} else {
stream.send(&data).await?;

View File

@ -146,7 +146,7 @@ fn run_cursor(sp: MouseCursorService, state: &mut StateCursor) -> ResultType<()>
msg = cached.clone();
} else {
let mut data = crate::get_cursor_data(hcursor)?;
data.colors = hbb_common::compress::compress(&data.colors[..], COMPRESS_LEVEL);
data.colors = hbb_common::compress::compress(&data.colors[..], COMPRESS_LEVEL).into();
let mut tmp = Message::new();
tmp.set_cursor_data(data);
msg = Arc::new(tmp);

View File

@ -26,11 +26,11 @@ use hbb_common::tokio::sync::{
use scrap::{
codec::{Encoder, EncoderCfg, HwEncoderConfig},
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
Capturer, Display, Frame,
Capturer, Display, TraitCapturer,
};
use std::{
collections::HashSet,
io::{ErrorKind::WouldBlock, Result},
io::ErrorKind::WouldBlock,
ops::{Deref, DerefMut},
time::{self, Duration, Instant},
};
@ -128,56 +128,6 @@ impl VideoFrameController {
}
}
pub(super) trait TraitCapturer {
fn frame<'a>(&'a mut self, timeout: Duration) -> Result<Frame<'a>>;
fn set_use_yuv(&mut self, use_yuv: bool);
#[cfg(windows)]
fn is_gdi(&self) -> bool;
#[cfg(windows)]
fn set_gdi(&mut self) -> bool;
}
impl TraitCapturer for Capturer {
fn frame<'a>(&'a mut self, timeout: Duration) -> Result<Frame<'a>> {
self.frame(timeout)
}
fn set_use_yuv(&mut self, use_yuv: bool) {
self.set_use_yuv(use_yuv);
}
#[cfg(windows)]
fn is_gdi(&self) -> bool {
self.is_gdi()
}
#[cfg(windows)]
fn set_gdi(&mut self) -> bool {
self.set_gdi()
}
}
#[cfg(windows)]
impl TraitCapturer for scrap::CapturerMag {
fn frame<'a>(&'a mut self, _timeout_ms: Duration) -> Result<Frame<'a>> {
self.frame(_timeout_ms)
}
fn set_use_yuv(&mut self, use_yuv: bool) {
self.set_use_yuv(use_yuv);
}
fn is_gdi(&self) -> bool {
false
}
fn set_gdi(&mut self) -> bool {
false
}
}
pub fn new() -> GenericService {
let sp = GenericService::new(NAME, true);
sp.run(run);
@ -393,8 +343,10 @@ fn get_capturer(use_yuv: bool) -> ResultType<CapturerInfo> {
#[cfg(windows)]
let mut captuerer_privacy_mode_id = privacy_mode_id;
#[cfg(windows)]
if crate::ui::win_privacy::is_process_consent_running()? {
captuerer_privacy_mode_id = 0;
if captuerer_privacy_mode_id != 0 {
if crate::ui::win_privacy::is_process_consent_running()? {
captuerer_privacy_mode_id = 0;
}
}
log::debug!(
"Try create capturer with captuerer privacy mode id {}",
@ -483,6 +435,7 @@ fn run(sp: GenericService) -> ResultType<()> {
let mut try_gdi = 1;
#[cfg(windows)]
log::info!("gdi: {}", c.is_gdi());
let codec_name = Encoder::current_hw_encoder_name();
while sp.ok() {
#[cfg(windows)]
@ -508,6 +461,9 @@ fn run(sp: GenericService) -> ResultType<()> {
*SWITCH.lock().unwrap() = true;
bail!("SWITCH");
}
if codec_name != Encoder::current_hw_encoder_name() {
bail!("SWITCH");
}
check_privacy_mode_changed(&sp, c.privacy_mode_id)?;
#[cfg(windows)]
{

View File

@ -1,30 +1,39 @@
use super::*;
use hbb_common::allow_err;
use scrap::{Capturer, Display, Frame};
use std::{io::Result, time::Duration};
use scrap::{Capturer, Display, Frame, TraitCapturer};
use std::io::Result;
lazy_static::lazy_static! {
static ref CAP_DISPLAY_INFO: RwLock<u64> = RwLock::new(0);
}
struct CapturerPtr(*mut Capturer);
impl Clone for CapturerPtr {
fn clone(&self) -> Self {
Self(self.0)
}
}
impl TraitCapturer for CapturerPtr {
fn frame<'a>(&'a mut self, timeout: Duration) -> Result<Frame<'a>> {
unsafe { (*self.0).frame(timeout) }
}
fn set_use_yuv(&mut self, use_yuv: bool) {
unsafe {
(*self.0).set_use_yuv(use_yuv);
}
}
}
struct CapDisplayInfo {
rects: Vec<((i32, i32), usize, usize)>,
displays: Vec<DisplayInfo>,
num: usize,
primary: usize,
current: usize,
capturer: *mut Capturer,
}
impl super::video_service::TraitCapturer for *mut Capturer {
fn frame<'a>(&'a mut self, timeout: Duration) -> Result<Frame<'a>> {
unsafe { (**self).frame(timeout) }
}
fn set_use_yuv(&mut self, use_yuv: bool) {
unsafe {
(**self).set_use_yuv(use_yuv);
}
}
capturer: CapturerPtr,
}
async fn check_init() -> ResultType<()> {
@ -68,6 +77,7 @@ async fn check_init() -> ResultType<()> {
let capturer = Box::into_raw(Box::new(
Capturer::new(display, true).with_context(|| "Failed to create capturer")?,
));
let capturer = CapturerPtr(capturer);
let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo {
rects,
displays,
@ -104,7 +114,7 @@ pub fn clear() {
if *lock != 0 {
unsafe {
let cap_display_info = Box::from_raw(*lock as *mut CapDisplayInfo);
let _ = Box::from_raw(cap_display_info.capturer);
let _ = Box::from_raw(cap_display_info.capturer.0);
}
*lock = 0;
}
@ -170,7 +180,7 @@ pub(super) fn get_capturer() -> ResultType<super::video_service::CapturerInfo> {
current: cap_display_info.current,
privacy_mode_id: 0,
_captuerer_privacy_mode_id: 0,
capturer: Box::new(cap_display_info.capturer),
capturer: Box::new(cap_display_info.capturer.clone()),
})
}
} else {

View File

@ -590,7 +590,7 @@ async fn start_pa() {
} else {
buf.clone()
};
if let Err(err) = stream.send_raw(out).await {
if let Err(err) = stream.send_raw(out.into()).await {
log::error!("Failed to send audio data:{}", err);
break;
}

View File

@ -94,3 +94,4 @@ span#fullscreen.active {
button:disabled {
opacity: 0.3;
}

View File

@ -156,6 +156,9 @@ class Header: Reactor.Component {
}
function renderDisplayPop() {
var codecs = handler.supported_hwcodec();
var show_codec = handler.has_hwcodec() && (codecs[0] || codecs[1]);
return <popup>
<menu.context #display-options>
<li #adjust-window style="display:none">{translate('Adjust Window')}</li>
@ -168,6 +171,13 @@ class Header: Reactor.Component {
<li #balanced type="image-quality"><span>{svg_checkmark}</span>{translate('Balanced')}</li>
<li #low type="image-quality"><span>{svg_checkmark}</span>{translate('Optimize reaction time')}</li>
<li #custom type="image-quality"><span>{svg_checkmark}</span>{translate('Custom')}</li>
{show_codec ? <div>
<div .separator />
<li #auto type="codec-preference"><span>{svg_checkmark}</span>Auto</li>
<li #vp9 type="codec-preference"><span>{svg_checkmark}</span>VP9</li>
{codecs[0] ? <li #h264 type="codec-preference"><span>{svg_checkmark}</span>H264</li> : ""}
{codecs[1] ? <li #h265 type="codec-preference"><span>{svg_checkmark}</span>H265</li> : ""}
</div> : ""}
<div .separator />
<li #show-remote-cursor .toggle-option><span>{svg_checkmark}</span>{translate('Show remote cursor')}</li>
<li #show-quality-monitor .toggle-option><span>{svg_checkmark}</span>{translate('Show quality monitor')}</li>
@ -327,7 +337,7 @@ class Header: Reactor.Component {
}
}
event click $(menu#display-options>li) (_, me) {
event click $(menu#display-options li) (_, me) {
if (me.id == "custom") {
handle_custom_image_quality();
} else if (me.id == "privacy-mode") {
@ -344,6 +354,9 @@ class Header: Reactor.Component {
} else if (type == "view-style") {
handler.save_view_style(me.id);
adaptDisplay();
} else if (type == "codec-preference") {
handler.set_option("codec-preference", me.id);
handler.change_prefer_codec();
}
toggleMenuState();
}
@ -383,7 +396,10 @@ function toggleMenuState() {
values.push(s);
var k = handler.get_keyboard_mode();
values.push(k);
for (var el in $$(menu#display-options>li)) {
var c = handler.get_option("codec-preference");
if (!c) c = "auto";
values.push(c);
for (var el in $$(menu#display-options li)) {
el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0);
}
for (var el in $$(menu#keyboard-options>li)) {

View File

@ -235,6 +235,9 @@ impl sciter::EventHandler for Handler {
fn set_write_override(i32, i32, bool, bool, bool);
fn get_keyboard_mode();
fn save_keyboard_mode(String);
fn has_hwcodec();
fn supported_hwcodec();
fn change_prefer_codec();
}
}
@ -441,6 +444,42 @@ impl Handler {
true
}
fn has_hwcodec(&self) -> bool {
#[cfg(not(feature = "hwcodec"))]
return false;
#[cfg(feature = "hwcodec")]
return true;
}
fn supported_hwcodec(&self) -> Value {
#[cfg(feature = "hwcodec")]
{
let mut v = Value::array(0);
let decoder = scrap::codec::Decoder::video_codec_state(&self.id);
let mut h264 = decoder.score_h264 > 0;
let mut h265 = decoder.score_h265 > 0;
if let Some((encoding_264, encoding_265)) = self.lc.read().unwrap().supported_encoding {
h264 = h264 && encoding_264;
h265 = h265 && encoding_265;
}
v.push(h264);
v.push(h265);
v
}
#[cfg(not(feature = "hwcodec"))]
{
let mut v = Value::array(0);
v.push(false);
v.push(false);
v
}
}
fn change_prefer_codec(&self) {
let msg = self.lc.write().unwrap().change_prefer_codec();
self.send(Data::Message(msg));
}
fn t(&self, name: String) -> String {
crate::client::translate(name)
}

View File

@ -5,6 +5,7 @@ use crate::{
use hbb_common::{allow_err, bail, lazy_static, log, tokio, ResultType};
use std::{
ffi::CString,
os::windows::process::CommandExt,
sync::Mutex,
time::{Duration, Instant},
};
@ -24,7 +25,9 @@ use winapi::{
CreateProcessAsUserW, GetCurrentThreadId, QueueUserAPC, ResumeThread,
PROCESS_INFORMATION, STARTUPINFOW,
},
winbase::{WTSGetActiveConsoleSessionId, CREATE_SUSPENDED, DETACHED_PROCESS},
winbase::{
WTSGetActiveConsoleSessionId, CREATE_NO_WINDOW, CREATE_SUSPENDED, DETACHED_PROCESS,
},
winnt::{MEM_COMMIT, PAGE_READWRITE},
winuser::*,
},
@ -317,6 +320,7 @@ fn wait_find_privacy_hwnd(msecs: u128) -> ResultType<HWND> {
pub fn is_process_consent_running() -> ResultType<bool> {
let output = std::process::Command::new("cmd")
.args(&["/C", "tasklist | findstr consent.exe"])
.creation_flags(CREATE_NO_WINDOW)
.output()?;
Ok(output.status.success() && !output.stdout.is_empty())
}