mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
hwcodec uses one repository (#7701)
* update hwcodec, gpucodec repo is merged to hwcodec Signed-off-by: 21pages <pages21@163.com> * rename gpucodec.rs to vram.rs Signed-off-by: 21pages <pages21@163.com> * rename all gpucodec to vram, because vram is a feature of hwcodec Signed-off-by: 21pages <pages21@163.com> * use one check process and one config file * set check encode image size to 720p Signed-off-by: 21pages <pages21@163.com> --------- Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
@@ -409,9 +409,7 @@ fn patch(path: PathBuf) -> PathBuf {
|
||||
if let Ok(user) = crate::platform::linux::run_cmds_trim_newline("whoami") {
|
||||
if user != "root" {
|
||||
let cmd = format!("getent passwd '{}' | awk -F':' '{{print $6}}'", user);
|
||||
if let Ok(output) =
|
||||
crate::platform::linux::run_cmds_trim_newline(&cmd)
|
||||
{
|
||||
if let Ok(output) = crate::platform::linux::run_cmds_trim_newline(&cmd) {
|
||||
return output.into();
|
||||
}
|
||||
return format!("/home/{user}").into();
|
||||
@@ -505,7 +503,7 @@ impl Config {
|
||||
fn store_<T: serde::Serialize>(config: &T, suffix: &str) {
|
||||
let file = Self::file_(suffix);
|
||||
if let Err(err) = store_path(file, config) {
|
||||
log::error!("Failed to store config: {}", err);
|
||||
log::error!("Failed to store {suffix} config: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1495,8 +1493,10 @@ impl LanPeers {
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct HwCodecConfig {
|
||||
#[serde(default, deserialize_with = "deserialize_hashmap_string_string")]
|
||||
pub options: HashMap<String, String>,
|
||||
#[serde(default, deserialize_with = "deserialize_string")]
|
||||
pub ram: String,
|
||||
#[serde(default, deserialize_with = "deserialize_string")]
|
||||
pub vram: String,
|
||||
}
|
||||
|
||||
impl HwCodecConfig {
|
||||
@@ -1511,25 +1511,17 @@ impl HwCodecConfig {
|
||||
pub fn clear() {
|
||||
HwCodecConfig::default().store();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct GpucodecConfig {
|
||||
#[serde(default, deserialize_with = "deserialize_string")]
|
||||
pub available: String,
|
||||
}
|
||||
|
||||
impl GpucodecConfig {
|
||||
pub fn load() -> GpucodecConfig {
|
||||
Config::load_::<GpucodecConfig>("_gpucodec")
|
||||
pub fn clear_ram() {
|
||||
let mut c = Self::load();
|
||||
c.ram = Default::default();
|
||||
c.store();
|
||||
}
|
||||
|
||||
pub fn store(&self) {
|
||||
Config::store_(self, "_gpucodec");
|
||||
}
|
||||
|
||||
pub fn clear() {
|
||||
GpucodecConfig::default().store();
|
||||
pub fn clear_vram() {
|
||||
let mut c = Self::load();
|
||||
c.vram = Default::default();
|
||||
c.store();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ pub mod keyboard;
|
||||
pub use dlopen;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub use machine_uid;
|
||||
pub use serde_derive;
|
||||
pub use serde_json;
|
||||
pub use sysinfo;
|
||||
pub use toml;
|
||||
pub use uuid;
|
||||
|
||||
@@ -13,6 +13,8 @@ edition = "2018"
|
||||
wayland = ["gstreamer", "gstreamer-app", "gstreamer-video", "dbus", "tracing"]
|
||||
mediacodec = ["ndk"]
|
||||
linux-pkg-config = ["dep:pkg-config"]
|
||||
hwcodec = ["dep:hwcodec"]
|
||||
vram = ["hwcodec/vram"]
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "1.0"
|
||||
@@ -20,6 +22,7 @@ num_cpus = "1.15"
|
||||
lazy_static = "1.4"
|
||||
hbb_common = { path = "../hbb_common" }
|
||||
webm = { git = "https://github.com/21pages/rust-webm" }
|
||||
serde = {version="1.0", features=["derive"]}
|
||||
|
||||
[dependencies.winapi]
|
||||
version = "0.3"
|
||||
@@ -41,7 +44,6 @@ ndk-context = "0.1"
|
||||
[target.'cfg(not(target_os = "android"))'.dev-dependencies]
|
||||
repng = "0.2"
|
||||
docopt = "1.1"
|
||||
serde = {version="1.0", features=["derive"]}
|
||||
quest = "0.3"
|
||||
|
||||
[build-dependencies]
|
||||
@@ -56,8 +58,9 @@ gstreamer = { version = "0.16", optional = true }
|
||||
gstreamer-app = { version = "0.16", features = ["v1_10"], optional = true }
|
||||
gstreamer-video = { version = "0.16", optional = true }
|
||||
|
||||
[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dependencies]
|
||||
hwcodec = { git = "https://github.com/21pages/hwcodec", branch = "stable", optional = true }
|
||||
[dependencies.hwcodec]
|
||||
git = "https://github.com/21pages/hwcodec"
|
||||
optional = true
|
||||
features = ["ffmpeg"]
|
||||
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
gpucodec = { git = "https://github.com/21pages/gpucodec", optional = true }
|
||||
|
||||
@@ -239,16 +239,16 @@ fn test_av1(
|
||||
|
||||
#[cfg(feature = "hwcodec")]
|
||||
mod hw {
|
||||
use hwcodec::ffmpeg::CodecInfo;
|
||||
use hwcodec::ffmpeg_ram::CodecInfo;
|
||||
use scrap::{
|
||||
hwcodec::{HwDecoder, HwEncoder, HwEncoderConfig},
|
||||
hwcodec::{HwRamDecoder, HwRamEncoder, HwRamEncoderConfig},
|
||||
CodecFormat,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn test(c: &mut Capturer, width: usize, height: usize, quality: Q, yuv_count: usize) {
|
||||
let best = HwEncoder::best();
|
||||
let best = HwRamEncoder::best();
|
||||
let mut h264s = Vec::new();
|
||||
let mut h265s = Vec::new();
|
||||
if let Some(info) = best.h264 {
|
||||
@@ -270,8 +270,8 @@ mod hw {
|
||||
yuv_count: usize,
|
||||
h26xs: &mut Vec<Vec<u8>>,
|
||||
) {
|
||||
let mut encoder = HwEncoder::new(
|
||||
EncoderCfg::HW(HwEncoderConfig {
|
||||
let mut encoder = HwRamEncoder::new(
|
||||
EncoderCfg::HWRAM(HwRamEncoderConfig {
|
||||
name: info.name.clone(),
|
||||
width,
|
||||
height,
|
||||
@@ -321,7 +321,7 @@ mod hw {
|
||||
}
|
||||
|
||||
fn test_decoder(format: CodecFormat, h26xs: &Vec<Vec<u8>>) {
|
||||
let mut decoder = HwDecoder::new(format).unwrap();
|
||||
let mut decoder = HwRamDecoder::new(format).unwrap();
|
||||
let start = Instant::now();
|
||||
let mut cnt = 0;
|
||||
for h26x in h26xs {
|
||||
|
||||
@@ -268,7 +268,7 @@ impl EncoderApi for AomEncoder {
|
||||
self.yuvfmt.clone()
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn input_texture(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ use std::{
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
use crate::gpucodec::*;
|
||||
#[cfg(feature = "hwcodec")]
|
||||
use crate::hwcodec::*;
|
||||
#[cfg(feature = "mediacodec")]
|
||||
use crate::mediacodec::{MediaCodecDecoder, H264_DECODER_SUPPORT, H265_DECODER_SUPPORT};
|
||||
#[cfg(feature = "vram")]
|
||||
use crate::vram::*;
|
||||
use crate::{
|
||||
aom::{self, AomDecoder, AomEncoder, AomEncoderConfig},
|
||||
common::GoogleImage,
|
||||
@@ -31,7 +31,7 @@ use hbb_common::{
|
||||
tokio::time::Instant,
|
||||
ResultType,
|
||||
};
|
||||
#[cfg(any(feature = "hwcodec", feature = "mediacodec", feature = "gpucodec"))]
|
||||
#[cfg(any(feature = "hwcodec", feature = "mediacodec", feature = "vram"))]
|
||||
use hbb_common::{config::Config2, lazy_static};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
@@ -47,9 +47,9 @@ pub enum EncoderCfg {
|
||||
VPX(VpxEncoderConfig),
|
||||
AOM(AomEncoderConfig),
|
||||
#[cfg(feature = "hwcodec")]
|
||||
HW(HwEncoderConfig),
|
||||
#[cfg(feature = "gpucodec")]
|
||||
GPU(GpuEncoderConfig),
|
||||
HWRAM(HwRamEncoderConfig),
|
||||
#[cfg(feature = "vram")]
|
||||
VRAM(VRamEncoderConfig),
|
||||
}
|
||||
|
||||
pub trait EncoderApi {
|
||||
@@ -61,7 +61,7 @@ pub trait EncoderApi {
|
||||
|
||||
fn yuvfmt(&self) -> EncodeYuvFormat;
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn input_texture(&self) -> bool;
|
||||
|
||||
fn set_quality(&mut self, quality: Quality) -> ResultType<()>;
|
||||
@@ -94,13 +94,13 @@ pub struct Decoder {
|
||||
vp9: Option<VpxDecoder>,
|
||||
av1: Option<AomDecoder>,
|
||||
#[cfg(feature = "hwcodec")]
|
||||
h264_ram: Option<HwDecoder>,
|
||||
h264_ram: Option<HwRamDecoder>,
|
||||
#[cfg(feature = "hwcodec")]
|
||||
h265_ram: Option<HwDecoder>,
|
||||
#[cfg(feature = "gpucodec")]
|
||||
h264_vram: Option<GpuDecoder>,
|
||||
#[cfg(feature = "gpucodec")]
|
||||
h265_vram: Option<GpuDecoder>,
|
||||
h265_ram: Option<HwRamDecoder>,
|
||||
#[cfg(feature = "vram")]
|
||||
h264_vram: Option<VRamDecoder>,
|
||||
#[cfg(feature = "vram")]
|
||||
h265_vram: Option<VRamDecoder>,
|
||||
#[cfg(feature = "mediacodec")]
|
||||
h264_media_codec: MediaCodecDecoder,
|
||||
#[cfg(feature = "mediacodec")]
|
||||
@@ -131,25 +131,25 @@ impl Encoder {
|
||||
}),
|
||||
|
||||
#[cfg(feature = "hwcodec")]
|
||||
EncoderCfg::HW(_) => match HwEncoder::new(config, i444) {
|
||||
EncoderCfg::HWRAM(_) => match HwRamEncoder::new(config, i444) {
|
||||
Ok(hw) => Ok(Encoder {
|
||||
codec: Box::new(hw),
|
||||
}),
|
||||
Err(e) => {
|
||||
log::error!("new hw encoder failed: {e:?}, clear config");
|
||||
hbb_common::config::HwCodecConfig::clear();
|
||||
hbb_common::config::HwCodecConfig::clear_ram();
|
||||
*ENCODE_CODEC_NAME.lock().unwrap() = CodecName::VP9;
|
||||
Err(e)
|
||||
}
|
||||
},
|
||||
#[cfg(feature = "gpucodec")]
|
||||
EncoderCfg::GPU(_) => match GpuEncoder::new(config, i444) {
|
||||
#[cfg(feature = "vram")]
|
||||
EncoderCfg::VRAM(_) => match VRamEncoder::new(config, i444) {
|
||||
Ok(tex) => Ok(Encoder {
|
||||
codec: Box::new(tex),
|
||||
}),
|
||||
Err(e) => {
|
||||
log::error!("new gpu encoder failed: {e:?}, clear config");
|
||||
hbb_common::config::GpucodecConfig::clear();
|
||||
log::error!("new vram encoder failed: {e:?}, clear config");
|
||||
hbb_common::config::HwCodecConfig::clear_vram();
|
||||
*ENCODE_CODEC_NAME.lock().unwrap() = CodecName::VP9;
|
||||
Err(e)
|
||||
}
|
||||
@@ -186,19 +186,19 @@ impl Encoder {
|
||||
let _all_support_h265_decoding =
|
||||
decodings.len() > 0 && decodings.iter().all(|(_, s)| s.ability_h265 > 0);
|
||||
#[allow(unused_mut)]
|
||||
let mut h264gpu_encoding = false;
|
||||
let mut h264vram_encoding = false;
|
||||
#[allow(unused_mut)]
|
||||
let mut h265gpu_encoding = false;
|
||||
#[cfg(feature = "gpucodec")]
|
||||
if enable_gpucodec_option() {
|
||||
let mut h265vram_encoding = false;
|
||||
#[cfg(feature = "vram")]
|
||||
if enable_vram_option() {
|
||||
if _all_support_h264_decoding {
|
||||
if GpuEncoder::available(CodecName::H264GPU).len() > 0 {
|
||||
h264gpu_encoding = true;
|
||||
if VRamEncoder::available(CodecName::H264VRAM).len() > 0 {
|
||||
h264vram_encoding = true;
|
||||
}
|
||||
}
|
||||
if _all_support_h265_decoding {
|
||||
if GpuEncoder::available(CodecName::H265GPU).len() > 0 {
|
||||
h265gpu_encoding = true;
|
||||
if VRamEncoder::available(CodecName::H265VRAM).len() > 0 {
|
||||
h265vram_encoding = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,7 +208,7 @@ impl Encoder {
|
||||
let mut h265hw_encoding = None;
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if enable_hwcodec_option() {
|
||||
let best = HwEncoder::best();
|
||||
let best = HwRamEncoder::best();
|
||||
if _all_support_h264_decoding {
|
||||
h264hw_encoding = best.h264.map_or(None, |c| Some(c.name));
|
||||
}
|
||||
@@ -217,9 +217,9 @@ impl Encoder {
|
||||
}
|
||||
}
|
||||
let h264_useable =
|
||||
_all_support_h264_decoding && (h264gpu_encoding || h264hw_encoding.is_some());
|
||||
_all_support_h264_decoding && (h264vram_encoding || h264hw_encoding.is_some());
|
||||
let h265_useable =
|
||||
_all_support_h265_decoding && (h265gpu_encoding || h265hw_encoding.is_some());
|
||||
_all_support_h265_decoding && (h265vram_encoding || h265hw_encoding.is_some());
|
||||
let mut name = ENCODE_CODEC_NAME.lock().unwrap();
|
||||
let mut preference = PreferCodec::Auto;
|
||||
let preferences: Vec<_> = decodings
|
||||
@@ -254,19 +254,19 @@ impl Encoder {
|
||||
PreferCodec::VP9 => CodecName::VP9,
|
||||
PreferCodec::AV1 => CodecName::AV1,
|
||||
PreferCodec::H264 => {
|
||||
if h264gpu_encoding {
|
||||
CodecName::H264GPU
|
||||
if h264vram_encoding {
|
||||
CodecName::H264VRAM
|
||||
} else if let Some(v) = h264hw_encoding {
|
||||
CodecName::H264HW(v)
|
||||
CodecName::H264RAM(v)
|
||||
} else {
|
||||
auto_codec
|
||||
}
|
||||
}
|
||||
PreferCodec::H265 => {
|
||||
if h265gpu_encoding {
|
||||
CodecName::H265GPU
|
||||
if h265vram_encoding {
|
||||
CodecName::H265VRAM
|
||||
} else if let Some(v) = h265hw_encoding {
|
||||
CodecName::H265HW(v)
|
||||
CodecName::H265RAM(v)
|
||||
} else {
|
||||
auto_codec
|
||||
}
|
||||
@@ -306,14 +306,14 @@ impl Encoder {
|
||||
};
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if enable_hwcodec_option() {
|
||||
let best = HwEncoder::best();
|
||||
let best = HwRamEncoder::best();
|
||||
encoding.h264 |= best.h264.is_some();
|
||||
encoding.h265 |= best.h265.is_some();
|
||||
}
|
||||
#[cfg(feature = "gpucodec")]
|
||||
if enable_gpucodec_option() {
|
||||
encoding.h264 |= GpuEncoder::available(CodecName::H264GPU).len() > 0;
|
||||
encoding.h265 |= GpuEncoder::available(CodecName::H265GPU).len() > 0;
|
||||
#[cfg(feature = "vram")]
|
||||
if enable_vram_option() {
|
||||
encoding.h264 |= VRamEncoder::available(CodecName::H264VRAM).len() > 0;
|
||||
encoding.h265 |= VRamEncoder::available(CodecName::H265VRAM).len() > 0;
|
||||
}
|
||||
encoding
|
||||
}
|
||||
@@ -326,21 +326,21 @@ impl Encoder {
|
||||
},
|
||||
EncoderCfg::AOM(_) => CodecName::AV1,
|
||||
#[cfg(feature = "hwcodec")]
|
||||
EncoderCfg::HW(hw) => {
|
||||
EncoderCfg::HWRAM(hw) => {
|
||||
if hw.name.to_lowercase().contains("h264") {
|
||||
CodecName::H264HW(hw.name.clone())
|
||||
CodecName::H264RAM(hw.name.clone())
|
||||
} else {
|
||||
CodecName::H265HW(hw.name.clone())
|
||||
CodecName::H265RAM(hw.name.clone())
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "gpucodec")]
|
||||
EncoderCfg::GPU(gpu) => match gpu.feature.data_format {
|
||||
gpucodec::gpu_common::DataFormat::H264 => CodecName::H264GPU,
|
||||
gpucodec::gpu_common::DataFormat::H265 => CodecName::H265GPU,
|
||||
#[cfg(feature = "vram")]
|
||||
EncoderCfg::VRAM(vram) => match vram.feature.data_format {
|
||||
hwcodec::common::DataFormat::H264 => CodecName::H264VRAM,
|
||||
hwcodec::common::DataFormat::H265 => CodecName::H265VRAM,
|
||||
_ => {
|
||||
log::error!(
|
||||
"should not reach here, gpucodec not support {:?}",
|
||||
gpu.feature.data_format
|
||||
"should not reach here, vram not support {:?}",
|
||||
vram.feature.data_format
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -365,9 +365,9 @@ impl Encoder {
|
||||
},
|
||||
EncoderCfg::AOM(_) => decodings.iter().all(|d| d.1.i444.av1),
|
||||
#[cfg(feature = "hwcodec")]
|
||||
EncoderCfg::HW(_) => false,
|
||||
#[cfg(feature = "gpucodec")]
|
||||
EncoderCfg::GPU(_) => false,
|
||||
EncoderCfg::HWRAM(_) => false,
|
||||
#[cfg(feature = "vram")]
|
||||
EncoderCfg::VRAM(_) => false,
|
||||
};
|
||||
prefer_i444 && i444_useable && !decodings.is_empty()
|
||||
}
|
||||
@@ -399,18 +399,18 @@ impl Decoder {
|
||||
};
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if enable_hwcodec_option() {
|
||||
let best = HwDecoder::best();
|
||||
let best = HwRamDecoder::best();
|
||||
decoding.ability_h264 |= if best.h264.is_some() { 1 } else { 0 };
|
||||
decoding.ability_h265 |= if best.h265.is_some() { 1 } else { 0 };
|
||||
}
|
||||
#[cfg(feature = "gpucodec")]
|
||||
if enable_gpucodec_option() && _flutter {
|
||||
decoding.ability_h264 |= if GpuDecoder::available(CodecFormat::H264, _luid).len() > 0 {
|
||||
#[cfg(feature = "vram")]
|
||||
if enable_vram_option() && _flutter {
|
||||
decoding.ability_h264 |= if VRamDecoder::available(CodecFormat::H264, _luid).len() > 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
decoding.ability_h265 |= if GpuDecoder::available(CodecFormat::H265, _luid).len() > 0 {
|
||||
decoding.ability_h265 |= if VRamDecoder::available(CodecFormat::H265, _luid).len() > 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
@@ -449,7 +449,7 @@ impl Decoder {
|
||||
let (mut vp8, mut vp9, mut av1) = (None, None, None);
|
||||
#[cfg(feature = "hwcodec")]
|
||||
let (mut h264_ram, mut h265_ram) = (None, None);
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
let (mut h264_vram, mut h265_vram) = (None, None);
|
||||
#[cfg(feature = "mediacodec")]
|
||||
let (mut h264_media_codec, mut h265_media_codec) = (None, None);
|
||||
@@ -482,9 +482,9 @@ impl Decoder {
|
||||
valid = av1.is_some();
|
||||
}
|
||||
CodecFormat::H264 => {
|
||||
#[cfg(feature = "gpucodec")]
|
||||
if !valid && enable_gpucodec_option() && _luid.clone().unwrap_or_default() != 0 {
|
||||
match GpuDecoder::new(format, _luid) {
|
||||
#[cfg(feature = "vram")]
|
||||
if !valid && enable_vram_option() && _luid.clone().unwrap_or_default() != 0 {
|
||||
match VRamDecoder::new(format, _luid) {
|
||||
Ok(v) => h264_vram = Some(v),
|
||||
Err(e) => log::error!("create H264 vram decoder failed: {}", e),
|
||||
}
|
||||
@@ -492,7 +492,7 @@ impl Decoder {
|
||||
}
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if !valid && enable_hwcodec_option() {
|
||||
match HwDecoder::new(format) {
|
||||
match HwRamDecoder::new(format) {
|
||||
Ok(v) => h264_ram = Some(v),
|
||||
Err(e) => log::error!("create H264 ram decoder failed: {}", e),
|
||||
}
|
||||
@@ -508,9 +508,9 @@ impl Decoder {
|
||||
}
|
||||
}
|
||||
CodecFormat::H265 => {
|
||||
#[cfg(feature = "gpucodec")]
|
||||
if !valid && enable_gpucodec_option() && _luid.clone().unwrap_or_default() != 0 {
|
||||
match GpuDecoder::new(format, _luid) {
|
||||
#[cfg(feature = "vram")]
|
||||
if !valid && enable_vram_option() && _luid.clone().unwrap_or_default() != 0 {
|
||||
match VRamDecoder::new(format, _luid) {
|
||||
Ok(v) => h265_vram = Some(v),
|
||||
Err(e) => log::error!("create H265 vram decoder failed: {}", e),
|
||||
}
|
||||
@@ -518,7 +518,7 @@ impl Decoder {
|
||||
}
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if !valid && enable_hwcodec_option() {
|
||||
match HwDecoder::new(format) {
|
||||
match HwRamDecoder::new(format) {
|
||||
Ok(v) => h265_ram = Some(v),
|
||||
Err(e) => log::error!("create H265 ram decoder failed: {}", e),
|
||||
}
|
||||
@@ -550,9 +550,9 @@ impl Decoder {
|
||||
h264_ram,
|
||||
#[cfg(feature = "hwcodec")]
|
||||
h265_ram,
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
h264_vram,
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
h265_vram,
|
||||
#[cfg(feature = "mediacodec")]
|
||||
h264_media_codec,
|
||||
@@ -604,31 +604,31 @@ impl Decoder {
|
||||
bail!("av1 decoder not available");
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "hwcodec", feature = "gpucodec"))]
|
||||
#[cfg(any(feature = "hwcodec", feature = "vram"))]
|
||||
video_frame::Union::H264s(h264s) => {
|
||||
*chroma = Some(Chroma::I420);
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
if let Some(decoder) = &mut self.h264_vram {
|
||||
*_pixelbuffer = false;
|
||||
return Decoder::handle_gpu_video_frame(decoder, h264s, _texture);
|
||||
return Decoder::handle_vram_video_frame(decoder, h264s, _texture);
|
||||
}
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if let Some(decoder) = &mut self.h264_ram {
|
||||
return Decoder::handle_hw_video_frame(decoder, h264s, rgb, &mut self.i420);
|
||||
return Decoder::handle_hwram_video_frame(decoder, h264s, rgb, &mut self.i420);
|
||||
}
|
||||
Err(anyhow!("don't support h264!"))
|
||||
}
|
||||
#[cfg(any(feature = "hwcodec", feature = "gpucodec"))]
|
||||
#[cfg(any(feature = "hwcodec", feature = "vram"))]
|
||||
video_frame::Union::H265s(h265s) => {
|
||||
*chroma = Some(Chroma::I420);
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
if let Some(decoder) = &mut self.h265_vram {
|
||||
*_pixelbuffer = false;
|
||||
return Decoder::handle_gpu_video_frame(decoder, h265s, _texture);
|
||||
return Decoder::handle_vram_video_frame(decoder, h265s, _texture);
|
||||
}
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if let Some(decoder) = &mut self.h265_ram {
|
||||
return Decoder::handle_hw_video_frame(decoder, h265s, rgb, &mut self.i420);
|
||||
return Decoder::handle_hwram_video_frame(decoder, h265s, rgb, &mut self.i420);
|
||||
}
|
||||
Err(anyhow!("don't support h265!"))
|
||||
}
|
||||
@@ -710,8 +710,8 @@ impl Decoder {
|
||||
|
||||
// rgb [in/out] fmt and stride must be set in ImageRgb
|
||||
#[cfg(feature = "hwcodec")]
|
||||
fn handle_hw_video_frame(
|
||||
decoder: &mut HwDecoder,
|
||||
fn handle_hwram_video_frame(
|
||||
decoder: &mut HwRamDecoder,
|
||||
frames: &EncodedVideoFrames,
|
||||
rgb: &mut ImageRgb,
|
||||
i420: &mut Vec<u8>,
|
||||
@@ -728,9 +728,9 @@ impl Decoder {
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
fn handle_gpu_video_frame(
|
||||
decoder: &mut GpuDecoder,
|
||||
#[cfg(feature = "vram")]
|
||||
fn handle_vram_video_frame(
|
||||
decoder: &mut VRamDecoder,
|
||||
frames: &EncodedVideoFrames,
|
||||
texture: &mut *mut c_void,
|
||||
) -> ResultType<bool> {
|
||||
@@ -796,8 +796,8 @@ pub fn enable_hwcodec_option() -> bool {
|
||||
}
|
||||
return true; // default is true
|
||||
}
|
||||
#[cfg(feature = "gpucodec")]
|
||||
pub fn enable_gpucodec_option() -> bool {
|
||||
#[cfg(feature = "vram")]
|
||||
pub fn enable_vram_option() -> bool {
|
||||
if let Some(v) = Config2::get().options.get("enable-hwcodec") {
|
||||
return v != "N";
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ pub mod hw {
|
||||
use super::*;
|
||||
use crate::ImageFormat;
|
||||
#[cfg(target_os = "windows")]
|
||||
use hwcodec::{ffmpeg::ffmpeg_linesize_offset_length, AVPixelFormat};
|
||||
use hwcodec::{ffmpeg::AVPixelFormat, ffmpeg_ram::ffmpeg_linesize_offset_length};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn hw_nv12_to(
|
||||
@@ -222,9 +222,7 @@ pub fn convert_to_yuv(
|
||||
);
|
||||
}
|
||||
}
|
||||
let align = |x:usize| {
|
||||
(x + 63) / 64 * 64
|
||||
};
|
||||
let align = |x: usize| (x + 63) / 64 * 64;
|
||||
|
||||
match (src_pixfmt, dst_fmt.pixfmt) {
|
||||
(crate::Pixfmt::BGRA, crate::Pixfmt::I420) | (crate::Pixfmt::RGBA, crate::Pixfmt::I420) => {
|
||||
@@ -282,7 +280,8 @@ pub fn convert_to_yuv(
|
||||
let dst_stride_u = dst_fmt.stride[1];
|
||||
let dst_stride_v = dst_fmt.stride[2];
|
||||
dst.resize(
|
||||
align(dst_fmt.h) * (align(dst_stride_y) + align(dst_stride_u) + align(dst_stride_v)),
|
||||
align(dst_fmt.h)
|
||||
* (align(dst_stride_y) + align(dst_stride_u) + align(dst_stride_v)),
|
||||
0,
|
||||
);
|
||||
let dst_y = dst.as_mut_ptr();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
use crate::AdapterDevice;
|
||||
use crate::{common::TraitCapturer, dxgi, Frame, Pixfmt};
|
||||
use std::{
|
||||
@@ -57,12 +57,12 @@ impl TraitCapturer for Capturer {
|
||||
self.inner.set_gdi()
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn device(&self) -> AdapterDevice {
|
||||
self.inner.device()
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn set_output_texture(&mut self, texture: bool) {
|
||||
self.inner.set_output_texture(texture);
|
||||
}
|
||||
@@ -197,7 +197,7 @@ impl Display {
|
||||
self.origin() == (0, 0)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
pub fn adapter_luid(&self) -> Option<i64> {
|
||||
self.0.adapter_luid()
|
||||
}
|
||||
@@ -247,11 +247,11 @@ impl TraitCapturer for CapturerMag {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn device(&self) -> AdapterDevice {
|
||||
AdapterDevice::default()
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn set_output_texture(&mut self, _texture: bool) {}
|
||||
}
|
||||
|
||||
@@ -9,20 +9,21 @@ use hbb_common::{
|
||||
config::HwCodecConfig,
|
||||
log,
|
||||
message_proto::{EncodedVideoFrame, EncodedVideoFrames, VideoFrame},
|
||||
ResultType,
|
||||
serde_derive::{Deserialize, Serialize},
|
||||
serde_json, ResultType,
|
||||
};
|
||||
use hwcodec::{
|
||||
decode::{DecodeContext, DecodeFrame, Decoder},
|
||||
encode::{EncodeContext, EncodeFrame, Encoder},
|
||||
ffmpeg::{CodecInfo, CodecInfos, DataFormat},
|
||||
AVPixelFormat,
|
||||
Quality::{self, *},
|
||||
RateControl::{self, *},
|
||||
common::DataFormat,
|
||||
ffmpeg::AVPixelFormat,
|
||||
ffmpeg_ram::{
|
||||
decode::{DecodeContext, DecodeFrame, Decoder},
|
||||
encode::{EncodeContext, EncodeFrame, Encoder},
|
||||
CodecInfo, CodecInfos,
|
||||
Quality::{self, *},
|
||||
RateControl::{self, *},
|
||||
},
|
||||
};
|
||||
|
||||
const CFG_KEY_ENCODER: &str = "bestHwEncoders";
|
||||
const CFG_KEY_DECODER: &str = "bestHwDecoders";
|
||||
|
||||
const DEFAULT_PIXFMT: AVPixelFormat = AVPixelFormat::AV_PIX_FMT_NV12;
|
||||
pub const DEFAULT_TIME_BASE: [i32; 2] = [1, 30];
|
||||
const DEFAULT_GOP: i32 = i32::MAX;
|
||||
@@ -30,7 +31,7 @@ const DEFAULT_HW_QUALITY: Quality = Quality_Default;
|
||||
const DEFAULT_RC: RateControl = RC_DEFAULT;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HwEncoderConfig {
|
||||
pub struct HwRamEncoderConfig {
|
||||
pub name: String,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
@@ -38,7 +39,7 @@ pub struct HwEncoderConfig {
|
||||
pub keyframe_interval: Option<usize>,
|
||||
}
|
||||
|
||||
pub struct HwEncoder {
|
||||
pub struct HwRamEncoder {
|
||||
encoder: Encoder,
|
||||
name: String,
|
||||
pub format: DataFormat,
|
||||
@@ -48,13 +49,13 @@ pub struct HwEncoder {
|
||||
bitrate: u32, //kbs
|
||||
}
|
||||
|
||||
impl EncoderApi for HwEncoder {
|
||||
impl EncoderApi for HwRamEncoder {
|
||||
fn new(cfg: EncoderCfg, _i444: bool) -> ResultType<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match cfg {
|
||||
EncoderCfg::HW(config) => {
|
||||
EncoderCfg::HWRAM(config) => {
|
||||
let b = Self::convert_quality(config.quality);
|
||||
let base_bitrate = base_bitrate(config.width as _, config.height as _);
|
||||
let mut bitrate = base_bitrate * b / 100;
|
||||
@@ -85,7 +86,7 @@ impl EncoderApi for HwEncoder {
|
||||
}
|
||||
};
|
||||
match Encoder::new(ctx.clone()) {
|
||||
Ok(encoder) => Ok(HwEncoder {
|
||||
Ok(encoder) => Ok(HwRamEncoder {
|
||||
encoder,
|
||||
name: config.name,
|
||||
format,
|
||||
@@ -95,7 +96,7 @@ impl EncoderApi for HwEncoder {
|
||||
bitrate,
|
||||
}),
|
||||
Err(_) => {
|
||||
HwCodecConfig::clear();
|
||||
HwCodecConfig::clear_ram();
|
||||
Err(anyhow!(format!("Failed to create encoder")))
|
||||
}
|
||||
}
|
||||
@@ -126,6 +127,7 @@ impl EncoderApi for HwEncoder {
|
||||
match self.format {
|
||||
DataFormat::H264 => vf.set_h264s(frames),
|
||||
DataFormat::H265 => vf.set_h265s(frames),
|
||||
_ => bail!("unsupported format: {:?}", self.format),
|
||||
}
|
||||
Ok(vf)
|
||||
} else {
|
||||
@@ -160,7 +162,7 @@ impl EncoderApi for HwEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn input_texture(&self) -> bool {
|
||||
false
|
||||
}
|
||||
@@ -184,9 +186,9 @@ impl EncoderApi for HwEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
impl HwEncoder {
|
||||
impl HwRamEncoder {
|
||||
pub fn best() -> CodecInfos {
|
||||
get_config(CFG_KEY_ENCODER).unwrap_or(CodecInfos {
|
||||
get_config().map(|c| c.e).unwrap_or(CodecInfos {
|
||||
h264: None,
|
||||
h265: None,
|
||||
})
|
||||
@@ -214,20 +216,14 @@ impl HwEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HwDecoder {
|
||||
pub struct HwRamDecoder {
|
||||
decoder: Decoder,
|
||||
pub info: CodecInfo,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct HwDecoders {
|
||||
pub h264: Option<HwDecoder>,
|
||||
pub h265: Option<HwDecoder>,
|
||||
}
|
||||
|
||||
impl HwDecoder {
|
||||
impl HwRamDecoder {
|
||||
pub fn best() -> CodecInfos {
|
||||
get_config(CFG_KEY_DECODER).unwrap_or(CodecInfos {
|
||||
get_config().map(|c| c.d).unwrap_or(CodecInfos {
|
||||
h264: None,
|
||||
h265: None,
|
||||
})
|
||||
@@ -235,7 +231,7 @@ impl HwDecoder {
|
||||
|
||||
pub fn new(format: CodecFormat) -> ResultType<Self> {
|
||||
log::info!("try create {format:?} ram decoder");
|
||||
let best = HwDecoder::best();
|
||||
let best = HwRamDecoder::best();
|
||||
let info = match format {
|
||||
CodecFormat::H264 => {
|
||||
if let Some(info) = best.h264 {
|
||||
@@ -259,26 +255,26 @@ impl HwDecoder {
|
||||
thread_count: codec_thread_num(16) as _,
|
||||
};
|
||||
match Decoder::new(ctx) {
|
||||
Ok(decoder) => Ok(HwDecoder { decoder, info }),
|
||||
Ok(decoder) => Ok(HwRamDecoder { decoder, info }),
|
||||
Err(_) => {
|
||||
HwCodecConfig::clear();
|
||||
HwCodecConfig::clear_ram();
|
||||
Err(anyhow!(format!("Failed to create decoder")))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn decode(&mut self, data: &[u8]) -> ResultType<Vec<HwDecoderImage>> {
|
||||
pub fn decode(&mut self, data: &[u8]) -> ResultType<Vec<HwRamDecoderImage>> {
|
||||
match self.decoder.decode(data) {
|
||||
Ok(v) => Ok(v.iter().map(|f| HwDecoderImage { frame: f }).collect()),
|
||||
Ok(v) => Ok(v.iter().map(|f| HwRamDecoderImage { frame: f }).collect()),
|
||||
Err(e) => Err(anyhow!(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HwDecoderImage<'a> {
|
||||
pub struct HwRamDecoderImage<'a> {
|
||||
frame: &'a DecodeFrame,
|
||||
}
|
||||
|
||||
impl HwDecoderImage<'_> {
|
||||
impl HwRamDecoderImage<'_> {
|
||||
// rgb [in/out] fmt and stride must be set in ImageRgb
|
||||
pub fn to_fmt(&self, rgb: &mut ImageRgb, i420: &mut Vec<u8>) -> ResultType<()> {
|
||||
let frame = self.frame;
|
||||
@@ -332,23 +328,24 @@ impl HwDecoderImage<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_config(k: &str) -> ResultType<CodecInfos> {
|
||||
let v = HwCodecConfig::load()
|
||||
.options
|
||||
.get(k)
|
||||
.unwrap_or(&"".to_owned())
|
||||
.to_owned();
|
||||
match CodecInfos::deserialize(&v) {
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||
struct Available {
|
||||
e: CodecInfos,
|
||||
d: CodecInfos,
|
||||
}
|
||||
|
||||
fn get_config() -> ResultType<Available> {
|
||||
match serde_json::from_str(&HwCodecConfig::load().ram) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(_) => Err(anyhow!("Failed to get config:{}", k)),
|
||||
Err(e) => Err(anyhow!("Failed to get config:{e:?}")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_available_hwcodec() {
|
||||
let ctx = EncodeContext {
|
||||
name: String::from(""),
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
width: 1280,
|
||||
height: 720,
|
||||
pixfmt: DEFAULT_PIXFMT,
|
||||
align: HW_STRIDE_ALIGN as _,
|
||||
bitrate: 0,
|
||||
@@ -358,27 +355,19 @@ pub fn check_available_hwcodec() {
|
||||
rc: DEFAULT_RC,
|
||||
thread_count: 4,
|
||||
};
|
||||
let encoders = CodecInfo::score(Encoder::available_encoders(ctx));
|
||||
let decoders = CodecInfo::score(Decoder::available_decoders());
|
||||
|
||||
if let Ok(old_encoders) = get_config(CFG_KEY_ENCODER) {
|
||||
if let Ok(old_decoders) = get_config(CFG_KEY_DECODER) {
|
||||
if encoders == old_encoders && decoders == old_decoders {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "vram")]
|
||||
let vram = crate::vram::check_available_vram();
|
||||
#[cfg(not(feature = "vram"))]
|
||||
let vram = "".to_owned();
|
||||
let encoders = CodecInfo::score(Encoder::available_encoders(ctx, Some(vram.clone())));
|
||||
let decoders = CodecInfo::score(Decoder::available_decoders(Some(vram.clone())));
|
||||
let ram = Available {
|
||||
e: encoders,
|
||||
d: decoders,
|
||||
};
|
||||
if let Ok(ram) = serde_json::to_string_pretty(&ram) {
|
||||
HwCodecConfig { ram, vram }.store();
|
||||
}
|
||||
|
||||
if let Ok(encoders) = encoders.serialize() {
|
||||
if let Ok(decoders) = decoders.serialize() {
|
||||
let mut config = HwCodecConfig::load();
|
||||
config.options.insert(CFG_KEY_ENCODER.to_owned(), encoders);
|
||||
config.options.insert(CFG_KEY_DECODER.to_owned(), decoders);
|
||||
config.store();
|
||||
return;
|
||||
}
|
||||
}
|
||||
log::error!("Failed to serialize codec info");
|
||||
}
|
||||
|
||||
pub fn hwcodec_new_check_process() {
|
||||
|
||||
@@ -37,13 +37,13 @@ cfg_if! {
|
||||
|
||||
pub mod codec;
|
||||
pub mod convert;
|
||||
#[cfg(feature = "gpucodec")]
|
||||
pub mod gpucodec;
|
||||
#[cfg(feature = "hwcodec")]
|
||||
pub mod hwcodec;
|
||||
#[cfg(feature = "mediacodec")]
|
||||
pub mod mediacodec;
|
||||
pub mod vpxcodec;
|
||||
#[cfg(feature = "vram")]
|
||||
pub mod vram;
|
||||
pub use self::convert::*;
|
||||
pub const STRIDE_ALIGN: usize = 64; // commonly used in libvpx vpx_img_alloc caller
|
||||
pub const HW_STRIDE_ALIGN: usize = 0; // recommended by av_frame_get_buffer
|
||||
@@ -111,10 +111,10 @@ pub trait TraitCapturer {
|
||||
#[cfg(windows)]
|
||||
fn set_gdi(&mut self) -> bool;
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn device(&self) -> AdapterDevice;
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn set_output_texture(&mut self, texture: bool);
|
||||
}
|
||||
|
||||
@@ -245,10 +245,10 @@ pub enum CodecName {
|
||||
VP8,
|
||||
VP9,
|
||||
AV1,
|
||||
H264HW(String),
|
||||
H265HW(String),
|
||||
H264GPU,
|
||||
H265GPU,
|
||||
H264RAM(String),
|
||||
H265RAM(String),
|
||||
H264VRAM,
|
||||
H265VRAM,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
@@ -280,8 +280,8 @@ impl From<&CodecName> for CodecFormat {
|
||||
CodecName::VP8 => Self::VP8,
|
||||
CodecName::VP9 => Self::VP9,
|
||||
CodecName::AV1 => Self::AV1,
|
||||
CodecName::H264HW(_) | CodecName::H264GPU => Self::H264,
|
||||
CodecName::H265HW(_) | CodecName::H265GPU => Self::H265,
|
||||
CodecName::H264RAM(_) | CodecName::H264VRAM => Self::H264,
|
||||
CodecName::H265RAM(_) | CodecName::H265VRAM => Self::H265,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ impl EncoderApi for VpxEncoder {
|
||||
self.yuvfmt.clone()
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn input_texture(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -5,24 +5,24 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
codec::{base_bitrate, enable_gpucodec_option, EncoderApi, EncoderCfg, Quality},
|
||||
codec::{base_bitrate, enable_vram_option, EncoderApi, EncoderCfg, Quality},
|
||||
AdapterDevice, CodecFormat, CodecName, EncodeInput, EncodeYuvFormat, Pixfmt,
|
||||
};
|
||||
use gpucodec::gpu_common::{
|
||||
self, Available, DecodeContext, DynamicContext, EncodeContext, FeatureContext, MAX_GOP,
|
||||
};
|
||||
use gpucodec::{
|
||||
decode::{self, DecodeFrame, Decoder},
|
||||
encode::{self, EncodeFrame, Encoder},
|
||||
};
|
||||
use hbb_common::{
|
||||
allow_err,
|
||||
anyhow::{anyhow, bail, Context},
|
||||
bytes::Bytes,
|
||||
log,
|
||||
message_proto::{EncodedVideoFrame, EncodedVideoFrames, VideoFrame},
|
||||
ResultType,
|
||||
};
|
||||
use hwcodec::{
|
||||
common::{DataFormat, Driver, MAX_GOP},
|
||||
native::{
|
||||
decode::{self, DecodeFrame, Decoder},
|
||||
encode::{self, EncodeFrame, Encoder},
|
||||
Available, DecodeContext, DynamicContext, EncodeContext, FeatureContext,
|
||||
},
|
||||
};
|
||||
|
||||
const OUTPUT_SHARED_HANDLE: bool = false;
|
||||
|
||||
@@ -35,31 +35,31 @@ lazy_static::lazy_static! {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GpuEncoderConfig {
|
||||
pub struct VRamEncoderConfig {
|
||||
pub device: AdapterDevice,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub quality: Quality,
|
||||
pub feature: gpucodec::gpu_common::FeatureContext,
|
||||
pub feature: FeatureContext,
|
||||
pub keyframe_interval: Option<usize>,
|
||||
}
|
||||
|
||||
pub struct GpuEncoder {
|
||||
pub struct VRamEncoder {
|
||||
encoder: Encoder,
|
||||
pub format: gpu_common::DataFormat,
|
||||
pub format: DataFormat,
|
||||
ctx: EncodeContext,
|
||||
bitrate: u32,
|
||||
last_frame_len: usize,
|
||||
same_bad_len_counter: usize,
|
||||
}
|
||||
|
||||
impl EncoderApi for GpuEncoder {
|
||||
impl EncoderApi for VRamEncoder {
|
||||
fn new(cfg: EncoderCfg, _i444: bool) -> ResultType<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match cfg {
|
||||
EncoderCfg::GPU(config) => {
|
||||
EncoderCfg::VRAM(config) => {
|
||||
let b = Self::convert_quality(config.quality, &config.feature);
|
||||
let base_bitrate = base_bitrate(config.width as _, config.height as _);
|
||||
let mut bitrate = base_bitrate * b / 100;
|
||||
@@ -79,7 +79,7 @@ impl EncoderApi for GpuEncoder {
|
||||
},
|
||||
};
|
||||
match Encoder::new(ctx.clone()) {
|
||||
Ok(encoder) => Ok(GpuEncoder {
|
||||
Ok(encoder) => Ok(VRamEncoder {
|
||||
encoder,
|
||||
ctx,
|
||||
format: config.feature.data_format,
|
||||
@@ -88,7 +88,7 @@ impl EncoderApi for GpuEncoder {
|
||||
same_bad_len_counter: 0,
|
||||
}),
|
||||
Err(_) => {
|
||||
hbb_common::config::GpucodecConfig::clear();
|
||||
hbb_common::config::HwCodecConfig::clear_vram();
|
||||
Err(anyhow!(format!("Failed to create encoder")))
|
||||
}
|
||||
}
|
||||
@@ -138,8 +138,8 @@ impl EncoderApi for GpuEncoder {
|
||||
..Default::default()
|
||||
};
|
||||
match self.format {
|
||||
gpu_common::DataFormat::H264 => vf.set_h264s(frames),
|
||||
gpu_common::DataFormat::H265 => vf.set_h265s(frames),
|
||||
DataFormat::H264 => vf.set_h264s(frames),
|
||||
DataFormat::H265 => vf.set_h265s(frames),
|
||||
_ => bail!("{:?} not supported", self.format),
|
||||
}
|
||||
Ok(vf)
|
||||
@@ -160,7 +160,7 @@ impl EncoderApi for GpuEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
fn input_texture(&self) -> bool {
|
||||
true
|
||||
}
|
||||
@@ -181,11 +181,11 @@ impl EncoderApi for GpuEncoder {
|
||||
}
|
||||
|
||||
fn support_abr(&self) -> bool {
|
||||
self.ctx.f.driver != gpu_common::EncodeDriver::VPL
|
||||
self.ctx.f.driver != Driver::VPL
|
||||
}
|
||||
}
|
||||
|
||||
impl GpuEncoder {
|
||||
impl VRamEncoder {
|
||||
pub fn try_get(device: &AdapterDevice, name: CodecName) -> Option<FeatureContext> {
|
||||
let v: Vec<_> = Self::available(name)
|
||||
.drain(..)
|
||||
@@ -201,12 +201,12 @@ impl GpuEncoder {
|
||||
pub fn available(name: CodecName) -> Vec<FeatureContext> {
|
||||
let not_use = ENOCDE_NOT_USE.lock().unwrap().clone();
|
||||
if not_use.values().any(|not_use| *not_use) {
|
||||
log::info!("currently not use gpucodec encoders: {not_use:?}");
|
||||
log::info!("currently not use vram encoders: {not_use:?}");
|
||||
return vec![];
|
||||
}
|
||||
let data_format = match name {
|
||||
CodecName::H264GPU => gpu_common::DataFormat::H264,
|
||||
CodecName::H265GPU => gpu_common::DataFormat::H265,
|
||||
CodecName::H264VRAM => DataFormat::H264,
|
||||
CodecName::H265VRAM => DataFormat::H265,
|
||||
_ => return vec![],
|
||||
};
|
||||
let Ok(displays) = crate::Display::all() else {
|
||||
@@ -252,27 +252,21 @@ impl GpuEncoder {
|
||||
pub fn convert_quality(quality: Quality, f: &FeatureContext) -> u32 {
|
||||
match quality {
|
||||
Quality::Best => {
|
||||
if f.driver == gpu_common::EncodeDriver::VPL
|
||||
&& f.data_format == gpu_common::DataFormat::H264
|
||||
{
|
||||
if f.driver == Driver::VPL && f.data_format == DataFormat::H264 {
|
||||
200
|
||||
} else {
|
||||
150
|
||||
}
|
||||
}
|
||||
Quality::Balanced => {
|
||||
if f.driver == gpu_common::EncodeDriver::VPL
|
||||
&& f.data_format == gpu_common::DataFormat::H264
|
||||
{
|
||||
if f.driver == Driver::VPL && f.data_format == DataFormat::H264 {
|
||||
150
|
||||
} else {
|
||||
100
|
||||
}
|
||||
}
|
||||
Quality::Low => {
|
||||
if f.driver == gpu_common::EncodeDriver::VPL
|
||||
&& f.data_format == gpu_common::DataFormat::H264
|
||||
{
|
||||
if f.driver == Driver::VPL && f.data_format == DataFormat::H264 {
|
||||
75
|
||||
} else {
|
||||
50
|
||||
@@ -283,7 +277,7 @@ impl GpuEncoder {
|
||||
}
|
||||
|
||||
pub fn set_not_use(display: usize, not_use: bool) {
|
||||
log::info!("set display#{display} not use gpucodec encode to {not_use}");
|
||||
log::info!("set display#{display} not use vram encode to {not_use}");
|
||||
ENOCDE_NOT_USE.lock().unwrap().insert(display, not_use);
|
||||
}
|
||||
|
||||
@@ -292,17 +286,11 @@ impl GpuEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GpuDecoder {
|
||||
pub struct VRamDecoder {
|
||||
decoder: Decoder,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GpuDecoders {
|
||||
pub h264: Option<GpuDecoder>,
|
||||
pub h265: Option<GpuDecoder>,
|
||||
}
|
||||
|
||||
impl GpuDecoder {
|
||||
impl VRamDecoder {
|
||||
pub fn try_get(format: CodecFormat, luid: Option<i64>) -> Option<DecodeContext> {
|
||||
let v: Vec<_> = Self::available(format, luid);
|
||||
if v.len() > 0 {
|
||||
@@ -315,8 +303,8 @@ impl GpuDecoder {
|
||||
pub fn available(format: CodecFormat, luid: Option<i64>) -> Vec<DecodeContext> {
|
||||
let luid = luid.unwrap_or_default();
|
||||
let data_format = match format {
|
||||
CodecFormat::H264 => gpu_common::DataFormat::H264,
|
||||
CodecFormat::H265 => gpu_common::DataFormat::H265,
|
||||
CodecFormat::H264 => DataFormat::H264,
|
||||
CodecFormat::H265 => DataFormat::H265,
|
||||
_ => return vec![],
|
||||
};
|
||||
get_available_config()
|
||||
@@ -328,15 +316,13 @@ impl GpuDecoder {
|
||||
}
|
||||
|
||||
pub fn possible_available_without_check() -> (bool, bool) {
|
||||
if !enable_gpucodec_option() {
|
||||
if !enable_vram_option() {
|
||||
return (false, false);
|
||||
}
|
||||
let v = get_available_config().map(|c| c.d).unwrap_or_default();
|
||||
(
|
||||
v.iter()
|
||||
.any(|d| d.data_format == gpu_common::DataFormat::H264),
|
||||
v.iter()
|
||||
.any(|d| d.data_format == gpu_common::DataFormat::H265),
|
||||
v.iter().any(|d| d.data_format == DataFormat::H264),
|
||||
v.iter().any(|d| d.data_format == DataFormat::H265),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -346,7 +332,7 @@ impl GpuDecoder {
|
||||
match Decoder::new(ctx) {
|
||||
Ok(decoder) => Ok(Self { decoder }),
|
||||
Err(_) => {
|
||||
hbb_common::config::GpucodecConfig::clear();
|
||||
hbb_common::config::HwCodecConfig::clear_vram();
|
||||
Err(anyhow!(format!(
|
||||
"Failed to create decoder, format: {:?}",
|
||||
format
|
||||
@@ -354,33 +340,33 @@ impl GpuDecoder {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn decode(&mut self, data: &[u8]) -> ResultType<Vec<GpuDecoderImage>> {
|
||||
pub fn decode(&mut self, data: &[u8]) -> ResultType<Vec<VRamDecoderImage>> {
|
||||
match self.decoder.decode(data) {
|
||||
Ok(v) => Ok(v.iter().map(|f| GpuDecoderImage { frame: f }).collect()),
|
||||
Ok(v) => Ok(v.iter().map(|f| VRamDecoderImage { frame: f }).collect()),
|
||||
Err(e) => Err(anyhow!(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GpuDecoderImage<'a> {
|
||||
pub struct VRamDecoderImage<'a> {
|
||||
pub frame: &'a DecodeFrame,
|
||||
}
|
||||
|
||||
impl GpuDecoderImage<'_> {}
|
||||
impl VRamDecoderImage<'_> {}
|
||||
|
||||
fn get_available_config() -> ResultType<Available> {
|
||||
let available = hbb_common::config::GpucodecConfig::load().available;
|
||||
let available = hbb_common::config::HwCodecConfig::load().vram;
|
||||
match Available::deserialize(&available) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(_) => Err(anyhow!("Failed to deserialize:{}", available)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_available_gpucodec() {
|
||||
pub(crate) fn check_available_vram() -> String {
|
||||
let d = DynamicContext {
|
||||
device: None,
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
width: 1280,
|
||||
height: 720,
|
||||
kbitrate: 5000,
|
||||
framerate: 60,
|
||||
gop: MAX_GOP as _,
|
||||
@@ -391,54 +377,5 @@ pub fn check_available_gpucodec() {
|
||||
e: encoders,
|
||||
d: decoders,
|
||||
};
|
||||
|
||||
if let Ok(available) = available.serialize() {
|
||||
let mut config = hbb_common::config::GpucodecConfig::load();
|
||||
config.available = available;
|
||||
config.store();
|
||||
return;
|
||||
}
|
||||
log::error!("Failed to serialize gpucodec");
|
||||
}
|
||||
|
||||
pub fn gpucodec_new_check_process() {
|
||||
use std::sync::Once;
|
||||
|
||||
static ONCE: Once = Once::new();
|
||||
ONCE.call_once(|| {
|
||||
std::thread::spawn(move || {
|
||||
// Remove to avoid checking process errors
|
||||
// But when the program is just started, the configuration file has not been updated, and the new connection will read an empty configuration
|
||||
hbb_common::config::GpucodecConfig::clear();
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
let arg = "--check-gpucodec-config";
|
||||
if let Ok(mut child) = std::process::Command::new(exe).arg(arg).spawn() {
|
||||
// wait up to 30 seconds
|
||||
for _ in 0..30 {
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
if let Ok(Some(_)) = child.try_wait() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
allow_err!(child.kill());
|
||||
std::thread::sleep(std::time::Duration::from_millis(30));
|
||||
match child.try_wait() {
|
||||
Ok(Some(status)) => {
|
||||
log::info!("Check gpucodec config, exit with: {status}")
|
||||
}
|
||||
Ok(None) => {
|
||||
log::info!(
|
||||
"Check gpucodec config, status not ready yet, let's really wait"
|
||||
);
|
||||
let res = child.wait();
|
||||
log::info!("Check gpucodec config, wait result: {res:?}");
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Check gpucodec config, error attempting to wait: {e}")
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
available.serialize().unwrap_or_default()
|
||||
}
|
||||
@@ -185,7 +185,7 @@ impl Capturer {
|
||||
self.gdi_capturer.take();
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
pub fn set_output_texture(&mut self, texture: bool) {
|
||||
self.output_texture = texture;
|
||||
}
|
||||
@@ -620,7 +620,7 @@ impl Display {
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpucodec")]
|
||||
#[cfg(feature = "vram")]
|
||||
pub fn adapter_luid(&self) -> Option<i64> {
|
||||
unsafe {
|
||||
if !self.adapter.is_null() {
|
||||
|
||||
Reference in New Issue
Block a user