fix multi display fps control (#8455)

* Calculate fps without distinguish displays, use one fps control
  because the controlled side control fps of all displays with one FPS
  variable.
* Because all displays decode frame in one thread, when there are N
  displays, the video frames received in one second is `fps * N`, so the
  calculated decode fps should be divided by N. Because the actual
  display count is not obvious in rust, when no data frame is received for 5 seconds, the display is considered inactive, and only the active display is used as the dividend.

Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
21pages
2024-06-24 19:41:15 +08:00
committed by GitHub
parent 65edd55516
commit 1765c7bbf4
3 changed files with 133 additions and 98 deletions

View File

@@ -43,8 +43,7 @@ use hbb_common::{
rand,
rendezvous_proto::*,
socket_client,
sodiumoxide::base64,
sodiumoxide::crypto::sign,
sodiumoxide::{base64, crypto::sign},
tcp::FramedStream,
timeout,
tokio::time::Duration,
@@ -2093,8 +2092,6 @@ pub type MediaSender = mpsc::Sender<MediaData>;
struct VideoHandlerController {
handler: VideoHandler,
count: u128,
duration: std::time::Duration,
skip_beginning: u32,
}
@@ -2111,7 +2108,7 @@ pub fn start_video_audio_threads<F, T>(
MediaSender,
MediaSender,
Arc<RwLock<HashMap<usize, ArrayQueue<VideoFrame>>>>,
Arc<RwLock<HashMap<usize, usize>>>,
Arc<RwLock<Option<usize>>>,
Arc<RwLock<Option<Chroma>>>,
)
where
@@ -2123,8 +2120,8 @@ where
let video_queue_map_cloned = video_queue_map.clone();
let mut video_callback = video_callback;
let fps_map = Arc::new(RwLock::new(HashMap::new()));
let decode_fps_map = fps_map.clone();
let fps = Arc::new(RwLock::new(None));
let decode_fps_map = fps.clone();
let chroma = Arc::new(RwLock::new(None));
let chroma_cloned = chroma.clone();
let mut last_chroma = None;
@@ -2134,9 +2131,8 @@ where
sync_cpu_usage();
get_hwcodec_config();
let mut handler_controller_map = HashMap::new();
// let mut count = Vec::new();
// let mut duration = std::time::Duration::ZERO;
// let mut skip_beginning = Vec::new();
let mut count = 0;
let mut duration = std::time::Duration::ZERO;
loop {
if let Ok(data) = video_receiver.recv() {
match data {
@@ -2169,8 +2165,6 @@ where
display,
VideoHandlerController {
handler: VideoHandler::new(format, display),
count: 0,
duration: std::time::Duration::ZERO,
skip_beginning: 0,
},
);
@@ -2178,6 +2172,8 @@ where
if let Some(handler_controller) = handler_controller_map.get_mut(&display) {
let mut pixelbuffer = true;
let mut tmp_chroma = None;
let format_changed =
handler_controller.handler.decoder.format() != format;
match handler_controller.handler.handle_frame(
vf,
&mut pixelbuffer,
@@ -2198,27 +2194,14 @@ where
}
// fps calculation
// The first frame will be very slow
if handler_controller.skip_beginning < 5 {
handler_controller.skip_beginning += 1;
continue;
}
handler_controller.duration += start.elapsed();
handler_controller.count += 1;
if handler_controller.count % 10 == 0 {
fps_map.write().unwrap().insert(
display,
(handler_controller.count * 1000
/ handler_controller.duration.as_millis())
as usize,
);
}
// Clear to get real-time fps
if handler_controller.count > 150 {
handler_controller.count = 0;
handler_controller.duration = Duration::ZERO;
}
fps_calculate(
handler_controller,
&fps,
format_changed,
start.elapsed(),
&mut count,
&mut duration,
);
}
Err(e) => {
// This is a simple workaround.
@@ -2334,6 +2317,38 @@ pub fn start_audio_thread() -> MediaSender {
audio_sender
}
#[inline]
fn fps_calculate(
handler_controller: &mut VideoHandlerController,
fps: &Arc<RwLock<Option<usize>>>,
format_changed: bool,
elapsed: std::time::Duration,
count: &mut usize,
duration: &mut std::time::Duration,
) {
if format_changed {
*count = 0;
*duration = std::time::Duration::ZERO;
handler_controller.skip_beginning = 0;
}
// // The first frame will be very slow
if handler_controller.skip_beginning < 3 {
handler_controller.skip_beginning += 1;
return;
}
*duration += elapsed;
*count += 1;
let ms = duration.as_millis();
if *count % 10 == 0 && ms > 0 {
*fps.write().unwrap() = Some((*count as usize) * 1000 / (ms as usize));
}
// Clear to get real-time fps
if *count >= 30 {
*count = 0;
*duration = Duration::ZERO;
}
}
fn get_hwcodec_config() {
// for sciter and unilink
#[cfg(feature = "hwcodec")]