21pages 0f6538c1a7
add enable directx option, android software encoding half resolution option (#8435)
* add option enable directx capture screen, default true

Signed-off-by: 21pages <sunboeasy@gmail.com>

* option android software encoding half scale, check isStart flag

Signed-off-by: 21pages <sunboeasy@gmail.com>

---------

Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-21 18:54:32 +08:00

190 lines
4.3 KiB
Rust

use crate::android::ffi::*;
use crate::{Frame, 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! {
pub(crate) 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 get_video_raw(&mut self.rgba, &mut self.saved_raw_data).is_some() {
Ok(Frame::PixelBuffer(PixelBuffer::new(
&self.rgba,
self.width(),
self.height(),
)))
} else {
return Err(io::ErrorKind::WouldBlock.into());
}
}
}
pub struct PixelBuffer<'a> {
data: &'a [u8],
width: usize,
height: usize,
stride: Vec<usize>,
}
impl<'a> PixelBuffer<'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);
PixelBuffer {
data,
width,
height,
stride,
}
}
}
impl<'a> crate::TraitPixelBuffer for PixelBuffer<'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
}
pub fn is_start() -> Option<bool> {
let res = call_main_service_get_by_name("is_start").ok()?;
Some(res == "true")
}