Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages
2023-03-31 16:10:52 +08:00
parent 02561c3fff
commit 78748271ac
22 changed files with 470 additions and 441 deletions

View File

@@ -44,9 +44,9 @@ use hbb_common::{
};
pub use helper::*;
use scrap::{
codec::{Decoder, DecoderCfg},
codec::Decoder,
record::{Recorder, RecorderContext},
ImageFormat, VpxDecoderConfig, VpxVideoCodecId,
ImageFormat,
};
use crate::{
@@ -917,12 +917,7 @@ impl VideoHandler {
/// Create a new video handler.
pub fn new() -> Self {
VideoHandler {
decoder: Decoder::new(DecoderCfg {
vpx: VpxDecoderConfig {
codec: VpxVideoCodecId::VP9,
num_threads: (num_cpus::get() / 2) as _,
},
}),
decoder: Decoder::new(),
rgb: Default::default(),
recorder: Default::default(),
record: false,
@@ -954,12 +949,7 @@ impl VideoHandler {
/// Reset the decoder.
pub fn reset(&mut self) {
self.decoder = Decoder::new(DecoderCfg {
vpx: VpxDecoderConfig {
codec: VpxVideoCodecId::VP9,
num_threads: 1,
},
});
self.decoder = Decoder::new();
}
/// Start or stop screen record.
@@ -973,7 +963,7 @@ impl VideoHandler {
filename: "".to_owned(),
width: w as _,
height: h as _,
codec_id: scrap::record::RecordCodecID::VP9,
format: scrap::CodecFormat::VP9,
tx: None,
})
.map_or(Default::default(), |r| Arc::new(Mutex::new(Some(r))));
@@ -999,7 +989,7 @@ pub struct LoginConfigHandler {
pub conn_id: i32,
features: Option<Features>,
session_id: u64,
pub supported_encoding: Option<(bool, bool)>,
pub supported_encoding: SupportedEncoding,
pub restarting_remote_device: bool,
pub force_relay: bool,
pub direct: Option<bool>,
@@ -1047,7 +1037,7 @@ impl LoginConfigHandler {
self.remember = !config.password.is_empty();
self.config = config;
self.session_id = rand::random();
self.supported_encoding = None;
self.supported_encoding = Default::default();
self.restarting_remote_device = false;
self.force_relay = !self.get_option("force-always-relay").is_empty() || force_relay;
self.direct = None;
@@ -1331,8 +1321,8 @@ impl LoginConfigHandler {
msg.disable_clipboard = BoolOption::Yes.into();
n += 1;
}
let state = Decoder::video_codec_state(&self.id);
msg.video_codec_state = hbb_common::protobuf::MessageField::some(state);
msg.supported_decoding =
hbb_common::protobuf::MessageField::some(Decoder::supported_decodings(Some(&self.id)));
n += 1;
if n > 0 {
@@ -1565,10 +1555,7 @@ impl LoginConfigHandler {
self.conn_id = pi.conn_id;
// no matter if change, for update file time
self.save_config(config);
#[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
{
self.supported_encoding = Some((pi.encoding.h264, pi.encoding.h265));
}
self.supported_encoding = pi.encoding.clone().unwrap_or_default();
}
pub fn get_remote_dir(&self) -> String {
@@ -1626,10 +1613,10 @@ impl LoginConfigHandler {
}
pub fn change_prefer_codec(&self) -> Message {
let state = scrap::codec::Decoder::video_codec_state(&self.id);
let decoding = scrap::codec::Decoder::supported_decodings(Some(&self.id));
let mut misc = Misc::new();
misc.set_option(OptionMessage {
video_codec_state: hbb_common::protobuf::MessageField::some(state),
supported_decoding: hbb_common::protobuf::MessageField::some(decoding),
..Default::default()
});
let mut msg_out = Message::new();

View File

@@ -1,37 +1,8 @@
use hbb_common::{
get_time,
message_proto::{video_frame, Message, VideoFrame, VoiceCallRequest, VoiceCallResponse},
message_proto::{Message, VoiceCallRequest, VoiceCallResponse},
};
#[derive(PartialEq, Debug, Clone)]
pub enum CodecFormat {
VP9,
H264,
H265,
Unknown,
}
impl From<&VideoFrame> for CodecFormat {
fn from(it: &VideoFrame) -> Self {
match it.union {
Some(video_frame::Union::Vp9s(_)) => CodecFormat::VP9,
Some(video_frame::Union::H264s(_)) => CodecFormat::H264,
Some(video_frame::Union::H265s(_)) => CodecFormat::H265,
_ => CodecFormat::Unknown,
}
}
}
impl ToString for CodecFormat {
fn to_string(&self) -> String {
match self {
CodecFormat::VP9 => "VP9".into(),
CodecFormat::H264 => "H264".into(),
CodecFormat::H265 => "H265".into(),
CodecFormat::Unknown => "Unknow".into(),
}
}
}
use scrap::CodecFormat;
#[derive(Debug, Default)]
pub struct QualityStatus {

View File

@@ -29,10 +29,10 @@ use hbb_common::tokio::{
time::{self, Duration, Instant, Interval},
};
use hbb_common::{allow_err, fs, get_time, log, message_proto::*, Stream};
use scrap::CodecFormat;
use crate::client::{
new_voice_call_request, Client, CodecFormat, MediaData, MediaSender, QualityStatus, MILLI1,
SEC30,
new_voice_call_request, Client, MediaData, MediaSender, QualityStatus, MILLI1, SEC30,
};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::common::{self, update_clipboard};
@@ -817,11 +817,10 @@ impl<T: InvokeUiSession> Remote<T> {
}
fn contains_key_frame(vf: &VideoFrame) -> bool {
use video_frame::Union::*;
match &vf.union {
Some(vf) => match vf {
video_frame::Union::Vp9s(f) => f.frames.iter().any(|e| e.key),
video_frame::Union::H264s(f) => f.frames.iter().any(|e| e.key),
video_frame::Union::H265s(f) => f.frames.iter().any(|e| e.key),
Vp8s(f) | Vp9s(f) | H264s(f) | H265s(f) => f.frames.iter().any(|e| e.key),
_ => false,
},
None => false,

View File

@@ -969,6 +969,13 @@ pub fn main_has_hwcodec() -> SyncReturn<bool> {
SyncReturn(has_hwcodec())
}
pub fn main_supported_hwdecodings() -> SyncReturn<String> {
let decoding = supported_hwdecodings();
let msg = HashMap::from([("h264", decoding.0), ("h265", decoding.1)]);
SyncReturn(serde_json::ser::to_string(&msg).unwrap_or("".to_owned()))
}
pub fn main_is_root() -> bool {
is_root()
}
@@ -1054,10 +1061,10 @@ pub fn session_send_note(id: String, note: String) {
}
}
pub fn session_supported_hwcodec(id: String) -> String {
pub fn session_alternative_codecs(id: String) -> String {
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
let (h264, h265) = session.supported_hwcodec();
let msg = HashMap::from([("h264", h264), ("h265", h265)]);
let (vp8, h264, h265) = session.alternative_codecs();
let msg = HashMap::from([("vp8", vp8), ("h264", h264), ("h265", h265)]);
serde_json::ser::to_string(&msg).unwrap_or("".to_owned())
} else {
String::new()

View File

@@ -533,7 +533,7 @@ impl Connection {
let _ = privacy_mode::turn_off_privacy(0);
}
video_service::notify_video_frame_fetched(id, None);
scrap::codec::Encoder::update_video_encoder(id, scrap::codec::EncoderUpdate::Remove);
scrap::codec::Encoder::update(id, scrap::codec::EncodingUpdate::Remove);
video_service::VIDEO_QOS.lock().unwrap().reset();
if conn.authorized {
password::update_temporary_password();
@@ -860,16 +860,7 @@ impl Connection {
}
}
#[cfg(feature = "hwcodec")]
{
let (h264, h265) = scrap::codec::Encoder::supported_encoding();
pi.encoding = Some(SupportedEncoding {
h264,
h265,
..Default::default()
})
.into();
}
pi.encoding = Some(scrap::codec::Encoder::supported_encoding()).into();
if self.port_forward_socket.is_some() {
let mut msg_out = Message::new();
@@ -1145,21 +1136,21 @@ impl Connection {
self.lr = lr.clone();
if let Some(o) = lr.option.as_ref() {
self.options_in_login = Some(o.clone());
if let Some(q) = o.video_codec_state.clone().take() {
scrap::codec::Encoder::update_video_encoder(
if let Some(q) = o.supported_decoding.clone().take() {
scrap::codec::Encoder::update(
self.inner.id(),
scrap::codec::EncoderUpdate::State(q),
scrap::codec::EncodingUpdate::New(q),
);
} else {
scrap::codec::Encoder::update_video_encoder(
scrap::codec::Encoder::update(
self.inner.id(),
scrap::codec::EncoderUpdate::DisableHwIfNotExist,
scrap::codec::EncodingUpdate::NewOnlyVP9,
);
}
} else {
scrap::codec::Encoder::update_video_encoder(
scrap::codec::Encoder::update(
self.inner.id(),
scrap::codec::EncoderUpdate::DisableHwIfNotExist,
scrap::codec::EncodingUpdate::NewOnlyVP9,
);
}
self.video_ack_required = lr.video_ack_required;
@@ -1758,11 +1749,8 @@ impl Connection {
.unwrap()
.update_user_fps(o.custom_fps as _);
}
if let Some(q) = o.video_codec_state.clone().take() {
scrap::codec::Encoder::update_video_encoder(
self.inner.id(),
scrap::codec::EncoderUpdate::State(q),
);
if let Some(q) = o.supported_decoding.clone().take() {
scrap::codec::Encoder::update(self.inner.id(), scrap::codec::EncodingUpdate::New(q));
}
if let Ok(q) = o.lock_after_session_end.enum_value() {
if q != BoolOption::NotSet {

View File

@@ -31,7 +31,7 @@ use scrap::{
codec::{Encoder, EncoderCfg, HwEncoderConfig},
record::{Recorder, RecorderContext},
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
Display, TraitCapturer,
CodecName, Display, TraitCapturer,
};
#[cfg(windows)]
use std::sync::Once;
@@ -468,21 +468,29 @@ fn run(sp: GenericService) -> ResultType<()> {
drop(video_qos);
log::info!("init bitrate={}, abr enabled:{}", bitrate, abr);
let encoder_cfg = match Encoder::current_hw_encoder_name() {
Some(codec_name) => EncoderCfg::HW(HwEncoderConfig {
codec_name,
width: c.width,
height: c.height,
bitrate: bitrate as _,
}),
None => EncoderCfg::VPX(VpxEncoderConfig {
width: c.width as _,
height: c.height as _,
timebase: [1, 1000], // Output timestamp precision
bitrate,
codec: VpxVideoCodecId::VP9,
num_threads: (num_cpus::get() / 2) as _,
}),
let encoder_cfg = match Encoder::negotiated_codec() {
scrap::CodecName::H264(name) | scrap::CodecName::H265(name) => {
EncoderCfg::HW(HwEncoderConfig {
name,
width: c.width,
height: c.height,
bitrate: bitrate as _,
})
}
name @ (scrap::CodecName::VP8 | scrap::CodecName::VP9) => {
EncoderCfg::VPX(VpxEncoderConfig {
width: c.width as _,
height: c.height as _,
timebase: [1, 1000], // Output timestamp precision
bitrate,
codec: if name == scrap::CodecName::VP8 {
VpxVideoCodecId::VP8
} else {
VpxVideoCodecId::VP9
},
num_threads: (num_cpus::get() / 2) as _,
})
}
};
let mut encoder;
@@ -526,7 +534,7 @@ fn run(sp: GenericService) -> ResultType<()> {
let mut try_gdi = 1;
#[cfg(windows)]
log::info!("gdi: {}", c.is_gdi());
let codec_name = Encoder::current_hw_encoder_name();
let codec_name = Encoder::negotiated_codec();
let recorder = get_recorder(c.width, c.height, &codec_name);
#[cfg(windows)]
start_uac_elevation_check();
@@ -557,7 +565,7 @@ fn run(sp: GenericService) -> ResultType<()> {
*SWITCH.lock().unwrap() = true;
bail!("SWITCH");
}
if codec_name != Encoder::current_hw_encoder_name() {
if codec_name != Encoder::negotiated_codec() {
bail!("SWITCH");
}
#[cfg(windows)]
@@ -603,8 +611,14 @@ fn run(sp: GenericService) -> ResultType<()> {
let time = now - start;
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
match frame {
scrap::Frame::VP8(data) => {
let send_conn_ids =
handle_one_frame_encoded(VpxVideoCodecId::VP8, &sp, data, ms)?;
frame_controller.set_send(now, send_conn_ids);
}
scrap::Frame::VP9(data) => {
let send_conn_ids = handle_one_frame_encoded(&sp, data, ms)?;
let send_conn_ids =
handle_one_frame_encoded(VpxVideoCodecId::VP9, &sp, data, ms)?;
frame_controller.set_send(now, send_conn_ids);
}
scrap::Frame::RAW(data) => {
@@ -717,12 +731,11 @@ fn run(sp: GenericService) -> ResultType<()> {
fn get_recorder(
width: usize,
height: usize,
codec_name: &Option<String>,
codec_name: &CodecName,
) -> Arc<Mutex<Option<Recorder>>> {
#[cfg(not(target_os = "ios"))]
let recorder = if !Config::get_option("allow-auto-record-incoming").is_empty() {
use crate::hbbs_http::record_upload;
use scrap::record::RecordCodecID::*;
let tx = if record_upload::is_enable() {
let (tx, rx) = std::sync::mpsc::channel();
@@ -731,16 +744,6 @@ fn get_recorder(
} else {
None
};
let codec_id = match codec_name {
Some(name) => {
if name.contains("264") {
H264
} else {
H265
}
}
None => VP9,
};
Recorder::new(RecorderContext {
server: true,
id: Config::get_id(),
@@ -748,7 +751,7 @@ fn get_recorder(
filename: "".to_owned(),
width,
height,
codec_id,
format: codec_name.into(),
tx,
})
.map_or(Default::default(), |r| Arc::new(Mutex::new(Some(r))))
@@ -775,19 +778,6 @@ fn check_privacy_mode_changed(sp: &GenericService, privacy_mode_id: i32) -> Resu
Ok(())
}
#[inline]
#[cfg(any(target_os = "android", target_os = "ios"))]
fn create_msg(vp9s: Vec<EncodedVideoFrame>) -> Message {
let mut msg_out = Message::new();
let mut vf = VideoFrame::new();
vf.set_vp9s(EncodedVideoFrames {
frames: vp9s.into(),
..Default::default()
});
msg_out.set_video_frame(vf);
msg_out
}
#[inline]
fn handle_one_frame(
sp: &GenericService,
@@ -820,6 +810,7 @@ fn handle_one_frame(
#[inline]
#[cfg(any(target_os = "android", target_os = "ios"))]
pub fn handle_one_frame_encoded(
codec: VpxVideoCodecId,
sp: &GenericService,
frame: &[u8],
ms: i64,
@@ -831,13 +822,13 @@ pub fn handle_one_frame_encoded(
}
Ok(())
})?;
let vp9_frame = EncodedVideoFrame {
let vpx_frame = EncodedVideoFrame {
data: frame.to_vec().into(),
key: true,
pts: ms,
..Default::default()
};
let send_conn_ids = sp.send_video_frame(create_msg(vec![vp9_frame]));
let send_conn_ids = sp.send_video_frame(scrap::VpxEncoder::create_msg(codec, vec![vpx_frame]));
Ok(send_conn_ids)
}

View File

@@ -161,8 +161,8 @@ class Header: Reactor.Component {
}
function renderDisplayPop() {
var codecs = handler.supported_hwcodec();
var show_codec = handler.has_hwcodec() && (codecs[0] || codecs[1]);
var codecs = handler.alternative_codecs();
var show_codec = codecs[0] || codecs[1] || codecs[2];
var cursor_embedded = false;
if ((pi.displays || []).length > 0) {
@@ -186,9 +186,10 @@ class Header: Reactor.Component {
{show_codec ? <div>
<div .separator />
<li #auto type="codec-preference"><span>{svg_checkmark}</span>Auto</li>
{codecs[0] ? <li #vp8 type="codec-preference"><span>{svg_checkmark}</span>VP8</li> : ""}
<li #vp9 type="codec-preference"><span>{svg_checkmark}</span>VP9</li>
{codecs[0] ? <li #h264 type="codec-preference"><span>{svg_checkmark}</span>H264</li> : ""}
{codecs[1] ? <li #h265 type="codec-preference"><span>{svg_checkmark}</span>H265</li> : ""}
{codecs[1] ? <li #h264 type="codec-preference"><span>{svg_checkmark}</span>H264</li> : ""}
{codecs[2] ? <li #h265 type="codec-preference"><span>{svg_checkmark}</span>H265</li> : ""}
</div> : ""}
<div .separator />
{!cursor_embedded && <li #show-remote-cursor .toggle-option><span>{svg_checkmark}</span>{translate('Show remote cursor')}</li>}

View File

@@ -20,7 +20,6 @@ use hbb_common::{
use crate::{
client::*,
ui_interface::has_hwcodec,
ui_session_interface::{InvokeUiSession, Session},
};
@@ -197,7 +196,14 @@ impl InvokeUiSession for SciterHandler {
self.call("confirmDeleteFiles", &make_args!(id, i, name));
}
fn override_file_confirm(&self, id: i32, file_num: i32, to: String, is_upload: bool, is_identical: bool) {
fn override_file_confirm(
&self,
id: i32,
file_num: i32,
to: String,
is_upload: bool,
is_identical: bool,
) {
self.call(
"overrideFileConfirm",
&make_args!(id, file_num, to, is_upload, is_identical),
@@ -451,8 +457,7 @@ impl sciter::EventHandler for SciterSession {
fn set_write_override(i32, i32, bool, bool, bool);
fn get_keyboard_mode();
fn save_keyboard_mode(String);
fn has_hwcodec();
fn supported_hwcodec();
fn alternative_codecs();
fn change_prefer_codec();
fn restart_remote_device();
fn request_voice_call();
@@ -504,10 +509,6 @@ impl SciterSession {
v
}
fn has_hwcodec(&self) -> bool {
has_hwcodec()
}
pub fn t(&self, name: String) -> String {
crate::client::translate(name)
}
@@ -516,9 +517,10 @@ impl SciterSession {
super::get_icon()
}
fn supported_hwcodec(&self) -> Value {
let (h264, h265) = self.0.supported_hwcodec();
fn alternative_codecs(&self) -> Value {
let (vp8, h264, h265) = self.0.alternative_codecs();
let mut v = Value::array(0);
v.push(vp8);
v.push(h264);
v.push(h265);
v

View File

@@ -752,6 +752,13 @@ pub fn has_hwcodec() -> bool {
return true;
}
#[cfg(feature = "flutter")]
#[inline]
pub fn supported_hwdecodings() -> (bool, bool) {
let decoding = scrap::codec::Decoder::supported_decodings(None);
(decoding.ability_h264 > 0, decoding.ability_h265 > 0)
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
#[inline]
pub fn is_root() -> bool {

View File

@@ -216,24 +216,16 @@ impl<T: InvokeUiSession> Session<T> {
true
}
pub fn supported_hwcodec(&self) -> (bool, bool) {
#[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
{
let decoder = scrap::codec::Decoder::video_codec_state(&self.id);
let mut h264 = decoder.score_h264 > 0;
let mut h265 = decoder.score_h265 > 0;
let (encoding_264, encoding_265) = self
.lc
.read()
.unwrap()
.supported_encoding
.unwrap_or_default();
h264 = h264 && encoding_264;
h265 = h265 && encoding_265;
return (h264, h265);
}
#[allow(unreachable_code)]
(false, false)
pub fn alternative_codecs(&self) -> (bool, bool, bool) {
let decoder = scrap::codec::Decoder::supported_decodings(None);
let mut vp8 = decoder.ability_vp8 > 0;
let mut h264 = decoder.ability_h264 > 0;
let mut h265 = decoder.ability_h265 > 0;
let enc = &self.lc.read().unwrap().supported_encoding;
vp8 = vp8 && enc.vp8;
h264 = h264 && enc.h264;
h265 = h265 && enc.h265;
(vp8, h264, h265)
}
pub fn change_prefer_codec(&self) {