fix black screen issue when controlling the second screen on versions that lack multiple display support while using vram decoding (#7836)

* avoid create unnecessary video decoder

Signed-off-by: 21pages <pages21@163.com>

* controlled side uses the most frequent selected codec

Signed-off-by: 21pages <pages21@163.com>

* fix black screen when control old version's second screen

For versions that do not support multiple displays, the display parameter is always 0, need set type of current display

Signed-off-by: 21pages <pages21@163.com>

---------

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2024-04-26 19:42:47 +08:00 committed by GitHub
parent 105a758914
commit 2626dcbc5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 69 additions and 53 deletions

4
Cargo.lock generated
View File

@ -3038,8 +3038,8 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hwcodec"
version = "0.4.1"
source = "git+https://github.com/21pages/hwcodec#17870c015a3f371339a91c5305d1e920bd8284e3"
version = "0.4.2"
source = "git+https://github.com/21pages/hwcodec#b8ed1e869b3456af6a5f77b7617f861d9a99dcdd"
dependencies = [
"bindgen 0.59.2",
"cc",

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_gpu_texture_renderer/flutter_gpu_texture_renderer.dart';
import 'package:flutter_hbb/common/shared_state.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/models/model.dart';
import 'package:get/get.dart';
@ -152,40 +153,36 @@ class TextureModel {
TextureModel(this.parent);
setTextureType({required int display, required bool gpuTexture}) {
debugPrint("setTextureType: display:$display, isGpuTexture:$gpuTexture");
var texture = _control[display];
if (texture == null) {
texture = _Control();
_control[display] = texture;
debugPrint("setTextureType: display=$display, isGpuTexture=$gpuTexture");
ensureControl(display);
_control[display]?.setTextureType(gpuTexture: gpuTexture);
// For versions that do not support multiple displays, the display parameter is always 0, need set type of current display
final ffi = parent.target;
if (ffi == null) return;
if (!ffi.ffiModel.pi.isSupportMultiDisplay) {
final currentDisplay = CurrentDisplayState.find(ffi.id).value;
if (currentDisplay != display) {
debugPrint(
"setTextureType: currentDisplay=$currentDisplay, isGpuTexture=$gpuTexture");
ensureControl(currentDisplay);
_control[currentDisplay]?.setTextureType(gpuTexture: gpuTexture);
}
}
texture.setTextureType(gpuTexture: gpuTexture);
}
setRgbaTextureId({required int display, required int id}) {
var ctl = _control[display];
if (ctl == null) {
ctl = _Control();
_control[display] = ctl;
}
ctl.setRgbaTextureId(id);
ensureControl(display);
_control[display]?.setRgbaTextureId(id);
}
setGpuTextureId({required int display, required int id}) {
var ctl = _control[display];
if (ctl == null) {
ctl = _Control();
_control[display] = ctl;
}
ctl.setGpuTextureId(id);
ensureControl(display);
_control[display]?.setGpuTextureId(id);
}
RxInt getTextureId(int display) {
var ctl = _control[display];
if (ctl == null) {
ctl = _Control();
_control[display] = ctl;
}
return ctl.textureID;
ensureControl(display);
return _control[display]!.textureID;
}
updateCurrentDisplay(int curDisplay) {
@ -241,4 +238,12 @@ class TextureModel {
await texture.destroy(ffi);
}
}
ensureControl(int display) {
var ctl = _control[display];
if (ctl == null) {
ctl = _Control();
_control[display] = ctl;
}
}
}

View File

@ -221,7 +221,6 @@ impl Encoder {
let h265_useable =
_all_support_h265_decoding && (h265vram_encoding || h265hw_encoding.is_some());
let mut name = ENCODE_CODEC_NAME.lock().unwrap();
let mut preference = PreferCodec::Auto;
let preferences: Vec<_> = decodings
.iter()
.filter(|(_, s)| {
@ -233,9 +232,20 @@ impl Encoder {
})
.map(|(_, s)| s.prefer)
.collect();
if preferences.len() > 0 && preferences.iter().all(|&p| p == preferences[0]) {
preference = preferences[0].enum_value_or(PreferCodec::Auto);
// find the most frequent preference
let mut counts = Vec::new();
for pref in &preferences {
match counts.iter_mut().find(|(p, _)| p == pref) {
Some((_, count)) => *count += 1,
None => counts.push((pref.clone(), 1)),
}
}
let max_count = counts.iter().map(|(_, count)| *count).max().unwrap_or(0);
let (most_frequent, _) = counts
.into_iter()
.find(|(_, count)| *count == max_count)
.unwrap_or((PreferCodec::Auto.into(), 0));
let preference = most_frequent.enum_value_or(PreferCodec::Auto);
#[allow(unused_mut)]
let mut auto_codec = CodecName::VP9;

View File

@ -24,8 +24,6 @@ use hwcodec::{
},
};
const OUTPUT_SHARED_HANDLE: bool = false;
// https://www.reddit.com/r/buildapc/comments/d2m4ny/two_graphics_cards_two_monitors/
// https://www.reddit.com/r/techsupport/comments/t2v9u6/dual_monitor_setup_with_dual_gpu/
// https://cybersided.com/two-monitors-two-gpus/
@ -331,8 +329,8 @@ impl VRamDecoder {
}
pub fn new(format: CodecFormat, luid: Option<i64>) -> ResultType<Self> {
log::info!("try create {format:?} vram decoder, luid: {luid:?}");
let ctx = Self::try_get(format, luid).ok_or(anyhow!("Failed to get decode context"))?;
log::info!("try create vram decoder: {ctx:?}");
match Decoder::new(ctx) {
Ok(decoder) => Ok(Self { decoder }),
Err(_) => {
@ -376,7 +374,7 @@ pub(crate) fn check_available_vram() -> String {
gop: MAX_GOP as _,
};
let encoders = encode::available(d);
let decoders = decode::available(OUTPUT_SHARED_HANDLE);
let decoders = decode::available();
let available = Available {
e: encoders,
d: decoders,

View File

@ -1580,7 +1580,10 @@ impl LoginConfigHandler {
///
/// * `ignore_default` - If `true`, ignore the default value of the option.
fn get_option_message(&self, ignore_default: bool) -> Option<OptionMessage> {
if self.conn_type.eq(&ConnType::PORT_FORWARD) || self.conn_type.eq(&ConnType::RDP) || self.conn_type.eq(&ConnType::FILE_TRANSFER) {
if self.conn_type.eq(&ConnType::PORT_FORWARD)
|| self.conn_type.eq(&ConnType::RDP)
|| self.conn_type.eq(&ConnType::FILE_TRANSFER)
{
return None;
}
let mut msg = OptionMessage::new();
@ -2110,7 +2113,7 @@ where
std::thread::spawn(move || {
#[cfg(windows)]
sync_cpu_usage();
let mut handler_controller_map = Vec::new();
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();
@ -2141,17 +2144,18 @@ where
let display = vf.display as usize;
let start = std::time::Instant::now();
let format = CodecFormat::from(&vf);
if handler_controller_map.len() <= display {
for _i in handler_controller_map.len()..=display {
handler_controller_map.push(VideoHandlerController {
handler: VideoHandler::new(format, _i),
if !handler_controller_map.contains_key(&display) {
handler_controller_map.insert(
display,
VideoHandlerController {
handler: VideoHandler::new(format, display),
count: 0,
duration: std::time::Duration::ZERO,
skip_beginning: 0,
});
}
},
);
}
if let Some(handler_controller) = handler_controller_map.get_mut(display) {
if let Some(handler_controller) = handler_controller_map.get_mut(&display) {
let mut pixelbuffer = true;
let mut tmp_chroma = None;
match handler_controller.handler.handle_frame(
@ -2219,7 +2223,7 @@ where
let mut should_update_supported = false;
handler_controller_map
.iter()
.map(|h| {
.map(|(_, h)| {
if !h.handler.decoder.valid() || h.handler.fail_counter >= MAX_DECODE_FAIL_COUNTER {
let mut lc = session.lc.write().unwrap();
let format = h.handler.decoder.format();
@ -2238,21 +2242,20 @@ where
}
}
MediaData::Reset(display) => {
if let Some(handler_controler) = handler_controller_map.get_mut(display) {
if let Some(handler_controler) = handler_controller_map.get_mut(&display) {
handler_controler.handler.reset(None);
}
}
MediaData::RecordScreen(start, display, w, h, id) => {
log::info!("record screen command: start: {start}, display: {display}");
if handler_controller_map.len() == 1 {
// Compatible with the sciter version(single ui session).
// For the sciter version, there're no multi-ui-sessions for one connection.
// The display is always 0, video_handler_controllers.len() is always 1. So we use the first video handler.
handler_controller_map[0]
.handler
.record_screen(start, w, h, id);
} else {
if let Some(handler_controler) = handler_controller_map.get_mut(display)
// Compatible with the sciter version(single ui session).
// For the sciter version, there're no multi-ui-sessions for one connection.
// The display is always 0, video_handler_controllers.len() is always 1. So we use the first video handler.
if let Some(handler_controler) = handler_controller_map.get_mut(&display) {
handler_controler.handler.record_screen(start, w, h, id);
} else if handler_controller_map.len() == 1 {
if let Some(handler_controler) =
handler_controller_map.values_mut().next()
{
handler_controler.handler.record_screen(start, w, h, id);
}