simple abr with delay

This commit is contained in:
csf 2022-06-27 21:23:14 +08:00
parent 0da5c2ec68
commit a7769da317
2 changed files with 56 additions and 120 deletions

View File

@ -57,23 +57,36 @@ pub struct VideoQoS {
height: u32, height: u32,
user_image_quality: u32, user_image_quality: u32,
current_image_quality: u32, current_image_quality: u32,
enable_abr: bool,
pub current_delay: u32, pub current_delay: u32,
pub fps: u8, // abr pub fps: u8, // abr
pub target_bitrate: u32, // abr pub target_bitrate: u32, // abr
updated: bool,
state: AdaptiveState, updated: bool,
last_delay: u32, state: DelayState,
count: u32, debounce_count: u32,
} }
#[derive(Debug)] #[derive(PartialEq, Debug)]
enum AdaptiveState { enum DelayState {
Normal, Normal = 0,
LowDelay, LowDelay = 200,
HighDelay, HighDelay = 500,
Broken = 1000,
}
impl DelayState {
fn from_delay(delay: u32) -> Self {
if delay > DelayState::Broken as u32 {
DelayState::Broken
} else if delay > DelayState::HighDelay as u32 {
DelayState::HighDelay
} else if delay > DelayState::LowDelay as u32 {
DelayState::LowDelay
} else {
DelayState::Normal
}
}
} }
impl Default for VideoQoS { impl Default for VideoQoS {
@ -82,24 +95,17 @@ impl Default for VideoQoS {
fps: FPS, fps: FPS,
user_image_quality: ImageQuality::Balanced.value() as _, user_image_quality: ImageQuality::Balanced.value() as _,
current_image_quality: ImageQuality::Balanced.value() as _, current_image_quality: ImageQuality::Balanced.value() as _,
enable_abr: false,
width: 0, width: 0,
height: 0, height: 0,
current_delay: 0, current_delay: 0,
target_bitrate: 0, target_bitrate: 0,
updated: false, updated: false,
state: AdaptiveState::Normal, state: DelayState::Normal,
last_delay: 0, debounce_count: 0,
count: 0,
} }
} }
} }
const THRESHOLD: f32 = 1.2;
const MAX_COUNT: u32 = 3;
const MAX_DELAY: u32 = 500;
const MIN_DELAY: u32 = 50;
impl VideoQoS { impl VideoQoS {
pub fn set_size(&mut self, width: u32, height: u32) { pub fn set_size(&mut self, width: u32, height: u32) {
if width == 0 || height == 0 { if width == 0 || height == 0 {
@ -121,123 +127,52 @@ impl VideoQoS {
self.current_delay = delay; self.current_delay = delay;
return; return;
} }
let current_delay = self.current_delay as f32;
self.current_delay = delay / 2 + self.current_delay / 2; self.current_delay = delay / 2 + self.current_delay / 2;
log::trace!( log::trace!(
"update_network_delay:{}, {}, state:{:?},count:{}", "VideoQoS update_network_delay:{}, {}, state:{:?},count:{}",
self.current_delay, self.current_delay,
delay, delay,
self.state, self.state,
self.count self.debounce_count
); );
// ABR // ABR
if !self.enable_abr { let current_state = DelayState::from_delay(self.current_delay);
// return; if current_state != self.state && self.debounce_count > 5 {
log::debug!(
"VideoQoS state changed:{:?} -> {:?}",
self.state,
current_state
);
self.state = current_state;
self.debounce_count = 0;
self.update_quality();
} else {
self.debounce_count += 1;
} }
if self.current_delay < MIN_DELAY { }
if self.fps != FPS && self.current_image_quality != self.user_image_quality {
log::debug!("current_delay is normal, set to user_image_quality"); fn update_quality(&mut self) {
match self.state {
DelayState::Normal => {
self.fps = FPS; self.fps = FPS;
self.current_image_quality = self.user_image_quality; self.current_image_quality = self.user_image_quality;
let _ = self.generate_bitrate().ok();
self.updated = true;
} }
self.state = AdaptiveState::Normal; DelayState::LowDelay => {
} else if self.current_delay > MAX_DELAY {
if self.fps != 5 && self.current_image_quality != 25 {
log::debug!("current_delay is very high, set fps to 5, image_quality to 25");
self.fps = 5;
self.current_image_quality = 25;
let _ = self.generate_bitrate().ok();
self.updated = true;
}
} else {
// MAX_DELAY to Normal
if self.fps == 5 && self.current_image_quality == 25 {
self.fps = FPS; self.fps = FPS;
self.current_image_quality = self.current_image_quality = std::cmp::min(self.user_image_quality, 50);
std::cmp::min(self.user_image_quality, ImageQuality::Low.value() as _);
self.last_delay = self.current_delay;
let _ = self.generate_bitrate().ok();
self.updated = true;
return;
} }
let delay = delay as f32; DelayState::HighDelay => {
let last_delay = self.last_delay as f32; self.fps = FPS / 2;
match self.state { self.current_image_quality = std::cmp::min(self.user_image_quality, 25);
AdaptiveState::Normal => { }
if delay > current_delay * THRESHOLD { DelayState::Broken => {
self.state = AdaptiveState::HighDelay; self.fps = FPS / 4;
} else if delay < current_delay * THRESHOLD self.current_image_quality = 10;
&& self.current_image_quality < self.user_image_quality
{
self.state = AdaptiveState::LowDelay;
}
self.count = 0;
self.last_delay = self.current_delay
}
AdaptiveState::HighDelay => {
if delay > last_delay {
if self.count > MAX_COUNT {
self.decrease_quality();
self.reset_state();
return;
}
self.count += 1;
} else {
self.reset_state();
}
}
AdaptiveState::LowDelay => {
if delay < last_delay * THRESHOLD {
if self.count > MAX_COUNT {
self.increase_quality();
self.reset_state();
return;
}
self.count += 1;
} else {
self.reset_state();
}
}
} }
} }
} let _ = self.generate_bitrate().ok();
fn reset_state(&mut self) {
self.count = 0;
self.state = AdaptiveState::Normal;
}
fn increase_quality(&mut self) {
log::debug!("Adaptive increase quality");
if self.fps < FPS {
log::debug!("increase fps {} -> {}", self.fps, FPS);
self.fps = FPS;
} else {
self.current_image_quality += self.current_image_quality / 2;
let _ = self.generate_bitrate().ok();
log::debug!("increase quality:{}", self.current_image_quality);
}
self.updated = true;
}
fn decrease_quality(&mut self) {
log::debug!("Adaptive decrease quality");
if self.fps < 15 {
log::debug!("fps is low enough :{}", self.fps);
return;
}
if self.current_image_quality < ImageQuality::Low.value() as _ {
self.fps = self.fps / 2;
log::debug!("decrease fps:{}", self.fps);
} else {
self.current_image_quality -= self.current_image_quality / 2;
let _ = self.generate_bitrate().ok();
log::debug!("decrease quality:{}", self.current_image_quality);
};
self.updated = true; self.updated = true;
} }

View File

@ -335,7 +335,8 @@ class Header: Reactor.Component {
} }
function handle_custom_image_quality() { function handle_custom_image_quality() {
var bitrate = handler.get_custom_image_quality()[0] / 2; var tmp = handler.get_custom_image_quality();
var bitrate = (tmp[0] || 100) / 2;
msgbox("custom", "Custom Image Quality", "<div .form> \ msgbox("custom", "Custom Image Quality", "<div .form> \
<div><input type=\"hslider\" style=\"width: 50%\" name=\"bitrate\" max=\"100\" min=\"10\" value=\"" + bitrate + "\"/ buddy=\"bitrate-buddy\"><b #bitrate-buddy>x</b>% Bitrate</div> \ <div><input type=\"hslider\" style=\"width: 50%\" name=\"bitrate\" max=\"100\" min=\"10\" value=\"" + bitrate + "\"/ buddy=\"bitrate-buddy\"><b #bitrate-buddy>x</b>% Bitrate</div> \
</div>", function(res=null) { </div>", function(res=null) {