2022-05-29 17:23:14 +08:00
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
2023-03-31 16:10:52 +08:00
|
|
|
ops::{Deref, DerefMut},
|
2022-05-29 17:23:14 +08:00
|
|
|
sync::{Arc, Mutex},
|
|
|
|
};
|
|
|
|
|
|
|
|
#[cfg(feature = "hwcodec")]
|
|
|
|
use crate::hwcodec::*;
|
2022-09-15 20:40:29 +08:00
|
|
|
#[cfg(feature = "mediacodec")]
|
|
|
|
use crate::mediacodec::{
|
|
|
|
MediaCodecDecoder, MediaCodecDecoders, H264_DECODER_SUPPORT, H265_DECODER_SUPPORT,
|
|
|
|
};
|
2023-05-08 20:35:24 +08:00
|
|
|
use crate::{
|
2023-07-20 21:16:38 +08:00
|
|
|
aom::{self, AomDecoder, AomEncoder, AomEncoderConfig},
|
2023-05-10 09:43:27 +08:00
|
|
|
common::GoogleImage,
|
2023-05-08 20:35:24 +08:00
|
|
|
vpxcodec::{self, VpxDecoder, VpxDecoderConfig, VpxEncoder, VpxEncoderConfig, VpxVideoCodecId},
|
2023-10-27 15:44:07 +08:00
|
|
|
CodecName, EncodeYuvFormat, ImageRgb,
|
2023-05-08 20:35:24 +08:00
|
|
|
};
|
2022-05-29 17:23:14 +08:00
|
|
|
|
|
|
|
use hbb_common::{
|
|
|
|
anyhow::anyhow,
|
2023-07-22 14:16:41 +08:00
|
|
|
bail,
|
2023-03-31 16:10:52 +08:00
|
|
|
config::PeerConfig,
|
2022-06-02 07:21:21 +08:00
|
|
|
log,
|
2023-03-31 16:10:52 +08:00
|
|
|
message_proto::{
|
2023-10-27 15:44:07 +08:00
|
|
|
supported_decoding::PreferCodec, video_frame, Chroma, CodecAbility, EncodedVideoFrames,
|
2023-10-08 21:44:54 +08:00
|
|
|
SupportedDecoding, SupportedEncoding, VideoFrame,
|
2023-03-31 16:10:52 +08:00
|
|
|
},
|
2023-11-08 08:59:27 +01:00
|
|
|
sysinfo::{System},
|
2023-07-22 14:16:41 +08:00
|
|
|
tokio::time::Instant,
|
2022-05-29 17:23:14 +08:00
|
|
|
ResultType,
|
|
|
|
};
|
2022-09-15 20:40:29 +08:00
|
|
|
#[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
|
2023-03-31 16:10:52 +08:00
|
|
|
use hbb_common::{config::Config2, lazy_static};
|
2022-05-29 17:23:14 +08:00
|
|
|
|
|
|
|
lazy_static::lazy_static! {
|
2023-03-31 16:10:52 +08:00
|
|
|
static ref PEER_DECODINGS: Arc<Mutex<HashMap<i32, SupportedDecoding>>> = Default::default();
|
|
|
|
static ref CODEC_NAME: Arc<Mutex<CodecName>> = Arc::new(Mutex::new(CodecName::VP9));
|
2023-07-20 21:16:38 +08:00
|
|
|
static ref THREAD_LOG_TIME: Arc<Mutex<Option<Instant>>> = Arc::new(Mutex::new(None));
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct HwEncoderConfig {
|
2023-03-31 16:10:52 +08:00
|
|
|
pub name: String,
|
2022-05-29 17:23:14 +08:00
|
|
|
pub width: usize,
|
|
|
|
pub height: usize,
|
2023-07-19 13:11:24 +08:00
|
|
|
pub quality: Quality,
|
2023-08-07 21:32:36 +08:00
|
|
|
pub keyframe_interval: Option<usize>,
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
|
|
|
|
2022-06-02 07:21:21 +08:00
|
|
|
#[derive(Debug, Clone)]
|
2022-05-29 17:23:14 +08:00
|
|
|
pub enum EncoderCfg {
|
|
|
|
VPX(VpxEncoderConfig),
|
2023-05-08 20:35:24 +08:00
|
|
|
AOM(AomEncoderConfig),
|
2022-05-29 17:23:14 +08:00
|
|
|
HW(HwEncoderConfig),
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait EncoderApi {
|
2023-10-27 15:44:07 +08:00
|
|
|
fn new(cfg: EncoderCfg, i444: bool) -> ResultType<Self>
|
2022-05-29 17:23:14 +08:00
|
|
|
where
|
|
|
|
Self: Sized;
|
|
|
|
|
2023-10-08 21:44:54 +08:00
|
|
|
fn encode_to_message(&mut self, frame: &[u8], ms: i64) -> ResultType<VideoFrame>;
|
2022-05-29 17:23:14 +08:00
|
|
|
|
2023-10-27 15:44:07 +08:00
|
|
|
fn yuvfmt(&self) -> EncodeYuvFormat;
|
2022-06-27 15:21:31 +08:00
|
|
|
|
2023-07-19 13:11:24 +08:00
|
|
|
fn set_quality(&mut self, quality: Quality) -> ResultType<()>;
|
|
|
|
|
|
|
|
fn bitrate(&self) -> u32;
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2023-07-22 14:16:41 +08:00
|
|
|
vp8: Option<VpxDecoder>,
|
|
|
|
vp9: Option<VpxDecoder>,
|
|
|
|
av1: Option<AomDecoder>,
|
2022-05-29 17:23:14 +08:00
|
|
|
#[cfg(feature = "hwcodec")]
|
2022-06-07 10:21:02 +08:00
|
|
|
hw: HwDecoders,
|
2022-05-29 17:23:14 +08:00
|
|
|
#[cfg(feature = "hwcodec")]
|
|
|
|
i420: Vec<u8>,
|
2022-09-15 20:40:29 +08:00
|
|
|
#[cfg(feature = "mediacodec")]
|
|
|
|
media_codec: MediaCodecDecoders,
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
|
|
|
|
2022-06-01 18:40:28 +08:00
|
|
|
#[derive(Debug, Clone)]
|
2023-03-31 16:10:52 +08:00
|
|
|
pub enum EncodingUpdate {
|
|
|
|
New(SupportedDecoding),
|
2022-06-01 18:40:28 +08:00
|
|
|
Remove,
|
2023-03-31 16:10:52 +08:00
|
|
|
NewOnlyVP9,
|
2022-06-01 18:40:28 +08:00
|
|
|
}
|
|
|
|
|
2022-05-29 17:23:14 +08:00
|
|
|
impl Encoder {
|
2023-10-27 15:44:07 +08:00
|
|
|
pub fn new(config: EncoderCfg, i444: bool) -> ResultType<Encoder> {
|
|
|
|
log::info!("new encoder:{config:?}, i444:{i444}");
|
2022-05-29 17:23:14 +08:00
|
|
|
match config {
|
|
|
|
EncoderCfg::VPX(_) => Ok(Encoder {
|
2023-10-27 15:44:07 +08:00
|
|
|
codec: Box::new(VpxEncoder::new(config, i444)?),
|
2022-05-29 17:23:14 +08:00
|
|
|
}),
|
2023-05-08 20:35:24 +08:00
|
|
|
EncoderCfg::AOM(_) => Ok(Encoder {
|
2023-10-27 15:44:07 +08:00
|
|
|
codec: Box::new(AomEncoder::new(config, i444)?),
|
2023-05-08 20:35:24 +08:00
|
|
|
}),
|
2022-05-29 17:23:14 +08:00
|
|
|
|
|
|
|
#[cfg(feature = "hwcodec")]
|
2023-10-27 15:44:07 +08:00
|
|
|
EncoderCfg::HW(_) => match HwEncoder::new(config, i444) {
|
2022-06-09 17:14:26 +08:00
|
|
|
Ok(hw) => Ok(Encoder {
|
|
|
|
codec: Box::new(hw),
|
|
|
|
}),
|
|
|
|
Err(e) => {
|
2023-04-04 21:21:00 +08:00
|
|
|
check_config_process();
|
2023-04-04 20:35:04 +08:00
|
|
|
*CODEC_NAME.lock().unwrap() = CodecName::VP9;
|
2022-06-09 17:14:26 +08:00
|
|
|
Err(e)
|
|
|
|
}
|
|
|
|
},
|
2022-05-29 17:23:14 +08:00
|
|
|
#[cfg(not(feature = "hwcodec"))]
|
|
|
|
_ => Err(anyhow!("unsupported encoder type")),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-31 16:10:52 +08:00
|
|
|
pub fn update(id: i32, update: EncodingUpdate) {
|
|
|
|
let mut decodings = PEER_DECODINGS.lock().unwrap();
|
|
|
|
match update {
|
|
|
|
EncodingUpdate::New(decoding) => {
|
|
|
|
decodings.insert(id, decoding);
|
|
|
|
}
|
|
|
|
EncodingUpdate::Remove => {
|
|
|
|
decodings.remove(&id);
|
|
|
|
}
|
|
|
|
EncodingUpdate::NewOnlyVP9 => {
|
|
|
|
decodings.insert(
|
|
|
|
id,
|
|
|
|
SupportedDecoding {
|
|
|
|
ability_vp9: 1,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let vp8_useable = decodings.len() > 0 && decodings.iter().all(|(_, s)| s.ability_vp8 > 0);
|
2023-05-08 20:35:24 +08:00
|
|
|
let av1_useable = decodings.len() > 0 && decodings.iter().all(|(_, s)| s.ability_av1 > 0);
|
2023-03-31 16:10:52 +08:00
|
|
|
#[allow(unused_mut)]
|
|
|
|
let mut h264_name = None;
|
|
|
|
#[allow(unused_mut)]
|
|
|
|
let mut h265_name = None;
|
2022-05-29 17:23:14 +08:00
|
|
|
#[cfg(feature = "hwcodec")]
|
|
|
|
{
|
2023-04-04 20:35:04 +08:00
|
|
|
if enable_hwcodec_option() {
|
|
|
|
let best = HwEncoder::best();
|
|
|
|
let h264_useable =
|
|
|
|
decodings.len() > 0 && decodings.iter().all(|(_, s)| s.ability_h264 > 0);
|
|
|
|
let h265_useable =
|
|
|
|
decodings.len() > 0 && decodings.iter().all(|(_, s)| s.ability_h265 > 0);
|
|
|
|
if h264_useable {
|
|
|
|
h264_name = best.h264.map_or(None, |c| Some(c.name));
|
|
|
|
}
|
|
|
|
if h265_useable {
|
|
|
|
h265_name = best.h265.map_or(None, |c| Some(c.name));
|
|
|
|
}
|
2023-03-31 16:10:52 +08:00
|
|
|
}
|
|
|
|
}
|
2022-06-02 07:21:21 +08:00
|
|
|
|
2023-03-31 16:10:52 +08:00
|
|
|
let mut name = CODEC_NAME.lock().unwrap();
|
|
|
|
let mut preference = PreferCodec::Auto;
|
|
|
|
let preferences: Vec<_> = decodings
|
|
|
|
.iter()
|
|
|
|
.filter(|(_, s)| {
|
|
|
|
s.prefer == PreferCodec::VP9.into()
|
|
|
|
|| s.prefer == PreferCodec::VP8.into() && vp8_useable
|
2023-05-08 20:35:24 +08:00
|
|
|
|| s.prefer == PreferCodec::AV1.into() && av1_useable
|
2023-03-31 16:10:52 +08:00
|
|
|
|| s.prefer == PreferCodec::H264.into() && h264_name.is_some()
|
|
|
|
|| s.prefer == PreferCodec::H265.into() && h265_name.is_some()
|
|
|
|
})
|
|
|
|
.map(|(_, s)| s.prefer)
|
|
|
|
.collect();
|
|
|
|
if preferences.len() > 0 && preferences.iter().all(|&p| p == preferences[0]) {
|
|
|
|
preference = preferences[0].enum_value_or(PreferCodec::Auto);
|
|
|
|
}
|
2022-07-09 20:17:10 +08:00
|
|
|
|
2023-03-31 16:10:52 +08:00
|
|
|
#[allow(unused_mut)]
|
|
|
|
let mut auto_codec = CodecName::VP9;
|
2023-09-27 18:42:57 +08:00
|
|
|
if av1_useable {
|
|
|
|
auto_codec = CodecName::AV1;
|
|
|
|
}
|
2023-03-31 16:10:52 +08:00
|
|
|
if vp8_useable && System::new_all().total_memory() <= 4 * 1024 * 1024 * 1024 {
|
|
|
|
// 4 Gb
|
|
|
|
auto_codec = CodecName::VP8
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
2023-03-31 16:10:52 +08:00
|
|
|
|
|
|
|
match preference {
|
|
|
|
PreferCodec::VP8 => *name = CodecName::VP8,
|
|
|
|
PreferCodec::VP9 => *name = CodecName::VP9,
|
2023-05-08 20:35:24 +08:00
|
|
|
PreferCodec::AV1 => *name = CodecName::AV1,
|
2023-03-31 16:10:52 +08:00
|
|
|
PreferCodec::H264 => *name = h264_name.map_or(auto_codec, |c| CodecName::H264(c)),
|
|
|
|
PreferCodec::H265 => *name = h265_name.map_or(auto_codec, |c| CodecName::H265(c)),
|
|
|
|
PreferCodec::Auto => *name = auto_codec,
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
2023-03-31 16:10:52 +08:00
|
|
|
|
|
|
|
log::info!(
|
|
|
|
"connection count:{}, used preference:{:?}, encoder:{:?}",
|
|
|
|
decodings.len(),
|
|
|
|
preference,
|
|
|
|
*name
|
|
|
|
)
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
2023-03-31 16:10:52 +08:00
|
|
|
|
2022-05-29 17:23:14 +08:00
|
|
|
#[inline]
|
2023-03-31 16:10:52 +08:00
|
|
|
pub fn negotiated_codec() -> CodecName {
|
|
|
|
CODEC_NAME.lock().unwrap().clone()
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
2022-07-09 20:17:10 +08:00
|
|
|
|
2023-03-31 16:10:52 +08:00
|
|
|
pub fn supported_encoding() -> SupportedEncoding {
|
|
|
|
#[allow(unused_mut)]
|
|
|
|
let mut encoding = SupportedEncoding {
|
|
|
|
vp8: true,
|
2023-05-08 20:35:24 +08:00
|
|
|
av1: true,
|
2023-10-27 15:44:07 +08:00
|
|
|
i444: Some(CodecAbility {
|
|
|
|
vp9: true,
|
|
|
|
av1: true,
|
|
|
|
..Default::default()
|
|
|
|
})
|
|
|
|
.into(),
|
2023-03-31 16:10:52 +08:00
|
|
|
..Default::default()
|
|
|
|
};
|
2022-07-09 20:17:10 +08:00
|
|
|
#[cfg(feature = "hwcodec")]
|
2022-12-13 09:47:23 +08:00
|
|
|
if enable_hwcodec_option() {
|
2022-07-09 20:17:10 +08:00
|
|
|
let best = HwEncoder::best();
|
2023-03-31 16:10:52 +08:00
|
|
|
encoding.h264 = best.h264.is_some();
|
|
|
|
encoding.h265 = best.h265.is_some();
|
2022-07-09 20:17:10 +08:00
|
|
|
}
|
2023-03-31 16:10:52 +08:00
|
|
|
encoding
|
2022-07-09 20:17:10 +08:00
|
|
|
}
|
2023-10-27 15:44:07 +08:00
|
|
|
|
|
|
|
pub fn use_i444(config: &EncoderCfg) -> bool {
|
|
|
|
let decodings = PEER_DECODINGS.lock().unwrap().clone();
|
|
|
|
let prefer_i444 = decodings
|
|
|
|
.iter()
|
|
|
|
.all(|d| d.1.prefer_chroma == Chroma::I444.into());
|
|
|
|
let i444_useable = match config {
|
|
|
|
EncoderCfg::VPX(vpx) => match vpx.codec {
|
|
|
|
VpxVideoCodecId::VP8 => false,
|
|
|
|
VpxVideoCodecId::VP9 => decodings.iter().all(|d| d.1.i444.vp9),
|
|
|
|
},
|
|
|
|
EncoderCfg::AOM(_) => decodings.iter().all(|d| d.1.i444.av1),
|
|
|
|
EncoderCfg::HW(_) => false,
|
|
|
|
};
|
|
|
|
prefer_i444 && i444_useable && !decodings.is_empty()
|
|
|
|
}
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Decoder {
|
2023-03-31 16:10:52 +08:00
|
|
|
pub fn supported_decodings(id_for_perfer: Option<&str>) -> SupportedDecoding {
|
2023-10-27 15:44:07 +08:00
|
|
|
let (prefer, prefer_chroma) = Self::preference(id_for_perfer);
|
|
|
|
|
2023-03-31 16:10:52 +08:00
|
|
|
#[allow(unused_mut)]
|
|
|
|
let mut decoding = SupportedDecoding {
|
|
|
|
ability_vp8: 1,
|
|
|
|
ability_vp9: 1,
|
2023-05-08 20:35:24 +08:00
|
|
|
ability_av1: 1,
|
2023-10-27 15:44:07 +08:00
|
|
|
i444: Some(CodecAbility {
|
|
|
|
vp9: true,
|
|
|
|
av1: true,
|
|
|
|
..Default::default()
|
|
|
|
})
|
|
|
|
.into(),
|
|
|
|
prefer: prefer.into(),
|
|
|
|
prefer_chroma: prefer_chroma.into(),
|
2023-03-31 16:10:52 +08:00
|
|
|
..Default::default()
|
|
|
|
};
|
2022-05-29 17:23:14 +08:00
|
|
|
#[cfg(feature = "hwcodec")]
|
2022-12-13 09:47:23 +08:00
|
|
|
if enable_hwcodec_option() {
|
2022-07-19 18:14:34 +08:00
|
|
|
let best = HwDecoder::best();
|
2023-03-31 16:10:52 +08:00
|
|
|
decoding.ability_h264 = if best.h264.is_some() { 1 } else { 0 };
|
|
|
|
decoding.ability_h265 = if best.h265.is_some() { 1 } else { 0 };
|
2022-09-15 20:40:29 +08:00
|
|
|
}
|
|
|
|
#[cfg(feature = "mediacodec")]
|
2022-12-13 09:47:23 +08:00
|
|
|
if enable_hwcodec_option() {
|
2023-03-31 16:10:52 +08:00
|
|
|
decoding.ability_h264 =
|
|
|
|
if H264_DECODER_SUPPORT.load(std::sync::atomic::Ordering::SeqCst) {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
|
|
|
decoding.ability_h265 =
|
|
|
|
if H265_DECODER_SUPPORT.load(std::sync::atomic::Ordering::SeqCst) {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
2023-03-31 16:10:52 +08:00
|
|
|
decoding
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
|
|
|
|
2023-03-31 16:10:52 +08:00
|
|
|
pub fn new() -> Decoder {
|
|
|
|
let vp8 = VpxDecoder::new(VpxDecoderConfig {
|
|
|
|
codec: VpxVideoCodecId::VP8,
|
|
|
|
})
|
2023-07-22 14:16:41 +08:00
|
|
|
.ok();
|
2023-03-31 16:10:52 +08:00
|
|
|
let vp9 = VpxDecoder::new(VpxDecoderConfig {
|
|
|
|
codec: VpxVideoCodecId::VP9,
|
2023-05-08 20:35:24 +08:00
|
|
|
})
|
2023-07-22 14:16:41 +08:00
|
|
|
.ok();
|
|
|
|
let av1 = AomDecoder::new().ok();
|
2022-07-19 18:14:34 +08:00
|
|
|
Decoder {
|
2023-03-31 16:10:52 +08:00
|
|
|
vp8,
|
|
|
|
vp9,
|
2023-05-08 20:35:24 +08:00
|
|
|
av1,
|
2022-05-29 17:23:14 +08:00
|
|
|
#[cfg(feature = "hwcodec")]
|
2022-12-13 09:47:23 +08:00
|
|
|
hw: if enable_hwcodec_option() {
|
|
|
|
HwDecoder::new_decoders()
|
|
|
|
} else {
|
|
|
|
HwDecoders::default()
|
|
|
|
},
|
2022-05-29 17:23:14 +08:00
|
|
|
#[cfg(feature = "hwcodec")]
|
|
|
|
i420: vec![],
|
2022-09-15 20:40:29 +08:00
|
|
|
#[cfg(feature = "mediacodec")]
|
2022-12-13 09:47:23 +08:00
|
|
|
media_codec: if enable_hwcodec_option() {
|
|
|
|
MediaCodecDecoder::new_decoders()
|
|
|
|
} else {
|
|
|
|
MediaCodecDecoders::default()
|
|
|
|
},
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-28 12:35:46 +08:00
|
|
|
// rgb [in/out] fmt and stride must be set in ImageRgb
|
2022-05-29 17:23:14 +08:00
|
|
|
pub fn handle_video_frame(
|
|
|
|
&mut self,
|
|
|
|
frame: &video_frame::Union,
|
2023-04-28 11:44:52 +08:00
|
|
|
rgb: &mut ImageRgb,
|
2023-10-27 15:44:07 +08:00
|
|
|
chroma: &mut Option<Chroma>,
|
2022-05-29 17:23:14 +08:00
|
|
|
) -> ResultType<bool> {
|
|
|
|
match frame {
|
2023-03-31 16:10:52 +08:00
|
|
|
video_frame::Union::Vp8s(vp8s) => {
|
2023-07-22 14:16:41 +08:00
|
|
|
if let Some(vp8) = &mut self.vp8 {
|
2023-10-27 15:44:07 +08:00
|
|
|
Decoder::handle_vpxs_video_frame(vp8, vp8s, rgb, chroma)
|
2023-07-22 14:16:41 +08:00
|
|
|
} else {
|
|
|
|
bail!("vp8 decoder not available");
|
|
|
|
}
|
2023-03-31 16:10:52 +08:00
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
video_frame::Union::Vp9s(vp9s) => {
|
2023-07-22 14:16:41 +08:00
|
|
|
if let Some(vp9) = &mut self.vp9 {
|
2023-10-27 15:44:07 +08:00
|
|
|
Decoder::handle_vpxs_video_frame(vp9, vp9s, rgb, chroma)
|
2023-07-22 14:16:41 +08:00
|
|
|
} else {
|
|
|
|
bail!("vp9 decoder not available");
|
|
|
|
}
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
2023-05-08 20:35:24 +08:00
|
|
|
video_frame::Union::Av1s(av1s) => {
|
2023-07-22 14:16:41 +08:00
|
|
|
if let Some(av1) = &mut self.av1 {
|
2023-10-27 15:44:07 +08:00
|
|
|
Decoder::handle_av1s_video_frame(av1, av1s, rgb, chroma)
|
2023-07-22 14:16:41 +08:00
|
|
|
} else {
|
|
|
|
bail!("av1 decoder not available");
|
|
|
|
}
|
2023-05-08 20:35:24 +08:00
|
|
|
}
|
2022-05-29 17:23:14 +08:00
|
|
|
#[cfg(feature = "hwcodec")]
|
2022-07-14 17:20:01 +08:00
|
|
|
video_frame::Union::H264s(h264s) => {
|
2023-10-27 15:44:07 +08:00
|
|
|
*chroma = Some(Chroma::I420);
|
2022-06-07 10:21:02 +08:00
|
|
|
if let Some(decoder) = &mut self.hw.h264 {
|
2023-04-28 11:44:52 +08:00
|
|
|
Decoder::handle_hw_video_frame(decoder, h264s, rgb, &mut self.i420)
|
2022-05-29 17:23:14 +08:00
|
|
|
} else {
|
|
|
|
Err(anyhow!("don't support h264!"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(feature = "hwcodec")]
|
2022-07-14 17:20:01 +08:00
|
|
|
video_frame::Union::H265s(h265s) => {
|
2023-10-27 15:44:07 +08:00
|
|
|
*chroma = Some(Chroma::I420);
|
2022-06-07 10:21:02 +08:00
|
|
|
if let Some(decoder) = &mut self.hw.h265 {
|
2023-04-28 11:44:52 +08:00
|
|
|
Decoder::handle_hw_video_frame(decoder, h265s, rgb, &mut self.i420)
|
2022-05-29 17:23:14 +08:00
|
|
|
} else {
|
|
|
|
Err(anyhow!("don't support h265!"))
|
|
|
|
}
|
|
|
|
}
|
2022-09-15 20:40:29 +08:00
|
|
|
#[cfg(feature = "mediacodec")]
|
|
|
|
video_frame::Union::H264s(h264s) => {
|
2023-10-27 15:44:07 +08:00
|
|
|
*chroma = Some(Chroma::I420);
|
2022-09-15 20:40:29 +08:00
|
|
|
if let Some(decoder) = &mut self.media_codec.h264 {
|
2023-04-28 11:44:52 +08:00
|
|
|
Decoder::handle_mediacodec_video_frame(decoder, h264s, rgb)
|
2022-09-15 20:40:29 +08:00
|
|
|
} else {
|
|
|
|
Err(anyhow!("don't support h264!"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(feature = "mediacodec")]
|
|
|
|
video_frame::Union::H265s(h265s) => {
|
2023-10-27 15:44:07 +08:00
|
|
|
*chroma = Some(Chroma::I420);
|
2022-09-15 20:40:29 +08:00
|
|
|
if let Some(decoder) = &mut self.media_codec.h265 {
|
2023-04-28 11:44:52 +08:00
|
|
|
Decoder::handle_mediacodec_video_frame(decoder, h265s, rgb)
|
2022-09-15 20:40:29 +08:00
|
|
|
} else {
|
|
|
|
Err(anyhow!("don't support h265!"))
|
|
|
|
}
|
|
|
|
}
|
2022-05-29 17:23:14 +08:00
|
|
|
_ => Err(anyhow!("unsupported video frame type!")),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-28 12:35:46 +08:00
|
|
|
// rgb [in/out] fmt and stride must be set in ImageRgb
|
2023-03-31 16:10:52 +08:00
|
|
|
fn handle_vpxs_video_frame(
|
2022-05-29 17:23:14 +08:00
|
|
|
decoder: &mut VpxDecoder,
|
2023-03-31 16:10:52 +08:00
|
|
|
vpxs: &EncodedVideoFrames,
|
2023-04-28 11:44:52 +08:00
|
|
|
rgb: &mut ImageRgb,
|
2023-10-27 15:44:07 +08:00
|
|
|
chroma: &mut Option<Chroma>,
|
2022-05-29 17:23:14 +08:00
|
|
|
) -> ResultType<bool> {
|
2023-05-08 20:35:24 +08:00
|
|
|
let mut last_frame = vpxcodec::Image::new();
|
2023-03-31 16:10:52 +08:00
|
|
|
for vpx in vpxs.frames.iter() {
|
|
|
|
for frame in decoder.decode(&vpx.data)? {
|
2022-05-29 17:23:14 +08:00
|
|
|
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 {
|
2023-10-27 15:44:07 +08:00
|
|
|
*chroma = Some(last_frame.chroma());
|
2023-04-28 11:44:52 +08:00
|
|
|
last_frame.to(rgb);
|
2022-05-29 17:23:14 +08:00
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 20:35:24 +08:00
|
|
|
// rgb [in/out] fmt and stride must be set in ImageRgb
|
|
|
|
fn handle_av1s_video_frame(
|
|
|
|
decoder: &mut AomDecoder,
|
|
|
|
av1s: &EncodedVideoFrames,
|
|
|
|
rgb: &mut ImageRgb,
|
2023-10-27 15:44:07 +08:00
|
|
|
chroma: &mut Option<Chroma>,
|
2023-05-08 20:35:24 +08:00
|
|
|
) -> ResultType<bool> {
|
|
|
|
let mut last_frame = aom::Image::new();
|
|
|
|
for av1 in av1s.frames.iter() {
|
|
|
|
for frame in decoder.decode(&av1.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 {
|
2023-10-27 15:44:07 +08:00
|
|
|
*chroma = Some(last_frame.chroma());
|
2023-05-08 20:35:24 +08:00
|
|
|
last_frame.to(rgb);
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-28 12:35:46 +08:00
|
|
|
// rgb [in/out] fmt and stride must be set in ImageRgb
|
2022-05-29 17:23:14 +08:00
|
|
|
#[cfg(feature = "hwcodec")]
|
2022-07-05 16:16:08 +08:00
|
|
|
fn handle_hw_video_frame(
|
2022-05-29 17:23:14 +08:00
|
|
|
decoder: &mut HwDecoder,
|
2022-07-05 16:16:08 +08:00
|
|
|
frames: &EncodedVideoFrames,
|
2023-04-28 11:44:52 +08:00
|
|
|
rgb: &mut ImageRgb,
|
2022-05-29 17:23:14 +08:00
|
|
|
i420: &mut Vec<u8>,
|
|
|
|
) -> ResultType<bool> {
|
|
|
|
let mut ret = false;
|
2022-07-05 16:16:08 +08:00
|
|
|
for h264 in frames.frames.iter() {
|
2022-05-29 17:23:14 +08:00
|
|
|
for image in decoder.decode(&h264.data)? {
|
|
|
|
// TODO: just process the last frame
|
2023-04-28 11:44:52 +08:00
|
|
|
if image.to_fmt(rgb, i420).is_ok() {
|
2022-05-29 17:23:14 +08:00
|
|
|
ret = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Ok(ret);
|
|
|
|
}
|
2022-07-09 20:17:10 +08:00
|
|
|
|
2023-04-28 12:35:46 +08:00
|
|
|
// rgb [in/out] fmt and stride must be set in ImageRgb
|
2022-09-15 20:40:29 +08:00
|
|
|
#[cfg(feature = "mediacodec")]
|
|
|
|
fn handle_mediacodec_video_frame(
|
|
|
|
decoder: &mut MediaCodecDecoder,
|
|
|
|
frames: &EncodedVideoFrames,
|
2023-04-28 11:44:52 +08:00
|
|
|
rgb: &mut ImageRgb,
|
2022-09-15 20:40:29 +08:00
|
|
|
) -> ResultType<bool> {
|
|
|
|
let mut ret = false;
|
|
|
|
for h264 in frames.frames.iter() {
|
2023-04-28 11:44:52 +08:00
|
|
|
return decoder.decode(&h264.data, rgb);
|
2022-09-15 20:40:29 +08:00
|
|
|
}
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
|
2023-10-27 15:44:07 +08:00
|
|
|
fn preference(id: Option<&str>) -> (PreferCodec, Chroma) {
|
|
|
|
let id = id.unwrap_or_default();
|
|
|
|
if id.is_empty() {
|
|
|
|
return (PreferCodec::Auto, Chroma::I420);
|
|
|
|
}
|
|
|
|
let options = PeerConfig::load(id).options;
|
|
|
|
let codec = options
|
2022-07-09 20:17:10 +08:00
|
|
|
.get("codec-preference")
|
|
|
|
.map_or("".to_owned(), |c| c.to_owned());
|
2023-10-27 15:44:07 +08:00
|
|
|
let codec = if codec == "vp8" {
|
2023-03-31 16:10:52 +08:00
|
|
|
PreferCodec::VP8
|
|
|
|
} else if codec == "vp9" {
|
|
|
|
PreferCodec::VP9
|
2023-05-08 20:35:24 +08:00
|
|
|
} else if codec == "av1" {
|
|
|
|
PreferCodec::AV1
|
2022-07-09 20:17:10 +08:00
|
|
|
} else if codec == "h264" {
|
2023-01-09 02:58:02 -05:00
|
|
|
PreferCodec::H264
|
2022-07-09 20:17:10 +08:00
|
|
|
} else if codec == "h265" {
|
2023-01-09 02:58:02 -05:00
|
|
|
PreferCodec::H265
|
2022-07-09 20:17:10 +08:00
|
|
|
} else {
|
2023-01-09 02:58:02 -05:00
|
|
|
PreferCodec::Auto
|
2023-10-27 15:44:07 +08:00
|
|
|
};
|
|
|
|
let chroma = if options.get("i444") == Some(&"Y".to_string()) {
|
|
|
|
Chroma::I444
|
|
|
|
} else {
|
|
|
|
Chroma::I420
|
|
|
|
};
|
|
|
|
(codec, chroma)
|
2022-07-09 20:17:10 +08:00
|
|
|
}
|
2022-05-29 17:23:14 +08:00
|
|
|
}
|
2022-06-30 16:19:36 +08:00
|
|
|
|
2022-09-15 20:40:29 +08:00
|
|
|
#[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
|
2022-12-13 09:47:23 +08:00
|
|
|
fn enable_hwcodec_option() -> bool {
|
2022-06-30 16:19:36 +08:00
|
|
|
if let Some(v) = Config2::get().options.get("enable-hwcodec") {
|
|
|
|
return v != "N";
|
|
|
|
}
|
|
|
|
return true; // default is true
|
|
|
|
}
|
2023-07-19 13:11:24 +08:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
pub enum Quality {
|
|
|
|
Best,
|
|
|
|
Balanced,
|
|
|
|
Low,
|
|
|
|
Custom(u32),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Quality {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::Balanced
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn base_bitrate(width: u32, height: u32) -> u32 {
|
|
|
|
#[allow(unused_mut)]
|
|
|
|
let mut base_bitrate = ((width * height) / 1000) as u32; // same as 1.1.9
|
|
|
|
if base_bitrate == 0 {
|
|
|
|
base_bitrate = 1920 * 1080 / 1000;
|
|
|
|
}
|
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
{
|
|
|
|
// fix when android screen shrinks
|
|
|
|
let fix = crate::Display::fix_quality() as u32;
|
|
|
|
log::debug!("Android screen, fix quality:{}", fix);
|
|
|
|
base_bitrate = base_bitrate * fix;
|
|
|
|
}
|
|
|
|
base_bitrate
|
|
|
|
}
|
2023-07-20 21:16:38 +08:00
|
|
|
|
|
|
|
pub fn codec_thread_num() -> usize {
|
|
|
|
let max: usize = num_cpus::get();
|
2023-07-24 14:17:09 +08:00
|
|
|
let mut res;
|
2023-07-20 21:16:38 +08:00
|
|
|
let info;
|
|
|
|
#[cfg(windows)]
|
|
|
|
{
|
2023-07-24 14:17:09 +08:00
|
|
|
res = 0;
|
2023-07-20 21:16:38 +08:00
|
|
|
let percent = hbb_common::platform::windows::cpu_uage_one_minute();
|
|
|
|
info = format!("cpu usage:{:?}", percent);
|
|
|
|
if let Some(pecent) = percent {
|
|
|
|
if pecent < 100.0 {
|
|
|
|
res = ((100.0 - pecent) * (max as f64) / 200.0).round() as usize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
{
|
|
|
|
let s = System::new_all();
|
|
|
|
// https://man7.org/linux/man-pages/man3/getloadavg.3.html
|
|
|
|
let avg = s.load_average();
|
|
|
|
info = format!("cpu loadavg:{}", avg.one);
|
|
|
|
res = (((max as f64) - avg.one) * 0.5).round() as usize;
|
|
|
|
}
|
2023-07-25 15:46:29 +08:00
|
|
|
res = std::cmp::min(res, max / 2);
|
|
|
|
if res == 0 {
|
|
|
|
res = 1;
|
|
|
|
}
|
2023-07-20 21:16:38 +08:00
|
|
|
// avoid frequent log
|
|
|
|
let log = match THREAD_LOG_TIME.lock().unwrap().clone() {
|
|
|
|
Some(instant) => instant.elapsed().as_secs() > 1,
|
|
|
|
None => true,
|
|
|
|
};
|
|
|
|
if log {
|
2023-07-24 14:17:09 +08:00
|
|
|
log::info!("cpu num:{max}, {info}, codec thread:{res}");
|
2023-07-20 21:16:38 +08:00
|
|
|
*THREAD_LOG_TIME.lock().unwrap() = Some(Instant::now());
|
|
|
|
}
|
|
|
|
res
|
|
|
|
}
|