2022-06-30 16:19:36 +08:00

352 lines
10 KiB
Rust

use std::ops::{Deref, DerefMut};
#[cfg(feature = "hwcodec")]
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
#[cfg(feature = "hwcodec")]
use crate::hwcodec::*;
use crate::vpxcodec::*;
use hbb_common::{
anyhow::anyhow,
config::Config2,
log,
message_proto::{test_delay, video_frame, Message, VP9s, VideoCodecState},
ResultType,
};
#[cfg(feature = "hwcodec")]
use hbb_common::{
lazy_static,
message_proto::{H264s, H265s},
};
#[cfg(feature = "hwcodec")]
lazy_static::lazy_static! {
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)]
pub struct HwEncoderConfig {
pub codec_name: String,
pub width: usize,
pub height: usize,
pub bitrate: i32,
}
#[derive(Debug, Clone)]
pub enum EncoderCfg {
VPX(VpxEncoderConfig),
HW(HwEncoderConfig),
}
pub trait EncoderApi {
fn new(cfg: EncoderCfg) -> ResultType<Self>
where
Self: Sized;
fn encode_to_message(&mut self, frame: &[u8], ms: i64) -> ResultType<Message>;
fn use_yuv(&self) -> bool;
fn set_bitrate(&mut self, bitrate: u32) -> ResultType<()>;
fn get_codec_format(&self) -> test_delay::CodecFormat;
}
pub struct DecoderCfg {
pub vpx: VpxDecoderConfig,
}
pub struct Encoder {
pub codec: Box<dyn EncoderApi>,
}
impl Deref for Encoder {
type Target = Box<dyn EncoderApi>;
fn deref(&self) -> &Self::Target {
&self.codec
}
}
impl DerefMut for Encoder {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.codec
}
}
pub struct Decoder {
vpx: VpxDecoder,
#[cfg(feature = "hwcodec")]
hw: HwDecoders,
#[cfg(feature = "hwcodec")]
i420: Vec<u8>,
}
#[derive(Debug, Clone)]
pub enum EncoderUpdate {
State(VideoCodecState),
Remove,
DisableHwIfNotExist,
}
impl Encoder {
pub fn new(config: EncoderCfg) -> ResultType<Encoder> {
log::info!("new encoder:{:?}", config);
match config {
EncoderCfg::VPX(_) => Ok(Encoder {
codec: Box::new(VpxEncoder::new(config)?),
}),
#[cfg(feature = "hwcodec")]
EncoderCfg::HW(_) => match HwEncoder::new(config) {
Ok(hw) => Ok(Encoder {
codec: Box::new(hw),
}),
Err(e) => {
HwEncoder::best(true, true);
Err(e)
}
},
#[cfg(not(feature = "hwcodec"))]
_ => Err(anyhow!("unsupported encoder type")),
}
}
// TODO
pub fn update_video_encoder(id: i32, update: EncoderUpdate) {
log::info!("encoder update: {:?}", update);
#[cfg(feature = "hwcodec")]
{
let mut states = PEER_DECODER_STATES.lock().unwrap();
match update {
EncoderUpdate::State(state) => {
states.insert(id, state);
}
EncoderUpdate::Remove => {
states.remove(&id);
}
EncoderUpdate::DisableHwIfNotExist => {
if !states.contains_key(&id) {
states.insert(id, VideoCodecState::default());
}
}
}
let current_encoder_name = HwEncoder::current_name();
if states.len() > 0 {
let (best, _) = HwEncoder::best(false, true);
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 = 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);
// score decoder
score_vpx += states.iter().map(|s| s.1.ScoreVpx).sum::<i32>();
if enabled_h264 {
score_h264 += states.iter().map(|s| s.1.ScoreH264).sum::<i32>();
}
if enabled_h265 {
score_h265 += states.iter().map(|s| s.1.ScoreH265).sum::<i32>();
}
if enabled_h265 && score_h265 >= score_vpx && score_h265 >= score_h264 {
*current_encoder_name.lock().unwrap() = Some(best.h265.unwrap().name);
} else if enabled_h264 && score_h264 >= score_vpx && score_h264 >= score_h265 {
*current_encoder_name.lock().unwrap() = Some(best.h264.unwrap().name);
} else {
*current_encoder_name.lock().unwrap() = None;
}
log::info!(
"connection count:{}, h264:{}, h265:{}, score: vpx({}), h264({}), h265({}), set current encoder name {:?}",
states.len(),
enabled_h264,
enabled_h265,
score_vpx,
score_h264,
score_h265,
current_encoder_name.lock().unwrap()
)
} else {
*current_encoder_name.lock().unwrap() = None;
}
}
#[cfg(not(feature = "hwcodec"))]
{
let _ = id;
let _ = update;
}
}
#[inline]
pub fn current_hw_encoder_name() -> Option<String> {
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
return HwEncoder::current_name().lock().unwrap().clone();
} else {
return None;
}
#[cfg(not(feature = "hwcodec"))]
return None;
}
}
#[cfg(feature = "hwcodec")]
impl Drop for Decoder {
fn drop(&mut self) {
*MY_DECODER_STATE.lock().unwrap() = VideoCodecState {
ScoreVpx: SCORE_VPX,
..Default::default()
};
}
}
impl Decoder {
pub fn video_codec_state() -> VideoCodecState {
// video_codec_state is mainted by creation and destruction of Decoder.
// It has been ensured to use after Decoder's creation.
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
return MY_DECODER_STATE.lock().unwrap().clone();
} else {
return VideoCodecState {
ScoreVpx: SCORE_VPX,
..Default::default()
};
}
#[cfg(not(feature = "hwcodec"))]
VideoCodecState {
ScoreVpx: SCORE_VPX,
..Default::default()
}
}
pub fn new(config: DecoderCfg) -> Decoder {
let vpx = VpxDecoder::new(config.vpx).unwrap();
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(
&mut self,
frame: &video_frame::Union,
rgb: &mut Vec<u8>,
) -> ResultType<bool> {
match frame {
video_frame::Union::vp9s(vp9s) => {
Decoder::handle_vp9s_video_frame(&mut self.vpx, vp9s, rgb)
}
#[cfg(feature = "hwcodec")]
video_frame::Union::h264s(h264s) => {
if let Some(decoder) = &mut self.hw.h264 {
Decoder::handle_h264s_video_frame(decoder, h264s, rgb, &mut self.i420)
} else {
Err(anyhow!("don't support h264!"))
}
}
#[cfg(feature = "hwcodec")]
video_frame::Union::h265s(h265s) => {
if let Some(decoder) = &mut self.hw.h265 {
Decoder::handle_h265s_video_frame(decoder, h265s, rgb, &mut self.i420)
} else {
Err(anyhow!("don't support h265!"))
}
}
_ => Err(anyhow!("unsupported video frame type!")),
}
}
fn handle_vp9s_video_frame(
decoder: &mut VpxDecoder,
vp9s: &VP9s,
rgb: &mut Vec<u8>,
) -> ResultType<bool> {
let mut last_frame = Image::new();
for vp9 in vp9s.frames.iter() {
for frame in decoder.decode(&vp9.data)? {
drop(last_frame);
last_frame = frame;
}
}
for frame in decoder.flush()? {
drop(last_frame);
last_frame = frame;
}
if last_frame.is_null() {
Ok(false)
} else {
last_frame.rgb(1, true, rgb);
Ok(true)
}
}
#[cfg(feature = "hwcodec")]
fn handle_h264s_video_frame(
decoder: &mut HwDecoder,
h264s: &H264s,
rgb: &mut Vec<u8>,
i420: &mut Vec<u8>,
) -> ResultType<bool> {
let mut ret = false;
for h264 in h264s.h264s.iter() {
for image in decoder.decode(&h264.data)? {
// TODO: just process the last frame
if image.bgra(rgb, i420).is_ok() {
ret = true;
}
}
}
return Ok(ret);
}
#[cfg(feature = "hwcodec")]
fn handle_h265s_video_frame(
decoder: &mut HwDecoder,
h265s: &H265s,
rgb: &mut Vec<u8>,
i420: &mut Vec<u8>,
) -> ResultType<bool> {
let mut ret = false;
for h265 in h265s.h265s.iter() {
for image in decoder.decode(&h265.data)? {
// TODO: just process the last frame
if image.bgra(rgb, i420).is_ok() {
ret = true;
}
}
}
return Ok(ret);
}
}
fn check_hwcodec_config() -> bool {
if let Some(v) = Config2::get().options.get("enable-hwcodec") {
return v != "N";
}
return true; // default is true
}