mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
add zero copy mode hareware codec for windows (#6778)
Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
@@ -233,6 +233,8 @@ pub struct Connection {
|
||||
auto_disconnect_timer: Option<(Instant, u64)>,
|
||||
authed_conn_id: Option<self::raii::AuthedConnID>,
|
||||
file_remove_log_control: FileRemoveLogControl,
|
||||
#[cfg(feature = "gpucodec")]
|
||||
supported_encoding_flag: (bool, Option<bool>),
|
||||
}
|
||||
|
||||
impl ConnInner {
|
||||
@@ -377,6 +379,8 @@ impl Connection {
|
||||
auto_disconnect_timer: None,
|
||||
authed_conn_id: None,
|
||||
file_remove_log_control: FileRemoveLogControl::new(id),
|
||||
#[cfg(feature = "gpucodec")]
|
||||
supported_encoding_flag: (false, None),
|
||||
};
|
||||
let addr = hbb_common::try_into_v4(addr);
|
||||
if !conn.on_open(addr).await {
|
||||
@@ -657,6 +661,8 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
conn.file_remove_log_control.on_timer().drain(..).map(|x| conn.send_to_cm(x)).count();
|
||||
#[cfg(feature = "gpucodec")]
|
||||
conn.update_supported_encoding();
|
||||
}
|
||||
_ = test_delay_timer.tick() => {
|
||||
if last_recv_time.elapsed() >= SEC30 {
|
||||
@@ -1112,7 +1118,9 @@ impl Connection {
|
||||
pi.platform_additions = serde_json::to_string(&platform_additions).unwrap_or("".into());
|
||||
}
|
||||
|
||||
pi.encoding = Some(scrap::codec::Encoder::supported_encoding()).into();
|
||||
let supported_encoding = scrap::codec::Encoder::supported_encoding();
|
||||
log::info!("peer info supported_encoding: {:?}", supported_encoding);
|
||||
pi.encoding = Some(supported_encoding).into();
|
||||
|
||||
if self.port_forward_socket.is_some() {
|
||||
let mut msg_out = Message::new();
|
||||
@@ -1454,23 +1462,15 @@ impl Connection {
|
||||
}
|
||||
|
||||
fn update_codec_on_login(&self) {
|
||||
use scrap::codec::{Encoder, EncodingUpdate::*};
|
||||
if let Some(o) = self.lr.clone().option.as_ref() {
|
||||
if let Some(q) = o.supported_decoding.clone().take() {
|
||||
scrap::codec::Encoder::update(
|
||||
self.inner.id(),
|
||||
scrap::codec::EncodingUpdate::New(q),
|
||||
);
|
||||
Encoder::update(Update(self.inner.id(), q));
|
||||
} else {
|
||||
scrap::codec::Encoder::update(
|
||||
self.inner.id(),
|
||||
scrap::codec::EncodingUpdate::NewOnlyVP9,
|
||||
);
|
||||
Encoder::update(NewOnlyVP9(self.inner.id()));
|
||||
}
|
||||
} else {
|
||||
scrap::codec::Encoder::update(
|
||||
self.inner.id(),
|
||||
scrap::codec::EncodingUpdate::NewOnlyVP9,
|
||||
);
|
||||
Encoder::update(NewOnlyVP9(self.inner.id()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2537,7 +2537,7 @@ impl Connection {
|
||||
.user_custom_fps(self.inner.id(), o.custom_fps as _);
|
||||
}
|
||||
if let Some(q) = o.supported_decoding.clone().take() {
|
||||
scrap::codec::Encoder::update(self.inner.id(), scrap::codec::EncodingUpdate::New(q));
|
||||
scrap::codec::Encoder::update(scrap::codec::EncodingUpdate::Update(self.inner.id(), q));
|
||||
}
|
||||
if let Ok(q) = o.lock_after_session_end.enum_value() {
|
||||
if q != BoolOption::NotSet {
|
||||
@@ -2904,6 +2904,24 @@ impl Connection {
|
||||
.as_mut()
|
||||
.map(|t| t.0 = Instant::now());
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
fn update_supported_encoding(&mut self) {
|
||||
let not_use = Some(scrap::gpucodec::GpuEncoder::not_use());
|
||||
if !self.authorized
|
||||
|| self.supported_encoding_flag.0 && self.supported_encoding_flag.1 == not_use
|
||||
{
|
||||
return;
|
||||
}
|
||||
let mut misc: Misc = Misc::new();
|
||||
let supported_encoding = scrap::codec::Encoder::supported_encoding();
|
||||
log::info!("update supported encoding: {:?}", supported_encoding);
|
||||
misc.set_supported_encoding(supported_encoding);
|
||||
let mut msg = Message::new();
|
||||
msg.set_misc(misc);
|
||||
self.inner.send(msg.into());
|
||||
self.supported_encoding_flag = (true, not_use);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_switch_sides_uuid(id: String, uuid: uuid::Uuid) {
|
||||
@@ -3367,7 +3385,7 @@ mod raii {
|
||||
impl Drop for AuthedConnID {
|
||||
fn drop(&mut self) {
|
||||
if self.1 == AuthConnType::Remote {
|
||||
scrap::codec::Encoder::update(self.0, scrap::codec::EncodingUpdate::Remove);
|
||||
scrap::codec::Encoder::update(scrap::codec::EncodingUpdate::Remove(self.0));
|
||||
}
|
||||
AUTHED_CONNS.lock().unwrap().retain(|&c| c.0 != self.0);
|
||||
let remote_count = AUTHED_CONNS
|
||||
|
||||
@@ -188,6 +188,11 @@ fn check_get_displays_changed_msg() -> Option<Message> {
|
||||
get_displays_msg()
|
||||
}
|
||||
|
||||
pub fn check_displays_changed() -> ResultType<()> {
|
||||
check_update_displays(&try_get_displays()?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_displays_msg() -> Option<Message> {
|
||||
let displays = SYNC_DISPLAYS.lock().unwrap().get_update_sync_displays()?;
|
||||
Some(displays_to_msg(displays))
|
||||
|
||||
@@ -8,7 +8,9 @@ use hbb_common::{
|
||||
tokio::{self, sync::mpsc},
|
||||
ResultType,
|
||||
};
|
||||
use scrap::{Capturer, Frame, TraitCapturer, TraitFrame};
|
||||
#[cfg(feature = "gpucodec")]
|
||||
use scrap::AdapterDevice;
|
||||
use scrap::{Capturer, Frame, TraitCapturer, TraitPixelBuffer};
|
||||
use shared_memory::*;
|
||||
use std::{
|
||||
mem::size_of,
|
||||
@@ -381,21 +383,26 @@ pub mod server {
|
||||
}
|
||||
}
|
||||
match c.as_mut().map(|f| f.frame(spf)) {
|
||||
Some(Ok(f)) => {
|
||||
utils::set_frame_info(
|
||||
&shmem,
|
||||
FrameInfo {
|
||||
length: f.data().len(),
|
||||
width: display_width,
|
||||
height: display_height,
|
||||
},
|
||||
);
|
||||
shmem.write(ADDR_CAPTURE_FRAME, f.data());
|
||||
shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE));
|
||||
utils::increase_counter(shmem.as_ptr().add(ADDR_CAPTURE_FRAME_COUNTER));
|
||||
first_frame_captured = true;
|
||||
dxgi_failed_times = 0;
|
||||
}
|
||||
Some(Ok(f)) => match f {
|
||||
Frame::PixelBuffer(f) => {
|
||||
utils::set_frame_info(
|
||||
&shmem,
|
||||
FrameInfo {
|
||||
length: f.data().len(),
|
||||
width: display_width,
|
||||
height: display_height,
|
||||
},
|
||||
);
|
||||
shmem.write(ADDR_CAPTURE_FRAME, f.data());
|
||||
shmem.write(ADDR_CAPTURE_WOULDBLOCK, &utils::i32_to_vec(TRUE));
|
||||
utils::increase_counter(shmem.as_ptr().add(ADDR_CAPTURE_FRAME_COUNTER));
|
||||
first_frame_captured = true;
|
||||
dxgi_failed_times = 0;
|
||||
}
|
||||
Frame::Texture(_) => {
|
||||
// should not happen
|
||||
}
|
||||
},
|
||||
Some(Err(e)) => {
|
||||
if e.kind() != std::io::ErrorKind::WouldBlock {
|
||||
// DXGI_ERROR_INVALID_CALL after each success on Microsoft GPU driver
|
||||
@@ -510,11 +517,10 @@ pub mod server {
|
||||
|
||||
// functions called in main process.
|
||||
pub mod client {
|
||||
use hbb_common::{anyhow::Context, message_proto::PointerDeviceEvent};
|
||||
|
||||
use crate::display_service;
|
||||
|
||||
use super::*;
|
||||
use crate::display_service;
|
||||
use hbb_common::{anyhow::Context, message_proto::PointerDeviceEvent};
|
||||
use scrap::PixelBuffer;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref RUNNING: Arc<Mutex<bool>> = Default::default();
|
||||
@@ -705,7 +711,11 @@ pub mod client {
|
||||
}
|
||||
let frame_ptr = base.add(ADDR_CAPTURE_FRAME);
|
||||
let data = slice::from_raw_parts(frame_ptr, (*frame_info).length);
|
||||
Ok(Frame::new(data, self.width, self.height))
|
||||
Ok(Frame::PixelBuffer(PixelBuffer::new(
|
||||
data,
|
||||
self.width,
|
||||
self.height,
|
||||
)))
|
||||
} else {
|
||||
let ptr = base.add(ADDR_CAPTURE_WOULDBLOCK);
|
||||
let wouldblock = utils::ptr_to_i32(ptr);
|
||||
@@ -732,6 +742,14 @@ pub mod client {
|
||||
fn set_gdi(&mut self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
fn device(&self) -> AdapterDevice {
|
||||
AdapterDevice::default()
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
fn set_output_texture(&mut self, _texture: bool) {}
|
||||
}
|
||||
|
||||
pub(super) fn start_ipc_server() -> mpsc::UnboundedSender<Data> {
|
||||
|
||||
@@ -43,6 +43,7 @@ pub struct VideoQoS {
|
||||
quality: Quality,
|
||||
users: HashMap<i32, UserData>,
|
||||
bitrate_store: u32,
|
||||
support_abr: HashMap<usize, bool>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
@@ -80,6 +81,7 @@ impl Default for VideoQoS {
|
||||
quality: Default::default(),
|
||||
users: Default::default(),
|
||||
bitrate_store: 0,
|
||||
support_abr: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,8 +120,8 @@ impl VideoQoS {
|
||||
self.users.iter().any(|u| u.1.record)
|
||||
}
|
||||
|
||||
pub fn abr_enabled() -> bool {
|
||||
"N" != Config::get_option("enable-abr")
|
||||
pub fn set_support_abr(&mut self, display_idx: usize, support: bool) {
|
||||
self.support_abr.insert(display_idx, support);
|
||||
}
|
||||
|
||||
pub fn refresh(&mut self, typ: Option<RefreshType>) {
|
||||
@@ -176,7 +178,9 @@ impl VideoQoS {
|
||||
let mut quality = latest_quality;
|
||||
|
||||
// network delay
|
||||
if Self::abr_enabled() && typ != Some(RefreshType::SetImageQuality) {
|
||||
let abr_enabled =
|
||||
Config::get_option("enable-abr") != "N" && self.support_abr.iter().all(|e| *e.1);
|
||||
if abr_enabled && typ != Some(RefreshType::SetImageQuality) {
|
||||
// max delay
|
||||
let delay = self
|
||||
.users
|
||||
|
||||
@@ -42,15 +42,18 @@ use hbb_common::{
|
||||
Mutex as TokioMutex,
|
||||
},
|
||||
};
|
||||
#[cfg(feature = "gpucodec")]
|
||||
use scrap::gpucodec::{GpuEncoder, GpuEncoderConfig};
|
||||
#[cfg(feature = "hwcodec")]
|
||||
use scrap::hwcodec::{HwEncoder, HwEncoderConfig};
|
||||
#[cfg(not(windows))]
|
||||
use scrap::Capturer;
|
||||
use scrap::{
|
||||
aom::AomEncoderConfig,
|
||||
codec::{Encoder, EncoderCfg, HwEncoderConfig, Quality},
|
||||
convert_to_yuv,
|
||||
codec::{Encoder, EncoderCfg, EncodingUpdate, Quality},
|
||||
record::{Recorder, RecorderContext},
|
||||
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
|
||||
CodecName, Display, Frame, TraitCapturer, TraitFrame,
|
||||
CodecName, Display, Frame, TraitCapturer,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use std::sync::Once;
|
||||
@@ -363,6 +366,7 @@ fn get_capturer(current: usize, portable_service_running: bool) -> ResultType<Ca
|
||||
}
|
||||
|
||||
fn run(vs: VideoService) -> ResultType<()> {
|
||||
let _raii = Raii::new(vs.idx);
|
||||
// Wayland only support one video capturer for now. It is ok to call ensure_inited() here.
|
||||
//
|
||||
// ensure_inited() is needed because clear() may be called.
|
||||
@@ -391,21 +395,33 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
video_qos.refresh(None);
|
||||
let mut spf;
|
||||
let mut quality = video_qos.quality();
|
||||
let abr = VideoQoS::abr_enabled();
|
||||
log::info!("initial quality: {quality:?}, abr enabled: {abr}");
|
||||
let codec_name = Encoder::negotiated_codec();
|
||||
let recorder = get_recorder(c.width, c.height, &codec_name);
|
||||
let last_recording = recorder.lock().unwrap().is_some() || video_qos.record();
|
||||
let record_incoming = !Config::get_option("allow-auto-record-incoming").is_empty();
|
||||
let client_record = video_qos.record();
|
||||
drop(video_qos);
|
||||
let encoder_cfg = get_encoder_config(&c, quality, last_recording);
|
||||
|
||||
let encoder_cfg = get_encoder_config(
|
||||
&c,
|
||||
display_idx,
|
||||
quality,
|
||||
client_record || record_incoming,
|
||||
last_portable_service_running,
|
||||
);
|
||||
Encoder::set_fallback(&encoder_cfg);
|
||||
let codec_name = Encoder::negotiated_codec();
|
||||
let recorder = get_recorder(c.width, c.height, &codec_name, record_incoming);
|
||||
let mut encoder;
|
||||
let use_i444 = Encoder::use_i444(&encoder_cfg);
|
||||
match Encoder::new(encoder_cfg.clone(), use_i444) {
|
||||
Ok(x) => encoder = x,
|
||||
Err(err) => bail!("Failed to create encoder: {}", err),
|
||||
}
|
||||
#[cfg(feature = "gpucodec")]
|
||||
c.set_output_texture(encoder.input_texture());
|
||||
VIDEO_QOS.lock().unwrap().store_bitrate(encoder.bitrate());
|
||||
VIDEO_QOS
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_support_abr(display_idx, encoder.support_abr());
|
||||
log::info!("initial quality: {quality:?}");
|
||||
|
||||
if sp.is_option_true(OPTION_REFRESH) {
|
||||
sp.set_option_bool(OPTION_REFRESH, false);
|
||||
@@ -439,8 +455,7 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
allow_err!(encoder.set_quality(quality));
|
||||
video_qos.store_bitrate(encoder.bitrate());
|
||||
}
|
||||
let recording = recorder.lock().unwrap().is_some() || video_qos.record();
|
||||
if recording != last_recording {
|
||||
if client_record != video_qos.record() {
|
||||
bail!("SWITCH");
|
||||
}
|
||||
drop(video_qos);
|
||||
@@ -459,6 +474,11 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
if Encoder::use_i444(&encoder_cfg) != use_i444 {
|
||||
bail!("SWITCH");
|
||||
}
|
||||
#[cfg(all(windows, feature = "gpucodec"))]
|
||||
if c.is_gdi() && (codec_name == CodecName::H264GPU || codec_name == CodecName::H265GPU) {
|
||||
log::info!("changed to gdi when using gpucodec");
|
||||
bail!("SWITCH");
|
||||
}
|
||||
check_privacy_mode_changed(&sp, c.privacy_mode_id)?;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
@@ -482,7 +502,7 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
Ok(frame) => {
|
||||
let time = now - start;
|
||||
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
|
||||
if frame.data().len() != 0 {
|
||||
if frame.valid() {
|
||||
let send_conn_ids = handle_one_frame(
|
||||
display_idx,
|
||||
&sp,
|
||||
@@ -533,6 +553,8 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
// Get display information again immediately after error.
|
||||
crate::display_service::check_displays_changed().ok();
|
||||
// This check may be redundant, but it is better to be safe.
|
||||
// The previous check in `sp.is_option_true(OPTION_REFRESH)` block may be enough.
|
||||
try_broadcast_display_changed(&sp, display_idx, &c)?;
|
||||
@@ -576,36 +598,159 @@ fn run(vs: VideoService) -> ResultType<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_encoder_config(c: &CapturerInfo, quality: Quality, recording: bool) -> EncoderCfg {
|
||||
struct Raii(usize);
|
||||
|
||||
impl Raii {
|
||||
fn new(display_idx: usize) -> Self {
|
||||
Raii(display_idx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Raii {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "gpucodec")]
|
||||
GpuEncoder::set_not_use(self.0, false);
|
||||
VIDEO_QOS.lock().unwrap().set_support_abr(self.0, true);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_encoder_config(
|
||||
c: &CapturerInfo,
|
||||
_display_idx: usize,
|
||||
quality: Quality,
|
||||
record: bool,
|
||||
_portable_service: bool,
|
||||
) -> EncoderCfg {
|
||||
#[cfg(all(windows, feature = "gpucodec"))]
|
||||
if _portable_service || c.is_gdi() {
|
||||
log::info!("gdi:{}, portable:{}", c.is_gdi(), _portable_service);
|
||||
GpuEncoder::set_not_use(_display_idx, true);
|
||||
}
|
||||
#[cfg(feature = "gpucodec")]
|
||||
Encoder::update(EncodingUpdate::Check);
|
||||
// https://www.wowza.com/community/t/the-correct-keyframe-interval-in-obs-studio/95162
|
||||
let keyframe_interval = if recording { Some(240) } else { None };
|
||||
match Encoder::negotiated_codec() {
|
||||
scrap::CodecName::H264(name) | scrap::CodecName::H265(name) => {
|
||||
EncoderCfg::HW(HwEncoderConfig {
|
||||
name,
|
||||
width: c.width,
|
||||
height: c.height,
|
||||
quality,
|
||||
let keyframe_interval = if record { Some(240) } else { None };
|
||||
let negotiated_codec = Encoder::negotiated_codec();
|
||||
match negotiated_codec.clone() {
|
||||
CodecName::H264GPU | CodecName::H265GPU => {
|
||||
#[cfg(feature = "gpucodec")]
|
||||
if let Some(feature) = GpuEncoder::try_get(&c.device(), negotiated_codec.clone()) {
|
||||
EncoderCfg::GPU(GpuEncoderConfig {
|
||||
device: c.device(),
|
||||
width: c.width,
|
||||
height: c.height,
|
||||
quality,
|
||||
feature,
|
||||
keyframe_interval,
|
||||
})
|
||||
} else {
|
||||
handle_hw_encoder(
|
||||
negotiated_codec.clone(),
|
||||
c.width,
|
||||
c.height,
|
||||
quality as _,
|
||||
keyframe_interval,
|
||||
)
|
||||
}
|
||||
#[cfg(not(feature = "gpucodec"))]
|
||||
handle_hw_encoder(
|
||||
negotiated_codec.clone(),
|
||||
c.width,
|
||||
c.height,
|
||||
quality as _,
|
||||
keyframe_interval,
|
||||
})
|
||||
)
|
||||
}
|
||||
name @ (scrap::CodecName::VP8 | scrap::CodecName::VP9) => {
|
||||
EncoderCfg::VPX(VpxEncoderConfig {
|
||||
width: c.width as _,
|
||||
height: c.height as _,
|
||||
quality,
|
||||
codec: if name == scrap::CodecName::VP8 {
|
||||
VpxVideoCodecId::VP8
|
||||
} else {
|
||||
VpxVideoCodecId::VP9
|
||||
},
|
||||
keyframe_interval,
|
||||
})
|
||||
}
|
||||
scrap::CodecName::AV1 => EncoderCfg::AOM(AomEncoderConfig {
|
||||
CodecName::H264HW(_name) | CodecName::H265HW(_name) => handle_hw_encoder(
|
||||
negotiated_codec.clone(),
|
||||
c.width,
|
||||
c.height,
|
||||
quality as _,
|
||||
keyframe_interval,
|
||||
),
|
||||
name @ (CodecName::VP8 | CodecName::VP9) => EncoderCfg::VPX(VpxEncoderConfig {
|
||||
width: c.width as _,
|
||||
height: c.height as _,
|
||||
quality,
|
||||
codec: if name == CodecName::VP8 {
|
||||
VpxVideoCodecId::VP8
|
||||
} else {
|
||||
VpxVideoCodecId::VP9
|
||||
},
|
||||
keyframe_interval,
|
||||
}),
|
||||
CodecName::AV1 => EncoderCfg::AOM(AomEncoderConfig {
|
||||
width: c.width as _,
|
||||
height: c.height as _,
|
||||
quality,
|
||||
keyframe_interval,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_hw_encoder(
|
||||
_name: CodecName,
|
||||
width: usize,
|
||||
height: usize,
|
||||
quality: Quality,
|
||||
keyframe_interval: Option<usize>,
|
||||
) -> EncoderCfg {
|
||||
let f = || {
|
||||
#[cfg(feature = "hwcodec")]
|
||||
match _name {
|
||||
CodecName::H264GPU | CodecName::H265GPU => {
|
||||
if !scrap::codec::enable_hwcodec_option() {
|
||||
return Err(());
|
||||
}
|
||||
let is_h265 = _name == CodecName::H265GPU;
|
||||
let best = HwEncoder::best();
|
||||
if let Some(h264) = best.h264 {
|
||||
if !is_h265 {
|
||||
return Ok(EncoderCfg::HW(HwEncoderConfig {
|
||||
name: h264.name,
|
||||
width,
|
||||
height,
|
||||
quality,
|
||||
keyframe_interval,
|
||||
}));
|
||||
}
|
||||
}
|
||||
if let Some(h265) = best.h265 {
|
||||
if is_h265 {
|
||||
return Ok(EncoderCfg::HW(HwEncoderConfig {
|
||||
name: h265.name,
|
||||
width,
|
||||
height,
|
||||
quality,
|
||||
keyframe_interval,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
CodecName::H264HW(name) | CodecName::H265HW(name) => {
|
||||
return Ok(EncoderCfg::HW(HwEncoderConfig {
|
||||
name,
|
||||
width,
|
||||
height,
|
||||
quality,
|
||||
keyframe_interval,
|
||||
}));
|
||||
}
|
||||
_ => {
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
Err(())
|
||||
};
|
||||
|
||||
match f() {
|
||||
Ok(cfg) => cfg,
|
||||
_ => EncoderCfg::VPX(VpxEncoderConfig {
|
||||
width: width as _,
|
||||
height: height as _,
|
||||
quality,
|
||||
codec: VpxVideoCodecId::VP9,
|
||||
keyframe_interval,
|
||||
}),
|
||||
}
|
||||
@@ -615,8 +760,9 @@ fn get_recorder(
|
||||
width: usize,
|
||||
height: usize,
|
||||
codec_name: &CodecName,
|
||||
record_incoming: bool,
|
||||
) -> Arc<Mutex<Option<Recorder>>> {
|
||||
let recorder = if !Config::get_option("allow-auto-record-incoming").is_empty() {
|
||||
let recorder = if record_incoming {
|
||||
use crate::hbbs_http::record_upload;
|
||||
|
||||
let tx = if record_upload::is_enable() {
|
||||
@@ -678,18 +824,26 @@ fn handle_one_frame(
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let frame = frame.to(encoder.yuvfmt(), yuv, mid_data)?;
|
||||
let mut send_conn_ids: HashSet<i32> = Default::default();
|
||||
convert_to_yuv(&frame, encoder.yuvfmt(), yuv, mid_data)?;
|
||||
if let Ok(mut vf) = encoder.encode_to_message(yuv, ms) {
|
||||
vf.display = display as _;
|
||||
let mut msg = Message::new();
|
||||
msg.set_video_frame(vf);
|
||||
recorder
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.map(|r| r.write_message(&msg));
|
||||
send_conn_ids = sp.send_video_frame(msg);
|
||||
match encoder.encode_to_message(frame, ms) {
|
||||
Ok(mut vf) => {
|
||||
vf.display = display as _;
|
||||
let mut msg = Message::new();
|
||||
msg.set_video_frame(vf);
|
||||
recorder
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.map(|r| r.write_message(&msg));
|
||||
send_conn_ids = sp.send_video_frame(msg);
|
||||
}
|
||||
Err(e) => match e.to_string().as_str() {
|
||||
scrap::codec::ENCODE_NEED_SWITCH => {
|
||||
bail!("SWITCH");
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
Ok(send_conn_ids)
|
||||
}
|
||||
|
||||
@@ -191,8 +191,7 @@ pub(super) async fn check_init() -> ResultType<()> {
|
||||
maxy = max_height;
|
||||
|
||||
let capturer = Box::into_raw(Box::new(
|
||||
Capturer::new(display)
|
||||
.with_context(|| "Failed to create capturer")?,
|
||||
Capturer::new(display).with_context(|| "Failed to create capturer")?,
|
||||
));
|
||||
let capturer = CapturerPtr(capturer);
|
||||
let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo {
|
||||
|
||||
Reference in New Issue
Block a user