Merge remote-tracking branch 'github/master' into sigma

# Conflicts:
#	flutter/lib/desktop/widgets/remote_menubar.dart
This commit is contained in:
sjpark
2023-02-25 11:37:12 +09:00
238 changed files with 8183 additions and 4234 deletions

View File

@@ -37,8 +37,5 @@ core-graphics = "0.22"
objc = "0.2"
unicode-segmentation = "1.6"
[target.'cfg(target_os = "linux")'.dependencies]
libc = "0.2"
[build-dependencies]
pkg-config = "0.3"

View File

@@ -1,8 +1,6 @@
use libc;
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
use self::libc::{c_char, c_int, c_void, useconds_t};
use hbb_common::libc::{c_char, c_int, c_void, useconds_t};
use std::{borrow::Cow, ffi::CString, ptr};
const CURRENT_WINDOW: c_int = 0;

View File

@@ -39,7 +39,7 @@ fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) }
}
fn keybd_event(flags: u32, vk: u16, scan: u16) -> DWORD {
fn keybd_event(mut flags: u32, vk: u16, scan: u16) -> DWORD {
let mut scan = scan;
unsafe {
// https://github.com/rustdesk/rustdesk/issues/366
@@ -52,35 +52,33 @@ fn keybd_event(flags: u32, vk: u16, scan: u16) -> DWORD {
scan = MapVirtualKeyExW(vk as _, 0, LAYOUT) as _;
}
}
let mut input: INPUT = unsafe { std::mem::MaybeUninit::zeroed().assume_init() };
input.type_ = INPUT_KEYBOARD;
if flags & KEYEVENTF_UNICODE == 0 {
if scan >> 8 == 0xE0 || scan >> 8 == 0xE1 {
flags |= winapi::um::winuser::KEYEVENTF_EXTENDEDKEY;
}
}
let mut union: INPUT_u = unsafe { std::mem::zeroed() };
unsafe {
let dst_ptr = (&mut input.u as *mut _) as *mut u8;
let flags = match vk as _ {
winapi::um::winuser::VK_HOME |
winapi::um::winuser::VK_UP |
winapi::um::winuser::VK_PRIOR |
winapi::um::winuser::VK_LEFT |
winapi::um::winuser::VK_RIGHT |
winapi::um::winuser::VK_END |
winapi::um::winuser::VK_DOWN |
winapi::um::winuser::VK_NEXT |
winapi::um::winuser::VK_INSERT |
winapi::um::winuser::VK_DELETE => flags | winapi::um::winuser::KEYEVENTF_EXTENDEDKEY,
_ => flags,
};
let k = KEYBDINPUT {
*union.ki_mut() = KEYBDINPUT {
wVk: vk,
wScan: scan,
dwFlags: flags,
time: 0,
dwExtraInfo: ENIGO_INPUT_EXTRA_VALUE,
};
let src_ptr = (&k as *const _) as *const u8;
std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, size_of::<KEYBDINPUT>());
}
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) }
let mut inputs = [INPUT {
type_: INPUT_KEYBOARD,
u: union,
}; 1];
unsafe {
SendInput(
inputs.len() as UINT,
inputs.as_mut_ptr(),
size_of::<INPUT>() as c_int,
)
}
}
fn get_error() -> String {

View File

@@ -31,6 +31,9 @@ sodiumoxide = "0.2"
regex = "1.4"
tokio-socks = { git = "https://github.com/open-trade/tokio-socks" }
chrono = "0.4"
backtrace = "0.3"
libc = "0.2"
sysinfo = "0.24"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
mac_address = "1.1"
@@ -46,6 +49,9 @@ protobuf-codegen = { version = "3.1" }
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winuser"] }
[target.'cfg(target_os = "macos")'.dependencies]
osascript = "0.3.0"
[dev-dependencies]
toml = "0.5"
serde_json = "1.0"

View File

@@ -0,0 +1,20 @@
extern crate hbb_common;
#[cfg(target_os = "linux")]
use hbb_common::platform::linux;
#[cfg(target_os = "macos")]
use hbb_common::platform::macos;
fn main() {
#[cfg(target_os = "linux")]
let res = linux::system_message("test title", "test message", true);
#[cfg(target_os = "macos")]
let res = macos::alert(
"System Preferences".to_owned(),
"warning".to_owned(),
"test title".to_owned(),
"test message".to_owned(),
["Ok".to_owned()].to_vec(),
);
#[cfg(any(target_os = "linux", target_os = "macos"))]
println!("result {:?}", &res);
}

View File

@@ -90,6 +90,7 @@ message PeerInfo {
int32 conn_id = 8;
Features features = 9;
SupportedEncoding encoding = 10;
SupportedResolutions resolutions = 11;
}
message LoginResponse {
@@ -201,6 +202,8 @@ message KeyEvent {
bool press = 2;
oneof union {
ControlKey control_key = 3;
// high word, sym key code. win: virtual-key code, linux: keysym ?, macos:
// low word, position key code. win: scancode, linux: key code, macos: key code
uint32 chr = 4;
uint32 unicode = 5;
string seq = 6;
@@ -414,6 +417,13 @@ message Cliprdr {
}
}
message Resolution {
int32 width = 1;
int32 height = 2;
}
message SupportedResolutions { repeated Resolution resolutions = 1; }
message SwitchDisplay {
int32 display = 1;
sint32 x = 2;
@@ -421,6 +431,7 @@ message SwitchDisplay {
int32 width = 4;
int32 height = 5;
bool cursor_embedded = 6;
SupportedResolutions resolutions = 7;
}
message PermissionInfo {
@@ -595,6 +606,7 @@ message Misc {
bool portable_service_running = 20;
SwitchSidesRequest switch_sides_request = 21;
SwitchBack switch_back = 22;
Resolution change_resolution = 24;
}
}
@@ -634,5 +646,6 @@ message Message {
SwitchSidesResponse switch_sides_response = 22;
VoiceCallRequest voice_call_request = 23;
VoiceCallResponse voice_call_response = 24;
PeerInfo peer_info = 25;
}
}

View File

@@ -30,13 +30,7 @@ pub const REG_INTERVAL: i64 = 12_000;
pub const COMPRESS_LEVEL: i32 = 3;
const SERIAL: i32 = 3;
const PASSWORD_ENC_VERSION: &str = "00";
// 128x128
#[cfg(target_os = "macos")] // 128x128 on 160x160 canvas, then shrink to 128, mac looks better with padding
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAyVBMVEUAAAAAcf8Acf8Acf8Acv8Acf8Acf8Acf8Acf8AcP8Acf8Ab/8AcP8Acf////8AaP/z+f/o8v/k7v/5/v/T5f8AYP/u9v/X6f+hx/+Kuv95pP8Aef/B1/+TwP9xoP8BdP/g6P+Irv9ZmP8Bgf/E3f98q/9sn/+01f+Es/9nm/9Jif8hhv8off/M4P+syP+avP86iP/c7f+xy/9yqf9Om/9hk/9Rjv+60P99tv9fpf88lv8yjf8Tgf8deP+kvP8BiP8NeP8hkP80gP8oj2VLAAAADXRSTlMA7o7qLvnaxZ1FOxYPjH9HWgAABHJJREFUeNrtm+tW4jAQgBfwuu7MtIUWsOUiCCioIIgLiqvr+z/UHq/LJKVkmwTcc/r9E2nzlU4mSTP9lpGRkZGR8VX5cZjfL+yCEXYL+/nDH//U/Pd8DgyTy39Xbv7oIAcWyB0cqbW/sweW2NtRaj8H1sgpGOwUIAH7Bkd7YJW9dXFwAJY5WNP/cmCZQnJvzIN18on5LwfWySXlxEPYAIcad8D6PdiHDbCfIFCADVBIENiFDbCbIACKPPXrZ+cP8E6/0znvP4EymgIEravIRcTxu8HxNSJ60a8W0AYECKrlAN+YwAthCd9wm1Ug6wKzIn5SgRduXfwkqDasCjx0XFzi9PV6zwNcIuhcWBOg+ikySq8C9UD4dEKWBCoOcspvAuLHTo9sCDQiFPHotRM48j8G5gVur1FdAN2uaYEuiz7xFsgEJ2RUoMUakXuBTHHoGxQYOBhHjeUBAefEnMAowFhaLBOKuOemBBbxLRQrH2PBCgMvNCPQGMeevTb9zLrPxz2Mo+QbEaijzPUcOOHMQZkKGRAIPem39+bypREMPTkQW/oCfk866zAkiIFG4yIKRE/aAnfiSd0WrORY6pFdXQEqi9mvAQm0RIOSnoCcZ8vJoz3diCnjRk+g8VP4/fuQDJ2Lxr6WwG0gXs9aTpDzW0vgDBlVUpixR8gYk44AD8FrUKHr8JQJGgIDnoDqoALxmWPQSi9AVVzm8gKUuEPGr/QCvptwJkbSYT/TC4S8C96DGjTj86aHtAI0x2WaBIq0eSYYpRa4EsdWVVwWu9O0Aj6f6dyBMnwEraeOgSYu0wZlauzA47QCbT7DgAQSE+hZWoEBF/BBmWOewNMK3BsSqKUW4MGcWqCSVmDkbvkXGKQOwg6PAUO9oL3xXhA20yaiCjuwYygRVQlUOTWTCf2SuNJTxeFjgaHByGuAIvd8ItdPLTDhS7IuqEE1YSKVOgbayLhSFQhMzYh8hwfBs1r7c505YVIQYEdNoKwxK06MJiyrpUFHiF0NAfCQUVHoiRclIXJIR6C2fqG37pBHvcWpgwzvAtYwkR5UGV2e42UISdBJETl3mg8ouo54Rcnti1/vaT+iuUQBt500Cgo4U10BeHSkk57FB0JjWkKRMWgLUA0lLodtImAQdaMiiri3+gIAPZQoutHNsgKF1aaDMhMyIdBf8Th+Bh8MTjGWCpl5Wv43tDmnF+IUVMrcZgRoiAxhtrloYizNkZaAnF5leglbNhj0wYCAbCDvGb0mP4nib7O7ZlcYQ2m1gPtIZgVgGNNMeaVAaWR+57TrqgtUnm3sHQ+kYeE6fufUubG1ez50FXbPnWgBlgSABmN3TTcsRl2yWkHRrwbiunvk/W2+Mg1hPZplPDeXRbZzStFH15s1QIVd3UImP5z/bHpeeQLvRJ7XLFUffQIlCvqlXETQbgN9/rlYABGosv+Vi9m2Xs639YLGrZd0br+odetlvdsvbN56abfd4vbCzv9Q3v/ygoOV21A4OPpfXvH4Ai+5ZGRkZGRkbJA/t/I0QMzoMiEAAAAASUVORK5CYII=
";
#[cfg(not(target_os = "macos"))] // 128x128 no padding
pub const ICON: &str = "data:image/png;base64,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
";
#[cfg(target_os = "macos")]
lazy_static::lazy_static! {
pub static ref ORG: Arc<RwLock<String>> = Arc::new(RwLock::new("com.carriez".to_owned()));

View File

@@ -39,8 +39,10 @@ pub use tokio_socks::IntoTargetAddr;
pub use tokio_socks::TargetAddr;
pub mod password_security;
pub use chrono;
pub use libc;
pub use directories_next;
pub mod keyboard;
pub use sysinfo;
#[cfg(feature = "quic")]
pub type Stream = quic::Connection;

View File

@@ -1,4 +1,5 @@
use crate::ResultType;
use std::{collections::HashMap, process::Command};
lazy_static::lazy_static! {
pub static ref DISTRO: Distro = Distro::new();
@@ -155,3 +156,42 @@ fn run_loginctl(args: Option<Vec<&str>>) -> std::io::Result<std::process::Output
.args(vec![String::from("--host"), l_args])
.output()
}
/// forever: may not work
#[cfg(target_os = "linux")]
pub fn system_message(title: &str, msg: &str, forever: bool) -> ResultType<()> {
let cmds: HashMap<&str, Vec<&str>> = HashMap::from([
("notify-send", [title, msg].to_vec()),
(
"zenity",
[
"--info",
"--timeout",
if forever { "0" } else { "3" },
"--title",
title,
"--text",
msg,
]
.to_vec(),
),
("kdialog", ["--title", title, "--msgbox", msg].to_vec()),
(
"xmessage",
[
"-center",
"-timeout",
if forever { "0" } else { "3" },
title,
msg,
]
.to_vec(),
),
]);
for (k, v) in cmds {
if Command::new(k).args(v).spawn().is_ok() {
return Ok(());
}
}
crate::bail!("failed to post system message");
}

View File

@@ -0,0 +1,55 @@
use crate::ResultType;
use osascript;
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize)]
struct AlertParams {
title: String,
message: String,
alert_type: String,
buttons: Vec<String>,
}
#[derive(Deserialize)]
struct AlertResult {
#[serde(rename = "buttonReturned")]
button: String,
}
/// Firstly run the specified app, then alert a dialog. Return the clicked button value.
///
/// # Arguments
///
/// * `app` - The app to execute the script.
/// * `alert_type` - Alert type. . informational, warning, critical
/// * `title` - The alert title.
/// * `message` - The alert message.
/// * `buttons` - The buttons to show.
pub fn alert(
app: String,
alert_type: String,
title: String,
message: String,
buttons: Vec<String>,
) -> ResultType<String> {
let script = osascript::JavaScript::new(&format!(
"
var App = Application('{}');
App.includeStandardAdditions = true;
return App.displayAlert($params.title, {{
message: $params.message,
'as': $params.alert_type,
buttons: $params.buttons,
}});
",
app
));
let result: AlertResult = script.execute_with_params(AlertParams {
title,
message,
alert_type,
buttons,
})?;
Ok(result.button)
}

View File

@@ -1,2 +1,51 @@
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "macos")]
pub mod macos;
use crate::{config::Config, log};
use std::process::exit;
extern "C" fn breakdown_signal_handler(sig: i32) {
let mut stack = vec![];
backtrace::trace(|frame| {
backtrace::resolve_frame(frame, |symbol| {
if let Some(name) = symbol.name() {
stack.push(name.to_string());
}
});
true // keep going to the next frame
});
let mut info = String::default();
if stack.iter().any(|s| {
s.contains(&"nouveau_pushbuf_kick")
|| s.to_lowercase().contains("nvidia")
|| s.contains("gdk_window_end_draw_frame")
}) {
Config::set_option("allow-always-software-render".to_string(), "Y".to_string());
info = "Always use software rendering will be set.".to_string();
log::info!("{}", info);
}
log::error!(
"Got signal {} and exit. stack:\n{}",
sig,
stack.join("\n").to_string()
);
if !info.is_empty() {
#[cfg(target_os = "linux")]
linux::system_message(
"RustDesk",
&format!("Got signal {} and exit.{}", sig, info),
true,
)
.ok();
}
exit(0);
}
pub fn register_breakdown_handler() {
unsafe {
libc::signal(libc::SIGSEGV, breakdown_signal_handler as _);
}
}

