Merge pull request #6229 from 21pages/444

yuv 444
This commit is contained in:
RustDesk
2023-10-31 10:08:59 +08:00
committed by GitHub
80 changed files with 1182 additions and 1186 deletions

View File

@@ -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,
);
}

View File

@@ -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]

View File

@@ -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()
});
}

View File

@@ -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())),
],
);
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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);
});
}

View File

@@ -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,
}

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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");

View File

@@ -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())
),
);
}

View File

@@ -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();
}

View File

@@ -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;