hwcodec: codec preference
Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
parent
1b1f28b872
commit
7aa431d349
@ -72,6 +72,11 @@ message Features {
|
|||||||
bool privacy_mode = 1;
|
bool privacy_mode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SupportedEncoding {
|
||||||
|
bool h264 = 1;
|
||||||
|
bool h265 = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message PeerInfo {
|
message PeerInfo {
|
||||||
string username = 1;
|
string username = 1;
|
||||||
string hostname = 2;
|
string hostname = 2;
|
||||||
@ -82,6 +87,7 @@ message PeerInfo {
|
|||||||
string version = 7;
|
string version = 7;
|
||||||
int32 conn_id = 8;
|
int32 conn_id = 8;
|
||||||
Features features = 9;
|
Features features = 9;
|
||||||
|
SupportedEncoding encoding = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LoginResponse {
|
message LoginResponse {
|
||||||
@ -434,9 +440,17 @@ enum ImageQuality {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message VideoCodecState {
|
message VideoCodecState {
|
||||||
int32 ScoreVpx = 1;
|
enum PerferCodec {
|
||||||
int32 ScoreH264 = 2;
|
Auto = 0;
|
||||||
int32 ScoreH265 = 3;
|
VPX = 1;
|
||||||
|
H264 = 2;
|
||||||
|
H265 = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 score_vpx = 1;
|
||||||
|
int32 score_h264 = 2;
|
||||||
|
int32 score_h265 = 3;
|
||||||
|
PerferCodec perfer = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OptionMessage {
|
message OptionMessage {
|
||||||
|
@ -16,7 +16,11 @@ use hbb_common::{
|
|||||||
ResultType,
|
ResultType,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "hwcodec")]
|
#[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")]
|
#[cfg(feature = "hwcodec")]
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
@ -113,7 +117,6 @@ impl Encoder {
|
|||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
pub fn update_video_encoder(id: i32, update: EncoderUpdate) {
|
pub fn update_video_encoder(id: i32, update: EncoderUpdate) {
|
||||||
log::info!("encoder update: {:?}", update);
|
|
||||||
#[cfg(feature = "hwcodec")]
|
#[cfg(feature = "hwcodec")]
|
||||||
{
|
{
|
||||||
let mut states = PEER_DECODER_STATES.lock().unwrap();
|
let mut states = PEER_DECODER_STATES.lock().unwrap();
|
||||||
@ -130,49 +133,75 @@ impl Encoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let current_encoder_name = HwEncoder::current_name();
|
let name = HwEncoder::current_name();
|
||||||
if states.len() > 0 {
|
if states.len() > 0 {
|
||||||
let best = HwEncoder::best();
|
let best = HwEncoder::best();
|
||||||
let enabled_h264 = best.h264.is_some()
|
let enabled_h264 = best.h264.is_some()
|
||||||
&& states.len() > 0
|
&& 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()
|
let enabled_h265 = best.h265.is_some()
|
||||||
&& states.len() > 0
|
&& states.len() > 0
|
||||||
&& states.iter().all(|(_, s)| s.ScoreH265 > 0);
|
&& states.iter().all(|(_, s)| s.score_h265 > 0);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// score encoder
|
||||||
let mut score_vpx = SCORE_VPX;
|
let mut score_vpx = SCORE_VPX;
|
||||||
let mut score_h264 = best.h264.as_ref().map_or(0, |c| c.score);
|
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);
|
let mut score_h265 = best.h265.as_ref().map_or(0, |c| c.score);
|
||||||
|
|
||||||
// score decoder
|
// score decoder
|
||||||
score_vpx += states.iter().map(|s| s.1.ScoreVpx).sum::<i32>();
|
score_vpx += states.iter().map(|s| s.1.score_vpx).sum::<i32>();
|
||||||
if enabled_h264 {
|
if enabled_h264 {
|
||||||
score_h264 += states.iter().map(|s| s.1.ScoreH264).sum::<i32>();
|
score_h264 += states.iter().map(|s| s.1.score_h264).sum::<i32>();
|
||||||
}
|
}
|
||||||
if enabled_h265 {
|
if enabled_h265 {
|
||||||
score_h265 += states.iter().map(|s| s.1.ScoreH265).sum::<i32>();
|
score_h265 += states.iter().map(|s| s.1.score_h265).sum::<i32>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if enabled_h265 && score_h265 >= score_vpx && score_h265 >= score_h264 {
|
if enabled_h265 && score_h265 >= score_vpx && score_h265 >= score_h264 {
|
||||||
*current_encoder_name.lock().unwrap() = Some(best.h265.unwrap().name);
|
*name.lock().unwrap() = best.h265.map_or(None, |c| Some(c.name));
|
||||||
} else if enabled_h264 && score_h264 >= score_vpx && score_h264 >= score_h265 {
|
} else if enabled_h264
|
||||||
*current_encoder_name.lock().unwrap() = Some(best.h264.unwrap().name);
|
&& score_h264 >= score_vpx
|
||||||
|
&& score_h264 >= score_h265
|
||||||
|
{
|
||||||
|
*name.lock().unwrap() = best.h264.map_or(None, |c| Some(c.name));
|
||||||
} else {
|
} else {
|
||||||
*current_encoder_name.lock().unwrap() = None;
|
*name.lock().unwrap() = None;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"connection count:{}, h264:{}, h265:{}, score: vpx({}), h264({}), h265({}), set current encoder name {:?}",
|
"connection count:{}, used preference:{:?}, encoder:{:?}",
|
||||||
states.len(),
|
states.len(),
|
||||||
enabled_h264,
|
preference,
|
||||||
enabled_h265,
|
name.lock().unwrap()
|
||||||
score_vpx,
|
|
||||||
score_h264,
|
|
||||||
score_h265,
|
|
||||||
current_encoder_name.lock().unwrap()
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
*current_encoder_name.lock().unwrap() = None;
|
*name.lock().unwrap() = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "hwcodec"))]
|
#[cfg(not(feature = "hwcodec"))]
|
||||||
@ -192,34 +221,51 @@ impl Encoder {
|
|||||||
#[cfg(not(feature = "hwcodec"))]
|
#[cfg(not(feature = "hwcodec"))]
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "hwcodec")]
|
#[cfg(feature = "hwcodec")]
|
||||||
impl Drop for Decoder {
|
impl Drop for Decoder {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
*MY_DECODER_STATE.lock().unwrap() = VideoCodecState {
|
*MY_DECODER_STATE.lock().unwrap() = VideoCodecState {
|
||||||
ScoreVpx: SCORE_VPX,
|
score_vpx: SCORE_VPX,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decoder {
|
impl Decoder {
|
||||||
pub fn video_codec_state() -> VideoCodecState {
|
pub fn video_codec_state(_id: &str) -> VideoCodecState {
|
||||||
// video_codec_state is mainted by creation and destruction of Decoder.
|
// video_codec_state is mainted by creation and destruction of Decoder.
|
||||||
// It has been ensured to use after Decoder's creation.
|
// It has been ensured to use after Decoder's creation.
|
||||||
#[cfg(feature = "hwcodec")]
|
#[cfg(feature = "hwcodec")]
|
||||||
if check_hwcodec_config() {
|
if check_hwcodec_config() {
|
||||||
return MY_DECODER_STATE.lock().unwrap().clone();
|
let mut state = MY_DECODER_STATE.lock().unwrap();
|
||||||
|
state.perfer = Self::codec_preference(_id).into();
|
||||||
|
state.clone()
|
||||||
} else {
|
} else {
|
||||||
return VideoCodecState {
|
return VideoCodecState {
|
||||||
ScoreVpx: SCORE_VPX,
|
score_vpx: SCORE_VPX,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "hwcodec"))]
|
#[cfg(not(feature = "hwcodec"))]
|
||||||
VideoCodecState {
|
VideoCodecState {
|
||||||
ScoreVpx: SCORE_VPX,
|
score_vpx: SCORE_VPX,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,9 +283,9 @@ impl Decoder {
|
|||||||
#[cfg(feature = "hwcodec")]
|
#[cfg(feature = "hwcodec")]
|
||||||
{
|
{
|
||||||
let mut state = MY_DECODER_STATE.lock().unwrap();
|
let mut state = MY_DECODER_STATE.lock().unwrap();
|
||||||
state.ScoreVpx = SCORE_VPX;
|
state.score_vpx = SCORE_VPX;
|
||||||
state.ScoreH264 = decoder.hw.h264.as_ref().map_or(0, |d| d.info.score);
|
state.score_h264 = 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);
|
state.score_h265 = decoder.hw.h265.as_ref().map_or(0, |d| d.info.score);
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder
|
decoder
|
||||||
@ -316,6 +362,23 @@ impl Decoder {
|
|||||||
}
|
}
|
||||||
return Ok(ret);
|
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")]
|
#[cfg(feature = "hwcodec")]
|
||||||
|
@ -784,6 +784,7 @@ pub struct LoginConfigHandler {
|
|||||||
pub conn_id: i32,
|
pub conn_id: i32,
|
||||||
features: Option<Features>,
|
features: Option<Features>,
|
||||||
session_id: u64,
|
session_id: u64,
|
||||||
|
pub supported_encoding: Option<(bool, bool)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for LoginConfigHandler {
|
impl Deref for LoginConfigHandler {
|
||||||
@ -808,6 +809,7 @@ impl LoginConfigHandler {
|
|||||||
self.remember = !config.password.is_empty();
|
self.remember = !config.password.is_empty();
|
||||||
self.config = config;
|
self.config = config;
|
||||||
self.session_id = rand::random();
|
self.session_id = rand::random();
|
||||||
|
self.supported_encoding = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_auto_login(&self) -> String {
|
pub fn should_auto_login(&self) -> String {
|
||||||
@ -958,8 +960,7 @@ impl LoginConfigHandler {
|
|||||||
msg.disable_clipboard = BoolOption::Yes.into();
|
msg.disable_clipboard = BoolOption::Yes.into();
|
||||||
n += 1;
|
n += 1;
|
||||||
}
|
}
|
||||||
// TODO: add option
|
let state = Decoder::video_codec_state(&self.id);
|
||||||
let state = Decoder::video_codec_state();
|
|
||||||
msg.video_codec_state = hbb_common::protobuf::MessageField::some(state);
|
msg.video_codec_state = hbb_common::protobuf::MessageField::some(state);
|
||||||
n += 1;
|
n += 1;
|
||||||
|
|
||||||
@ -1111,6 +1112,10 @@ impl LoginConfigHandler {
|
|||||||
self.conn_id = pi.conn_id;
|
self.conn_id = pi.conn_id;
|
||||||
// no matter if change, for update file time
|
// no matter if change, for update file time
|
||||||
self.save_config(config);
|
self.save_config(config);
|
||||||
|
#[cfg(feature = "hwcodec")]
|
||||||
|
{
|
||||||
|
self.supported_encoding = Some((pi.encoding.h264, pi.encoding.h265));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_remote_dir(&self) -> String {
|
pub fn get_remote_dir(&self) -> String {
|
||||||
@ -1163,6 +1168,18 @@ impl LoginConfigHandler {
|
|||||||
msg_out.set_login_request(lr);
|
msg_out.set_login_request(lr);
|
||||||
msg_out
|
msg_out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn change_prefer_codec(&self) -> Message {
|
||||||
|
let state = scrap::codec::Decoder::video_codec_state(&self.id);
|
||||||
|
let mut misc = Misc::new();
|
||||||
|
misc.set_option(OptionMessage {
|
||||||
|
video_codec_state: hbb_common::protobuf::MessageField::some(state),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let mut msg_out = Message::new();
|
||||||
|
msg_out.set_misc(misc);
|
||||||
|
msg_out
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MediaData {
|
pub enum MediaData {
|
||||||
|
@ -635,6 +635,16 @@ impl Connection {
|
|||||||
pi.hostname = MOBILE_INFO2.lock().unwrap().clone();
|
pi.hostname = MOBILE_INFO2.lock().unwrap().clone();
|
||||||
pi.platform = "Android".into();
|
pi.platform = "Android".into();
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "hwcodec")]
|
||||||
|
{
|
||||||
|
let (h264, h265) = scrap::codec::Encoder::supported_encoding();
|
||||||
|
pi.encoding = Some(SupportedEncoding {
|
||||||
|
h264,
|
||||||
|
h265,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
|
||||||
if self.port_forward_socket.is_some() {
|
if self.port_forward_socket.is_some() {
|
||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
@ -1351,6 +1361,12 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(q) = o.video_codec_state.clone().take() {
|
||||||
|
scrap::codec::Encoder::update_video_encoder(
|
||||||
|
self.inner.id(),
|
||||||
|
scrap::codec::EncoderUpdate::State(q),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_close(&mut self, reason: &str, lock: bool) {
|
async fn on_close(&mut self, reason: &str, lock: bool) {
|
||||||
|
@ -483,6 +483,7 @@ fn run(sp: GenericService) -> ResultType<()> {
|
|||||||
let mut try_gdi = 1;
|
let mut try_gdi = 1;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
log::info!("gdi: {}", c.is_gdi());
|
log::info!("gdi: {}", c.is_gdi());
|
||||||
|
let codec_name = Encoder::current_hw_encoder_name();
|
||||||
|
|
||||||
while sp.ok() {
|
while sp.ok() {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -508,6 +509,9 @@ fn run(sp: GenericService) -> ResultType<()> {
|
|||||||
*SWITCH.lock().unwrap() = true;
|
*SWITCH.lock().unwrap() = true;
|
||||||
bail!("SWITCH");
|
bail!("SWITCH");
|
||||||
}
|
}
|
||||||
|
if codec_name != Encoder::current_hw_encoder_name() {
|
||||||
|
bail!("SWITCH");
|
||||||
|
}
|
||||||
check_privacy_mode_changed(&sp, c.privacy_mode_id)?;
|
check_privacy_mode_changed(&sp, c.privacy_mode_id)?;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
|
@ -94,3 +94,4 @@ span#fullscreen.active {
|
|||||||
button:disabled {
|
button:disabled {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +145,9 @@ class Header: Reactor.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderDisplayPop() {
|
function renderDisplayPop() {
|
||||||
|
var codecs = handler.supported_hwcodec();
|
||||||
|
var show_codec = handler.has_hwcodec() && (codecs[0] || codecs[1]);
|
||||||
|
|
||||||
return <popup>
|
return <popup>
|
||||||
<menu.context #display-options>
|
<menu.context #display-options>
|
||||||
<li #adjust-window style="display:none">{translate('Adjust Window')}</li>
|
<li #adjust-window style="display:none">{translate('Adjust Window')}</li>
|
||||||
@ -157,6 +160,13 @@ class Header: Reactor.Component {
|
|||||||
<li #balanced type="image-quality"><span>{svg_checkmark}</span>{translate('Balanced')}</li>
|
<li #balanced type="image-quality"><span>{svg_checkmark}</span>{translate('Balanced')}</li>
|
||||||
<li #low type="image-quality"><span>{svg_checkmark}</span>{translate('Optimize reaction time')}</li>
|
<li #low type="image-quality"><span>{svg_checkmark}</span>{translate('Optimize reaction time')}</li>
|
||||||
<li #custom type="image-quality"><span>{svg_checkmark}</span>{translate('Custom')}</li>
|
<li #custom type="image-quality"><span>{svg_checkmark}</span>{translate('Custom')}</li>
|
||||||
|
{show_codec ? <div>
|
||||||
|
<div .separator />
|
||||||
|
<li #auto type="codec-preference"><span>{svg_checkmark}</span>Auto</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> : ""}
|
||||||
|
</div> : ""}
|
||||||
<div .separator />
|
<div .separator />
|
||||||
<li #show-remote-cursor .toggle-option><span>{svg_checkmark}</span>{translate('Show remote cursor')}</li>
|
<li #show-remote-cursor .toggle-option><span>{svg_checkmark}</span>{translate('Show remote cursor')}</li>
|
||||||
<li #show-quality-monitor .toggle-option><span>{svg_checkmark}</span>{translate('Show quality monitor')}</li>
|
<li #show-quality-monitor .toggle-option><span>{svg_checkmark}</span>{translate('Show quality monitor')}</li>
|
||||||
@ -311,7 +321,7 @@ class Header: Reactor.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event click $(menu#display-options>li) (_, me) {
|
event click $(menu#display-options li) (_, me) {
|
||||||
if (me.id == "custom") {
|
if (me.id == "custom") {
|
||||||
handle_custom_image_quality();
|
handle_custom_image_quality();
|
||||||
} else if (me.id == "privacy-mode") {
|
} else if (me.id == "privacy-mode") {
|
||||||
@ -328,6 +338,9 @@ class Header: Reactor.Component {
|
|||||||
} else if (type == "view-style") {
|
} else if (type == "view-style") {
|
||||||
handler.save_view_style(me.id);
|
handler.save_view_style(me.id);
|
||||||
adaptDisplay();
|
adaptDisplay();
|
||||||
|
} else if (type == "codec-preference") {
|
||||||
|
handler.set_option("codec-preference", me.id);
|
||||||
|
handler.change_prefer_codec();
|
||||||
}
|
}
|
||||||
toggleMenuState();
|
toggleMenuState();
|
||||||
}
|
}
|
||||||
@ -355,7 +368,10 @@ function toggleMenuState() {
|
|||||||
var s = handler.get_view_style();
|
var s = handler.get_view_style();
|
||||||
if (!s) s = "original";
|
if (!s) s = "original";
|
||||||
values.push(s);
|
values.push(s);
|
||||||
for (var el in $$(menu#display-options>li)) {
|
var c = handler.get_option("codec-preference");
|
||||||
|
if (!c) c = "auto";
|
||||||
|
values.push(c);
|
||||||
|
for (var el in $$(menu#display-options li)) {
|
||||||
el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0);
|
el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0);
|
||||||
}
|
}
|
||||||
for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end"]) {
|
for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end"]) {
|
||||||
|
@ -231,6 +231,9 @@ impl sciter::EventHandler for Handler {
|
|||||||
fn get_remember();
|
fn get_remember();
|
||||||
fn peer_platform();
|
fn peer_platform();
|
||||||
fn set_write_override(i32, i32, bool, bool, bool);
|
fn set_write_override(i32, i32, bool, bool, bool);
|
||||||
|
fn has_hwcodec();
|
||||||
|
fn supported_hwcodec();
|
||||||
|
fn change_prefer_codec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,6 +598,42 @@ impl Handler {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_hwcodec(&self) -> bool {
|
||||||
|
#[cfg(not(feature = "hwcodec"))]
|
||||||
|
return false;
|
||||||
|
#[cfg(feature = "hwcodec")]
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supported_hwcodec(&self) -> Value {
|
||||||
|
#[cfg(feature = "hwcodec")]
|
||||||
|
{
|
||||||
|
let mut v = Value::array(0);
|
||||||
|
let decoder = scrap::codec::Decoder::video_codec_state(&self.id);
|
||||||
|
let mut h264 = decoder.score_h264 > 0;
|
||||||
|
let mut h265 = decoder.score_h265 > 0;
|
||||||
|
if let Some((encoding_264, encoding_265)) = self.lc.read().unwrap().supported_encoding {
|
||||||
|
h264 = h264 && encoding_264;
|
||||||
|
h265 = h265 && encoding_265;
|
||||||
|
}
|
||||||
|
v.push(h264);
|
||||||
|
v.push(h265);
|
||||||
|
v
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "hwcodec"))]
|
||||||
|
{
|
||||||
|
let mut v = Value::array(0);
|
||||||
|
v.push(false);
|
||||||
|
v.push(false);
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_prefer_codec(&self) {
|
||||||
|
let msg = self.lc.write().unwrap().change_prefer_codec();
|
||||||
|
self.send(Data::Message(msg));
|
||||||
|
}
|
||||||
|
|
||||||
fn t(&self, name: String) -> String {
|
fn t(&self, name: String) -> String {
|
||||||
crate::client::translate(name)
|
crate::client::translate(name)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user