scrap: ensure video_handler's creation before client start

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2022-06-09 17:14:26 +08:00
parent 2a91fb842d
commit feaadcfc96
3 changed files with 72 additions and 45 deletions

View File

@ -23,8 +23,10 @@ use hbb_common::{
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref VIDEO_CODEC_STATES: Arc<Mutex<HashMap<i32, VideoCodecState>>> = Default::default(); static ref PEER_DECODER_STATES: Arc<Mutex<HashMap<i32, VideoCodecState>>> = Default::default();
static ref MY_DECODER_STATE: Arc<Mutex<VideoCodecState>> = Default::default();
} }
const SCORE_VPX: i32 = 90;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct HwEncoderConfig { pub struct HwEncoderConfig {
@ -96,9 +98,15 @@ impl Encoder {
}), }),
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
EncoderCfg::HW(_) => Ok(Encoder { EncoderCfg::HW(_) => match HwEncoder::new(config) {
codec: Box::new(HwEncoder::new(config)?), Ok(hw) => Ok(Encoder {
}), codec: Box::new(hw),
}),
Err(e) => {
HwEncoder::best(true);
Err(e)
}
},
#[cfg(not(feature = "hwcodec"))] #[cfg(not(feature = "hwcodec"))]
_ => Err(anyhow!("unsupported encoder type")), _ => Err(anyhow!("unsupported encoder type")),
} }
@ -109,7 +117,7 @@ impl Encoder {
log::info!("update video encoder:{:?}", update); log::info!("update video encoder:{:?}", update);
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
{ {
let mut states = VIDEO_CODEC_STATES.lock().unwrap(); let mut states = PEER_DECODER_STATES.lock().unwrap();
match update { match update {
EncoderUpdate::State(state) => { EncoderUpdate::State(state) => {
states.insert(id, state); states.insert(id, state);
@ -125,14 +133,14 @@ impl Encoder {
} }
let current_encoder_name = HwEncoder::current_name(); let current_encoder_name = HwEncoder::current_name();
if states.len() > 0 { if states.len() > 0 {
let best = HwEncoder::best(); let best = HwEncoder::best(false);
let enabled_h264 = let enabled_h264 =
best.h264.is_some() && states.len() > 0 && states.iter().all(|(_, s)| s.H264); best.h264.is_some() && states.len() > 0 && states.iter().all(|(_, s)| s.H264);
let enabled_h265 = let enabled_h265 =
best.h265.is_some() && states.len() > 0 && states.iter().all(|(_, s)| s.H265); best.h265.is_some() && states.len() > 0 && states.iter().all(|(_, s)| s.H265);
// score encoder // score encoder
let mut score_vpx = 90; let mut score_vpx = SCORE_VPX;
let mut score_h264 = best.h264.as_ref().map_or(0, |c| c.score); let mut score_h264 = best.h264.as_ref().map_or(0, |c| c.score);
let mut score_h265 = best.h265.as_ref().map_or(0, |c| c.score); let mut score_h265 = best.h265.as_ref().map_or(0, |c| c.score);
@ -181,33 +189,50 @@ impl Encoder {
} }
} }
#[cfg(feature = "hwcodec")]
impl Drop for Decoder {
fn drop(&mut self) {
*MY_DECODER_STATE.lock().unwrap() = VideoCodecState {
ScoreVpx: SCORE_VPX,
..Default::default()
};
}
}
impl Decoder { impl Decoder {
// TODO
pub fn video_codec_state() -> VideoCodecState { pub fn video_codec_state() -> VideoCodecState {
let mut state = VideoCodecState::default(); // video_codec_state is mainted by creation and destruction of Decoder.
state.ScoreVpx = 90; // It has been ensured to use after Decoder's creation.
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
{ return MY_DECODER_STATE.lock().unwrap().clone();
let best = super::hwcodec::HwDecoder::best(false); #[cfg(not(feature = "hwcodec"))]
state.H264 = best.h264.is_some(); VideoCodecState {
state.ScoreH264 = best.h264.map_or(0, |c| c.score); ScoreVpx: SCORE_VPX,
state.H265 = best.h265.is_some(); ..Default::default()
state.ScoreH265 = best.h265.map_or(0, |c| c.score);
} }
state
} }
pub fn new(config: DecoderCfg) -> Decoder { pub fn new(config: DecoderCfg) -> Decoder {
let vpx = VpxDecoder::new(config.vpx).unwrap(); let vpx = VpxDecoder::new(config.vpx).unwrap();
Decoder { let decoder = Decoder {
vpx, vpx,
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
hw: HwDecoder::new_decoders(), hw: HwDecoder::new_decoders(),
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
i420: vec![], i420: vec![],
};
#[cfg(feature = "hwcodec")]
{
let mut state = MY_DECODER_STATE.lock().unwrap();
state.ScoreVpx = SCORE_VPX;
state.H264 = decoder.hw.h264.is_some();
state.ScoreH264 = decoder.hw.h264.as_ref().map_or(0, |d| d.info.score);
state.H265 = decoder.hw.h265.is_some();
state.ScoreH265 = decoder.hw.h265.as_ref().map_or(0, |d| d.info.score);
} }
decoder
} }
pub fn handle_video_frame( pub fn handle_video_frame(

View File

@ -137,29 +137,30 @@ impl EncoderApi for HwEncoder {
} }
impl HwEncoder { impl HwEncoder {
pub fn best() -> CodecInfos { pub fn best(force_reset: bool) -> CodecInfos {
let key = "bestHwEncoders"; let key = "bestHwEncoders";
match get_config(key) {
Ok(config) => config, let config = get_config(key);
Err(_) => { if !force_reset && config.is_ok() {
let ctx = EncodeContext { config.unwrap()
name: String::from(""), } else {
width: 1920, let ctx = EncodeContext {
height: 1080, name: String::from(""),
pixfmt: DEFAULT_PIXFMT, width: 1920,
align: HW_STRIDE_ALIGN as _, height: 1080,
bitrate: 0, pixfmt: DEFAULT_PIXFMT,
timebase: DEFAULT_TIME_BASE, align: HW_STRIDE_ALIGN as _,
gop: DEFAULT_GOP, bitrate: 0,
quality: DEFAULT_HW_QUALITY, timebase: DEFAULT_TIME_BASE,
rc: DEFAULT_RC, gop: DEFAULT_GOP,
}; quality: DEFAULT_HW_QUALITY,
let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx)); rc: DEFAULT_RC,
let _ = set_config(key, &encoders) };
.map_err(|e| log::error!("{:?}", e)) let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx));
.ok(); let _ = set_config(key, &encoders)
encoders .map_err(|e| log::error!("{:?}", e))
} .ok();
encoders
} }
} }
@ -234,7 +235,7 @@ pub struct HwDecoders {
impl HwDecoder { impl HwDecoder {
/// H264, H265 decoder info with the highest score. /// H264, H265 decoder info with the highest score.
pub fn best(force_reset: bool) -> CodecInfos { fn best(force_reset: bool) -> CodecInfos {
let key = "bestHwDecoders"; let key = "bestHwDecoders";
let config = get_config(key); let config = get_config(key);
if !force_reset && config.is_ok() { if !force_reset && config.is_ok() {
@ -268,7 +269,6 @@ impl HwDecoder {
} }
if fail { if fail {
HwDecoder::best(true); HwDecoder::best(true);
// TODO: notify encoder
} }
if h264.is_some() { if h264.is_some() {

View File

@ -1159,9 +1159,11 @@ where
let latency_controller = LatencyController::new(); let latency_controller = LatencyController::new();
let latency_controller_cl = latency_controller.clone(); let latency_controller_cl = latency_controller.clone();
// Create video_handler out of the thread below to ensure that the handler exists before client start.
// It will take a few tenths of a second for the first time, and then tens of milliseconds.
let mut video_handler = VideoHandler::new(latency_controller);
std::thread::spawn(move || { std::thread::spawn(move || {
let mut video_handler = VideoHandler::new(latency_controller);
loop { loop {
if let Ok(data) = video_receiver.recv() { if let Ok(data) = video_receiver.recv() {
match data { match data {