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:
parent
105a758914
commit
2626dcbc5f
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -3038,8 +3038,8 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hwcodec"
|
name = "hwcodec"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "git+https://github.com/21pages/hwcodec#17870c015a3f371339a91c5305d1e920bd8284e3"
|
source = "git+https://github.com/21pages/hwcodec#b8ed1e869b3456af6a5f77b7617f861d9a99dcdd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen 0.59.2",
|
"bindgen 0.59.2",
|
||||||
"cc",
|
"cc",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gpu_texture_renderer/flutter_gpu_texture_renderer.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/consts.dart';
|
||||||
import 'package:flutter_hbb/models/model.dart';
|
import 'package:flutter_hbb/models/model.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@ -152,40 +153,36 @@ class TextureModel {
|
|||||||
TextureModel(this.parent);
|
TextureModel(this.parent);
|
||||||
|
|
||||||
setTextureType({required int display, required bool gpuTexture}) {
|
setTextureType({required int display, required bool gpuTexture}) {
|
||||||
debugPrint("setTextureType: display:$display, isGpuTexture:$gpuTexture");
|
debugPrint("setTextureType: display=$display, isGpuTexture=$gpuTexture");
|
||||||
var texture = _control[display];
|
ensureControl(display);
|
||||||
if (texture == null) {
|
_control[display]?.setTextureType(gpuTexture: gpuTexture);
|
||||||
texture = _Control();
|
// For versions that do not support multiple displays, the display parameter is always 0, need set type of current display
|
||||||
_control[display] = texture;
|
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}) {
|
setRgbaTextureId({required int display, required int id}) {
|
||||||
var ctl = _control[display];
|
ensureControl(display);
|
||||||
if (ctl == null) {
|
_control[display]?.setRgbaTextureId(id);
|
||||||
ctl = _Control();
|
|
||||||
_control[display] = ctl;
|
|
||||||
}
|
|
||||||
ctl.setRgbaTextureId(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setGpuTextureId({required int display, required int id}) {
|
setGpuTextureId({required int display, required int id}) {
|
||||||
var ctl = _control[display];
|
ensureControl(display);
|
||||||
if (ctl == null) {
|
_control[display]?.setGpuTextureId(id);
|
||||||
ctl = _Control();
|
|
||||||
_control[display] = ctl;
|
|
||||||
}
|
|
||||||
ctl.setGpuTextureId(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RxInt getTextureId(int display) {
|
RxInt getTextureId(int display) {
|
||||||
var ctl = _control[display];
|
ensureControl(display);
|
||||||
if (ctl == null) {
|
return _control[display]!.textureID;
|
||||||
ctl = _Control();
|
|
||||||
_control[display] = ctl;
|
|
||||||
}
|
|
||||||
return ctl.textureID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCurrentDisplay(int curDisplay) {
|
updateCurrentDisplay(int curDisplay) {
|
||||||
@ -241,4 +238,12 @@ class TextureModel {
|
|||||||
await texture.destroy(ffi);
|
await texture.destroy(ffi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureControl(int display) {
|
||||||
|
var ctl = _control[display];
|
||||||
|
if (ctl == null) {
|
||||||
|
ctl = _Control();
|
||||||
|
_control[display] = ctl;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,6 @@ impl Encoder {
|
|||||||
let h265_useable =
|
let h265_useable =
|
||||||
_all_support_h265_decoding && (h265vram_encoding || h265hw_encoding.is_some());
|
_all_support_h265_decoding && (h265vram_encoding || h265hw_encoding.is_some());
|
||||||
let mut name = ENCODE_CODEC_NAME.lock().unwrap();
|
let mut name = ENCODE_CODEC_NAME.lock().unwrap();
|
||||||
let mut preference = PreferCodec::Auto;
|
|
||||||
let preferences: Vec<_> = decodings
|
let preferences: Vec<_> = decodings
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, s)| {
|
.filter(|(_, s)| {
|
||||||
@ -233,9 +232,20 @@ impl Encoder {
|
|||||||
})
|
})
|
||||||
.map(|(_, s)| s.prefer)
|
.map(|(_, s)| s.prefer)
|
||||||
.collect();
|
.collect();
|
||||||
if preferences.len() > 0 && preferences.iter().all(|&p| p == preferences[0]) {
|
// find the most frequent preference
|
||||||
preference = preferences[0].enum_value_or(PreferCodec::Auto);
|
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)]
|
#[allow(unused_mut)]
|
||||||
let mut auto_codec = CodecName::VP9;
|
let mut auto_codec = CodecName::VP9;
|
||||||
|
@ -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/buildapc/comments/d2m4ny/two_graphics_cards_two_monitors/
|
||||||
// https://www.reddit.com/r/techsupport/comments/t2v9u6/dual_monitor_setup_with_dual_gpu/
|
// https://www.reddit.com/r/techsupport/comments/t2v9u6/dual_monitor_setup_with_dual_gpu/
|
||||||
// https://cybersided.com/two-monitors-two-gpus/
|
// https://cybersided.com/two-monitors-two-gpus/
|
||||||
@ -331,8 +329,8 @@ impl VRamDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(format: CodecFormat, luid: Option<i64>) -> ResultType<Self> {
|
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"))?;
|
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) {
|
match Decoder::new(ctx) {
|
||||||
Ok(decoder) => Ok(Self { decoder }),
|
Ok(decoder) => Ok(Self { decoder }),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@ -376,7 +374,7 @@ pub(crate) fn check_available_vram() -> String {
|
|||||||
gop: MAX_GOP as _,
|
gop: MAX_GOP as _,
|
||||||
};
|
};
|
||||||
let encoders = encode::available(d);
|
let encoders = encode::available(d);
|
||||||
let decoders = decode::available(OUTPUT_SHARED_HANDLE);
|
let decoders = decode::available();
|
||||||
let available = Available {
|
let available = Available {
|
||||||
e: encoders,
|
e: encoders,
|
||||||
d: decoders,
|
d: decoders,
|
||||||
|
@ -1580,7 +1580,10 @@ impl LoginConfigHandler {
|
|||||||
///
|
///
|
||||||
/// * `ignore_default` - If `true`, ignore the default value of the option.
|
/// * `ignore_default` - If `true`, ignore the default value of the option.
|
||||||
fn get_option_message(&self, ignore_default: bool) -> Option<OptionMessage> {
|
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;
|
return None;
|
||||||
}
|
}
|
||||||
let mut msg = OptionMessage::new();
|
let mut msg = OptionMessage::new();
|
||||||
@ -2110,7 +2113,7 @@ where
|
|||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
sync_cpu_usage();
|
sync_cpu_usage();
|
||||||
let mut handler_controller_map = Vec::new();
|
let mut handler_controller_map = HashMap::new();
|
||||||
// let mut count = Vec::new();
|
// let mut count = Vec::new();
|
||||||
// let mut duration = std::time::Duration::ZERO;
|
// let mut duration = std::time::Duration::ZERO;
|
||||||
// let mut skip_beginning = Vec::new();
|
// let mut skip_beginning = Vec::new();
|
||||||
@ -2141,17 +2144,18 @@ where
|
|||||||
let display = vf.display as usize;
|
let display = vf.display as usize;
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
let format = CodecFormat::from(&vf);
|
let format = CodecFormat::from(&vf);
|
||||||
if handler_controller_map.len() <= display {
|
if !handler_controller_map.contains_key(&display) {
|
||||||
for _i in handler_controller_map.len()..=display {
|
handler_controller_map.insert(
|
||||||
handler_controller_map.push(VideoHandlerController {
|
display,
|
||||||
handler: VideoHandler::new(format, _i),
|
VideoHandlerController {
|
||||||
|
handler: VideoHandler::new(format, display),
|
||||||
count: 0,
|
count: 0,
|
||||||
duration: std::time::Duration::ZERO,
|
duration: std::time::Duration::ZERO,
|
||||||
skip_beginning: 0,
|
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 pixelbuffer = true;
|
||||||
let mut tmp_chroma = None;
|
let mut tmp_chroma = None;
|
||||||
match handler_controller.handler.handle_frame(
|
match handler_controller.handler.handle_frame(
|
||||||
@ -2219,7 +2223,7 @@ where
|
|||||||
let mut should_update_supported = false;
|
let mut should_update_supported = false;
|
||||||
handler_controller_map
|
handler_controller_map
|
||||||
.iter()
|
.iter()
|
||||||
.map(|h| {
|
.map(|(_, h)| {
|
||||||
if !h.handler.decoder.valid() || h.handler.fail_counter >= MAX_DECODE_FAIL_COUNTER {
|
if !h.handler.decoder.valid() || h.handler.fail_counter >= MAX_DECODE_FAIL_COUNTER {
|
||||||
let mut lc = session.lc.write().unwrap();
|
let mut lc = session.lc.write().unwrap();
|
||||||
let format = h.handler.decoder.format();
|
let format = h.handler.decoder.format();
|
||||||
@ -2238,21 +2242,20 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
MediaData::Reset(display) => {
|
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);
|
handler_controler.handler.reset(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MediaData::RecordScreen(start, display, w, h, id) => {
|
MediaData::RecordScreen(start, display, w, h, id) => {
|
||||||
log::info!("record screen command: start: {start}, display: {display}");
|
log::info!("record screen command: start: {start}, display: {display}");
|
||||||
if handler_controller_map.len() == 1 {
|
// Compatible with the sciter version(single ui session).
|
||||||
// Compatible with the sciter version(single ui session).
|
// For the sciter version, there're no multi-ui-sessions for one connection.
|
||||||
// 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.
|
||||||
// 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_controller_map[0]
|
handler_controler.handler.record_screen(start, w, h, id);
|
||||||
.handler
|
} else if handler_controller_map.len() == 1 {
|
||||||
.record_screen(start, w, h, id);
|
if let Some(handler_controler) =
|
||||||
} else {
|
handler_controller_map.values_mut().next()
|
||||||
if let Some(handler_controler) = handler_controller_map.get_mut(display)
|
|
||||||
{
|
{
|
||||||
handler_controler.handler.record_screen(start, w, h, id);
|
handler_controler.handler.record_screen(start, w, h, id);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user