mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
@@ -1017,10 +1017,16 @@ impl VideoHandler {
|
||||
|
||||
/// Handle a new video frame.
|
||||
#[inline]
|
||||
pub fn handle_frame(&mut self, vf: VideoFrame) -> ResultType<bool> {
|
||||
pub fn handle_frame(
|
||||
&mut self,
|
||||
vf: VideoFrame,
|
||||
chroma: &mut Option<Chroma>,
|
||||
) -> ResultType<bool> {
|
||||
match &vf.union {
|
||||
Some(frame) => {
|
||||
let res = self.decoder.handle_video_frame(frame, &mut self.rgb);
|
||||
let res = self
|
||||
.decoder
|
||||
.handle_video_frame(frame, &mut self.rgb, chroma);
|
||||
if self.record {
|
||||
self.recorder
|
||||
.lock()
|
||||
@@ -1855,6 +1861,7 @@ pub fn start_video_audio_threads<F, T>(
|
||||
MediaSender,
|
||||
Arc<RwLock<HashMap<usize, ArrayQueue<VideoFrame>>>>,
|
||||
Arc<RwLock<HashMap<usize, usize>>>,
|
||||
Arc<RwLock<Option<Chroma>>>,
|
||||
)
|
||||
where
|
||||
F: 'static + FnMut(usize, &mut scrap::ImageRgb) + Send,
|
||||
@@ -1866,6 +1873,9 @@ where
|
||||
let mut video_callback = video_callback;
|
||||
let fps_map = Arc::new(RwLock::new(HashMap::new()));
|
||||
let decode_fps_map = fps_map.clone();
|
||||
let chroma = Arc::new(RwLock::new(None));
|
||||
let chroma_cloned = chroma.clone();
|
||||
let mut last_chroma = None;
|
||||
|
||||
std::thread::spawn(move || {
|
||||
#[cfg(windows)]
|
||||
@@ -1911,10 +1921,17 @@ where
|
||||
}
|
||||
}
|
||||
if let Some(handler_controller) = handler_controller_map.get_mut(display) {
|
||||
match handler_controller.handler.handle_frame(vf) {
|
||||
let mut tmp_chroma = None;
|
||||
match handler_controller.handler.handle_frame(vf, &mut tmp_chroma) {
|
||||
Ok(true) => {
|
||||
video_callback(display, &mut handler_controller.handler.rgb);
|
||||
|
||||
// chroma
|
||||
if tmp_chroma.is_some() && last_chroma != tmp_chroma {
|
||||
last_chroma = tmp_chroma;
|
||||
*chroma.write().unwrap() = tmp_chroma;
|
||||
}
|
||||
|
||||
// fps calculation
|
||||
// The first frame will be very slow
|
||||
if handler_controller.skip_beginning < 5 {
|
||||
@@ -1992,6 +2009,7 @@ where
|
||||
audio_sender,
|
||||
video_queue_map_cloned,
|
||||
decode_fps_map,
|
||||
chroma_cloned,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use hbb_common::{
|
||||
get_time,
|
||||
message_proto::{Message, VoiceCallRequest, VoiceCallResponse},
|
||||
};
|
||||
use scrap::CodecFormat;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct QualityStatus {
|
||||
@@ -12,6 +12,7 @@ pub struct QualityStatus {
|
||||
pub delay: Option<i32>,
|
||||
pub target_bitrate: Option<i32>,
|
||||
pub codec_format: Option<CodecFormat>,
|
||||
pub chroma: Option<String>,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -74,6 +74,7 @@ pub struct Remote<T: InvokeUiSession> {
|
||||
elevation_requested: bool,
|
||||
fps_control_map: HashMap<usize, FpsControl>,
|
||||
decode_fps_map: Arc<RwLock<HashMap<usize, usize>>>,
|
||||
chroma: Arc<RwLock<Option<Chroma>>>,
|
||||
}
|
||||
|
||||
impl<T: InvokeUiSession> Remote<T> {
|
||||
@@ -86,6 +87,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
sender: mpsc::UnboundedSender<Data>,
|
||||
frame_count_map: Arc<RwLock<HashMap<usize, usize>>>,
|
||||
decode_fps: Arc<RwLock<HashMap<usize, usize>>>,
|
||||
chroma: Arc<RwLock<Option<Chroma>>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
handler,
|
||||
@@ -111,6 +113,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
elevation_requested: false,
|
||||
fps_control_map: Default::default(),
|
||||
decode_fps_map: decode_fps,
|
||||
chroma,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,9 +250,17 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
// Correcting the inaccuracy of status_timer
|
||||
(k.clone(), (*v as i32) * 1000 / elapsed as i32)
|
||||
}).collect::<HashMap<usize, i32>>();
|
||||
let chroma = self.chroma.read().unwrap().clone();
|
||||
let chroma = match chroma {
|
||||
Some(Chroma::I444) => "4:4:4",
|
||||
Some(Chroma::I420) => "4:2:0",
|
||||
None => "-",
|
||||
};
|
||||
let chroma = Some(chroma.to_string());
|
||||
self.handler.update_quality_status(QualityStatus {
|
||||
speed: Some(speed),
|
||||
fps,
|
||||
chroma,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -471,6 +471,7 @@ impl InvokeUiSession for FlutterHandler {
|
||||
"codec_format",
|
||||
&status.codec_format.map_or(NULL, |it| it.to_string()),
|
||||
),
|
||||
("chroma", &status.chroma.map_or(NULL, |it| it.to_string())),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", "列表"),
|
||||
("Virtual display", "虚拟显示器"),
|
||||
("Plug out all", "拔出所有"),
|
||||
("True color(4:4:4)", "真彩模式(4:4:4)"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", "Seznam"),
|
||||
("Virtual display", "Virtuální obrazovka"),
|
||||
("Plug out all", "Odpojit všechny"),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", "Liste"),
|
||||
("Virtual display", "Virtueller Bildschirm"),
|
||||
("Plug out all", "Alle ausschalten"),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -565,13 +565,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("Open in new window", "Abrir en una nueva ventana"),
|
||||
("Show displays as individual windows", "Mostrar pantallas como ventanas individuales"),
|
||||
("Use all my displays for the remote session", "Usar todas mis pantallas para la sesión remota"),
|
||||
("selinux_tip", "SELinux está activado en tu dispositivo, lo que puede hacer que RustDesk no se ejecute correctamente como lado controlado."),
|
||||
("selinux_tip", ""),
|
||||
("Change view", ""),
|
||||
("Big tiles", ""),
|
||||
("Small tiles", ""),
|
||||
("List", ""),
|
||||
("selinux_tip", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", "Tampilan virtual"),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", "Elenco"),
|
||||
("Virtual display", "Scehrmo virtuale"),
|
||||
("Plug out all", "Scollega tutto"),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", "Saraksts"),
|
||||
("Virtual display", "Virtuālais displejs"),
|
||||
("Plug out all", "Atvienot visu"),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", "Lista"),
|
||||
("Virtual display", "Witualne ekrany"),
|
||||
("Plug out all", "Odłącz wszystko"),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", "Список"),
|
||||
("Virtual display", "Виртуальный дисплей"),
|
||||
("Plug out all", "Отключить все"),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -572,5 +572,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("List", ""),
|
||||
("Virtual display", ""),
|
||||
("Plug out all", ""),
|
||||
("True color(4:4:4)", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ pub fn is_can_screen_recording(prompt: bool) -> bool {
|
||||
if !can_record_screen && prompt {
|
||||
use scrap::{Capturer, Display};
|
||||
if let Ok(d) = Display::primary() {
|
||||
Capturer::new(d, true).ok();
|
||||
Capturer::new(d).ok();
|
||||
}
|
||||
}
|
||||
can_record_screen
|
||||
|
||||
@@ -1214,7 +1214,7 @@ impl Connection {
|
||||
|
||||
fn on_remote_authorized() {
|
||||
use std::sync::Once;
|
||||
static ONCE: Once = Once::new();
|
||||
static _ONCE: Once = Once::new();
|
||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
if !Config::get_option("allow-remove-wallpaper").is_empty() {
|
||||
// multi connections set once
|
||||
@@ -1223,7 +1223,7 @@ impl Connection {
|
||||
match crate::platform::WallPaperRemover::new() {
|
||||
Ok(remover) => {
|
||||
*wallpaper = Some(remover);
|
||||
ONCE.call_once(|| {
|
||||
_ONCE.call_once(|| {
|
||||
shutdown_hooks::add_shutdown_hook(shutdown_hook);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use hbb_common::{
|
||||
tokio::{self, sync::mpsc},
|
||||
ResultType,
|
||||
};
|
||||
use scrap::{Capturer, Frame, TraitCapturer};
|
||||
use scrap::{Capturer, Frame, TraitCapturer, TraitFrame};
|
||||
use shared_memory::*;
|
||||
use std::{
|
||||
mem::size_of,
|
||||
@@ -300,7 +300,6 @@ pub mod server {
|
||||
fn run_capture(shmem: Arc<SharedMemory>) {
|
||||
let mut c = None;
|
||||
let mut last_current_display = usize::MAX;
|
||||
let mut last_use_yuv = false;
|
||||
let mut last_timeout_ms: i32 = 33;
|
||||
let mut spf = Duration::from_millis(last_timeout_ms as _);
|
||||
let mut first_frame_captured = false;
|
||||
@@ -316,14 +315,7 @@ pub mod server {
|
||||
let para = para_ptr as *const CapturerPara;
|
||||
let recreate = (*para).recreate;
|
||||
let current_display = (*para).current_display;
|
||||
let use_yuv = (*para).use_yuv;
|
||||
let use_yuv_set = (*para).use_yuv_set;
|
||||
let timeout_ms = (*para).timeout_ms;
|
||||
if !use_yuv_set {
|
||||
c = None;
|
||||
std::thread::sleep(spf);
|
||||
continue;
|
||||
}
|
||||
if c.is_none() {
|
||||
let Ok(mut displays) = display_service::try_get_displays() else {
|
||||
log::error!("Failed to get displays");
|
||||
@@ -338,11 +330,10 @@ pub mod server {
|
||||
let display = displays.remove(current_display);
|
||||
display_width = display.width();
|
||||
display_height = display.height();
|
||||
match Capturer::new(display, use_yuv) {
|
||||
match Capturer::new(display) {
|
||||
Ok(mut v) => {
|
||||
c = {
|
||||
last_current_display = current_display;
|
||||
last_use_yuv = use_yuv;
|
||||
first_frame_captured = false;
|
||||
if dxgi_failed_times > MAX_DXGI_FAIL_TIME {
|
||||
dxgi_failed_times = 0;
|
||||
@@ -353,8 +344,6 @@ pub mod server {
|
||||
CapturerPara {
|
||||
recreate: false,
|
||||
current_display: (*para).current_display,
|
||||
use_yuv: (*para).use_yuv,
|
||||
use_yuv_set: (*para).use_yuv_set,
|
||||
timeout_ms: (*para).timeout_ms,
|
||||
},
|
||||
);
|
||||
@@ -368,16 +357,11 @@ pub mod server {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if recreate
|
||||
|| current_display != last_current_display
|
||||
|| use_yuv != last_use_yuv
|
||||
{
|
||||
if recreate || current_display != last_current_display {
|
||||
log::info!(
|
||||
"create capturer, display:{}->{}, use_yuv:{}->{}",
|
||||
"create capturer, display:{}->{}",
|
||||
last_current_display,
|
||||
current_display,
|
||||
last_use_yuv,
|
||||
use_yuv
|
||||
);
|
||||
c = None;
|
||||
continue;
|
||||
@@ -401,12 +385,12 @@ pub mod server {
|
||||
utils::set_frame_info(
|
||||
&shmem,
|
||||
FrameInfo {
|
||||
length: f.0.len(),
|
||||
length: f.data().len(),
|
||||
width: display_width,
|
||||
height: display_height,
|
||||
},
|
||||
);
|
||||
shmem.write(ADDR_CAPTURE_FRAME, f.0);
|
||||
shmem.write(ADDR_CAPTURE_FRAME, f.data());
|
||||
shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE));
|
||||
utils::increase_counter(shmem.as_ptr().add(ADDR_CAPTURE_FRAME_COUNTER));
|
||||
first_frame_captured = true;
|
||||
@@ -651,7 +635,7 @@ pub mod client {
|
||||
}
|
||||
|
||||
impl CapturerPortable {
|
||||
pub fn new(current_display: usize, use_yuv: bool) -> Self
|
||||
pub fn new(current_display: usize) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -665,8 +649,6 @@ pub mod client {
|
||||
CapturerPara {
|
||||
recreate: true,
|
||||
current_display,
|
||||
use_yuv,
|
||||
use_yuv_set: false,
|
||||
timeout_ms: 33,
|
||||
},
|
||||
);
|
||||
@@ -684,26 +666,6 @@ pub mod client {
|
||||
}
|
||||
|
||||
impl TraitCapturer for CapturerPortable {
|
||||
fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
let mut option = SHMEM.lock().unwrap();
|
||||
if let Some(shmem) = option.as_mut() {
|
||||
unsafe {
|
||||
let para_ptr = shmem.as_ptr().add(ADDR_CAPTURER_PARA);
|
||||
let para = para_ptr as *const CapturerPara;
|
||||
utils::set_para(
|
||||
shmem,
|
||||
CapturerPara {
|
||||
recreate: (*para).recreate,
|
||||
current_display: (*para).current_display,
|
||||
use_yuv,
|
||||
use_yuv_set: true,
|
||||
timeout_ms: (*para).timeout_ms,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn frame<'a>(&'a mut self, timeout: Duration) -> std::io::Result<Frame<'a>> {
|
||||
let mut lock = SHMEM.lock().unwrap();
|
||||
let shmem = lock.as_mut().ok_or(std::io::Error::new(
|
||||
@@ -720,8 +682,6 @@ pub mod client {
|
||||
CapturerPara {
|
||||
recreate: (*para).recreate,
|
||||
current_display: (*para).current_display,
|
||||
use_yuv: (*para).use_yuv,
|
||||
use_yuv_set: (*para).use_yuv_set,
|
||||
timeout_ms: timeout.as_millis() as _,
|
||||
},
|
||||
);
|
||||
@@ -744,7 +704,7 @@ pub mod client {
|
||||
}
|
||||
let frame_ptr = base.add(ADDR_CAPTURE_FRAME);
|
||||
let data = slice::from_raw_parts(frame_ptr, (*frame_info).length);
|
||||
Ok(Frame(data))
|
||||
Ok(Frame::new(data, self.height))
|
||||
} else {
|
||||
let ptr = base.add(ADDR_CAPTURE_WOULDBLOCK);
|
||||
let wouldblock = utils::ptr_to_i32(ptr);
|
||||
@@ -910,7 +870,6 @@ pub mod client {
|
||||
pub fn create_capturer(
|
||||
current_display: usize,
|
||||
display: scrap::Display,
|
||||
use_yuv: bool,
|
||||
portable_service_running: bool,
|
||||
) -> ResultType<Box<dyn TraitCapturer>> {
|
||||
if portable_service_running != RUNNING.lock().unwrap().clone() {
|
||||
@@ -919,7 +878,7 @@ pub mod client {
|
||||
if portable_service_running {
|
||||
log::info!("Create shared memory capturer");
|
||||
if current_display == *display_service::PRIMARY_DISPLAY_IDX {
|
||||
return Ok(Box::new(CapturerPortable::new(current_display, use_yuv)));
|
||||
return Ok(Box::new(CapturerPortable::new(current_display)));
|
||||
} else {
|
||||
bail!(
|
||||
"Ignore capture display index: {}, the primary display index is: {}",
|
||||
@@ -930,7 +889,7 @@ pub mod client {
|
||||
} else {
|
||||
log::debug!("Create capturer dxgi|gdi");
|
||||
return Ok(Box::new(
|
||||
Capturer::new(display, use_yuv).with_context(|| "Failed to create capturer")?,
|
||||
Capturer::new(display).with_context(|| "Failed to create capturer")?,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -981,8 +940,6 @@ pub mod client {
|
||||
pub struct CapturerPara {
|
||||
recreate: bool,
|
||||
current_display: usize,
|
||||
use_yuv: bool,
|
||||
use_yuv_set: bool,
|
||||
timeout_ms: i32,
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,10 @@ use scrap::Capturer;
|
||||
use scrap::{
|
||||
aom::AomEncoderConfig,
|
||||
codec::{Encoder, EncoderCfg, HwEncoderConfig, Quality},
|
||||
convert_to_yuv,
|
||||
record::{Recorder, RecorderContext},
|
||||
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
|
||||
CodecName, Display, TraitCapturer,
|
||||
CodecName, Display, Frame, TraitCapturer, TraitFrame,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use std::sync::Once;
|
||||
@@ -171,7 +172,6 @@ pub fn new(idx: usize) -> GenericService {
|
||||
fn create_capturer(
|
||||
privacy_mode_id: i32,
|
||||
display: Display,
|
||||
use_yuv: bool,
|
||||
_current: usize,
|
||||
_portable_service_running: bool,
|
||||
) -> ResultType<Box<dyn TraitCapturer>> {
|
||||
@@ -182,12 +182,7 @@ fn create_capturer(
|
||||
if privacy_mode_id > 0 {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
match scrap::CapturerMag::new(
|
||||
display.origin(),
|
||||
display.width(),
|
||||
display.height(),
|
||||
use_yuv,
|
||||
) {
|
||||
match scrap::CapturerMag::new(display.origin(), display.width(), display.height()) {
|
||||
Ok(mut c1) => {
|
||||
let mut ok = false;
|
||||
let check_begin = Instant::now();
|
||||
@@ -236,12 +231,11 @@ fn create_capturer(
|
||||
return crate::portable_service::client::create_capturer(
|
||||
_current,
|
||||
display,
|
||||
use_yuv,
|
||||
_portable_service_running,
|
||||
);
|
||||
#[cfg(not(windows))]
|
||||
return Ok(Box::new(
|
||||
Capturer::new(display, use_yuv).with_context(|| "Failed to create capturer")?,
|
||||
Capturer::new(display).with_context(|| "Failed to create capturer")?,
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -265,7 +259,7 @@ pub fn test_create_capturer(
|
||||
)
|
||||
} else {
|
||||
let display = displays.remove(display_idx);
|
||||
match create_capturer(privacy_mode_id, display, true, display_idx, false) {
|
||||
match create_capturer(privacy_mode_id, display, display_idx, false) {
|
||||
Ok(_) => return "".to_owned(),
|
||||
Err(e) => e,
|
||||
}
|
||||
@@ -320,11 +314,7 @@ impl DerefMut for CapturerInfo {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_capturer(
|
||||
current: usize,
|
||||
use_yuv: bool,
|
||||
portable_service_running: bool,
|
||||
) -> ResultType<CapturerInfo> {
|
||||
fn get_capturer(current: usize, portable_service_running: bool) -> ResultType<CapturerInfo> {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
if !is_x11() {
|
||||
@@ -382,7 +372,6 @@ fn get_capturer(
|
||||
let capturer = create_capturer(
|
||||
capturer_privacy_mode_id,
|
||||
display,
|
||||
use_yuv,
|
||||
current,
|
||||
portable_service_running,
|
||||
)?;
|
||||
@@ -424,7 +413,7 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
|
||||
let display_idx = vs.idx;
|
||||
let sp = vs.sp;
|
||||
let mut c = get_capturer(display_idx, true, last_portable_service_running)?;
|
||||
let mut c = get_capturer(display_idx, last_portable_service_running)?;
|
||||
|
||||
let mut video_qos = VIDEO_QOS.lock().unwrap();
|
||||
video_qos.refresh(None);
|
||||
@@ -439,11 +428,11 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
let encoder_cfg = get_encoder_config(&c, quality, last_recording);
|
||||
|
||||
let mut encoder;
|
||||
match Encoder::new(encoder_cfg) {
|
||||
let use_i444 = Encoder::use_i444(&encoder_cfg);
|
||||
match Encoder::new(encoder_cfg.clone(), use_i444) {
|
||||
Ok(x) => encoder = x,
|
||||
Err(err) => bail!("Failed to create encoder: {}", err),
|
||||
}
|
||||
c.set_use_yuv(encoder.use_yuv());
|
||||
VIDEO_QOS.lock().unwrap().store_bitrate(encoder.bitrate());
|
||||
|
||||
if sp.is_option_true(OPTION_REFRESH) {
|
||||
@@ -463,6 +452,8 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
let mut would_block_count = 0u32;
|
||||
let mut yuv = Vec::new();
|
||||
let mut mid_data = Vec::new();
|
||||
|
||||
while sp.ok() {
|
||||
#[cfg(windows)]
|
||||
@@ -493,6 +484,9 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
if last_portable_service_running != crate::portable_service::client::running() {
|
||||
bail!("SWITCH");
|
||||
}
|
||||
if Encoder::use_i444(&encoder_cfg) != use_i444 {
|
||||
bail!("SWITCH");
|
||||
}
|
||||
check_privacy_mode_changed(&sp, c.privacy_mode_id)?;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
@@ -512,40 +506,23 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
|
||||
frame_controller.reset();
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
let res = match c.frame(spf) {
|
||||
Ok(frame) => {
|
||||
let time = now - start;
|
||||
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
|
||||
match frame {
|
||||
scrap::Frame::RAW(data) => {
|
||||
if data.len() != 0 {
|
||||
let send_conn_ids = handle_one_frame(
|
||||
display_idx,
|
||||
&sp,
|
||||
data,
|
||||
ms,
|
||||
&mut encoder,
|
||||
recorder.clone(),
|
||||
)?;
|
||||
frame_controller.set_send(now, send_conn_ids);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
};
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
let res = match c.frame(spf) {
|
||||
Ok(frame) => {
|
||||
let time = now - start;
|
||||
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
|
||||
let send_conn_ids =
|
||||
handle_one_frame(display_idx, &sp, &frame, ms, &mut encoder, recorder.clone())?;
|
||||
frame_controller.set_send(now, send_conn_ids);
|
||||
if frame.data().len() != 0 {
|
||||
let send_conn_ids = handle_one_frame(
|
||||
display_idx,
|
||||
&sp,
|
||||
frame,
|
||||
&mut yuv,
|
||||
&mut mid_data,
|
||||
ms,
|
||||
&mut encoder,
|
||||
recorder.clone(),
|
||||
)?;
|
||||
frame_controller.set_send(now, send_conn_ids);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
try_gdi = 0;
|
||||
@@ -718,7 +695,9 @@ fn check_privacy_mode_changed(sp: &GenericService, privacy_mode_id: i32) -> Resu
|
||||
fn handle_one_frame(
|
||||
display: usize,
|
||||
sp: &GenericService,
|
||||
frame: &[u8],
|
||||
frame: Frame,
|
||||
yuv: &mut Vec<u8>,
|
||||
mid_data: &mut Vec<u8>,
|
||||
ms: i64,
|
||||
encoder: &mut Encoder,
|
||||
recorder: Arc<Mutex<Option<Recorder>>>,
|
||||
@@ -732,7 +711,8 @@ fn handle_one_frame(
|
||||
})?;
|
||||
|
||||
let mut send_conn_ids: HashSet<i32> = Default::default();
|
||||
if let Ok(mut vf) = encoder.encode_to_message(frame, ms) {
|
||||
convert_to_yuv(&frame, encoder.yuvfmt(), yuv, mid_data)?;
|
||||
if let Ok(mut vf) = encoder.encode_to_message(yuv, ms) {
|
||||
vf.display = display as _;
|
||||
let mut msg = Message::new();
|
||||
msg.set_video_frame(vf);
|
||||
|
||||
@@ -76,12 +76,6 @@ impl TraitCapturer for CapturerPtr {
|
||||
fn frame<'a>(&'a mut self, timeout: Duration) -> io::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 {
|
||||
@@ -192,7 +186,8 @@ pub(super) async fn check_init() -> ResultType<()> {
|
||||
maxy = max_height;
|
||||
|
||||
let capturer = Box::into_raw(Box::new(
|
||||
Capturer::new(display, true).with_context(|| "Failed to create capturer")?,
|
||||
Capturer::new(display)
|
||||
.with_context(|| "Failed to create capturer")?,
|
||||
));
|
||||
let capturer = CapturerPtr(capturer);
|
||||
let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo {
|
||||
|
||||
@@ -201,6 +201,7 @@ class Header: Reactor.Component {
|
||||
{keyboard_enabled ? <li #lock-after-session-end .toggle-option><span>{svg_checkmark}</span>{translate('Lock after session end')}</li> : ""}
|
||||
{keyboard_enabled && pi.platform == "Windows" ? <li #privacy-mode><span>{svg_checkmark}</span>{translate('Privacy mode')}</li> : ""}
|
||||
{keyboard_enabled && ((is_osx && pi.platform != "Mac OS") || (!is_osx && pi.platform == "Mac OS")) ? <li #allow_swap_key .toggle-option><span>{svg_checkmark}</span>{translate('Swap control-command key')}</li> : ""}
|
||||
{handler.version_cmp(pi.version, '1.2.4') >= 0 ? <li #i444><span>{svg_checkmark}</span>{translate('True color(4:4:4)')}</li> : ""}
|
||||
</menu>
|
||||
</popup>;
|
||||
}
|
||||
@@ -402,6 +403,8 @@ class Header: Reactor.Component {
|
||||
togglePrivacyMode(me.id);
|
||||
} else if (me.id == "show-quality-monitor") {
|
||||
toggleQualityMonitor(me.id);
|
||||
} else if (me.id == "i444") {
|
||||
toggleI444(me.id);
|
||||
} else if (me.attributes.hasClass("toggle-option")) {
|
||||
handler.toggle_option(me.id);
|
||||
toggleMenuState();
|
||||
@@ -476,7 +479,7 @@ function toggleMenuState() {
|
||||
for (var el in $$(menu#keyboard-options>li)) {
|
||||
el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0);
|
||||
}
|
||||
for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end", "allow_swap_key"]) {
|
||||
for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end", "allow_swap_key", "i444"]) {
|
||||
var el = self.select('#' + id);
|
||||
if (el) {
|
||||
var value = handler.get_toggle_option(id);
|
||||
@@ -563,6 +566,12 @@ function toggleQualityMonitor(name) {
|
||||
toggleMenuState();
|
||||
}
|
||||
|
||||
function toggleI444(name) {
|
||||
handler.toggle_option(name);
|
||||
handler.change_prefer_codec();
|
||||
toggleMenuState();
|
||||
}
|
||||
|
||||
handler.updateBlockInputState = function(input_blocked) {
|
||||
if (!input_blocked) {
|
||||
handler.toggle_option("block-input");
|
||||
|
||||
@@ -131,7 +131,8 @@ impl InvokeUiSession for SciterHandler {
|
||||
status.target_bitrate.map_or(Value::null(), |it| it.into()),
|
||||
status
|
||||
.codec_format
|
||||
.map_or(Value::null(), |it| it.to_string().into())
|
||||
.map_or(Value::null(), |it| it.to_string().into()),
|
||||
status.chroma.map_or(Value::null(), |it| it.into())
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -510,17 +510,21 @@ class QualityMonitor: Reactor.Component
|
||||
<div>
|
||||
Codec: {qualityMonitorData[4]}
|
||||
</div>
|
||||
<div>
|
||||
Chroma: {qualityMonitorData[5]}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
$(#quality-monitor).content(<QualityMonitor />);
|
||||
handler.updateQualityStatus = function(speed, fps, delay, bitrate, codec_format) {
|
||||
handler.updateQualityStatus = function(speed, fps, delay, bitrate, codec_format, chroma) {
|
||||
speed ? qualityMonitorData[0] = speed:null;
|
||||
fps ? qualityMonitorData[1] = fps:null;
|
||||
delay ? qualityMonitorData[2] = delay:null;
|
||||
bitrate ? qualityMonitorData[3] = bitrate:null;
|
||||
codec_format ? qualityMonitorData[4] = codec_format:null;
|
||||
chroma ? qualityMonitorData[5] = chroma:null;
|
||||
qualityMonitor.update();
|
||||
}
|
||||
|
||||
|
||||
@@ -1527,16 +1527,17 @@ pub async fn io_loop<T: InvokeUiSession>(handler: Session<T>, round: u32) {
|
||||
let frame_count_map: Arc<RwLock<HashMap<usize, usize>>> = Default::default();
|
||||
let frame_count_map_cl = frame_count_map.clone();
|
||||
let ui_handler = handler.ui_handler.clone();
|
||||
let (video_sender, audio_sender, video_queue_map, decode_fps_map) = start_video_audio_threads(
|
||||
handler.clone(),
|
||||
move |display: usize, data: &mut scrap::ImageRgb| {
|
||||
let mut write_lock = frame_count_map_cl.write().unwrap();
|
||||
let count = write_lock.get(&display).unwrap_or(&0) + 1;
|
||||
write_lock.insert(display, count);
|
||||
drop(write_lock);
|
||||
ui_handler.on_rgba(display, data);
|
||||
},
|
||||
);
|
||||
let (video_sender, audio_sender, video_queue_map, decode_fps_map, chroma) =
|
||||
start_video_audio_threads(
|
||||
handler.clone(),
|
||||
move |display: usize, data: &mut scrap::ImageRgb| {
|
||||
let mut write_lock = frame_count_map_cl.write().unwrap();
|
||||
let count = write_lock.get(&display).unwrap_or(&0) + 1;
|
||||
write_lock.insert(display, count);
|
||||
drop(write_lock);
|
||||
ui_handler.on_rgba(display, data);
|
||||
},
|
||||
);
|
||||
|
||||
let mut remote = Remote::new(
|
||||
handler,
|
||||
@@ -1547,6 +1548,7 @@ pub async fn io_loop<T: InvokeUiSession>(handler: Session<T>, round: u32) {
|
||||
sender,
|
||||
frame_count_map,
|
||||
decode_fps_map,
|
||||
chroma,
|
||||
);
|
||||
remote.io_loop(&key, &token, round).await;
|
||||
remote.sync_jobs_status_to_local().await;
|
||||
|
||||
Reference in New Issue
Block a user