Merge branch 'master' of https://github.com/rustdesk/rustdesk
This commit is contained in:
@@ -11,7 +11,7 @@ protobuf = { version = "3.1", features = ["with-bytes"] }
|
||||
tokio = { version = "1.20", features = ["full"] }
|
||||
tokio-util = { version = "0.7", features = ["full"] }
|
||||
futures = "0.3"
|
||||
bytes = "1.1"
|
||||
bytes = { version = "1.2", features = ["serde"] }
|
||||
log = "0.4"
|
||||
env_logger = "0.9"
|
||||
socket2 = { version = "0.3", features = ["reuseport"] }
|
||||
|
||||
@@ -5,6 +5,10 @@ fn main() {
|
||||
.out_dir("src/protos")
|
||||
.inputs(&["protos/rendezvous.proto", "protos/message.proto"])
|
||||
.include("protos")
|
||||
.customize(
|
||||
protobuf_codegen::Customize::default()
|
||||
.tokio_bytes(true)
|
||||
)
|
||||
.run()
|
||||
.expect("Codegen failed.");
|
||||
}
|
||||
|
||||
@@ -72,6 +72,11 @@ message Features {
|
||||
bool privacy_mode = 1;
|
||||
}
|
||||
|
||||
message SupportedEncoding {
|
||||
bool h264 = 1;
|
||||
bool h265 = 2;
|
||||
}
|
||||
|
||||
message PeerInfo {
|
||||
string username = 1;
|
||||
string hostname = 2;
|
||||
@@ -82,6 +87,7 @@ message PeerInfo {
|
||||
string version = 7;
|
||||
int32 conn_id = 8;
|
||||
Features features = 9;
|
||||
SupportedEncoding encoding = 10;
|
||||
}
|
||||
|
||||
message LoginResponse {
|
||||
@@ -442,9 +448,17 @@ enum ImageQuality {
|
||||
}
|
||||
|
||||
message VideoCodecState {
|
||||
int32 ScoreVpx = 1;
|
||||
int32 ScoreH264 = 2;
|
||||
int32 ScoreH265 = 3;
|
||||
enum PerferCodec {
|
||||
Auto = 0;
|
||||
VPX = 1;
|
||||
H264 = 2;
|
||||
H265 = 3;
|
||||
}
|
||||
|
||||
int32 score_vpx = 1;
|
||||
int32 score_h264 = 2;
|
||||
int32 score_h265 = 3;
|
||||
PerferCodec perfer = 4;
|
||||
}
|
||||
|
||||
message OptionMessage {
|
||||
|
||||
@@ -978,6 +978,10 @@ impl HwCodecConfig {
|
||||
pub fn store(&self) {
|
||||
Config::store_(self, "_hwcodec");
|
||||
}
|
||||
|
||||
pub fn remove() {
|
||||
std::fs::remove_file(Config::file_("_hwcodec")).ok();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -50,5 +50,5 @@ gstreamer = { version = "0.16", optional = true }
|
||||
gstreamer-app = { version = "0.16", features = ["v1_10"], optional = true }
|
||||
gstreamer-video = { version = "0.16", optional = true }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dependencies]
|
||||
hwcodec = { git = "https://github.com/21pages/hwcodec", optional = true }
|
||||
|
||||
@@ -4,7 +4,7 @@ extern crate scrap;
|
||||
use std::fs::File;
|
||||
|
||||
#[cfg(windows)]
|
||||
use scrap::CapturerMag;
|
||||
use scrap::{CapturerMag, TraitCapturer};
|
||||
use scrap::{i420_to_rgb, Display};
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::time::Duration;
|
||||
extern crate scrap;
|
||||
|
||||
fn main() {
|
||||
use scrap::{Capturer, Display};
|
||||
use scrap::{Capturer, Display, TraitCapturer};
|
||||
use std::io::ErrorKind::WouldBlock;
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
@@ -18,7 +18,7 @@ use webm::mux;
|
||||
use webm::mux::Track;
|
||||
|
||||
use scrap::vpxcodec as vpx_encode;
|
||||
use scrap::{Capturer, Display, STRIDE_ALIGN};
|
||||
use scrap::{TraitCapturer, Capturer, Display, STRIDE_ALIGN};
|
||||
|
||||
const USAGE: &'static str = "
|
||||
Simple WebM screen capture.
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::io::ErrorKind::WouldBlock;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use scrap::{i420_to_rgb, Capturer, Display};
|
||||
use scrap::{i420_to_rgb, Capturer, Display, TraitCapturer};
|
||||
|
||||
fn main() {
|
||||
let n = Display::all().unwrap().len();
|
||||
|
||||
@@ -32,8 +32,12 @@ impl Capturer {
|
||||
pub fn height(&self) -> usize {
|
||||
self.display.height() as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame<'a>(&'a mut self, _timeout: Duration) -> io::Result<Frame<'a>> {
|
||||
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);
|
||||
|
||||
@@ -16,12 +16,15 @@ use hbb_common::{
|
||||
ResultType,
|
||||
};
|
||||
#[cfg(feature = "hwcodec")]
|
||||
use hbb_common::{config::Config2, lazy_static};
|
||||
use hbb_common::{
|
||||
config::{Config2, PeerConfig},
|
||||
lazy_static,
|
||||
message_proto::video_codec_state::PerferCodec,
|
||||
};
|
||||
|
||||
#[cfg(feature = "hwcodec")]
|
||||
lazy_static::lazy_static! {
|
||||
static ref PEER_DECODER_STATES: Arc<Mutex<HashMap<i32, VideoCodecState>>> = Default::default();
|
||||
static ref MY_DECODER_STATE: Arc<Mutex<VideoCodecState>> = Default::default();
|
||||
}
|
||||
const SCORE_VPX: i32 = 90;
|
||||
|
||||
@@ -102,7 +105,7 @@ impl Encoder {
|
||||
codec: Box::new(hw),
|
||||
}),
|
||||
Err(e) => {
|
||||
HwEncoder::best(true, true);
|
||||
check_config_process(true);
|
||||
Err(e)
|
||||
}
|
||||
},
|
||||
@@ -113,7 +116,6 @@ impl Encoder {
|
||||
|
||||
// TODO
|
||||
pub fn update_video_encoder(id: i32, update: EncoderUpdate) {
|
||||
log::info!("encoder update: {:?}", update);
|
||||
#[cfg(feature = "hwcodec")]
|
||||
{
|
||||
let mut states = PEER_DECODER_STATES.lock().unwrap();
|
||||
@@ -130,49 +132,75 @@ impl Encoder {
|
||||
}
|
||||
}
|
||||
}
|
||||
let current_encoder_name = HwEncoder::current_name();
|
||||
let name = HwEncoder::current_name();
|
||||
if states.len() > 0 {
|
||||
let (best, _) = HwEncoder::best(false, true);
|
||||
let best = HwEncoder::best();
|
||||
let enabled_h264 = best.h264.is_some()
|
||||
&& states.len() > 0
|
||||
&& states.iter().all(|(_, s)| s.ScoreH264 > 0);
|
||||
&& states.iter().all(|(_, s)| s.score_h264 > 0);
|
||||
let enabled_h265 = best.h265.is_some()
|
||||
&& states.len() > 0
|
||||
&& states.iter().all(|(_, s)| s.ScoreH265 > 0);
|
||||
&& states.iter().all(|(_, s)| s.score_h265 > 0);
|
||||
|
||||
// score encoder
|
||||
let mut score_vpx = SCORE_VPX;
|
||||
let mut score_h264 = best.h264.as_ref().map_or(0, |c| c.score);
|
||||
let mut score_h265 = best.h265.as_ref().map_or(0, |c| c.score);
|
||||
|
||||
// score decoder
|
||||
score_vpx += states.iter().map(|s| s.1.ScoreVpx).sum::<i32>();
|
||||
if enabled_h264 {
|
||||
score_h264 += states.iter().map(|s| s.1.ScoreH264).sum::<i32>();
|
||||
}
|
||||
if enabled_h265 {
|
||||
score_h265 += states.iter().map(|s| s.1.ScoreH265).sum::<i32>();
|
||||
// Preference first
|
||||
let mut preference = PerferCodec::Auto;
|
||||
let preferences: Vec<_> = states
|
||||
.iter()
|
||||
.filter(|(_, s)| {
|
||||
s.perfer == PerferCodec::VPX.into()
|
||||
|| s.perfer == PerferCodec::H264.into() && enabled_h264
|
||||
|| s.perfer == PerferCodec::H265.into() && enabled_h265
|
||||
})
|
||||
.map(|(_, s)| s.perfer)
|
||||
.collect();
|
||||
if preferences.len() > 0 && preferences.iter().all(|&p| p == preferences[0]) {
|
||||
preference = preferences[0].enum_value_or(PerferCodec::Auto);
|
||||
}
|
||||
|
||||
if enabled_h265 && score_h265 >= score_vpx && score_h265 >= score_h264 {
|
||||
*current_encoder_name.lock().unwrap() = Some(best.h265.unwrap().name);
|
||||
} else if enabled_h264 && score_h264 >= score_vpx && score_h264 >= score_h265 {
|
||||
*current_encoder_name.lock().unwrap() = Some(best.h264.unwrap().name);
|
||||
} else {
|
||||
*current_encoder_name.lock().unwrap() = None;
|
||||
match preference {
|
||||
PerferCodec::VPX => *name.lock().unwrap() = None,
|
||||
PerferCodec::H264 => {
|
||||
*name.lock().unwrap() = best.h264.map_or(None, |c| Some(c.name))
|
||||
}
|
||||
PerferCodec::H265 => {
|
||||
*name.lock().unwrap() = best.h265.map_or(None, |c| Some(c.name))
|
||||
}
|
||||
PerferCodec::Auto => {
|
||||
// score encoder
|
||||
let mut score_vpx = SCORE_VPX;
|
||||
let mut score_h264 = best.h264.as_ref().map_or(0, |c| c.score);
|
||||
let mut score_h265 = best.h265.as_ref().map_or(0, |c| c.score);
|
||||
|
||||
// score decoder
|
||||
score_vpx += states.iter().map(|s| s.1.score_vpx).sum::<i32>();
|
||||
if enabled_h264 {
|
||||
score_h264 += states.iter().map(|s| s.1.score_h264).sum::<i32>();
|
||||
}
|
||||
if enabled_h265 {
|
||||
score_h265 += states.iter().map(|s| s.1.score_h265).sum::<i32>();
|
||||
}
|
||||
|
||||
if enabled_h265 && score_h265 >= score_vpx && score_h265 >= score_h264 {
|
||||
*name.lock().unwrap() = best.h265.map_or(None, |c| Some(c.name));
|
||||
} else if enabled_h264
|
||||
&& score_h264 >= score_vpx
|
||||
&& score_h264 >= score_h265
|
||||
{
|
||||
*name.lock().unwrap() = best.h264.map_or(None, |c| Some(c.name));
|
||||
} else {
|
||||
*name.lock().unwrap() = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"connection count:{}, h264:{}, h265:{}, score: vpx({}), h264({}), h265({}), set current encoder name {:?}",
|
||||
"connection count:{}, used preference:{:?}, encoder:{:?}",
|
||||
states.len(),
|
||||
enabled_h264,
|
||||
enabled_h265,
|
||||
score_vpx,
|
||||
score_h264,
|
||||
score_h265,
|
||||
current_encoder_name.lock().unwrap()
|
||||
)
|
||||
preference,
|
||||
name.lock().unwrap()
|
||||
)
|
||||
} else {
|
||||
*current_encoder_name.lock().unwrap() = None;
|
||||
*name.lock().unwrap() = None;
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "hwcodec"))]
|
||||
@@ -192,57 +220,57 @@ impl Encoder {
|
||||
#[cfg(not(feature = "hwcodec"))]
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "hwcodec")]
|
||||
impl Drop for Decoder {
|
||||
fn drop(&mut self) {
|
||||
*MY_DECODER_STATE.lock().unwrap() = VideoCodecState {
|
||||
ScoreVpx: SCORE_VPX,
|
||||
..Default::default()
|
||||
};
|
||||
pub fn supported_encoding() -> (bool, bool) {
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if check_hwcodec_config() {
|
||||
let best = HwEncoder::best();
|
||||
(
|
||||
best.h264.as_ref().map_or(false, |c| c.score > 0),
|
||||
best.h265.as_ref().map_or(false, |c| c.score > 0),
|
||||
)
|
||||
} else {
|
||||
(false, false)
|
||||
}
|
||||
#[cfg(not(feature = "hwcodec"))]
|
||||
(false, false)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decoder {
|
||||
pub fn video_codec_state() -> VideoCodecState {
|
||||
// video_codec_state is mainted by creation and destruction of Decoder.
|
||||
// It has been ensured to use after Decoder's creation.
|
||||
pub fn video_codec_state(_id: &str) -> VideoCodecState {
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if check_hwcodec_config() {
|
||||
return MY_DECODER_STATE.lock().unwrap().clone();
|
||||
let best = HwDecoder::best();
|
||||
VideoCodecState {
|
||||
score_vpx: SCORE_VPX,
|
||||
score_h264: best.h264.map_or(0, |c| c.score),
|
||||
score_h265: best.h265.map_or(0, |c| c.score),
|
||||
perfer: Self::codec_preference(_id).into(),
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
return VideoCodecState {
|
||||
ScoreVpx: SCORE_VPX,
|
||||
score_vpx: SCORE_VPX,
|
||||
..Default::default()
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "hwcodec"))]
|
||||
VideoCodecState {
|
||||
ScoreVpx: SCORE_VPX,
|
||||
score_vpx: SCORE_VPX,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(config: DecoderCfg) -> Decoder {
|
||||
let vpx = VpxDecoder::new(config.vpx).unwrap();
|
||||
let decoder = Decoder {
|
||||
Decoder {
|
||||
vpx,
|
||||
#[cfg(feature = "hwcodec")]
|
||||
hw: HwDecoder::new_decoders(),
|
||||
#[cfg(feature = "hwcodec")]
|
||||
i420: vec![],
|
||||
};
|
||||
|
||||
#[cfg(feature = "hwcodec")]
|
||||
{
|
||||
let mut state = MY_DECODER_STATE.lock().unwrap();
|
||||
state.ScoreVpx = SCORE_VPX;
|
||||
state.ScoreH264 = decoder.hw.h264.as_ref().map_or(0, |d| d.info.score);
|
||||
state.ScoreH265 = decoder.hw.h265.as_ref().map_or(0, |d| d.info.score);
|
||||
}
|
||||
|
||||
decoder
|
||||
}
|
||||
|
||||
pub fn handle_video_frame(
|
||||
@@ -316,6 +344,23 @@ impl Decoder {
|
||||
}
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
#[cfg(feature = "hwcodec")]
|
||||
fn codec_preference(id: &str) -> PerferCodec {
|
||||
let codec = PeerConfig::load(id)
|
||||
.options
|
||||
.get("codec-preference")
|
||||
.map_or("".to_owned(), |c| c.to_owned());
|
||||
if codec == "vp9" {
|
||||
PerferCodec::VPX
|
||||
} else if codec == "h264" {
|
||||
PerferCodec::H264
|
||||
} else if codec == "h265" {
|
||||
PerferCodec::H265
|
||||
} else {
|
||||
PerferCodec::Auto
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "hwcodec")]
|
||||
|
||||
@@ -246,6 +246,7 @@ pub unsafe fn nv12_to_i420(
|
||||
#[cfg(feature = "hwcodec")]
|
||||
pub mod hw {
|
||||
use hbb_common::{anyhow::anyhow, ResultType};
|
||||
#[cfg(target_os = "windows")]
|
||||
use hwcodec::{ffmpeg::ffmpeg_linesize_offset_length, AVPixelFormat};
|
||||
|
||||
pub fn hw_bgra_to_i420(
|
||||
@@ -381,6 +382,8 @@ pub mod hw {
|
||||
src_stride_y: usize,
|
||||
src_stride_uv: usize,
|
||||
dst: &mut Vec<u8>,
|
||||
_i420: &mut Vec<u8>,
|
||||
_align: usize,
|
||||
) -> ResultType<()> {
|
||||
dst.resize(width * height * 4, 0);
|
||||
unsafe {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
use crate::dxgi;
|
||||
use std::io::ErrorKind::{NotFound, TimedOut, WouldBlock};
|
||||
use std::time::Duration;
|
||||
use std::{io, ops};
|
||||
use crate::{common::TraitCapturer, dxgi};
|
||||
use std::{
|
||||
io::{
|
||||
self,
|
||||
ErrorKind::{NotFound, TimedOut, WouldBlock},
|
||||
},
|
||||
ops,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
pub struct Capturer {
|
||||
inner: dxgi::Capturer,
|
||||
@@ -21,18 +26,6 @@ impl Capturer {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
self.inner.set_use_yuv(use_yuv);
|
||||
}
|
||||
|
||||
pub fn is_gdi(&self) -> bool {
|
||||
self.inner.is_gdi()
|
||||
}
|
||||
|
||||
pub fn set_gdi(&mut self) -> bool {
|
||||
self.inner.set_gdi()
|
||||
}
|
||||
|
||||
pub fn cancel_gdi(&mut self) {
|
||||
self.inner.cancel_gdi()
|
||||
}
|
||||
@@ -44,14 +37,28 @@ impl Capturer {
|
||||
pub fn height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
|
||||
impl TraitCapturer for Capturer {
|
||||
fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
self.inner.set_use_yuv(use_yuv);
|
||||
}
|
||||
|
||||
fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
|
||||
match self.inner.frame(timeout.as_millis() as _) {
|
||||
Ok(frame) => Ok(Frame(frame)),
|
||||
Err(ref error) if error.kind() == TimedOut => Err(WouldBlock.into()),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_gdi(&self) -> bool {
|
||||
self.inner.is_gdi()
|
||||
}
|
||||
|
||||
fn set_gdi(&mut self) -> bool {
|
||||
self.inner.set_gdi()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Frame<'a>(&'a [u8]);
|
||||
@@ -134,10 +141,6 @@ impl CapturerMag {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
self.inner.set_use_yuv(use_yuv)
|
||||
}
|
||||
|
||||
pub fn exclude(&mut self, cls: &str, name: &str) -> io::Result<bool> {
|
||||
self.inner.exclude(cls, name)
|
||||
}
|
||||
@@ -145,8 +148,23 @@ impl CapturerMag {
|
||||
pub fn get_rect(&self) -> ((i32, i32), usize, usize) {
|
||||
self.inner.get_rect()
|
||||
}
|
||||
pub fn frame<'a>(&'a mut self, _timeout_ms: Duration) -> io::Result<Frame<'a>> {
|
||||
}
|
||||
|
||||
impl TraitCapturer for CapturerMag {
|
||||
fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
self.inner.set_use_yuv(use_yuv)
|
||||
}
|
||||
|
||||
fn frame<'a>(&'a mut self, _timeout_ms: Duration) -> io::Result<Frame<'a>> {
|
||||
self.inner.frame(&mut self.data)?;
|
||||
Ok(Frame(&self.data))
|
||||
}
|
||||
|
||||
fn is_gdi(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn set_gdi(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use hbb_common::{
|
||||
config::HwCodecConfig,
|
||||
lazy_static, log,
|
||||
message_proto::{EncodedVideoFrame, EncodedVideoFrames, Message, VideoFrame},
|
||||
ResultType,
|
||||
ResultType, bytes::Bytes,
|
||||
};
|
||||
use hwcodec::{
|
||||
decode::{DecodeContext, DecodeFrame, Decoder},
|
||||
@@ -91,7 +91,7 @@ impl EncoderApi for HwEncoder {
|
||||
let mut frames = Vec::new();
|
||||
for frame in self.encode(frame).with_context(|| "Failed to encode")? {
|
||||
frames.push(EncodedVideoFrame {
|
||||
data: frame.data,
|
||||
data: Bytes::from(frame.data),
|
||||
pts: frame.pts as _,
|
||||
..Default::default()
|
||||
});
|
||||
@@ -123,40 +123,11 @@ impl EncoderApi for HwEncoder {
|
||||
}
|
||||
|
||||
impl HwEncoder {
|
||||
/// Get best encoders.
|
||||
///
|
||||
/// # Parameter
|
||||
/// `force_reset`: force to refresh config.
|
||||
/// `write`: write to config file.
|
||||
///
|
||||
/// # Return
|
||||
/// `CodecInfos`: infos.
|
||||
/// `bool`: whether the config is refreshed.
|
||||
pub fn best(force_reset: bool, write: bool) -> (CodecInfos, bool) {
|
||||
let config = get_config(CFG_KEY_ENCODER);
|
||||
if !force_reset && config.is_ok() {
|
||||
(config.unwrap(), false)
|
||||
} else {
|
||||
let ctx = EncodeContext {
|
||||
name: String::from(""),
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
pixfmt: DEFAULT_PIXFMT,
|
||||
align: HW_STRIDE_ALIGN as _,
|
||||
bitrate: 0,
|
||||
timebase: DEFAULT_TIME_BASE,
|
||||
gop: DEFAULT_GOP,
|
||||
quality: DEFAULT_HW_QUALITY,
|
||||
rc: DEFAULT_RC,
|
||||
};
|
||||
let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx));
|
||||
if write {
|
||||
set_config(CFG_KEY_ENCODER, &encoders)
|
||||
.map_err(|e| log::error!("{:?}", e))
|
||||
.ok();
|
||||
}
|
||||
(encoders, true)
|
||||
}
|
||||
pub fn best() -> CodecInfos {
|
||||
get_config(CFG_KEY_ENCODER).unwrap_or(CodecInfos {
|
||||
h264: None,
|
||||
h265: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn current_name() -> Arc<Mutex<Option<String>>> {
|
||||
@@ -207,24 +178,15 @@ pub struct HwDecoders {
|
||||
}
|
||||
|
||||
impl HwDecoder {
|
||||
/// See HwEncoder::best
|
||||
fn best(force_reset: bool, write: bool) -> (CodecInfos, bool) {
|
||||
let config = get_config(CFG_KEY_DECODER);
|
||||
if !force_reset && config.is_ok() {
|
||||
(config.unwrap(), false)
|
||||
} else {
|
||||
let decoders = CodecInfo::score(Decoder::avaliable_decoders());
|
||||
if write {
|
||||
set_config(CFG_KEY_DECODER, &decoders)
|
||||
.map_err(|e| log::error!("{:?}", e))
|
||||
.ok();
|
||||
}
|
||||
(decoders, true)
|
||||
}
|
||||
pub fn best() -> CodecInfos {
|
||||
get_config(CFG_KEY_DECODER).unwrap_or(CodecInfos {
|
||||
h264: None,
|
||||
h265: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_decoders() -> HwDecoders {
|
||||
let (best, _) = HwDecoder::best(false, true);
|
||||
let best = HwDecoder::best();
|
||||
let mut h264: Option<HwDecoder> = None;
|
||||
let mut h265: Option<HwDecoder> = None;
|
||||
let mut fail = false;
|
||||
@@ -242,7 +204,7 @@ impl HwDecoder {
|
||||
}
|
||||
}
|
||||
if fail {
|
||||
HwDecoder::best(true, true);
|
||||
check_config_process(true);
|
||||
}
|
||||
HwDecoders { h264, h265 }
|
||||
}
|
||||
@@ -314,31 +276,52 @@ fn get_config(k: &str) -> ResultType<CodecInfos> {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_config(k: &str, v: &CodecInfos) -> ResultType<()> {
|
||||
match v.serialize() {
|
||||
Ok(v) => {
|
||||
let mut config = HwCodecConfig::load();
|
||||
config.options.insert(k.to_owned(), v);
|
||||
config.store();
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => Err(anyhow!("Failed to set config:{}", k)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_config() {
|
||||
let (encoders, update_encoders) = HwEncoder::best(false, false);
|
||||
let (decoders, update_decoders) = HwDecoder::best(false, false);
|
||||
if update_encoders || update_decoders {
|
||||
if let Ok(encoders) = encoders.serialize() {
|
||||
if let Ok(decoders) = decoders.serialize() {
|
||||
let mut config = HwCodecConfig::load();
|
||||
config.options.insert(CFG_KEY_ENCODER.to_owned(), encoders);
|
||||
config.options.insert(CFG_KEY_DECODER.to_owned(), decoders);
|
||||
config.store();
|
||||
let ctx = EncodeContext {
|
||||
name: String::from(""),
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
pixfmt: DEFAULT_PIXFMT,
|
||||
align: HW_STRIDE_ALIGN as _,
|
||||
bitrate: 0,
|
||||
timebase: DEFAULT_TIME_BASE,
|
||||
gop: DEFAULT_GOP,
|
||||
quality: DEFAULT_HW_QUALITY,
|
||||
rc: DEFAULT_RC,
|
||||
};
|
||||
let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx));
|
||||
let decoders = CodecInfo::score(Decoder::avaliable_decoders());
|
||||
|
||||
if let Ok(old_encoders) = get_config(CFG_KEY_ENCODER) {
|
||||
if let Ok(old_decoders) = get_config(CFG_KEY_DECODER) {
|
||||
if encoders == old_encoders && decoders == old_decoders {
|
||||
return;
|
||||
}
|
||||
}
|
||||
log::error!("Failed to serialize codec info");
|
||||
}
|
||||
|
||||
if let Ok(encoders) = encoders.serialize() {
|
||||
if let Ok(decoders) = decoders.serialize() {
|
||||
let mut config = HwCodecConfig::load();
|
||||
config.options.insert(CFG_KEY_ENCODER.to_owned(), encoders);
|
||||
config.options.insert(CFG_KEY_DECODER.to_owned(), decoders);
|
||||
config.store();
|
||||
return;
|
||||
}
|
||||
}
|
||||
log::error!("Failed to serialize codec info");
|
||||
}
|
||||
|
||||
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()
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::common::{
|
||||
wayland,
|
||||
x11::{self, Frame},
|
||||
TraitCapturer,
|
||||
};
|
||||
use std::{io, time::Duration};
|
||||
|
||||
@@ -17,13 +18,6 @@ impl Capturer {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
match self {
|
||||
Capturer::X11(d) => d.set_use_yuv(use_yuv),
|
||||
Capturer::WAYLAND(d) => d.set_use_yuv(use_yuv),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
match self {
|
||||
Capturer::X11(d) => d.width(),
|
||||
@@ -37,8 +31,17 @@ impl Capturer {
|
||||
Capturer::WAYLAND(d) => d.height(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
|
||||
impl TraitCapturer for Capturer {
|
||||
fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
match self {
|
||||
Capturer::X11(d) => d.set_use_yuv(use_yuv),
|
||||
Capturer::WAYLAND(d) => d.set_use_yuv(use_yuv),
|
||||
}
|
||||
}
|
||||
|
||||
fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
|
||||
match self {
|
||||
Capturer::X11(d) => d.frame(timeout),
|
||||
Capturer::WAYLAND(d) => d.frame(timeout),
|
||||
|
||||
@@ -49,3 +49,13 @@ pub fn would_block_if_equal(old: &mut Vec<u128>, b: &[u8]) -> std::io::Result<()
|
||||
old.copy_from_slice(b);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub trait TraitCapturer {
|
||||
fn set_use_yuv(&mut self, use_yuv: bool);
|
||||
fn frame<'a>(&'a mut self, timeout: std::time::Duration) -> std::io::Result<Frame<'a>>;
|
||||
|
||||
#[cfg(windows)]
|
||||
fn is_gdi(&self) -> bool;
|
||||
#[cfg(windows)]
|
||||
fn set_gdi(&mut self) -> bool;
|
||||
}
|
||||
|
||||
@@ -50,8 +50,14 @@ impl Capturer {
|
||||
pub fn height(&self) -> usize {
|
||||
self.inner.height()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame<'a>(&'a mut self, _timeout_ms: std::time::Duration) -> io::Result<Frame<'a>> {
|
||||
impl crate::TraitCapturer for Capturer {
|
||||
fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
self.use_yuv = use_yuv;
|
||||
}
|
||||
|
||||
fn frame<'a>(&'a mut self, _timeout_ms: std::time::Duration) -> io::Result<Frame<'a>> {
|
||||
match self.frame.try_lock() {
|
||||
Ok(mut handle) => {
|
||||
let mut frame = None;
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::STRIDE_ALIGN;
|
||||
use super::vpx::{vp8e_enc_control_id::*, vpx_codec_err_t::*, *};
|
||||
use std::os::raw::{c_int, c_uint};
|
||||
use std::{ptr, slice};
|
||||
use hbb_common::bytes::Bytes;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum VpxVideoCodecId {
|
||||
@@ -291,7 +292,7 @@ impl VpxEncoder {
|
||||
#[inline]
|
||||
fn create_frame(frame: &EncodeFrame) -> EncodedVideoFrame {
|
||||
EncodedVideoFrame {
|
||||
data: frame.data.to_vec(),
|
||||
data: Bytes::from(frame.data.to_vec()),
|
||||
key: frame.key,
|
||||
pts: frame.pts,
|
||||
..Default::default()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::common::x11::Frame;
|
||||
use crate::common::{x11::Frame, TraitCapturer};
|
||||
use crate::wayland::{capturable::*, *};
|
||||
use std::{io, time::Duration};
|
||||
|
||||
@@ -14,10 +14,6 @@ impl Capturer {
|
||||
Ok(Capturer(display, r, yuv, Default::default()))
|
||||
}
|
||||
|
||||
pub fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
self.2 = use_yuv;
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
self.0.width()
|
||||
}
|
||||
@@ -25,8 +21,14 @@ impl Capturer {
|
||||
pub fn height(&self) -> usize {
|
||||
self.0.height()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
|
||||
impl TraitCapturer for Capturer {
|
||||
fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
self.2 = use_yuv;
|
||||
}
|
||||
|
||||
fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result<Frame<'a>> {
|
||||
match self.1.capture(timeout.as_millis() as _).map_err(map_err)? {
|
||||
PixelProvider::BGR0(w, h, x) => Ok(Frame(if self.2 {
|
||||
crate::common::bgra_to_i420(w as _, h as _, &x, &mut self.3);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::x11;
|
||||
use crate::{x11, common::TraitCapturer};
|
||||
use std::{io, ops, time::Duration};
|
||||
|
||||
pub struct Capturer(x11::Capturer);
|
||||
@@ -8,10 +8,6 @@ impl Capturer {
|
||||
x11::Capturer::new(display.0, yuv).map(Capturer)
|
||||
}
|
||||
|
||||
pub fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
self.0.set_use_yuv(use_yuv);
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
self.0.display().rect().w as usize
|
||||
}
|
||||
@@ -19,8 +15,14 @@ impl Capturer {
|
||||
pub fn height(&self) -> usize {
|
||||
self.0.display().rect().h as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame<'a>(&'a mut self, _timeout: Duration) -> io::Result<Frame<'a>> {
|
||||
impl TraitCapturer for Capturer {
|
||||
fn set_use_yuv(&mut self, use_yuv: bool) {
|
||||
self.0.set_use_yuv(use_yuv);
|
||||
}
|
||||
|
||||
fn frame<'a>(&'a mut self, _timeout: Duration) -> io::Result<Frame<'a>> {
|
||||
Ok(Frame(self.0.frame()?))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user