linux_wayland_support: refactor

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou
2022-07-20 09:50:08 -07:00
parent 613b1a8582
commit 634cb5ef1a
6 changed files with 879 additions and 867 deletions

View File

@@ -31,6 +31,7 @@ use scrap::{
use std::{
collections::HashSet,
io::{ErrorKind::WouldBlock, Result},
ops::{Deref, DerefMut},
time::{self, Duration, Instant},
};
#[cfg(windows)]
@@ -127,7 +128,7 @@ impl VideoFrameController {
}
}
trait TraitCapturer {
pub(super) trait TraitCapturer {
fn frame<'a>(&'a mut self, timeout: Duration) -> Result<Frame<'a>>;
fn set_use_yuv(&mut self, use_yuv: bool);
@@ -340,22 +341,36 @@ fn check_uac_switch(privacy_mode_id: i32, captuerer_privacy_mode_id: i32) -> Res
Ok(())
}
struct CapturerInfo {
origin: (i32, i32),
width: usize,
height: usize,
ndisplay: usize,
current: usize,
privacy_mode_id: i32,
_captuerer_privacy_mode_id: i32,
capturer: Box<dyn TraitCapturer>,
pub(super) struct CapturerInfo {
pub origin: (i32, i32),
pub width: usize,
pub height: usize,
pub ndisplay: usize,
pub current: usize,
pub privacy_mode_id: i32,
pub _captuerer_privacy_mode_id: i32,
pub capturer: Box<dyn TraitCapturer>,
}
impl Deref for CapturerInfo {
type Target = Box<dyn TraitCapturer>;
fn deref(&self) -> &Self::Target {
&self.capturer
}
}
impl DerefMut for CapturerInfo {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.capturer
}
}
fn get_capturer(use_yuv: bool) -> ResultType<CapturerInfo> {
#[cfg(target_os = "linux")]
{
if scrap::is_wayland() {
return wayland_support::get_capturer();
return super::wayland::get_capturer();
}
}
@@ -441,7 +456,7 @@ fn run(sp: GenericService) -> ResultType<()> {
Ok(x) => encoder = x,
Err(err) => bail!("Failed to create encoder: {}", err),
}
c.capturer.set_use_yuv(encoder.use_yuv());
c.set_use_yuv(encoder.use_yuv());
if *SWITCH.lock().unwrap() {
log::debug!("Broadcasting display switch");
@@ -467,7 +482,7 @@ fn run(sp: GenericService) -> ResultType<()> {
#[cfg(windows)]
let mut try_gdi = 1;
#[cfg(windows)]
log::info!("gdi: {}", c.capturer.is_gdi());
log::info!("gdi: {}", c.is_gdi());
while sp.ok() {
#[cfg(windows)]
@@ -515,7 +530,7 @@ fn run(sp: GenericService) -> ResultType<()> {
frame_controller.reset();
#[cfg(any(target_os = "android", target_os = "ios"))]
let res = match (*c.capturer).frame(spf) {
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;
@@ -538,7 +553,7 @@ fn run(sp: GenericService) -> ResultType<()> {
};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let res = match (*c.capturer).frame(spf) {
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;
@@ -557,9 +572,9 @@ fn run(sp: GenericService) -> ResultType<()> {
Err(ref e) if e.kind() == WouldBlock =>
{
#[cfg(windows)]
if try_gdi > 0 && !c.capturer.is_gdi() {
if try_gdi > 0 && !c.is_gdi() {
if try_gdi > 3 {
c.capturer.set_gdi();
c.set_gdi();
try_gdi = 0;
log::info!("No image, fall back to gdi");
}
@@ -574,8 +589,8 @@ fn run(sp: GenericService) -> ResultType<()> {
}
#[cfg(windows)]
if !c.capturer.is_gdi() {
c.capturer.set_gdi();
if !c.is_gdi() {
c.set_gdi();
log::info!("dxgi error, fall back to gdi: {:?}", err);
continue;
}
@@ -688,7 +703,7 @@ fn get_display_num() -> usize {
#[cfg(target_os = "linux")]
{
if scrap::is_wayland() {
return if let Ok(n) = wayland_support::get_display_num() {
return if let Ok(n) = super::wayland::get_display_num() {
n
} else {
0
@@ -703,7 +718,7 @@ fn get_display_num() -> usize {
}
}
fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) {
pub(super) fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) {
let mut displays = Vec::new();
let mut primary = 0;
for (i, d) in all.iter().enumerate() {
@@ -731,7 +746,7 @@ pub async fn get_displays() -> ResultType<(usize, Vec<DisplayInfo>)> {
#[cfg(target_os = "linux")]
{
if scrap::is_wayland() {
return wayland_support::get_displays().await;
return super::wayland::get_displays().await;
}
}
// switch to primary display if long time (30 seconds) no users
@@ -760,7 +775,7 @@ fn get_primary() -> usize {
#[cfg(target_os = "linux")]
{
if scrap::is_wayland() {
return match wayland_support::get_primary() {
return match super::wayland::get_primary() {
Ok(n) => n,
Err(_) => 0,
};
@@ -816,7 +831,7 @@ fn try_get_displays() -> ResultType<Vec<Display>> {
Ok(displays)
}
fn get_current_display_2(mut all: Vec<Display>) -> ResultType<(usize, usize, Display)> {
pub(super) fn get_current_display_2(mut all: Vec<Display>) -> ResultType<(usize, usize, Display)> {
let mut current = *CURRENT_DISPLAY.lock().unwrap() as usize;
if all.len() == 0 {
bail!("No displays");
@@ -838,185 +853,3 @@ fn get_current_display_2(mut all: Vec<Display>) -> ResultType<(usize, usize, Dis
fn get_current_display() -> ResultType<(usize, usize, Display)> {
get_current_display_2(try_get_displays()?)
}
#[cfg(target_os = "linux")]
pub mod wayland_support {
use super::*;
use hbb_common::allow_err;
lazy_static::lazy_static! {
static ref CAP_DISPLAY_INFO: RwLock<u64> = RwLock::new(0);
}
struct CapDisplayInfo {
rects: Vec<((i32, i32), usize, usize)>,
displays: Vec<DisplayInfo>,
num: usize,
primary: usize,
current: usize,
capturer: *mut Capturer,
}
impl TraitCapturer for *mut Capturer {
fn frame<'a>(&'a mut self, timeout: Duration) -> Result<Frame<'a>> {
unsafe { (**self).frame(timeout) }
}
fn set_use_yuv(&mut self, use_yuv: bool) {
unsafe {
(**self).set_use_yuv(use_yuv);
}
}
}
async fn check_init() -> ResultType<()> {
if scrap::is_wayland() {
let mut minx = 0;
let mut maxx = 0;
let mut miny = 0;
let mut maxy = 0;
if *CAP_DISPLAY_INFO.read().unwrap() == 0 {
let mut lock = CAP_DISPLAY_INFO.write().unwrap();
if *lock == 0 {
let all = Display::all()?;
let num = all.len();
let (primary, displays) = get_displays_2(&all);
let mut rects: Vec<((i32, i32), usize, usize)> = Vec::new();
for d in &all {
rects.push((d.origin(), d.width(), d.height()));
}
let (ndisplay, current, display) = get_current_display_2(all)?;
let (origin, width, height) =
(display.origin(), display.width(), display.height());
log::debug!(
"#displays={}, current={}, origin: {:?}, width={}, height={}, cpus={}/{}",
ndisplay,
current,
&origin,
width,
height,
num_cpus::get_physical(),
num_cpus::get(),
);
minx = origin.0;
maxx = origin.0 + width as i32;
miny = origin.1;
maxy = origin.1 + height as i32;
let capturer = Box::into_raw(Box::new(
Capturer::new(display, true)
.with_context(|| "Failed to create capturer")?,
));
let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo {
rects,
displays,
num,
primary,
current,
capturer,
}));
*lock = cap_display_info as _;
}
}
if minx != maxx && miny != maxy {
log::info!(
"send uinput resolution: ({}, {}), ({}, {})",
minx,
maxx,
miny,
maxy
);
allow_err!(input_service::set_uinput_resolution(minx, maxx, miny, maxy).await);
allow_err!(input_service::set_uinput().await);
}
}
Ok(())
}
pub fn clear() {
if !scrap::is_wayland() {
return;
}
let mut lock = CAP_DISPLAY_INFO.write().unwrap();
if *lock != 0 {
unsafe {
let cap_display_info = Box::from_raw(*lock as *mut CapDisplayInfo);
let _ = Box::from_raw(cap_display_info.capturer);
}
*lock = 0;
}
}
pub(super) async fn get_displays() -> ResultType<(usize, Vec<DisplayInfo>)> {
check_init().await?;
let addr = *CAP_DISPLAY_INFO.read().unwrap();
if addr != 0 {
let cap_display_info: *const CapDisplayInfo = addr as _;
unsafe {
let cap_display_info = &*cap_display_info;
let primary = cap_display_info.primary;
let displays = cap_display_info.displays.clone();
Ok((primary, displays))
}
} else {
bail!("Failed to get capturer display info");
}
}
pub(super) fn get_primary() -> ResultType<usize> {
let addr = *CAP_DISPLAY_INFO.read().unwrap();
if addr != 0 {
let cap_display_info: *const CapDisplayInfo = addr as _;
unsafe {
let cap_display_info = &*cap_display_info;
Ok(cap_display_info.primary)
}
} else {
bail!("Failed to get capturer display info");
}
}
pub(super) fn get_display_num() -> ResultType<usize> {
let addr = *CAP_DISPLAY_INFO.read().unwrap();
if addr != 0 {
let cap_display_info: *const CapDisplayInfo = addr as _;
unsafe {
let cap_display_info = &*cap_display_info;
Ok(cap_display_info.num)
}
} else {
bail!("Failed to get capturer display info");
}
}
pub(super) fn get_capturer() -> ResultType<CapturerInfo> {
if !scrap::is_wayland() {
bail!("Do not call this function if not wayland");
}
let addr = *CAP_DISPLAY_INFO.read().unwrap();
if addr != 0 {
let cap_display_info: *const CapDisplayInfo = addr as _;
unsafe {
let cap_display_info = &*cap_display_info;
let rect = cap_display_info.rects[cap_display_info.current];
Ok(CapturerInfo {
origin: rect.0,
width: rect.1,
height: rect.2,
ndisplay: cap_display_info.num,
current: cap_display_info.current,
privacy_mode_id: 0,
_captuerer_privacy_mode_id: 0,
capturer: Box::new(cap_display_info.capturer),
})
}
} else {
bail!("Failed to get capturer display info");
}
}
}