148 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::android::ffi::*;
 | |
| use crate::rgba_to_i420;
 | |
| 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,
 | |
|     bgra: Vec<u8>,
 | |
|     saved_raw_data: Vec<u128>, // for faster compare and copy
 | |
| }
 | |
| 
 | |
| impl Capturer {
 | |
|     pub fn new(display: Display, _yuv: bool) -> io::Result<Capturer> {
 | |
|         Ok(Capturer {
 | |
|             display,
 | |
|             bgra: 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 set_use_yuv(&mut self, _use_yuv: bool) {}
 | |
| 
 | |
|     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)?;
 | |
|             rgba_to_i420(self.width(), self.height(), buf, &mut self.bgra);
 | |
|             Ok(Frame::RAW(&self.bgra))
 | |
|         } else {
 | |
|             return Err(io::ErrorKind::WouldBlock.into());
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| pub enum Frame<'a> {
 | |
|     RAW(&'a [u8]),
 | |
|     VP9(&'a [u8]),
 | |
|     Empty,
 | |
| }
 | |
| 
 | |
| 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
 | |
| }
 |