* Adjust bitrate and fps based on TestDelay messages.
* Bitrate is adjusted every 3 seconds, fps is adjusted every second and when receiving test lag.
* Latency optimized at high resolutions. However, when the network is poor, the delay when just connecting or sliding static pages is still obvious.

Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
21pages
2025-01-20 17:59:36 +08:00
committed by GitHub
parent c44803f5b0
commit 5fa8c25e65
10 changed files with 735 additions and 548 deletions

View File

@@ -1,7 +1,5 @@
use crate::{
codec::{
base_bitrate, codec_thread_num, enable_hwcodec_option, EncoderApi, EncoderCfg, Quality as Q,
},
codec::{base_bitrate, codec_thread_num, enable_hwcodec_option, EncoderApi, EncoderCfg},
convert::*,
CodecFormat, EncodeInput, ImageFormat, ImageRgb, Pixfmt, HW_STRIDE_ALIGN,
};
@@ -47,7 +45,7 @@ pub struct HwRamEncoderConfig {
pub mc_name: Option<String>,
pub width: usize,
pub height: usize,
pub quality: Q,
pub quality: f32,
pub keyframe_interval: Option<usize>,
}
@@ -67,12 +65,8 @@ impl EncoderApi for HwRamEncoder {
match cfg {
EncoderCfg::HWRAM(config) => {
let rc = Self::rate_control(&config);
let b = Self::convert_quality(&config.name, config.quality);
let base_bitrate = base_bitrate(config.width as _, config.height as _);
let mut bitrate = base_bitrate * b / 100;
if bitrate <= 0 {
bitrate = base_bitrate;
}
let mut bitrate =
Self::bitrate(&config.name, config.width, config.height, config.quality);
bitrate = Self::check_bitrate_range(&config, bitrate);
let gop = config.keyframe_interval.unwrap_or(DEFAULT_GOP as _) as i32;
let ctx = EncodeContext {
@@ -176,15 +170,19 @@ impl EncoderApi for HwRamEncoder {
false
}
fn set_quality(&mut self, quality: crate::codec::Quality) -> ResultType<()> {
let b = Self::convert_quality(&self.config.name, quality);
let mut bitrate = base_bitrate(self.config.width as _, self.config.height as _) * b / 100;
fn set_quality(&mut self, ratio: f32) -> ResultType<()> {
let mut bitrate = Self::bitrate(
&self.config.name,
self.config.width,
self.config.height,
ratio,
);
if bitrate > 0 {
bitrate = Self::check_bitrate_range(&self.config, bitrate);
self.encoder.set_bitrate(bitrate as _).ok();
self.bitrate = bitrate;
}
self.config.quality = quality;
self.config.quality = ratio;
Ok(())
}
@@ -192,10 +190,6 @@ impl EncoderApi for HwRamEncoder {
self.bitrate
}
fn support_abr(&self) -> bool {
["vaapi"].iter().all(|&x| !self.config.name.contains(x))
}
fn support_changing_quality(&self) -> bool {
["vaapi"].iter().all(|&x| !self.config.name.contains(x))
}
@@ -254,21 +248,35 @@ impl HwRamEncoder {
RC_CBR
}
pub fn convert_quality(name: &str, quality: crate::codec::Quality) -> u32 {
use crate::codec::Quality;
let quality = match quality {
Quality::Best => 150,
Quality::Balanced => 100,
Quality::Low => 50,
Quality::Custom(b) => b,
};
let factor = if name.contains("mediacodec") {
pub fn bitrate(name: &str, width: usize, height: usize, ratio: f32) -> u32 {
Self::calc_bitrate(width, height, ratio, name.contains("h264"))
}
pub fn calc_bitrate(width: usize, height: usize, ratio: f32, h264: bool) -> u32 {
let base = base_bitrate(width as _, height as _) as f32 * ratio;
let threshold = 2000.0;
let decay_rate = 0.001; // 1000 * 0.001 = 1
let factor: f32 = if cfg!(target_os = "android") {
// https://stackoverflow.com/questions/26110337/what-are-valid-bit-rates-to-set-for-mediacodec?rq=3
5
if base > threshold {
1.0 + 4.0 / (1.0 + (base - threshold) * decay_rate)
} else {
5.0
}
} else if h264 {
if base > threshold {
1.0 + 1.0 / (1.0 + (base - threshold) * decay_rate)
} else {
2.0
}
} else {
1
if base > threshold {
1.0 + 0.5 / (1.0 + (base - threshold) * decay_rate)
} else {
1.5
}
};
quality * factor
(base * factor) as u32
}
pub fn check_bitrate_range(_config: &HwRamEncoderConfig, bitrate: u32) -> u32 {