View File

@@ -16,7 +16,6 @@ mediacodec = ["ndk"]
[dependencies]
block = "0.1"
cfg-if = "1.0"
libc = "0.2"
num_cpus = "1.13"
lazy_static = "1.4"
hbb_common = { path = "../hbb_common" }

View File

@@ -11,7 +11,7 @@ use crate::hwcodec::*;
use crate::mediacodec::{
MediaCodecDecoder, MediaCodecDecoders, H264_DECODER_SUPPORT, H265_DECODER_SUPPORT,
};
use crate::vpxcodec::*;
use crate::{vpxcodec::*, ImageFormat};
use hbb_common::{
anyhow::anyhow,
@@ -306,16 +306,17 @@ impl Decoder {
pub fn handle_video_frame(
&mut self,
frame: &video_frame::Union,
fmt: ImageFormat,
rgb: &mut Vec<u8>,
) -> ResultType<bool> {
match frame {
video_frame::Union::Vp9s(vp9s) => {
Decoder::handle_vp9s_video_frame(&mut self.vpx, vp9s, rgb)
Decoder::handle_vp9s_video_frame(&mut self.vpx, vp9s, fmt, rgb)
}
#[cfg(feature = "hwcodec")]
video_frame::Union::H264s(h264s) => {
if let Some(decoder) = &mut self.hw.h264 {
Decoder::handle_hw_video_frame(decoder, h264s, rgb, &mut self.i420)
Decoder::handle_hw_video_frame(decoder, h264s, fmt, rgb, &mut self.i420)
} else {
Err(anyhow!("don't support h264!"))
}
@@ -323,7 +324,7 @@ impl Decoder {
#[cfg(feature = "hwcodec")]
video_frame::Union::H265s(h265s) => {
if let Some(decoder) = &mut self.hw.h265 {
Decoder::handle_hw_video_frame(decoder, h265s, rgb, &mut self.i420)
Decoder::handle_hw_video_frame(decoder, h265s, fmt, rgb, &mut self.i420)
} else {
Err(anyhow!("don't support h265!"))
}
@@ -331,7 +332,7 @@ impl Decoder {
#[cfg(feature = "mediacodec")]
video_frame::Union::H264s(h264s) => {
if let Some(decoder) = &mut self.media_codec.h264 {
Decoder::handle_mediacodec_video_frame(decoder, h264s, rgb)
Decoder::handle_mediacodec_video_frame(decoder, h264s, fmt, rgb)
} else {
Err(anyhow!("don't support h264!"))
}
@@ -339,7 +340,7 @@ impl Decoder {
#[cfg(feature = "mediacodec")]
video_frame::Union::H265s(h265s) => {
if let Some(decoder) = &mut self.media_codec.h265 {
Decoder::handle_mediacodec_video_frame(decoder, h265s, rgb)
Decoder::handle_mediacodec_video_frame(decoder, h265s, fmt, rgb)
} else {
Err(anyhow!("don't support h265!"))
}
@@ -351,6 +352,7 @@ impl Decoder {
fn handle_vp9s_video_frame(
decoder: &mut VpxDecoder,
vp9s: &EncodedVideoFrames,
fmt: ImageFormat,
rgb: &mut Vec<u8>,
) -> ResultType<bool> {
let mut last_frame = Image::new();
@@ -367,7 +369,7 @@ impl Decoder {
if last_frame.is_null() {
Ok(false)
} else {
last_frame.rgb(1, true, rgb);
last_frame.to(fmt, 1, rgb);
Ok(true)
}
}
@@ -376,14 +378,15 @@ impl Decoder {
fn handle_hw_video_frame(
decoder: &mut HwDecoder,
frames: &EncodedVideoFrames,
rgb: &mut Vec<u8>,
fmt: ImageFormat,
raw: &mut Vec<u8>,
i420: &mut Vec<u8>,
) -> ResultType<bool> {
let mut ret = false;
for h264 in frames.frames.iter() {
for image in decoder.decode(&h264.data)? {
// TODO: just process the last frame
if image.bgra(rgb, i420).is_ok() {
if image.to_fmt(fmt, raw, i420).is_ok() {
ret = true;
}
}
@@ -395,11 +398,12 @@ impl Decoder {
fn handle_mediacodec_video_frame(
decoder: &mut MediaCodecDecoder,
frames: &EncodedVideoFrames,
rgb: &mut Vec<u8>,
fmt: ImageFormat,
raw: &mut Vec<u8>,
) -> ResultType<bool> {
let mut ret = false;
for h264 in frames.frames.iter() {
return decoder.decode(&h264.data, rgb);
return decoder.decode(&h264.data, fmt, raw);
}
return Ok(false);
}

View File

@@ -103,6 +103,19 @@ extern "C" {
height: c_int,
) -> c_int;
pub fn I420ToABGR(
src_y: *const u8,
src_stride_y: c_int,
src_u: *const u8,
src_stride_u: c_int,
src_v: *const u8,
src_stride_v: c_int,
dst_rgba: *mut u8,
dst_stride_rgba: c_int,
width: c_int,
height: c_int,
) -> c_int;
pub fn NV12ToARGB(
src_y: *const u8,
src_stride_y: c_int,
@@ -113,6 +126,17 @@ extern "C" {
width: c_int,
height: c_int,
) -> c_int;
pub fn NV12ToABGR(
src_y: *const u8,
src_stride_y: c_int,
src_uv: *const u8,
src_stride_uv: c_int,
dst_rgba: *mut u8,
dst_stride_rgba: c_int,
width: c_int,
height: c_int,
) -> c_int;
}
// https://github.com/webmproject/libvpx/blob/master/vpx/src/vpx_image.c
@@ -246,6 +270,7 @@ pub unsafe fn nv12_to_i420(
#[cfg(feature = "hwcodec")]
pub mod hw {
use hbb_common::{anyhow::anyhow, ResultType};
use crate::ImageFormat;
#[cfg(target_os = "windows")]
use hwcodec::{ffmpeg::ffmpeg_linesize_offset_length, AVPixelFormat};
@@ -315,7 +340,8 @@ pub mod hw {
}
#[cfg(target_os = "windows")]
pub fn hw_nv12_to_bgra(
pub fn hw_nv12_to(
fmt: ImageFormat,
width: usize,
height: usize,
src_y: &[u8],
@@ -355,18 +381,39 @@ pub mod hw {
width as _,
height as _,
);
super::I420ToARGB(
i420_offset_y,
i420_stride_y,
i420_offset_u,
i420_stride_u,
i420_offset_v,
i420_stride_v,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
);
match fmt {
ImageFormat::ARGB => {
super::I420ToARGB(
i420_offset_y,
i420_stride_y,
i420_offset_u,
i420_stride_u,
i420_offset_v,
i420_stride_v,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
);
}
ImageFormat::ABGR => {
super::I420ToABGR(
i420_offset_y,
i420_stride_y,
i420_offset_u,
i420_stride_u,
i420_offset_v,
i420_stride_v,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
);
}
_ => {
return Err(anyhow!("unsupported image format"));
}
}
return Ok(());
};
}
@@ -374,7 +421,8 @@ pub mod hw {
}
#[cfg(not(target_os = "windows"))]
pub fn hw_nv12_to_bgra(
pub fn hw_nv12_to(
fmt: ImageFormat,
width: usize,
height: usize,
src_y: &[u8],
@@ -387,23 +435,46 @@ pub mod hw {
) -> ResultType<()> {
dst.resize(width * height * 4, 0);
unsafe {
match super::NV12ToARGB(
src_y.as_ptr(),
src_stride_y as _,
src_uv.as_ptr(),
src_stride_uv as _,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
) {
0 => Ok(()),
_ => Err(anyhow!("NV12ToARGB failed")),
match fmt {
ImageFormat::ARGB => {
match super::NV12ToARGB(
src_y.as_ptr(),
src_stride_y as _,
src_uv.as_ptr(),
src_stride_uv as _,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
) {
0 => Ok(()),
_ => Err(anyhow!("NV12ToARGB failed")),
}
}
ImageFormat::ABGR => {
match super::NV12ToABGR(
src_y.as_ptr(),
src_stride_y as _,
src_uv.as_ptr(),
src_stride_uv as _,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
) {
0 => Ok(()),
_ => Err(anyhow!("NV12ToABGR failed")),
}
}
_ => {
Err(anyhow!("unsupported image format"))
}
}
}
}
pub fn hw_i420_to_bgra(
pub fn hw_i420_to(
fmt: ImageFormat,
width: usize,
height: usize,
src_y: &[u8],
@@ -419,18 +490,38 @@ pub mod hw {
let src_v = src_v.as_ptr();
dst.resize(width * height * 4, 0);
unsafe {
super::I420ToARGB(
src_y,
src_stride_y as _,
src_u,
src_stride_u as _,
src_v,
src_stride_v as _,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
);
match fmt {
ImageFormat::ARGB => {
super::I420ToARGB(
src_y,
src_stride_y as _,
src_u,
src_stride_u as _,
src_v,
src_stride_v as _,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
);
}
ImageFormat::ABGR => {
super::I420ToABGR(
src_y,
src_stride_y as _,
src_u,
src_stride_u as _,
src_v,
src_stride_v as _,
dst.as_mut_ptr(),
(width * 4) as _,
width as _,
height as _,
);
}
_ => {
}
}
};
}
}

View File

@@ -1,6 +1,6 @@
use crate::{
codec::{EncoderApi, EncoderCfg},
hw, HW_STRIDE_ALIGN,
hw, ImageFormat, HW_STRIDE_ALIGN,
};
use hbb_common::{
anyhow::{anyhow, Context},
@@ -236,22 +236,24 @@ pub struct HwDecoderImage<'a> {
}
impl HwDecoderImage<'_> {
pub fn bgra(&self, bgra: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
pub fn to_fmt(&self, fmt: ImageFormat, fmt_data: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
let frame = self.frame;
match frame.pixfmt {
AVPixelFormat::AV_PIX_FMT_NV12 => hw::hw_nv12_to_bgra(
AVPixelFormat::AV_PIX_FMT_NV12 => hw::hw_nv12_to(
fmt,
frame.width as _,
frame.height as _,
&frame.data[0],
&frame.data[1],
frame.linesize[0] as _,
frame.linesize[1] as _,
bgra,
fmt_data,
i420,
HW_STRIDE_ALIGN,
),
AVPixelFormat::AV_PIX_FMT_YUV420P => {
hw::hw_i420_to_bgra(
hw::hw_i420_to(
fmt,
frame.width as _,
frame.height as _,
&frame.data[0],
@@ -260,12 +262,20 @@ impl HwDecoderImage<'_> {
frame.linesize[0] as _,
frame.linesize[1] as _,
frame.linesize[2] as _,
bgra,
fmt_data,
);
return Ok(());
}
}
}
pub fn bgra(&self, bgra: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
self.to_fmt(ImageFormat::ARGB, bgra, i420)
}
pub fn rgba(&self, rgba: &mut Vec<u8>, i420: &mut Vec<u8>) -> ResultType<()> {
self.to_fmt(ImageFormat::ABGR, rgba, i420)
}
}
fn get_config(k: &str) -> ResultType<CodecInfos> {
@@ -317,16 +327,30 @@ pub fn check_config() {
}
pub fn check_config_process(force_reset: bool) {
if force_reset {
HwCodecConfig::remove();
}
if let Ok(exe) = std::env::current_exe() {
std::thread::spawn(move || {
std::process::Command::new(exe)
.arg("--check-hwcodec-config")
.status()
.ok();
HwCodecConfig::refresh();
});
};
use hbb_common::sysinfo::{ProcessExt, System, SystemExt};
std::thread::spawn(move || {
if force_reset {
HwCodecConfig::remove();
}
if let Ok(exe) = std::env::current_exe() {
if let Some(file_name) = exe.file_name().to_owned() {
let s = System::new_all();
let arg = "--check-hwcodec-config";
for process in s.processes_by_name(&file_name.to_string_lossy().to_string()) {
if process.cmd().iter().any(|cmd| cmd.contains(arg)) {
log::warn!("already have process {}", arg);
return;
}
}
if let Ok(mut child) = std::process::Command::new(exe).arg(arg).spawn() {
let second = 3;
std::thread::sleep(std::time::Duration::from_secs(second));
// kill: Different platforms have different results
child.kill().ok();
HwCodecConfig::refresh();
}
}
};
});
}

View File

@@ -1,5 +1,4 @@
use hbb_common::anyhow::Error;
use hbb_common::{bail, ResultType};
use hbb_common::{log, anyhow::Error, bail, ResultType};
use ndk::media::media_codec::{MediaCodec, MediaCodecDirection, MediaFormat};
use std::ops::Deref;
use std::{
@@ -8,9 +7,10 @@ use std::{
time::Duration,
};
use crate::ImageFormat;
use crate::{
codec::{EncoderApi, EncoderCfg},
I420ToARGB,
I420ToABGR, I420ToARGB,
};
/// MediaCodec mime type name
@@ -50,7 +50,7 @@ impl MediaCodecDecoder {
MediaCodecDecoders { h264, h265 }
}
pub fn decode(&mut self, data: &[u8], rgb: &mut Vec<u8>) -> ResultType<bool> {
pub fn decode(&mut self, data: &[u8], fmt: ImageFormat, raw: &mut Vec<u8>) -> ResultType<bool> {
match self.dequeue_input_buffer(Duration::from_millis(10))? {
Some(mut input_buffer) => {
let mut buf = input_buffer.buffer_mut();
@@ -83,23 +83,44 @@ impl MediaCodecDecoder {
let bps = 4;
let u = buf.len() * 2 / 3;
let v = buf.len() * 5 / 6;
rgb.resize(h * w * bps, 0);
raw.resize(h * w * bps, 0);
let y_ptr = buf.as_ptr();
let u_ptr = buf[u..].as_ptr();
let v_ptr = buf[v..].as_ptr();
unsafe {
I420ToARGB(
y_ptr,
stride,
u_ptr,
stride / 2,
v_ptr,
stride / 2,
rgb.as_mut_ptr(),
(w * bps) as _,
w as _,
h as _,
);
match fmt {
ImageFormat::ARGB => {
I420ToARGB(
y_ptr,
stride,
u_ptr,
stride / 2,
v_ptr,
stride / 2,
raw.as_mut_ptr(),
(w * bps) as _,
w as _,
h as _,
);
}
ImageFormat::ARGB => {
I420ToABGR(
y_ptr,
stride,
u_ptr,
stride / 2,
v_ptr,
stride / 2,
raw.as_mut_ptr(),
(w * bps) as _,
w as _,
h as _,
);
}
_ => {
bail!("Unsupported image format");
}
}
}
self.release_output_buffer(output_buffer, false)?;
Ok(true)

View File

@@ -43,6 +43,13 @@ pub const HW_STRIDE_ALIGN: usize = 0; // recommended by av_frame_get_buffer
pub mod record;
mod vpx;
#[derive(Copy, Clone)]
pub enum ImageFormat {
Raw,
ABGR,
ARGB,
}
#[inline]
pub fn would_block_if_equal(old: &mut Vec<u8>, b: &[u8]) -> std::io::Result<()> {
// does this really help?

View File

@@ -6,8 +6,8 @@ use hbb_common::anyhow::{anyhow, Context};
use hbb_common::message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame};
use hbb_common::{get_time, ResultType};
use crate::codec::EncoderApi;
use crate::STRIDE_ALIGN;
use crate::{codec::EncoderApi, ImageFormat};
use super::vpx::{vp8e_enc_control_id::*, vpx_codec_err_t::*, *};
use hbb_common::bytes::Bytes;
@@ -417,7 +417,7 @@ impl VpxDecoder {
Ok(Self { ctx })
}
pub fn decode2rgb(&mut self, data: &[u8], rgba: bool) -> Result<Vec<u8>> {
pub fn decode2rgb(&mut self, data: &[u8], fmt: ImageFormat) -> Result<Vec<u8>> {
let mut img = Image::new();
for frame in self.decode(data)? {
drop(img);
@@ -431,7 +431,7 @@ impl VpxDecoder {
Ok(Vec::new())
} else {
let mut out = Default::default();
img.rgb(1, rgba, &mut out);
img.to(fmt, 1, &mut out);
Ok(out)
}
}
@@ -539,40 +539,60 @@ impl Image {
self.inner().stride[iplane]
}
pub fn rgb(&self, stride_align: usize, rgba: bool, dst: &mut Vec<u8>) {
pub fn to(&self, fmt: ImageFormat, stride_align: usize, dst: &mut Vec<u8>) {
let h = self.height();
let mut w = self.width();
let bps = if rgba { 4 } else { 3 };
let bps = match fmt {
ImageFormat::Raw => 3,
ImageFormat::ARGB | ImageFormat::ABGR => 4,
};
w = (w + stride_align - 1) & !(stride_align - 1);
dst.resize(h * w * bps, 0);
let img = self.inner();
unsafe {
if rgba {
super::I420ToARGB(
img.planes[0],
img.stride[0],
img.planes[1],
img.stride[1],
img.planes[2],
img.stride[2],
dst.as_mut_ptr(),
(w * bps) as _,
self.width() as _,
self.height() as _,
);
} else {
super::I420ToRAW(
img.planes[0],
img.stride[0],
img.planes[1],
img.stride[1],
img.planes[2],
img.stride[2],
dst.as_mut_ptr(),
(w * bps) as _,
self.width() as _,
self.height() as _,
);
match fmt {
ImageFormat::Raw => {
super::I420ToRAW(
img.planes[0],
img.stride[0],
img.planes[1],
img.stride[1],
img.planes[2],
img.stride[2],
dst.as_mut_ptr(),
(w * bps) as _,
self.width() as _,
self.height() as _,
);
}
ImageFormat::ARGB => {
super::I420ToARGB(
img.planes[0],
img.stride[0],
img.planes[1],
img.stride[1],
img.planes[2],
img.stride[2],
dst.as_mut_ptr(),
(w * bps) as _,
self.width() as _,
self.height() as _,
);
}
ImageFormat::ABGR => {
super::I420ToABGR(
img.planes[0],
img.stride[0],
img.planes[1],
img.stride[1],
img.planes[2],
img.stride[2],
dst.as_mut_ptr(),
(w * bps) as _,
self.width() as _,
self.height() as _,
);
}
}
}
}

View File

@@ -1,4 +1,4 @@
use crate::{x11, common::TraitCapturer};
use crate::{common::TraitCapturer, x11};
use std::{io, ops, time::Duration};
pub struct Capturer(x11::Capturer);
@@ -90,6 +90,6 @@ impl Display {
}
pub fn name(&self) -> String {
"".to_owned()
self.0.name()
}
}

View File

@@ -2,7 +2,7 @@
extern crate block;
#[macro_use]
extern crate cfg_if;
pub extern crate libc;
pub use hbb_common::libc;
#[cfg(dxgi)]
extern crate winapi;

View File

@@ -1,7 +1,7 @@
use std::ptr;
use block::{Block, ConcreteBlock};
use libc::c_void;
use hbb_common::libc::c_void;
use std::sync::{Arc, Mutex};
use super::config::Config;

View File

@@ -1,6 +1,6 @@
use std::ptr;
use libc::c_void;
use hbb_common::libc::c_void;
use super::ffi::*;

View File

@@ -1,7 +1,7 @@
#![allow(dead_code)]
use block::RcBlock;
use libc::c_void;
use hbb_common::libc::c_void;
pub type CGDisplayStreamRef = *mut c_void;
pub type CFDictionaryRef = *mut c_void;

View File

@@ -1,6 +1,6 @@
use std::{io, ptr, slice};
use libc;
use hbb_common::libc;
use super::ffi::*;
use super::Display;

View File

@@ -9,6 +9,7 @@ pub struct Display {
default: bool,
rect: Rect,
root: xcb_window_t,
name: String,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
@@ -25,12 +26,14 @@ impl Display {
default: bool,
rect: Rect,
root: xcb_window_t,
name: String,
) -> Display {
Display {
server,
default,
rect,
root,
name,
}
}
@@ -52,4 +55,8 @@ impl Display {
pub fn root(&self) -> xcb_window_t {
self.root
}
pub fn name(&self) -> String {
self.name.clone()
}
}

View File

@@ -1,6 +1,6 @@
#![allow(non_camel_case_types)]
use libc::c_void;
use hbb_common::libc::c_void;
#[link(name = "xcb")]
#[link(name = "xcb-shm")]
@@ -65,6 +65,21 @@ extern "C" {
) -> xcb_randr_monitor_info_iterator_t;
pub fn xcb_randr_monitor_info_next(i: *mut xcb_randr_monitor_info_iterator_t);
pub fn xcb_get_atom_name(
c: *mut xcb_connection_t,
atom: xcb_atom_t,
) -> xcb_get_atom_name_cookie_t;
pub fn xcb_get_atom_name_reply(
c: *mut xcb_connection_t,
cookie: xcb_get_atom_name_cookie_t,
e: *mut *mut xcb_generic_error_t,
) -> *const xcb_get_atom_name_reply_t;
pub fn xcb_get_atom_name_name(reply: *const xcb_get_atom_name_request_t) -> *const u8;
pub fn xcb_get_atom_name_name_length(reply: *const xcb_get_atom_name_reply_t) -> i32;
}
pub const XCB_IMAGE_FORMAT_Z_PIXMAP: u8 = 2;
@@ -78,6 +93,9 @@ pub type xcb_timestamp_t = u32;
pub type xcb_colormap_t = u32;
pub type xcb_shm_seg_t = u32;
pub type xcb_drawable_t = u32;
pub type xcb_get_atom_name_cookie_t = u32;
pub type xcb_get_atom_name_reply_t = u32;
pub type xcb_get_atom_name_request_t = xcb_get_atom_name_reply_t;
#[repr(C)]
pub struct xcb_setup_t {

View File

@@ -1,7 +1,8 @@
use std::ffi::CString;
use std::ptr;
use std::rc::Rc;
use libc;
use hbb_common::libc;
use super::ffi::*;
use super::{Display, Rect, Server};
@@ -64,6 +65,7 @@ impl Iterator for DisplayIter {
if inner.rem != 0 {
unsafe {
let data = &*inner.data;
let name = get_atom_name(self.server.raw(), data.name);
let display = Display::new(
self.server.clone(),
@@ -75,6 +77,7 @@ impl Iterator for DisplayIter {
h: data.height,
},
root,
name,
);
xcb_randr_monitor_info_next(inner);
@@ -91,3 +94,30 @@ impl Iterator for DisplayIter {
}
}
}
fn get_atom_name(conn: *mut xcb_connection_t, atom: xcb_atom_t) -> String {
let empty = "".to_owned();
if atom == 0 {
return empty;
}
unsafe {
let mut e: xcb_generic_error_t = std::mem::zeroed();
let reply = xcb_get_atom_name_reply(
conn,
xcb_get_atom_name(conn, atom),
&mut ((&mut e) as *mut xcb_generic_error_t) as _,
);
if reply == std::ptr::null() {
return empty;
}
let length = xcb_get_atom_name_name_length(reply);
let name = xcb_get_atom_name_name(reply);
let mut v = vec![0u8; length as _];
std::ptr::copy_nonoverlapping(name as _, v.as_mut_ptr(), length as _);
libc::free(reply as *mut _);
if let Ok(s) = CString::new(v) {
return s.to_string_lossy().to_string();
}
empty
}
}