From feaadcfc9677f846bf82449b2f74d8fb4ba02feb Mon Sep 17 00:00:00 2001 From: 21pages Date: Thu, 9 Jun 2022 17:14:26 +0800 Subject: [PATCH] scrap: ensure video_handler's creation before client start Signed-off-by: 21pages --- libs/scrap/src/common/codec.rs | 65 ++++++++++++++++++++++---------- libs/scrap/src/common/hwcodec.rs | 48 +++++++++++------------ src/client.rs | 4 +- 3 files changed, 72 insertions(+), 45 deletions(-) diff --git a/libs/scrap/src/common/codec.rs b/libs/scrap/src/common/codec.rs index d57b77b40..9e9a824dd 100644 --- a/libs/scrap/src/common/codec.rs +++ b/libs/scrap/src/common/codec.rs @@ -23,8 +23,10 @@ use hbb_common::{ #[cfg(feature = "hwcodec")] lazy_static::lazy_static! { - static ref VIDEO_CODEC_STATES: Arc>> = Default::default(); + static ref PEER_DECODER_STATES: Arc>> = Default::default(); + static ref MY_DECODER_STATE: Arc> = Default::default(); } +const SCORE_VPX: i32 = 90; #[derive(Debug, Clone)] pub struct HwEncoderConfig { @@ -96,9 +98,15 @@ impl Encoder { }), #[cfg(feature = "hwcodec")] - EncoderCfg::HW(_) => Ok(Encoder { - codec: Box::new(HwEncoder::new(config)?), - }), + EncoderCfg::HW(_) => match HwEncoder::new(config) { + Ok(hw) => Ok(Encoder { + codec: Box::new(hw), + }), + Err(e) => { + HwEncoder::best(true); + Err(e) + } + }, #[cfg(not(feature = "hwcodec"))] _ => Err(anyhow!("unsupported encoder type")), } @@ -109,7 +117,7 @@ impl Encoder { log::info!("update video encoder:{:?}", update); #[cfg(feature = "hwcodec")] { - let mut states = VIDEO_CODEC_STATES.lock().unwrap(); + let mut states = PEER_DECODER_STATES.lock().unwrap(); match update { EncoderUpdate::State(state) => { states.insert(id, state); @@ -125,14 +133,14 @@ impl Encoder { } let current_encoder_name = HwEncoder::current_name(); if states.len() > 0 { - let best = HwEncoder::best(); + let best = HwEncoder::best(false); let enabled_h264 = best.h264.is_some() && states.len() > 0 && states.iter().all(|(_, s)| s.H264); let enabled_h265 = best.h265.is_some() && states.len() > 0 && states.iter().all(|(_, s)| s.H265); // 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_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 { - // TODO pub fn video_codec_state() -> VideoCodecState { - let mut state = VideoCodecState::default(); - state.ScoreVpx = 90; - + // video_codec_state is mainted by creation and destruction of Decoder. + // It has been ensured to use after Decoder's creation. #[cfg(feature = "hwcodec")] - { - let best = super::hwcodec::HwDecoder::best(false); - state.H264 = best.h264.is_some(); - state.ScoreH264 = best.h264.map_or(0, |c| c.score); - state.H265 = best.h265.is_some(); - state.ScoreH265 = best.h265.map_or(0, |c| c.score); + return MY_DECODER_STATE.lock().unwrap().clone(); + #[cfg(not(feature = "hwcodec"))] + VideoCodecState { + ScoreVpx: SCORE_VPX, + ..Default::default() } - - state } pub fn new(config: DecoderCfg) -> Decoder { let vpx = VpxDecoder::new(config.vpx).unwrap(); - Decoder { + let decoder = Decoder { vpx, #[cfg(feature = "hwcodec")] hw: HwDecoder::new_decoders(), #[cfg(feature = "hwcodec")] 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( diff --git a/libs/scrap/src/common/hwcodec.rs b/libs/scrap/src/common/hwcodec.rs index 18c153587..2d7b6b138 100644 --- a/libs/scrap/src/common/hwcodec.rs +++ b/libs/scrap/src/common/hwcodec.rs @@ -137,29 +137,30 @@ impl EncoderApi for HwEncoder { } impl HwEncoder { - pub fn best() -> CodecInfos { + pub fn best(force_reset: bool) -> CodecInfos { let key = "bestHwEncoders"; - match get_config(key) { - Ok(config) => config, - Err(_) => { - let ctx = EncodeContext { - name: String::from(""), - width: 1920, - height: 1080, - pixfmt: DEFAULT_PIXFMT, - align: HW_STRIDE_ALIGN as _, - bitrate: 0, - timebase: DEFAULT_TIME_BASE, - gop: DEFAULT_GOP, - quality: DEFAULT_HW_QUALITY, - rc: DEFAULT_RC, - }; - let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx)); - let _ = set_config(key, &encoders) - .map_err(|e| log::error!("{:?}", e)) - .ok(); - encoders - } + + let config = get_config(key); + if !force_reset && config.is_ok() { + config.unwrap() + } else { + let ctx = EncodeContext { + name: String::from(""), + width: 1920, + height: 1080, + pixfmt: DEFAULT_PIXFMT, + align: HW_STRIDE_ALIGN as _, + bitrate: 0, + timebase: DEFAULT_TIME_BASE, + gop: DEFAULT_GOP, + quality: DEFAULT_HW_QUALITY, + rc: DEFAULT_RC, + }; + let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx)); + let _ = set_config(key, &encoders) + .map_err(|e| log::error!("{:?}", e)) + .ok(); + encoders } } @@ -234,7 +235,7 @@ pub struct HwDecoders { impl HwDecoder { /// 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 config = get_config(key); if !force_reset && config.is_ok() { @@ -268,7 +269,6 @@ impl HwDecoder { } if fail { HwDecoder::best(true); - // TODO: notify encoder } if h264.is_some() { diff --git a/src/client.rs b/src/client.rs index 2cbf007d5..c4ebbc537 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1159,9 +1159,11 @@ where let latency_controller = LatencyController::new(); 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 || { - let mut video_handler = VideoHandler::new(latency_controller); loop { if let Ok(data) = video_receiver.recv() { match data {