simple abr with delay
This commit is contained in:
parent
0da5c2ec68
commit
a7769da317
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user