Files
rustdesk/libs/scrap/src/common/android.rs
21pages 534bfad50f opt codec
1. use src width/height to convert yuv
2. align dst yuv to avoid illegal memory access
3. init yuvfmt when new codec
4. move remote reset calls from empty conns judge to emtpy remote conns
   judge

Signed-off-by: 21pages <pages21@163.com>
2023-11-03 11:52:41 +08:00

187 lines
4.4 KiB
Rust

use crate::android::ffi::*;
use crate::Pixfmt;
use lazy_static::lazy_static;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Mutex;
use std::{io, time::Duration};
lazy_static! {
static ref SCREEN_SIZE: Mutex<(u16, u16, u16)> = Mutex::new((0, 0, 0)); // (width, height, scale)
}
pub struct Capturer {
display: Display,
rgba: Vec<u8>,
saved_raw_data: Vec<u8>, // for faster compare and copy
}
impl Capturer {
pub fn new(display: Display) -> io::Result<Capturer> {
Ok(Capturer {
display,
rgba: Vec::new(),
saved_raw_data: Vec::new(),
})
}
pub fn width(&self) -> usize {
self.display.width() as usize
}
pub fn height(&self) -> usize {
self.display.height() as usize
}
}
impl crate::TraitCapturer for Capturer {
fn frame<'a>(&'a mut self, _timeout: Duration) -> io::Result<Frame<'a>> {
if let Some(buf) = get_video_raw() {
crate::would_block_if_equal(&mut self.saved_raw_data, buf)?;
// Is it safe to directly return buf without copy?
self.rgba.resize(buf.len(), 0);
unsafe {
std::ptr::copy_nonoverlapping(buf.as_ptr(), self.rgba.as_mut_ptr(), buf.len())
};
Ok(Frame::new(&self.rgba, self.width(), self.height()))
} else {
return Err(io::ErrorKind::WouldBlock.into());
}
}
}
pub struct Frame<'a> {
data: &'a [u8],
width: usize,
height: usize,
stride: Vec<usize>,
}
impl<'a> Frame<'a> {
pub fn new(data: &'a [u8], width: usize, height: usize) -> Self {
let stride0 = data.len() / height;
let mut stride = Vec::new();
stride.push(stride0);
Frame {
data,
width,
height,
stride,
}
}
}
impl<'a> crate::TraitFrame for Frame<'a> {
fn data(&self) -> &[u8] {
self.data
}
fn width(&self) -> usize {
self.width
}
fn height(&self) -> usize {
self.height
}
fn stride(&self) -> Vec<usize> {
self.stride.clone()
}
fn pixfmt(&self) -> Pixfmt {
Pixfmt::RGBA
}
}
pub struct Display {
default: bool,
rect: Rect,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
struct Rect {
pub x: i16,
pub y: i16,
pub w: u16,
pub h: u16,
}
impl Display {
pub fn primary() -> io::Result<Display> {
let mut size = SCREEN_SIZE.lock().unwrap();
if size.0 == 0 || size.1 == 0 {
*size = get_size().unwrap_or_default();
}
Ok(Display {
default: true,
rect: Rect {
x: 0,
y: 0,
w: size.0,
h: size.1,
},
})
}
pub fn all() -> io::Result<Vec<Display>> {
Ok(vec![Display::primary()?])
}
pub fn width(&self) -> usize {
self.rect.w as usize
}
pub fn height(&self) -> usize {
self.rect.h as usize
}
pub fn origin(&self) -> (i32, i32) {
let r = self.rect;
(r.x as _, r.y as _)
}
pub fn is_online(&self) -> bool {
true
}
pub fn is_primary(&self) -> bool {
self.default
}
pub fn name(&self) -> String {
"Android".into()
}
pub fn refresh_size() {
let mut size = SCREEN_SIZE.lock().unwrap();
*size = get_size().unwrap_or_default();
}
// Big android screen size will be shrinked, to improve performance when screen-capturing and encoding
// e.g 2280x1080 size will be set to 1140x540, and `scale` is 2
// need to multiply by `4` (2*2) when compute the bitrate
pub fn fix_quality() -> u16 {
let scale = SCREEN_SIZE.lock().unwrap().2;
if scale <= 0 {
1
} else {
scale * scale
}
}
}
fn get_size() -> Option<(u16, u16, u16)> {
let res = call_main_service_get_by_name("screen_size").ok()?;
if let Ok(json) = serde_json::from_str::<HashMap<String, Value>>(&res) {
if let (Some(Value::Number(w)), Some(Value::Number(h)), Some(Value::Number(scale))) =
(json.get("width"), json.get("height"), json.get("scale"))
{
let w = w.as_i64()? as _;
let h = h.as_i64()? as _;
let scale = scale.as_i64()? as _;
return Some((w, h, scale));
}
}
None
}