add ffmpeg mediacodec h264/h265 encode (#8028)

* Check available when app start from kotlin via get codec info
* For latency free, repeat encode 10 frame at most when capture return WouldBlock
* For changing quality, kotlin support but jni doesn't support, rerun video service when quality is manualy
  changed
* 3 or 6 times bitrate for mediacodec because its quality is poor

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages
2024-05-13 12:39:04 +08:00
committed by GitHub
parent 4c99b8c70e
commit a7499c2de8
13 changed files with 380 additions and 31 deletions

View File

@@ -124,6 +124,10 @@ impl VideoQoS {
self.support_abr.insert(display_idx, support);
}
pub fn in_vbr_state(&self) -> bool {
Config::get_option("enable-abr") != "N" && self.support_abr.iter().all(|e| *e.1)
}
pub fn refresh(&mut self, typ: Option<RefreshType>) {
// fps
let user_fps = |u: &UserData| {
@@ -178,8 +182,7 @@ impl VideoQoS {
let mut quality = latest_quality;
// network delay
let abr_enabled =
Config::get_option("enable-abr") != "N" && self.support_abr.iter().all(|e| *e.1);
let abr_enabled = self.in_vbr_state();
if abr_enabled && typ != Some(RefreshType::SetImageQuality) {
// max delay
let delay = self

View File

@@ -53,7 +53,7 @@ use scrap::{
codec::{Encoder, EncoderCfg, Quality},
record::{Recorder, RecorderContext},
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
CodecFormat, Display, Frame, TraitCapturer,
CodecFormat, Display, EncodeInput, Frame, TraitCapturer,
};
#[cfg(windows)]
use std::sync::Once;
@@ -470,6 +470,8 @@ fn run(vs: VideoService) -> ResultType<()> {
let mut would_block_count = 0u32;
let mut yuv = Vec::new();
let mut mid_data = Vec::new();
let mut repeat_encode_counter = 0;
let repeat_encode_max = 10;
while sp.ok() {
#[cfg(windows)]
@@ -480,8 +482,15 @@ fn run(vs: VideoService) -> ResultType<()> {
if quality != video_qos.quality() {
log::debug!("quality: {:?} -> {:?}", quality, video_qos.quality());
quality = video_qos.quality();
allow_err!(encoder.set_quality(quality));
video_qos.store_bitrate(encoder.bitrate());
if encoder.support_changing_quality() {
allow_err!(encoder.set_quality(quality));
video_qos.store_bitrate(encoder.bitrate());
} else {
if !video_qos.in_vbr_state() && !quality.is_custom() {
log::info!("switch to change quality");
bail!("SWITCH");
}
}
}
if client_record != video_qos.record() {
bail!("SWITCH");
@@ -526,17 +535,17 @@ fn run(vs: VideoService) -> ResultType<()> {
frame_controller.reset();
let time = now - start;
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
let res = match c.frame(spf) {
Ok(frame) => {
let time = now - start;
let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64;
repeat_encode_counter = 0;
if frame.valid() {
let frame = frame.to(encoder.yuvfmt(), &mut yuv, &mut mid_data)?;
let send_conn_ids = handle_one_frame(
display_idx,
&sp,
frame,
&mut yuv,
&mut mid_data,
ms,
&mut encoder,
recorder.clone(),
@@ -579,6 +588,21 @@ fn run(vs: VideoService) -> ResultType<()> {
}
}
}
if !encoder.latency_free() && yuv.len() > 0 {
// yun.len() > 0 means the frame is not texture.
if repeat_encode_counter < repeat_encode_max {
repeat_encode_counter += 1;
let send_conn_ids = handle_one_frame(
display_idx,
&sp,
EncodeInput::YUV(&yuv),
ms,
&mut encoder,
recorder.clone(),
)?;
frame_controller.set_send(now, send_conn_ids);
}
}
}
Err(err) => {
// Get display information again immediately after error.
@@ -707,6 +731,7 @@ fn get_encoder_config(
if let Some(hw) = HwRamEncoder::try_get(negotiated_codec) {
return EncoderCfg::HWRAM(HwRamEncoderConfig {
name: hw.name,
mc_name: hw.mc_name,
width: c.width,
height: c.height,
quality,
@@ -805,9 +830,7 @@ fn check_privacy_mode_changed(sp: &GenericService, privacy_mode_id: i32) -> Resu
fn handle_one_frame(
display: usize,
sp: &GenericService,
frame: Frame,
yuv: &mut Vec<u8>,
mid_data: &mut Vec<u8>,
frame: EncodeInput,
ms: i64,
encoder: &mut Encoder,
recorder: Arc<Mutex<Option<Recorder>>>,
@@ -820,7 +843,6 @@ fn handle_one_frame(
Ok(())
})?;
let frame = frame.to(encoder.yuvfmt(), yuv, mid_data)?;
let mut send_conn_ids: HashSet<i32> = Default::default();
match encoder.encode_to_message(frame, ms) {
Ok(mut vf) => {