Merge branch 'hwcodec' into hwcodec

This commit is contained in:
21pages 2022-07-06 10:39:00 +08:00 committed by GitHub
commit ce89e7fd8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 83 additions and 193 deletions

View File

@ -1,33 +1,13 @@
syntax = "proto3"; syntax = "proto3";
package hbb; package hbb;
message VP9 { message EncodedVideoFrame {
bytes data = 1; bytes data = 1;
bool key = 2; bool key = 2;
int64 pts = 3; int64 pts = 3;
} }
message VP9s { repeated VP9 frames = 1; } message EncodedVideoFrames { repeated EncodedVideoFrame frames = 1; }
message H264 {
bytes data = 1;
bool key = 2;
int64 pts = 3;
}
message H264s {
repeated H264 h264s = 1;
}
message H265 {
bytes data = 1;
bool key = 2;
int64 pts = 3;
}
message H265s {
repeated H265 h265s = 1;
}
message RGB { bool compress = 1; } message RGB { bool compress = 1; }
@ -39,11 +19,11 @@ message YUV {
message VideoFrame { message VideoFrame {
oneof union { oneof union {
VP9s vp9s = 6; EncodedVideoFrames vp9s = 6;
RGB rgb = 7; RGB rgb = 7;
YUV yuv = 8; YUV yuv = 8;
H264s h264s = 10; EncodedVideoFrames h264s = 10;
H265s h265s = 11; EncodedVideoFrames h265s = 11;
} }
int64 timestamp = 9; int64 timestamp = 9;
} }
@ -454,10 +434,8 @@ enum ImageQuality {
message VideoCodecState { message VideoCodecState {
int32 ScoreVpx = 1; int32 ScoreVpx = 1;
bool H264 = 2; int32 ScoreH264 = 2;
int32 ScoreH264 = 3; int32 ScoreH265 = 3;
bool H265 = 4;
int32 ScoreH265 = 5;
} }
message OptionMessage { message OptionMessage {

View File

@ -35,7 +35,6 @@ lazy_static::lazy_static! {
static ref CONFIG: Arc<RwLock<Config>> = Arc::new(RwLock::new(Config::load())); static ref CONFIG: Arc<RwLock<Config>> = Arc::new(RwLock::new(Config::load()));
static ref CONFIG2: Arc<RwLock<Config2>> = Arc::new(RwLock::new(Config2::load())); static ref CONFIG2: Arc<RwLock<Config2>> = Arc::new(RwLock::new(Config2::load()));
static ref LOCAL_CONFIG: Arc<RwLock<LocalConfig>> = Arc::new(RwLock::new(LocalConfig::load())); static ref LOCAL_CONFIG: Arc<RwLock<LocalConfig>> = Arc::new(RwLock::new(LocalConfig::load()));
static ref HWCODEC_CONFIG: Arc<RwLock<HwCodecConfig>> = Arc::new(RwLock::new(HwCodecConfig::load()));
pub static ref ONLINE: Arc<Mutex<HashMap<String, i64>>> = Default::default(); pub static ref ONLINE: Arc<Mutex<HashMap<String, i64>>> = Default::default();
pub static ref PROD_RENDEZVOUS_SERVER: Arc<RwLock<String>> = Default::default(); pub static ref PROD_RENDEZVOUS_SERVER: Arc<RwLock<String>> = Default::default();
pub static ref APP_NAME: Arc<RwLock<String>> = Arc::new(RwLock::new("RustDesk".to_owned())); pub static ref APP_NAME: Arc<RwLock<String>> = Arc::new(RwLock::new("RustDesk".to_owned()));
@ -887,38 +886,17 @@ impl LanPeers {
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct HwCodecConfig { pub struct HwCodecConfig {
#[serde(default)] #[serde(default)]
options: HashMap<String, String>, pub options: HashMap<String, String>,
} }
impl HwCodecConfig { impl HwCodecConfig {
fn load() -> HwCodecConfig { pub fn load() -> HwCodecConfig {
Config::load_::<HwCodecConfig>("_hwcodec") Config::load_::<HwCodecConfig>("_hwcodec")
} }
fn store(&self) { pub fn store(&self) {
Config::store_(self, "_hwcodec"); Config::store_(self, "_hwcodec");
} }
pub fn get_option(k: &str) -> String {
if let Some(v) = HWCODEC_CONFIG.read().unwrap().options.get(k) {
v.clone()
} else {
"".to_owned()
}
}
pub fn set_option(k: String, v: String) {
let mut config = HWCODEC_CONFIG.write().unwrap();
let v2 = if v.is_empty() { None } else { Some(&v) };
if v2 != config.options.get(&k) {
if v2.is_none() {
config.options.remove(&k);
} else {
config.options.insert(k, v);
}
config.store();
}
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -12,15 +12,11 @@ use crate::vpxcodec::*;
use hbb_common::{ use hbb_common::{
anyhow::anyhow, anyhow::anyhow,
log, log,
message_proto::{video_frame, Message, VP9s, VideoCodecState}, message_proto::{video_frame, EncodedVideoFrames, Message, VideoCodecState},
ResultType, ResultType,
}; };
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
use hbb_common::{ use hbb_common::{config::Config2, lazy_static};
config::Config2,
lazy_static,
message_proto::{H264s, H265s},
};
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
lazy_static::lazy_static! { lazy_static::lazy_static! {
@ -137,10 +133,12 @@ impl Encoder {
let current_encoder_name = HwEncoder::current_name(); let current_encoder_name = HwEncoder::current_name();
if states.len() > 0 { if states.len() > 0 {
let (best, _) = HwEncoder::best(false, true); let (best, _) = HwEncoder::best(false, true);
let enabled_h264 = let enabled_h264 = best.h264.is_some()
best.h264.is_some() && states.len() > 0 && states.iter().all(|(_, s)| s.H264); && states.len() > 0
let enabled_h265 = && states.iter().all(|(_, s)| s.ScoreH264 > 0);
best.h265.is_some() && states.len() > 0 && states.iter().all(|(_, s)| s.H265); let enabled_h265 = best.h265.is_some()
&& states.len() > 0
&& states.iter().all(|(_, s)| s.ScoreH265 > 0);
// score encoder // score encoder
let mut score_vpx = SCORE_VPX; let mut score_vpx = SCORE_VPX;
@ -240,9 +238,7 @@ impl Decoder {
{ {
let mut state = MY_DECODER_STATE.lock().unwrap(); let mut state = MY_DECODER_STATE.lock().unwrap();
state.ScoreVpx = SCORE_VPX; state.ScoreVpx = SCORE_VPX;
state.H264 = decoder.hw.h264.is_some();
state.ScoreH264 = decoder.hw.h264.as_ref().map_or(0, |d| d.info.score); state.ScoreH264 = decoder.hw.h264.as_ref().map_or(0, |d| d.info.score);
state.H265 = decoder.hw.h265.is_some();
state.ScoreH265 = decoder.hw.h265.as_ref().map_or(0, |d| d.info.score); state.ScoreH265 = decoder.hw.h265.as_ref().map_or(0, |d| d.info.score);
} }
@ -261,7 +257,7 @@ impl Decoder {
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
video_frame::Union::h264s(h264s) => { video_frame::Union::h264s(h264s) => {
if let Some(decoder) = &mut self.hw.h264 { if let Some(decoder) = &mut self.hw.h264 {
Decoder::handle_h264s_video_frame(decoder, h264s, rgb, &mut self.i420) Decoder::handle_hw_video_frame(decoder, h264s, rgb, &mut self.i420)
} else { } else {
Err(anyhow!("don't support h264!")) Err(anyhow!("don't support h264!"))
} }
@ -269,7 +265,7 @@ impl Decoder {
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
video_frame::Union::h265s(h265s) => { video_frame::Union::h265s(h265s) => {
if let Some(decoder) = &mut self.hw.h265 { if let Some(decoder) = &mut self.hw.h265 {
Decoder::handle_h265s_video_frame(decoder, h265s, rgb, &mut self.i420) Decoder::handle_hw_video_frame(decoder, h265s, rgb, &mut self.i420)
} else { } else {
Err(anyhow!("don't support h265!")) Err(anyhow!("don't support h265!"))
} }
@ -280,7 +276,7 @@ impl Decoder {
fn handle_vp9s_video_frame( fn handle_vp9s_video_frame(
decoder: &mut VpxDecoder, decoder: &mut VpxDecoder,
vp9s: &VP9s, vp9s: &EncodedVideoFrames,
rgb: &mut Vec<u8>, rgb: &mut Vec<u8>,
) -> ResultType<bool> { ) -> ResultType<bool> {
let mut last_frame = Image::new(); let mut last_frame = Image::new();
@ -303,14 +299,14 @@ impl Decoder {
} }
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
fn handle_h264s_video_frame( fn handle_hw_video_frame(
decoder: &mut HwDecoder, decoder: &mut HwDecoder,
h264s: &H264s, frames: &EncodedVideoFrames,
rgb: &mut Vec<u8>, rgb: &mut Vec<u8>,
i420: &mut Vec<u8>, i420: &mut Vec<u8>,
) -> ResultType<bool> { ) -> ResultType<bool> {
let mut ret = false; let mut ret = false;
for h264 in h264s.h264s.iter() { for h264 in frames.frames.iter() {
for image in decoder.decode(&h264.data)? { for image in decoder.decode(&h264.data)? {
// TODO: just process the last frame // TODO: just process the last frame
if image.bgra(rgb, i420).is_ok() { if image.bgra(rgb, i420).is_ok() {
@ -320,25 +316,6 @@ impl Decoder {
} }
return Ok(ret); return Ok(ret);
} }
#[cfg(feature = "hwcodec")]
fn handle_h265s_video_frame(
decoder: &mut HwDecoder,
h265s: &H265s,
rgb: &mut Vec<u8>,
i420: &mut Vec<u8>,
) -> ResultType<bool> {
let mut ret = false;
for h265 in h265s.h265s.iter() {
for image in decoder.decode(&h265.data)? {
// TODO: just process the last frame
if image.bgra(rgb, i420).is_ok() {
ret = true;
}
}
}
return Ok(ret);
}
} }
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]

View File

@ -6,7 +6,7 @@ use hbb_common::{
anyhow::{anyhow, Context}, anyhow::{anyhow, Context},
config::HwCodecConfig, config::HwCodecConfig,
lazy_static, log, lazy_static, log,
message_proto::{H264s, H265s, Message, VideoFrame, H264, H265}, message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame},
ResultType, ResultType,
}; };
use hwcodec::{ use hwcodec::{
@ -17,10 +17,7 @@ use hwcodec::{
Quality::{self, *}, Quality::{self, *},
RateContorl::{self, *}, RateContorl::{self, *},
}; };
use std::{ use std::sync::{Arc, Mutex};
collections::HashMap,
sync::{Arc, Mutex},
};
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref HW_ENCODER_NAME: Arc<Mutex<Option<String>>> = Default::default(); static ref HW_ENCODER_NAME: Arc<Mutex<Option<String>>> = Default::default();
@ -91,49 +88,29 @@ impl EncoderApi for HwEncoder {
) -> ResultType<hbb_common::message_proto::Message> { ) -> ResultType<hbb_common::message_proto::Message> {
let mut msg_out = Message::new(); let mut msg_out = Message::new();
let mut vf = VideoFrame::new(); let mut vf = VideoFrame::new();
match self.format { let mut frames = Vec::new();
DataFormat::H264 => {
let mut h264s = Vec::new();
for frame in self.encode(frame).with_context(|| "Failed to encode")? { for frame in self.encode(frame).with_context(|| "Failed to encode")? {
h264s.push(H264 { frames.push(EncodedVideoFrame {
data: frame.data, data: frame.data,
pts: frame.pts as _, pts: frame.pts as _,
..Default::default() ..Default::default()
}); });
} }
if h264s.len() > 0 { if frames.len() > 0 {
vf.set_h264s(H264s { let frames = EncodedVideoFrames {
h264s: h264s.into(), frames: frames.into(),
..Default::default() ..Default::default()
}); };
match self.format {
DataFormat::H264 => vf.set_h264s(frames),
DataFormat::H265 => vf.set_h265s(frames),
}
msg_out.set_video_frame(vf); msg_out.set_video_frame(vf);
Ok(msg_out) Ok(msg_out)
} else { } else {
Err(anyhow!("no valid frame")) Err(anyhow!("no valid frame"))
} }
} }
DataFormat::H265 => {
let mut h265s = Vec::new();
for frame in self.encode(frame).with_context(|| "Failed to encode")? {
h265s.push(H265 {
data: frame.data,
pts: frame.pts,
..Default::default()
});
}
if h265s.len() > 0 {
vf.set_h265s(H265s {
h265s,
..Default::default()
});
msg_out.set_video_frame(vf);
Ok(msg_out)
} else {
Err(anyhow!("no valid frame"))
}
}
}
}
fn use_yuv(&self) -> bool { fn use_yuv(&self) -> bool {
false false
@ -174,7 +151,7 @@ impl HwEncoder {
}; };
let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx)); let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx));
if write { if write {
let _ = set_config(CFG_KEY_ENCODER, &encoders) set_config(CFG_KEY_ENCODER, &encoders)
.map_err(|e| log::error!("{:?}", e)) .map_err(|e| log::error!("{:?}", e))
.ok(); .ok();
} }
@ -326,7 +303,11 @@ impl HwDecoderImage<'_> {
} }
fn get_config(k: &str) -> ResultType<CodecInfos> { fn get_config(k: &str) -> ResultType<CodecInfos> {
let v = HwCodecConfig::get_option(k); let v = HwCodecConfig::load()
.options
.get(k)
.unwrap_or(&"".to_owned())
.to_owned();
match CodecInfos::deserialize(&v) { match CodecInfos::deserialize(&v) {
Ok(v) => Ok(v), Ok(v) => Ok(v),
Err(_) => Err(anyhow!("Failed to get config:{}", k)), Err(_) => Err(anyhow!("Failed to get config:{}", k)),
@ -336,26 +317,28 @@ fn get_config(k: &str) -> ResultType<CodecInfos> {
fn set_config(k: &str, v: &CodecInfos) -> ResultType<()> { fn set_config(k: &str, v: &CodecInfos) -> ResultType<()> {
match v.serialize() { match v.serialize() {
Ok(v) => { Ok(v) => {
HwCodecConfig::set_option(k.to_owned(), v); let mut config = HwCodecConfig::load();
config.options.insert(k.to_owned(), v);
config.store();
Ok(()) Ok(())
} }
Err(_) => Err(anyhow!("Failed to set config:{}", k)), Err(_) => Err(anyhow!("Failed to set config:{}", k)),
} }
} }
pub fn check_config() -> Option<HashMap<String, String>> { pub fn check_config() {
let (encoders, update_encoders) = HwEncoder::best(false, false); let (encoders, update_encoders) = HwEncoder::best(false, false);
let (decoders, update_decoders) = HwDecoder::best(false, false); let (decoders, update_decoders) = HwDecoder::best(false, false);
if update_encoders || update_decoders { if update_encoders || update_decoders {
if let Ok(encoders) = encoders.serialize() { if let Ok(encoders) = encoders.serialize() {
if let Ok(decoders) = decoders.serialize() { if let Ok(decoders) = decoders.serialize() {
return Some(HashMap::from([ let mut config = HwCodecConfig::load();
(CFG_KEY_ENCODER.to_owned(), encoders), config.options.insert(CFG_KEY_ENCODER.to_owned(), encoders);
(CFG_KEY_DECODER.to_owned(), decoders), config.options.insert(CFG_KEY_DECODER.to_owned(), decoders);
])); config.store();
return;
} }
} }
log::error!("Failed to serialize codec info"); log::error!("Failed to serialize codec info");
} }
None
} }

View File

@ -3,7 +3,7 @@
// https://github.com/rust-av/vpx-rs/blob/master/src/decoder.rs // https://github.com/rust-av/vpx-rs/blob/master/src/decoder.rs
use hbb_common::anyhow::{anyhow, Context}; use hbb_common::anyhow::{anyhow, Context};
use hbb_common::message_proto::{Message, VP9s, VideoFrame, VP9}; use hbb_common::message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame};
use hbb_common::ResultType; use hbb_common::ResultType;
use crate::codec::EncoderApi; use crate::codec::EncoderApi;
@ -277,10 +277,10 @@ impl VpxEncoder {
} }
#[inline] #[inline]
fn create_msg(vp9s: Vec<VP9>) -> Message { fn create_msg(vp9s: Vec<EncodedVideoFrame>) -> Message {
let mut msg_out = Message::new(); let mut msg_out = Message::new();
let mut vf = VideoFrame::new(); let mut vf = VideoFrame::new();
vf.set_vp9s(VP9s { vf.set_vp9s(EncodedVideoFrames {
frames: vp9s.into(), frames: vp9s.into(),
..Default::default() ..Default::default()
}); });
@ -289,8 +289,8 @@ impl VpxEncoder {
} }
#[inline] #[inline]
fn create_frame(frame: &EncodeFrame) -> VP9 { fn create_frame(frame: &EncodeFrame) -> EncodedVideoFrame {
VP9 { EncodedVideoFrame {
data: frame.data.to_vec(), data: frame.data.to_vec(),
key: frame.key, key: frame.key,
pts: frame.pts, pts: frame.pts,

View File

@ -1,8 +1,6 @@
use crate::rendezvous_mediator::RendezvousMediator; use crate::rendezvous_mediator::RendezvousMediator;
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use clipboard::ClipbaordFile; pub use clipboard::ClipbaordFile;
#[cfg(feature = "hwcodec")]
use hbb_common::config::HwCodecConfig;
use hbb_common::{ use hbb_common::{
allow_err, bail, bytes, allow_err, bail, bytes,
bytes_codec::BytesCodec, bytes_codec::BytesCodec,
@ -129,8 +127,6 @@ pub enum Data {
ClipbaordFile(ClipbaordFile), ClipbaordFile(ClipbaordFile),
ClipboardFileEnabled(bool), ClipboardFileEnabled(bool),
PrivacyModeState((i32, PrivacyModeState)), PrivacyModeState((i32, PrivacyModeState)),
#[cfg(feature = "hwcodec")]
HwCodecConfig(Option<HashMap<String, String>>),
} }
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
@ -340,12 +336,7 @@ async fn handle(data: Data, stream: &mut Connection) {
.await .await
); );
} }
#[cfg(feature = "hwcodec")]
Data::HwCodecConfig(Some(config)) => {
for (k, v) in config {
HwCodecConfig::set_option(k, v);
}
}
_ => {} _ => {}
} }
} }
@ -645,20 +636,3 @@ pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> {
.await?; .await?;
Ok(()) Ok(())
} }
#[cfg(feature = "hwcodec")]
#[tokio::main]
pub async fn check_hwcodec_config() {
if let Some(config) = scrap::hwcodec::check_config() {
match connect(1000, "").await {
Ok(mut conn) => {
if conn.send(&Data::HwCodecConfig(Some(config))).await.is_err() {
log::error!("Failed to send hwcodec config by ipc");
}
}
Err(err) => {
log::info!("Failed to connect ipc: {:?}", err);
}
}
}
}

View File

@ -70,15 +70,6 @@ fn main() {
} }
if args.is_empty() { if args.is_empty() {
std::thread::spawn(move || start_server(false)); std::thread::spawn(move || start_server(false));
#[cfg(feature = "hwcodec")]
if let Ok(exe) = std::env::current_exe() {
std::thread::spawn(move || {
std::process::Command::new(exe)
.arg("--check-hwcodec-config")
.status()
.ok()
});
}
} else { } else {
#[cfg(windows)] #[cfg(windows)]
{ {
@ -117,10 +108,6 @@ fn main() {
args.len() > 1, args.len() > 1,
)); ));
return; return;
} else if args[0] == "--check-hwcodec-config" {
#[cfg(feature = "hwcodec")]
ipc::check_hwcodec_config();
return;
} }
} }
if args[0] == "--remove" { if args[0] == "--remove" {
@ -164,6 +151,10 @@ fn main() {
ipc::set_password(args[1].to_owned()).unwrap(); ipc::set_password(args[1].to_owned()).unwrap();
} }
return; return;
} else if args[0] == "--check-hwcodec-config" {
#[cfg(feature = "hwcodec")]
scrap::hwcodec::check_config();
return;
} }
} }
ui::start(&mut args[..]); ui::start(&mut args[..]);

View File

@ -321,6 +321,15 @@ pub async fn start_server(is_server: bool) {
std::process::exit(-1); std::process::exit(-1);
} }
}); });
#[cfg(feature = "hwcodec")]
if let Ok(exe) = std::env::current_exe() {
std::thread::spawn(move || {
std::process::Command::new(exe)
.arg("--check-hwcodec-config")
.status()
.ok()
});
}
#[cfg(windows)] #[cfg(windows)]
crate::platform::windows::bootstrap(); crate::platform::windows::bootstrap();
input_service::fix_key_down_timeout_loop(); input_service::fix_key_down_timeout_loop();

View File

@ -573,10 +573,10 @@ fn check_privacy_mode_changed(sp: &GenericService, privacy_mode_id: i32) -> Resu
#[inline] #[inline]
#[cfg(any(target_os = "android", target_os = "ios"))] #[cfg(any(target_os = "android", target_os = "ios"))]
fn create_msg(vp9s: Vec<VP9>) -> Message { fn create_msg(vp9s: Vec<EncodedVideoFrame>) -> Message {
let mut msg_out = Message::new(); let mut msg_out = Message::new();
let mut vf = VideoFrame::new(); let mut vf = VideoFrame::new();
vf.set_vp9s(VP9s { vf.set_vp9s(EncodedVideoFrames {
frames: vp9s.into(), frames: vp9s.into(),
..Default::default() ..Default::default()
}); });
@ -622,7 +622,7 @@ pub fn handle_one_frame_encoded(
Ok(()) Ok(())
})?; })?;
let mut send_conn_ids: HashSet<i32> = Default::default(); let mut send_conn_ids: HashSet<i32> = Default::default();
let vp9_frame = VP9 { let vp9_frame = EncodedVideoFrame {
data: frame.to_vec(), data: frame.to_vec(),
key: true, key: true,
pts: ms, pts: ms,