diff --git a/flutter/lib/common/widgets/dialog.dart b/flutter/lib/common/widgets/dialog.dart index 9f4eb1427..6f9248c1d 100644 --- a/flutter/lib/common/widgets/dialog.dart +++ b/flutter/lib/common/widgets/dialog.dart @@ -947,7 +947,9 @@ showSetOSPassword( Function()? closeCallback, ) async { final controller = TextEditingController(); - osPassword ??= await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ?? ''; + osPassword ??= + await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ?? + ''; var autoLogin = await bind.sessionGetOption(sessionId: sessionId, arg: 'auto-login') != ''; @@ -957,6 +959,7 @@ showSetOSPassword( close(); if (closeCallback != null) closeCallback(); } + submit() { var text = controller.text.trim(); bind.sessionPeerOption( @@ -1220,7 +1223,8 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async { qualityInitValue = quality != null && quality.isNotEmpty ? quality[0].toDouble() : 50.0; const qualityMinValue = 10.0; - const qualityMaxValue = 100.0; + const qualityMoreThresholdValue = 100.0; + const qualityMaxValue = 2000.0; if (qualityInitValue < qualityMinValue) { qualityInitValue = qualityMinValue; } @@ -1228,6 +1232,8 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async { qualityInitValue = qualityMaxValue; } final RxDouble qualitySliderValue = RxDouble(qualityInitValue); + final moreQualityInitValue = qualityInitValue > qualityMoreThresholdValue; + final RxBool moreQualityChecked = RxBool(moreQualityInitValue); final debouncerQuality = Debouncer( Duration(milliseconds: 1000), onChanged: (double v) { @@ -1242,7 +1248,9 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async { child: Slider( value: qualitySliderValue.value, min: qualityMinValue, - max: qualityMaxValue, + max: moreQualityChecked.value + ? qualityMaxValue + : qualityMoreThresholdValue, divisions: 18, onChanged: (double value) { qualitySliderValue.value = value; @@ -1256,11 +1264,32 @@ customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async { style: const TextStyle(fontSize: 15), )), Expanded( - flex: 2, + flex: 1, child: Text( translate('Bitrate'), style: const TextStyle(fontSize: 15), )), + Expanded( + flex: 1, + child: Row( + children: [ + Checkbox( + value: moreQualityChecked.value, + onChanged: (bool? value) { + moreQualityChecked.value = value!; + if (!value && + qualitySliderValue.value > + qualityMoreThresholdValue) { + qualitySliderValue.value = qualityMoreThresholdValue; + debouncerQuality.value = qualityMoreThresholdValue; + } + }, + ).marginOnly(right: 5), + Expanded( + child: Text(translate('More')), + ) + ], + )), ], )); // fps diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 8f2e180a0..7bdd322d3 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -1078,7 +1078,7 @@ impl PeerConfig { D: de::Deserializer<'de>, { let v: Vec = de::Deserialize::deserialize(deserializer)?; - if v.len() == 1 && v[0] >= 10 && v[0] <= 100 { + if v.len() == 1 && v[0] >= 10 && v[0] <= 0xFFF { Ok(v) } else { Ok(Self::default_custom_image_quality()) @@ -1402,7 +1402,7 @@ impl UserDefaultConfig { "codec-preference" => { self.get_string(key, "auto", vec!["vp8", "vp9", "av1", "h264", "h265"]) } - "custom_image_quality" => self.get_double_string(key, 50.0, 10.0, 100.0), + "custom_image_quality" => self.get_double_string(key, 50.0, 10.0, 0xFFF as f64), "custom-fps" => self.get_double_string(key, 30.0, 5.0, 120.0), _ => self .options diff --git a/libs/scrap/src/common/aom.rs b/libs/scrap/src/common/aom.rs index 10886075d..f677858a7 100644 --- a/libs/scrap/src/common/aom.rs +++ b/libs/scrap/src/common/aom.rs @@ -344,7 +344,7 @@ impl AomEncoder { fn calc_q_values(b: u32) -> (u32, u32) { let b = std::cmp::min(b, 200); let q_min1: i32 = 24; - let q_min2 = 12; + let q_min2 = 5; let q_max1 = 45; let q_max2 = 25; diff --git a/libs/scrap/src/common/vpxcodec.rs b/libs/scrap/src/common/vpxcodec.rs index 8fc33c4b2..d17aad676 100644 --- a/libs/scrap/src/common/vpxcodec.rs +++ b/libs/scrap/src/common/vpxcodec.rs @@ -303,7 +303,7 @@ impl VpxEncoder { fn calc_q_values(b: u32) -> (u32, u32) { let b = std::cmp::min(b, 200); let q_min1: i32 = 36; - let q_min2 = 12; + let q_min2 = 0; let q_max1 = 56; let q_max2 = 37; diff --git a/src/server/video_qos.rs b/src/server/video_qos.rs index dda15fd55..2ebcdaa84 100644 --- a/src/server/video_qos.rs +++ b/src/server/video_qos.rs @@ -299,9 +299,9 @@ impl VideoQoS { } else if q == ImageQuality::Best.value() { Quality::Best } else { - let mut b = (q >> 8 & 0xFF) * 2; - b = std::cmp::max(b, 10); - b = std::cmp::min(b, 200); + let mut b = (q >> 8 & 0xFFF) * 2; + b = std::cmp::max(b, 20); + b = std::cmp::min(b, 8000); Quality::Custom(b as u32) } }; diff --git a/src/ui/header.tis b/src/ui/header.tis index 2d79db8fa..666150fb3 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -424,10 +424,22 @@ class Header: Reactor.Component { function handle_custom_image_quality() { var tmp = handler.get_custom_image_quality(); var bitrate = (tmp[0] || 50); - msgbox("custom", "Custom Image Quality", "
\ -
x% Bitrate
\ + var extendedBitrate = bitrate > 100; + var maxRate = extendedBitrate ? 2000 : 100; + msgbox("custom-image-quality", "Custom Image Quality", "
\ +
x% Bitrate More
\
", "", function(res=null) { if (!res) return; + if (res.id === "extended-slider") { + var slider = res.parent.$(#bitrate-slider) + slider.slider.max = res.checked ? 2000 : 100; + if (slider.value > slider.slider.max) { + slider.value = slider.slider.max; + } + var buddy = res.parent.$(#bitrate-buddy); + buddy.value = slider.value; + return; + } if (!res.bitrate) return; handler.save_custom_image_quality(res.bitrate); toggleMenuState();