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:
21pages 2024-04-12 17:26:24 +08:00 committed by GitHub
parent d8875f381b
commit 98df2b111e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 330 additions and 478 deletions

View File

@ -113,7 +113,7 @@ jobs:
shell: bash shell: bash
- name: Build rustdesk - name: Build rustdesk
run: python3 .\build.py --portable --hwcodec --flutter --gpucodec --skip-portable-pack run: python3 .\build.py --portable --hwcodec --flutter --vram --skip-portable-pack
- name: find Runner.res - name: find Runner.res
# Windows: find Runner.res (compiled from ./flutter/windows/runner/Runner.rc), copy to ./Runner.res # Windows: find Runner.res (compiled from ./flutter/windows/runner/Runner.rc), copy to ./Runner.res
@ -251,7 +251,7 @@ jobs:
python3 res/inline-sciter.py python3 res/inline-sciter.py
# Patch sciter x86 # Patch sciter x86
sed -i 's/branch = "dyn"/branch = "dyn_x86"/g' ./Cargo.toml sed -i 's/branch = "dyn"/branch = "dyn_x86"/g' ./Cargo.toml
cargo build --features inline,gpucodec --release --bins cargo build --features inline,vram,hwcodec --release --bins
mkdir -p ./Release mkdir -p ./Release
mv ./target/release/rustdesk.exe ./Release/rustdesk.exe mv ./target/release/rustdesk.exe ./Release/rustdesk.exe
curl -LJ -o ./Release/sciter.dll https://github.com/c-smile/sciter-sdk/raw/master/bin.win/x32/sciter.dll curl -LJ -o ./Release/sciter.dll https://github.com/c-smile/sciter-sdk/raw/master/bin.win/x32/sciter.dll
@ -1600,7 +1600,7 @@ jobs:
;; ;;
esac esac
export CARGO_INCREMENTAL=0 export CARGO_INCREMENTAL=0
python3 ./build.py --flutter --hwcodec --skip-cargo python3 ./build.py --flutter --skip-cargo
# rpm package # rpm package
echo -e "start packaging fedora package" echo -e "start packaging fedora package"
pushd /workspace pushd /workspace

68
Cargo.lock generated
View File

@ -115,17 +115,6 @@ dependencies = [
"pkg-config", "pkg-config",
] ]
[[package]]
name = "amf"
version = "0.1.0"
source = "git+https://github.com/21pages/gpucodec#546f7f644ce15a35b833c1531a4fead4b34a1b3b"
dependencies = [
"bindgen 0.59.2",
"cc",
"gpu_common",
"log",
]
[[package]] [[package]]
name = "android-tzdata" name = "android-tzdata"
version = "0.1.1" version = "0.1.1"
@ -2649,36 +2638,6 @@ dependencies = [
"system-deps 6.1.2", "system-deps 6.1.2",
] ]
[[package]]
name = "gpu_common"
version = "0.1.0"
source = "git+https://github.com/21pages/gpucodec#546f7f644ce15a35b833c1531a4fead4b34a1b3b"
dependencies = [
"bindgen 0.59.2",
"cc",
"log",
"serde 1.0.190",
"serde_derive",
"serde_json 1.0.107",
]
[[package]]
name = "gpucodec"
version = "0.1.0"
source = "git+https://github.com/21pages/gpucodec#546f7f644ce15a35b833c1531a4fead4b34a1b3b"
dependencies = [
"amf",
"bindgen 0.59.2",
"cc",
"gpu_common",
"log",
"nv",
"serde 1.0.190",
"serde_derive",
"serde_json 1.0.107",
"vpl",
]
[[package]] [[package]]
name = "gstreamer" name = "gstreamer"
version = "0.16.7" version = "0.16.7"
@ -3065,8 +3024,8 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "hwcodec" name = "hwcodec"
version = "0.2.0" version = "0.3.0"
source = "git+https://github.com/21pages/hwcodec?branch=stable#52e1da2aae86acec5f374bc065f5921945b55e7b" source = "git+https://github.com/21pages/hwcodec#6ce1cbab2ff270a81784303192e8906ef597ee02"
dependencies = [ dependencies = [
"bindgen 0.59.2", "bindgen 0.59.2",
"cc", "cc",
@ -4134,17 +4093,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "nv"
version = "0.1.0"
source = "git+https://github.com/21pages/gpucodec#546f7f644ce15a35b833c1531a4fead4b34a1b3b"
dependencies = [
"bindgen 0.59.2",
"cc",
"gpu_common",
"log",
]
[[package]] [[package]]
name = "objc" name = "objc"
version = "0.2.7" version = "0.2.7"
@ -5683,7 +5631,6 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"dbus", "dbus",
"docopt", "docopt",
"gpucodec",
"gstreamer", "gstreamer",
"gstreamer-app", "gstreamer-app",
"gstreamer-video", "gstreamer-video",
@ -6900,17 +6847,6 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "vpl"
version = "0.1.0"
source = "git+https://github.com/21pages/gpucodec#546f7f644ce15a35b833c1531a4fead4b34a1b3b"
dependencies = [
"bindgen 0.59.2",
"cc",
"gpu_common",
"log",
]
[[package]] [[package]]
name = "waker-fn" name = "waker-fn"
version = "1.1.1" version = "1.1.1"

View File

@ -28,7 +28,7 @@ use_dasp = ["dasp"]
flutter = ["flutter_rust_bridge"] flutter = ["flutter_rust_bridge"]
default = ["use_dasp"] default = ["use_dasp"]
hwcodec = ["scrap/hwcodec"] hwcodec = ["scrap/hwcodec"]
gpucodec = ["scrap/gpucodec"] vram = ["scrap/vram"]
mediacodec = ["scrap/mediacodec"] mediacodec = ["scrap/mediacodec"]
linux_headless = ["pam" ] linux_headless = ["pam" ]
virtual_display_driver = ["virtual_display"] virtual_display_driver = ["virtual_display"]

View File

@ -118,9 +118,9 @@ def make_parser():
'' if windows or osx else ', need libva-dev, libvdpau-dev.') '' if windows or osx else ', need libva-dev, libvdpau-dev.')
) )
parser.add_argument( parser.add_argument(
'--gpucodec', '--vram',
action='store_true', action='store_true',
help='Enable feature gpucodec, only available on windows now.' help='Enable feature vram, only available on windows now.'
) )
parser.add_argument( parser.add_argument(
'--portable', '--portable',
@ -282,8 +282,8 @@ def get_features(args):
features = ['inline'] if not args.flutter else [] features = ['inline'] if not args.flutter else []
if args.hwcodec: if args.hwcodec:
features.append('hwcodec') features.append('hwcodec')
if args.gpucodec: if args.vram:
features.append('gpucodec') features.append('vram')
if args.flutter: if args.flutter:
features.append('flutter') features.append('flutter')
features.append('flutter_texture_render') features.append('flutter_texture_render')

View File

@ -400,9 +400,9 @@ class _GeneralState extends State<_General> {
Widget hwcodec() { Widget hwcodec() {
final hwcodec = bind.mainHasHwcodec(); final hwcodec = bind.mainHasHwcodec();
final gpucodec = bind.mainHasGpucodec(); final vram = bind.mainHasVram();
return Offstage( return Offstage(
offstage: !(hwcodec || gpucodec), offstage: !(hwcodec || vram),
child: _Card(title: 'Hardware Codec', children: [ child: _Card(title: 'Hardware Codec', children: [
_OptionCheckBox(context, 'Enable hardware codec', 'enable-hwcodec') _OptionCheckBox(context, 'Enable hardware codec', 'enable-hwcodec')
]), ]),

View File

@ -10,7 +10,7 @@ import './platform_model.dart';
import 'package:texture_rgba_renderer/texture_rgba_renderer.dart' import 'package:texture_rgba_renderer/texture_rgba_renderer.dart'
if (dart.library.html) 'package:flutter_hbb/web/texture_rgba_renderer.dart'; if (dart.library.html) 'package:flutter_hbb/web/texture_rgba_renderer.dart';
// Feature flutter_texture_render need to be enabled if feature gpucodec is enabled. // Feature flutter_texture_render need to be enabled if feature vram is enabled.
final useTextureRender = !isWeb && final useTextureRender = !isWeb &&
(bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender()); (bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender());

View File

@ -1052,7 +1052,7 @@ class RustdeskImpl {
throw UnimplementedError(); throw UnimplementedError();
} }
bool mainHasGpucodec({dynamic hint}) { bool mainHasVram({dynamic hint}) {
throw UnimplementedError(); throw UnimplementedError();
} }

View File

@ -409,9 +409,7 @@ fn patch(path: PathBuf) -> PathBuf {
if let Ok(user) = crate::platform::linux::run_cmds_trim_newline("whoami") { if let Ok(user) = crate::platform::linux::run_cmds_trim_newline("whoami") {
if user != "root" { if user != "root" {
let cmd = format!("getent passwd '{}' | awk -F':' '{{print $6}}'", user); let cmd = format!("getent passwd '{}' | awk -F':' '{{print $6}}'", user);
if let Ok(output) = if let Ok(output) = crate::platform::linux::run_cmds_trim_newline(&cmd) {
crate::platform::linux::run_cmds_trim_newline(&cmd)
{
return output.into(); return output.into();
} }
return format!("/home/{user}").into(); return format!("/home/{user}").into();
@ -505,7 +503,7 @@ impl Config {
fn store_<T: serde::Serialize>(config: &T, suffix: &str) { fn store_<T: serde::Serialize>(config: &T, suffix: &str) {
let file = Self::file_(suffix); let file = Self::file_(suffix);
if let Err(err) = store_path(file, config) { 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)] #[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct HwCodecConfig { pub struct HwCodecConfig {
#[serde(default, deserialize_with = "deserialize_hashmap_string_string")] #[serde(default, deserialize_with = "deserialize_string")]
pub options: HashMap<String, String>, pub ram: String,
#[serde(default, deserialize_with = "deserialize_string")]
pub vram: String,
} }
impl HwCodecConfig { impl HwCodecConfig {
@ -1511,25 +1511,17 @@ impl HwCodecConfig {
pub fn clear() { pub fn clear() {
HwCodecConfig::default().store(); HwCodecConfig::default().store();
} }
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)] pub fn clear_ram() {
pub struct GpucodecConfig { let mut c = Self::load();
#[serde(default, deserialize_with = "deserialize_string")] c.ram = Default::default();
pub available: String, c.store();
}
impl GpucodecConfig {
pub fn load() -> GpucodecConfig {
Config::load_::<GpucodecConfig>("_gpucodec")
} }
pub fn store(&self) { pub fn clear_vram() {
Config::store_(self, "_gpucodec"); let mut c = Self::load();
} c.vram = Default::default();
c.store();
pub fn clear() {
GpucodecConfig::default().store();
} }
} }

View File

@ -46,6 +46,8 @@ pub mod keyboard;
pub use dlopen; pub use dlopen;
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use machine_uid; pub use machine_uid;
pub use serde_derive;
pub use serde_json;
pub use sysinfo; pub use sysinfo;
pub use toml; pub use toml;
pub use uuid; pub use uuid;

View File

@ -13,6 +13,8 @@ edition = "2018"
wayland = ["gstreamer", "gstreamer-app", "gstreamer-video", "dbus", "tracing"] wayland = ["gstreamer", "gstreamer-app", "gstreamer-video", "dbus", "tracing"]
mediacodec = ["ndk"] mediacodec = ["ndk"]
linux-pkg-config = ["dep:pkg-config"] linux-pkg-config = ["dep:pkg-config"]
hwcodec = ["dep:hwcodec"]
vram = ["hwcodec/vram"]
[dependencies] [dependencies]
cfg-if = "1.0" cfg-if = "1.0"
@ -20,6 +22,7 @@ num_cpus = "1.15"
lazy_static = "1.4" lazy_static = "1.4"
hbb_common = { path = "../hbb_common" } hbb_common = { path = "../hbb_common" }
webm = { git = "https://github.com/21pages/rust-webm" } webm = { git = "https://github.com/21pages/rust-webm" }
serde = {version="1.0", features=["derive"]}
[dependencies.winapi] [dependencies.winapi]
version = "0.3" version = "0.3"
@ -41,7 +44,6 @@ ndk-context = "0.1"
[target.'cfg(not(target_os = "android"))'.dev-dependencies] [target.'cfg(not(target_os = "android"))'.dev-dependencies]
repng = "0.2" repng = "0.2"
docopt = "1.1" docopt = "1.1"
serde = {version="1.0", features=["derive"]}
quest = "0.3" quest = "0.3"
[build-dependencies] [build-dependencies]
@ -56,8 +58,9 @@ gstreamer = { version = "0.16", optional = true }
gstreamer-app = { version = "0.16", features = ["v1_10"], optional = true } gstreamer-app = { version = "0.16", features = ["v1_10"], optional = true }
gstreamer-video = { version = "0.16", optional = true } gstreamer-video = { version = "0.16", optional = true }
[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dependencies] [dependencies.hwcodec]
hwcodec = { git = "https://github.com/21pages/hwcodec", branch = "stable", optional = true } 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 }

View File

@ -239,16 +239,16 @@ fn test_av1(
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
mod hw { mod hw {
use hwcodec::ffmpeg::CodecInfo; use hwcodec::ffmpeg_ram::CodecInfo;
use scrap::{ use scrap::{
hwcodec::{HwDecoder, HwEncoder, HwEncoderConfig}, hwcodec::{HwRamDecoder, HwRamEncoder, HwRamEncoderConfig},
CodecFormat, CodecFormat,
}; };
use super::*; use super::*;
pub fn test(c: &mut Capturer, width: usize, height: usize, quality: Q, yuv_count: usize) { 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 h264s = Vec::new();
let mut h265s = Vec::new(); let mut h265s = Vec::new();
if let Some(info) = best.h264 { if let Some(info) = best.h264 {
@ -270,8 +270,8 @@ mod hw {
yuv_count: usize, yuv_count: usize,
h26xs: &mut Vec<Vec<u8>>, h26xs: &mut Vec<Vec<u8>>,
) { ) {
let mut encoder = HwEncoder::new( let mut encoder = HwRamEncoder::new(
EncoderCfg::HW(HwEncoderConfig { EncoderCfg::HWRAM(HwRamEncoderConfig {
name: info.name.clone(), name: info.name.clone(),
width, width,
height, height,
@ -321,7 +321,7 @@ mod hw {
} }
fn test_decoder(format: CodecFormat, h26xs: &Vec<Vec<u8>>) { 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 start = Instant::now();
let mut cnt = 0; let mut cnt = 0;
for h26x in h26xs { for h26x in h26xs {

View File

@ -268,7 +268,7 @@ impl EncoderApi for AomEncoder {
self.yuvfmt.clone() self.yuvfmt.clone()
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn input_texture(&self) -> bool { fn input_texture(&self) -> bool {
false false
} }

View File

@ -5,12 +5,12 @@ use std::{
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
#[cfg(feature = "gpucodec")]
use crate::gpucodec::*;
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
use crate::hwcodec::*; use crate::hwcodec::*;
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
use crate::mediacodec::{MediaCodecDecoder, H264_DECODER_SUPPORT, H265_DECODER_SUPPORT}; use crate::mediacodec::{MediaCodecDecoder, H264_DECODER_SUPPORT, H265_DECODER_SUPPORT};
#[cfg(feature = "vram")]
use crate::vram::*;
use crate::{ use crate::{
aom::{self, AomDecoder, AomEncoder, AomEncoderConfig}, aom::{self, AomDecoder, AomEncoder, AomEncoderConfig},
common::GoogleImage, common::GoogleImage,
@ -31,7 +31,7 @@ use hbb_common::{
tokio::time::Instant, tokio::time::Instant,
ResultType, ResultType,
}; };
#[cfg(any(feature = "hwcodec", feature = "mediacodec", feature = "gpucodec"))] #[cfg(any(feature = "hwcodec", feature = "mediacodec", feature = "vram"))]
use hbb_common::{config::Config2, lazy_static}; use hbb_common::{config::Config2, lazy_static};
lazy_static::lazy_static! { lazy_static::lazy_static! {
@ -47,9 +47,9 @@ pub enum EncoderCfg {
VPX(VpxEncoderConfig), VPX(VpxEncoderConfig),
AOM(AomEncoderConfig), AOM(AomEncoderConfig),
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
HW(HwEncoderConfig), HWRAM(HwRamEncoderConfig),
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
GPU(GpuEncoderConfig), VRAM(VRamEncoderConfig),
} }
pub trait EncoderApi { pub trait EncoderApi {
@ -61,7 +61,7 @@ pub trait EncoderApi {
fn yuvfmt(&self) -> EncodeYuvFormat; fn yuvfmt(&self) -> EncodeYuvFormat;
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn input_texture(&self) -> bool; fn input_texture(&self) -> bool;
fn set_quality(&mut self, quality: Quality) -> ResultType<()>; fn set_quality(&mut self, quality: Quality) -> ResultType<()>;
@ -94,13 +94,13 @@ pub struct Decoder {
vp9: Option<VpxDecoder>, vp9: Option<VpxDecoder>,
av1: Option<AomDecoder>, av1: Option<AomDecoder>,
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
h264_ram: Option<HwDecoder>, h264_ram: Option<HwRamDecoder>,
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
h265_ram: Option<HwDecoder>, h265_ram: Option<HwRamDecoder>,
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
h264_vram: Option<GpuDecoder>, h264_vram: Option<VRamDecoder>,
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
h265_vram: Option<GpuDecoder>, h265_vram: Option<VRamDecoder>,
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
h264_media_codec: MediaCodecDecoder, h264_media_codec: MediaCodecDecoder,
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
@ -131,25 +131,25 @@ impl Encoder {
}), }),
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
EncoderCfg::HW(_) => match HwEncoder::new(config, i444) { EncoderCfg::HWRAM(_) => match HwRamEncoder::new(config, i444) {
Ok(hw) => Ok(Encoder { Ok(hw) => Ok(Encoder {
codec: Box::new(hw), codec: Box::new(hw),
}), }),
Err(e) => { Err(e) => {
log::error!("new hw encoder failed: {e:?}, clear config"); 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; *ENCODE_CODEC_NAME.lock().unwrap() = CodecName::VP9;
Err(e) Err(e)
} }
}, },
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
EncoderCfg::GPU(_) => match GpuEncoder::new(config, i444) { EncoderCfg::VRAM(_) => match VRamEncoder::new(config, i444) {
Ok(tex) => Ok(Encoder { Ok(tex) => Ok(Encoder {
codec: Box::new(tex), codec: Box::new(tex),
}), }),
Err(e) => { Err(e) => {
log::error!("new gpu encoder failed: {e:?}, clear config"); log::error!("new vram encoder failed: {e:?}, clear config");
hbb_common::config::GpucodecConfig::clear(); hbb_common::config::HwCodecConfig::clear_vram();
*ENCODE_CODEC_NAME.lock().unwrap() = CodecName::VP9; *ENCODE_CODEC_NAME.lock().unwrap() = CodecName::VP9;
Err(e) Err(e)
} }
@ -186,19 +186,19 @@ impl Encoder {
let _all_support_h265_decoding = let _all_support_h265_decoding =
decodings.len() > 0 && decodings.iter().all(|(_, s)| s.ability_h265 > 0); decodings.len() > 0 && decodings.iter().all(|(_, s)| s.ability_h265 > 0);
#[allow(unused_mut)] #[allow(unused_mut)]
let mut h264gpu_encoding = false; let mut h264vram_encoding = false;
#[allow(unused_mut)] #[allow(unused_mut)]
let mut h265gpu_encoding = false; let mut h265vram_encoding = false;
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
if enable_gpucodec_option() { if enable_vram_option() {
if _all_support_h264_decoding { if _all_support_h264_decoding {
if GpuEncoder::available(CodecName::H264GPU).len() > 0 { if VRamEncoder::available(CodecName::H264VRAM).len() > 0 {
h264gpu_encoding = true; h264vram_encoding = true;
} }
} }
if _all_support_h265_decoding { if _all_support_h265_decoding {
if GpuEncoder::available(CodecName::H265GPU).len() > 0 { if VRamEncoder::available(CodecName::H265VRAM).len() > 0 {
h265gpu_encoding = true; h265vram_encoding = true;
} }
} }
} }
@ -208,7 +208,7 @@ impl Encoder {
let mut h265hw_encoding = None; let mut h265hw_encoding = None;
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
if enable_hwcodec_option() { if enable_hwcodec_option() {
let best = HwEncoder::best(); let best = HwRamEncoder::best();
if _all_support_h264_decoding { if _all_support_h264_decoding {
h264hw_encoding = best.h264.map_or(None, |c| Some(c.name)); h264hw_encoding = best.h264.map_or(None, |c| Some(c.name));
} }
@ -217,9 +217,9 @@ impl Encoder {
} }
} }
let h264_useable = 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 = 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 name = ENCODE_CODEC_NAME.lock().unwrap();
let mut preference = PreferCodec::Auto; let mut preference = PreferCodec::Auto;
let preferences: Vec<_> = decodings let preferences: Vec<_> = decodings
@ -254,19 +254,19 @@ impl Encoder {
PreferCodec::VP9 => CodecName::VP9, PreferCodec::VP9 => CodecName::VP9,
PreferCodec::AV1 => CodecName::AV1, PreferCodec::AV1 => CodecName::AV1,
PreferCodec::H264 => { PreferCodec::H264 => {
if h264gpu_encoding { if h264vram_encoding {
CodecName::H264GPU CodecName::H264VRAM
} else if let Some(v) = h264hw_encoding { } else if let Some(v) = h264hw_encoding {
CodecName::H264HW(v) CodecName::H264RAM(v)
} else { } else {
auto_codec auto_codec
} }
} }
PreferCodec::H265 => { PreferCodec::H265 => {
if h265gpu_encoding { if h265vram_encoding {
CodecName::H265GPU CodecName::H265VRAM
} else if let Some(v) = h265hw_encoding { } else if let Some(v) = h265hw_encoding {
CodecName::H265HW(v) CodecName::H265RAM(v)
} else { } else {
auto_codec auto_codec
} }
@ -306,14 +306,14 @@ impl Encoder {
}; };
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
if enable_hwcodec_option() { if enable_hwcodec_option() {
let best = HwEncoder::best(); let best = HwRamEncoder::best();
encoding.h264 |= best.h264.is_some(); encoding.h264 |= best.h264.is_some();
encoding.h265 |= best.h265.is_some(); encoding.h265 |= best.h265.is_some();
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
if enable_gpucodec_option() { if enable_vram_option() {
encoding.h264 |= GpuEncoder::available(CodecName::H264GPU).len() > 0; encoding.h264 |= VRamEncoder::available(CodecName::H264VRAM).len() > 0;
encoding.h265 |= GpuEncoder::available(CodecName::H265GPU).len() > 0; encoding.h265 |= VRamEncoder::available(CodecName::H265VRAM).len() > 0;
} }
encoding encoding
} }
@ -326,21 +326,21 @@ impl Encoder {
}, },
EncoderCfg::AOM(_) => CodecName::AV1, EncoderCfg::AOM(_) => CodecName::AV1,
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
EncoderCfg::HW(hw) => { EncoderCfg::HWRAM(hw) => {
if hw.name.to_lowercase().contains("h264") { if hw.name.to_lowercase().contains("h264") {
CodecName::H264HW(hw.name.clone()) CodecName::H264RAM(hw.name.clone())
} else { } else {
CodecName::H265HW(hw.name.clone()) CodecName::H265RAM(hw.name.clone())
} }
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
EncoderCfg::GPU(gpu) => match gpu.feature.data_format { EncoderCfg::VRAM(vram) => match vram.feature.data_format {
gpucodec::gpu_common::DataFormat::H264 => CodecName::H264GPU, hwcodec::common::DataFormat::H264 => CodecName::H264VRAM,
gpucodec::gpu_common::DataFormat::H265 => CodecName::H265GPU, hwcodec::common::DataFormat::H265 => CodecName::H265VRAM,
_ => { _ => {
log::error!( log::error!(
"should not reach here, gpucodec not support {:?}", "should not reach here, vram not support {:?}",
gpu.feature.data_format vram.feature.data_format
); );
return; return;
} }
@ -365,9 +365,9 @@ impl Encoder {
}, },
EncoderCfg::AOM(_) => decodings.iter().all(|d| d.1.i444.av1), EncoderCfg::AOM(_) => decodings.iter().all(|d| d.1.i444.av1),
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
EncoderCfg::HW(_) => false, EncoderCfg::HWRAM(_) => false,
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
EncoderCfg::GPU(_) => false, EncoderCfg::VRAM(_) => false,
}; };
prefer_i444 && i444_useable && !decodings.is_empty() prefer_i444 && i444_useable && !decodings.is_empty()
} }
@ -399,18 +399,18 @@ impl Decoder {
}; };
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
if enable_hwcodec_option() { 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_h264 |= if best.h264.is_some() { 1 } else { 0 };
decoding.ability_h265 |= if best.h265.is_some() { 1 } else { 0 }; decoding.ability_h265 |= if best.h265.is_some() { 1 } else { 0 };
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
if enable_gpucodec_option() && _flutter { if enable_vram_option() && _flutter {
decoding.ability_h264 |= if GpuDecoder::available(CodecFormat::H264, _luid).len() > 0 { decoding.ability_h264 |= if VRamDecoder::available(CodecFormat::H264, _luid).len() > 0 {
1 1
} else { } else {
0 0
}; };
decoding.ability_h265 |= if GpuDecoder::available(CodecFormat::H265, _luid).len() > 0 { decoding.ability_h265 |= if VRamDecoder::available(CodecFormat::H265, _luid).len() > 0 {
1 1
} else { } else {
0 0
@ -449,7 +449,7 @@ impl Decoder {
let (mut vp8, mut vp9, mut av1) = (None, None, None); let (mut vp8, mut vp9, mut av1) = (None, None, None);
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
let (mut h264_ram, mut h265_ram) = (None, None); let (mut h264_ram, mut h265_ram) = (None, None);
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
let (mut h264_vram, mut h265_vram) = (None, None); let (mut h264_vram, mut h265_vram) = (None, None);
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
let (mut h264_media_codec, mut h265_media_codec) = (None, None); let (mut h264_media_codec, mut h265_media_codec) = (None, None);
@ -482,9 +482,9 @@ impl Decoder {
valid = av1.is_some(); valid = av1.is_some();
} }
CodecFormat::H264 => { CodecFormat::H264 => {
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
if !valid && enable_gpucodec_option() && _luid.clone().unwrap_or_default() != 0 { if !valid && enable_vram_option() && _luid.clone().unwrap_or_default() != 0 {
match GpuDecoder::new(format, _luid) { match VRamDecoder::new(format, _luid) {
Ok(v) => h264_vram = Some(v), Ok(v) => h264_vram = Some(v),
Err(e) => log::error!("create H264 vram decoder failed: {}", e), Err(e) => log::error!("create H264 vram decoder failed: {}", e),
} }
@ -492,7 +492,7 @@ impl Decoder {
} }
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
if !valid && enable_hwcodec_option() { if !valid && enable_hwcodec_option() {
match HwDecoder::new(format) { match HwRamDecoder::new(format) {
Ok(v) => h264_ram = Some(v), Ok(v) => h264_ram = Some(v),
Err(e) => log::error!("create H264 ram decoder failed: {}", e), Err(e) => log::error!("create H264 ram decoder failed: {}", e),
} }
@ -508,9 +508,9 @@ impl Decoder {
} }
} }
CodecFormat::H265 => { CodecFormat::H265 => {
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
if !valid && enable_gpucodec_option() && _luid.clone().unwrap_or_default() != 0 { if !valid && enable_vram_option() && _luid.clone().unwrap_or_default() != 0 {
match GpuDecoder::new(format, _luid) { match VRamDecoder::new(format, _luid) {
Ok(v) => h265_vram = Some(v), Ok(v) => h265_vram = Some(v),
Err(e) => log::error!("create H265 vram decoder failed: {}", e), Err(e) => log::error!("create H265 vram decoder failed: {}", e),
} }
@ -518,7 +518,7 @@ impl Decoder {
} }
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
if !valid && enable_hwcodec_option() { if !valid && enable_hwcodec_option() {
match HwDecoder::new(format) { match HwRamDecoder::new(format) {
Ok(v) => h265_ram = Some(v), Ok(v) => h265_ram = Some(v),
Err(e) => log::error!("create H265 ram decoder failed: {}", e), Err(e) => log::error!("create H265 ram decoder failed: {}", e),
} }
@ -550,9 +550,9 @@ impl Decoder {
h264_ram, h264_ram,
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
h265_ram, h265_ram,
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
h264_vram, h264_vram,
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
h265_vram, h265_vram,
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
h264_media_codec, h264_media_codec,
@ -604,31 +604,31 @@ impl Decoder {
bail!("av1 decoder not available"); bail!("av1 decoder not available");
} }
} }
#[cfg(any(feature = "hwcodec", feature = "gpucodec"))] #[cfg(any(feature = "hwcodec", feature = "vram"))]
video_frame::Union::H264s(h264s) => { video_frame::Union::H264s(h264s) => {
*chroma = Some(Chroma::I420); *chroma = Some(Chroma::I420);
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
if let Some(decoder) = &mut self.h264_vram { if let Some(decoder) = &mut self.h264_vram {
*_pixelbuffer = false; *_pixelbuffer = false;
return Decoder::handle_gpu_video_frame(decoder, h264s, _texture); return Decoder::handle_vram_video_frame(decoder, h264s, _texture);
} }
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
if let Some(decoder) = &mut self.h264_ram { 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!")) Err(anyhow!("don't support h264!"))
} }
#[cfg(any(feature = "hwcodec", feature = "gpucodec"))] #[cfg(any(feature = "hwcodec", feature = "vram"))]
video_frame::Union::H265s(h265s) => { video_frame::Union::H265s(h265s) => {
*chroma = Some(Chroma::I420); *chroma = Some(Chroma::I420);
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
if let Some(decoder) = &mut self.h265_vram { if let Some(decoder) = &mut self.h265_vram {
*_pixelbuffer = false; *_pixelbuffer = false;
return Decoder::handle_gpu_video_frame(decoder, h265s, _texture); return Decoder::handle_vram_video_frame(decoder, h265s, _texture);
} }
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
if let Some(decoder) = &mut self.h265_ram { 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!")) Err(anyhow!("don't support h265!"))
} }
@ -710,8 +710,8 @@ impl Decoder {
// rgb [in/out] fmt and stride must be set in ImageRgb // rgb [in/out] fmt and stride must be set in ImageRgb
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
fn handle_hw_video_frame( fn handle_hwram_video_frame(
decoder: &mut HwDecoder, decoder: &mut HwRamDecoder,
frames: &EncodedVideoFrames, frames: &EncodedVideoFrames,
rgb: &mut ImageRgb, rgb: &mut ImageRgb,
i420: &mut Vec<u8>, i420: &mut Vec<u8>,
@ -728,9 +728,9 @@ impl Decoder {
return Ok(ret); return Ok(ret);
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn handle_gpu_video_frame( fn handle_vram_video_frame(
decoder: &mut GpuDecoder, decoder: &mut VRamDecoder,
frames: &EncodedVideoFrames, frames: &EncodedVideoFrames,
texture: &mut *mut c_void, texture: &mut *mut c_void,
) -> ResultType<bool> { ) -> ResultType<bool> {
@ -796,8 +796,8 @@ pub fn enable_hwcodec_option() -> bool {
} }
return true; // default is true return true; // default is true
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
pub fn enable_gpucodec_option() -> bool { pub fn enable_vram_option() -> bool {
if let Some(v) = Config2::get().options.get("enable-hwcodec") { if let Some(v) = Config2::get().options.get("enable-hwcodec") {
return v != "N"; return v != "N";
} }

View File

@ -18,7 +18,7 @@ pub mod hw {
use super::*; use super::*;
use crate::ImageFormat; use crate::ImageFormat;
#[cfg(target_os = "windows")] #[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")] #[cfg(target_os = "windows")]
pub fn hw_nv12_to( pub fn hw_nv12_to(
@ -222,9 +222,7 @@ pub fn convert_to_yuv(
); );
} }
} }
let align = |x:usize| { let align = |x: usize| (x + 63) / 64 * 64;
(x + 63) / 64 * 64
};
match (src_pixfmt, dst_fmt.pixfmt) { match (src_pixfmt, dst_fmt.pixfmt) {
(crate::Pixfmt::BGRA, crate::Pixfmt::I420) | (crate::Pixfmt::RGBA, crate::Pixfmt::I420) => { (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_u = dst_fmt.stride[1];
let dst_stride_v = dst_fmt.stride[2]; let dst_stride_v = dst_fmt.stride[2];
dst.resize( 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, 0,
); );
let dst_y = dst.as_mut_ptr(); let dst_y = dst.as_mut_ptr();

View File

@ -1,4 +1,4 @@
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
use crate::AdapterDevice; use crate::AdapterDevice;
use crate::{common::TraitCapturer, dxgi, Frame, Pixfmt}; use crate::{common::TraitCapturer, dxgi, Frame, Pixfmt};
use std::{ use std::{
@ -57,12 +57,12 @@ impl TraitCapturer for Capturer {
self.inner.set_gdi() self.inner.set_gdi()
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn device(&self) -> AdapterDevice { fn device(&self) -> AdapterDevice {
self.inner.device() self.inner.device()
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn set_output_texture(&mut self, texture: bool) { fn set_output_texture(&mut self, texture: bool) {
self.inner.set_output_texture(texture); self.inner.set_output_texture(texture);
} }
@ -197,7 +197,7 @@ impl Display {
self.origin() == (0, 0) self.origin() == (0, 0)
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
pub fn adapter_luid(&self) -> Option<i64> { pub fn adapter_luid(&self) -> Option<i64> {
self.0.adapter_luid() self.0.adapter_luid()
} }
@ -247,11 +247,11 @@ impl TraitCapturer for CapturerMag {
false false
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn device(&self) -> AdapterDevice { fn device(&self) -> AdapterDevice {
AdapterDevice::default() AdapterDevice::default()
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn set_output_texture(&mut self, _texture: bool) {} fn set_output_texture(&mut self, _texture: bool) {}
} }

View File

@ -9,20 +9,21 @@ use hbb_common::{
config::HwCodecConfig, config::HwCodecConfig,
log, log,
message_proto::{EncodedVideoFrame, EncodedVideoFrames, VideoFrame}, message_proto::{EncodedVideoFrame, EncodedVideoFrames, VideoFrame},
ResultType, serde_derive::{Deserialize, Serialize},
serde_json, ResultType,
}; };
use hwcodec::{ use hwcodec::{
common::DataFormat,
ffmpeg::AVPixelFormat,
ffmpeg_ram::{
decode::{DecodeContext, DecodeFrame, Decoder}, decode::{DecodeContext, DecodeFrame, Decoder},
encode::{EncodeContext, EncodeFrame, Encoder}, encode::{EncodeContext, EncodeFrame, Encoder},
ffmpeg::{CodecInfo, CodecInfos, DataFormat}, CodecInfo, CodecInfos,
AVPixelFormat,
Quality::{self, *}, Quality::{self, *},
RateControl::{self, *}, RateControl::{self, *},
},
}; };
const CFG_KEY_ENCODER: &str = "bestHwEncoders";
const CFG_KEY_DECODER: &str = "bestHwDecoders";
const DEFAULT_PIXFMT: AVPixelFormat = AVPixelFormat::AV_PIX_FMT_NV12; const DEFAULT_PIXFMT: AVPixelFormat = AVPixelFormat::AV_PIX_FMT_NV12;
pub const DEFAULT_TIME_BASE: [i32; 2] = [1, 30]; pub const DEFAULT_TIME_BASE: [i32; 2] = [1, 30];
const DEFAULT_GOP: i32 = i32::MAX; const DEFAULT_GOP: i32 = i32::MAX;
@ -30,7 +31,7 @@ const DEFAULT_HW_QUALITY: Quality = Quality_Default;
const DEFAULT_RC: RateControl = RC_DEFAULT; const DEFAULT_RC: RateControl = RC_DEFAULT;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct HwEncoderConfig { pub struct HwRamEncoderConfig {
pub name: String, pub name: String,
pub width: usize, pub width: usize,
pub height: usize, pub height: usize,
@ -38,7 +39,7 @@ pub struct HwEncoderConfig {
pub keyframe_interval: Option<usize>, pub keyframe_interval: Option<usize>,
} }
pub struct HwEncoder { pub struct HwRamEncoder {
encoder: Encoder, encoder: Encoder,
name: String, name: String,
pub format: DataFormat, pub format: DataFormat,
@ -48,13 +49,13 @@ pub struct HwEncoder {
bitrate: u32, //kbs bitrate: u32, //kbs
} }
impl EncoderApi for HwEncoder { impl EncoderApi for HwRamEncoder {
fn new(cfg: EncoderCfg, _i444: bool) -> ResultType<Self> fn new(cfg: EncoderCfg, _i444: bool) -> ResultType<Self>
where where
Self: Sized, Self: Sized,
{ {
match cfg { match cfg {
EncoderCfg::HW(config) => { EncoderCfg::HWRAM(config) => {
let b = Self::convert_quality(config.quality); let b = Self::convert_quality(config.quality);
let base_bitrate = base_bitrate(config.width as _, config.height as _); let base_bitrate = base_bitrate(config.width as _, config.height as _);
let mut bitrate = base_bitrate * b / 100; let mut bitrate = base_bitrate * b / 100;
@ -85,7 +86,7 @@ impl EncoderApi for HwEncoder {
} }
}; };
match Encoder::new(ctx.clone()) { match Encoder::new(ctx.clone()) {
Ok(encoder) => Ok(HwEncoder { Ok(encoder) => Ok(HwRamEncoder {
encoder, encoder,
name: config.name, name: config.name,
format, format,
@ -95,7 +96,7 @@ impl EncoderApi for HwEncoder {
bitrate, bitrate,
}), }),
Err(_) => { Err(_) => {
HwCodecConfig::clear(); HwCodecConfig::clear_ram();
Err(anyhow!(format!("Failed to create encoder"))) Err(anyhow!(format!("Failed to create encoder")))
} }
} }
@ -126,6 +127,7 @@ impl EncoderApi for HwEncoder {
match self.format { match self.format {
DataFormat::H264 => vf.set_h264s(frames), DataFormat::H264 => vf.set_h264s(frames),
DataFormat::H265 => vf.set_h265s(frames), DataFormat::H265 => vf.set_h265s(frames),
_ => bail!("unsupported format: {:?}", self.format),
} }
Ok(vf) Ok(vf)
} else { } else {
@ -160,7 +162,7 @@ impl EncoderApi for HwEncoder {
} }
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn input_texture(&self) -> bool { fn input_texture(&self) -> bool {
false false
} }
@ -184,9 +186,9 @@ impl EncoderApi for HwEncoder {
} }
} }
impl HwEncoder { impl HwRamEncoder {
pub fn best() -> CodecInfos { pub fn best() -> CodecInfos {
get_config(CFG_KEY_ENCODER).unwrap_or(CodecInfos { get_config().map(|c| c.e).unwrap_or(CodecInfos {
h264: None, h264: None,
h265: None, h265: None,
}) })
@ -214,20 +216,14 @@ impl HwEncoder {
} }
} }
pub struct HwDecoder { pub struct HwRamDecoder {
decoder: Decoder, decoder: Decoder,
pub info: CodecInfo, pub info: CodecInfo,
} }
#[derive(Default)] impl HwRamDecoder {
pub struct HwDecoders {
pub h264: Option<HwDecoder>,
pub h265: Option<HwDecoder>,
}
impl HwDecoder {
pub fn best() -> CodecInfos { pub fn best() -> CodecInfos {
get_config(CFG_KEY_DECODER).unwrap_or(CodecInfos { get_config().map(|c| c.d).unwrap_or(CodecInfos {
h264: None, h264: None,
h265: None, h265: None,
}) })
@ -235,7 +231,7 @@ impl HwDecoder {
pub fn new(format: CodecFormat) -> ResultType<Self> { pub fn new(format: CodecFormat) -> ResultType<Self> {
log::info!("try create {format:?} ram decoder"); log::info!("try create {format:?} ram decoder");
let best = HwDecoder::best(); let best = HwRamDecoder::best();
let info = match format { let info = match format {
CodecFormat::H264 => { CodecFormat::H264 => {
if let Some(info) = best.h264 { if let Some(info) = best.h264 {
@ -259,26 +255,26 @@ impl HwDecoder {
thread_count: codec_thread_num(16) as _, thread_count: codec_thread_num(16) as _,
}; };
match Decoder::new(ctx) { match Decoder::new(ctx) {
Ok(decoder) => Ok(HwDecoder { decoder, info }), Ok(decoder) => Ok(HwRamDecoder { decoder, info }),
Err(_) => { Err(_) => {
HwCodecConfig::clear(); HwCodecConfig::clear_ram();
Err(anyhow!(format!("Failed to create decoder"))) 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) { 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)), Err(e) => Err(anyhow!(e)),
} }
} }
} }
pub struct HwDecoderImage<'a> { pub struct HwRamDecoderImage<'a> {
frame: &'a DecodeFrame, frame: &'a DecodeFrame,
} }
impl HwDecoderImage<'_> { impl HwRamDecoderImage<'_> {
// rgb [in/out] fmt and stride must be set in ImageRgb // rgb [in/out] fmt and stride must be set in ImageRgb
pub fn to_fmt(&self, rgb: &mut ImageRgb, i420: &mut Vec<u8>) -> ResultType<()> { pub fn to_fmt(&self, rgb: &mut ImageRgb, i420: &mut Vec<u8>) -> ResultType<()> {
let frame = self.frame; let frame = self.frame;
@ -332,23 +328,24 @@ impl HwDecoderImage<'_> {
} }
} }
fn get_config(k: &str) -> ResultType<CodecInfos> { #[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
let v = HwCodecConfig::load() struct Available {
.options e: CodecInfos,
.get(k) d: CodecInfos,
.unwrap_or(&"".to_owned()) }
.to_owned();
match CodecInfos::deserialize(&v) { fn get_config() -> ResultType<Available> {
match serde_json::from_str(&HwCodecConfig::load().ram) {
Ok(v) => Ok(v), 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() { pub fn check_available_hwcodec() {
let ctx = EncodeContext { let ctx = EncodeContext {
name: String::from(""), name: String::from(""),
width: 1920, width: 1280,
height: 1080, height: 720,
pixfmt: DEFAULT_PIXFMT, pixfmt: DEFAULT_PIXFMT,
align: HW_STRIDE_ALIGN as _, align: HW_STRIDE_ALIGN as _,
bitrate: 0, bitrate: 0,
@ -358,27 +355,19 @@ pub fn check_available_hwcodec() {
rc: DEFAULT_RC, rc: DEFAULT_RC,
thread_count: 4, thread_count: 4,
}; };
let encoders = CodecInfo::score(Encoder::available_encoders(ctx)); #[cfg(feature = "vram")]
let decoders = CodecInfo::score(Decoder::available_decoders()); let vram = crate::vram::check_available_vram();
#[cfg(not(feature = "vram"))]
if let Ok(old_encoders) = get_config(CFG_KEY_ENCODER) { let vram = "".to_owned();
if let Ok(old_decoders) = get_config(CFG_KEY_DECODER) { let encoders = CodecInfo::score(Encoder::available_encoders(ctx, Some(vram.clone())));
if encoders == old_encoders && decoders == old_decoders { let decoders = CodecInfo::score(Decoder::available_decoders(Some(vram.clone())));
return; 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() { pub fn hwcodec_new_check_process() {

View File

@ -37,13 +37,13 @@ cfg_if! {
pub mod codec; pub mod codec;
pub mod convert; pub mod convert;
#[cfg(feature = "gpucodec")]
pub mod gpucodec;
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
pub mod hwcodec; pub mod hwcodec;
#[cfg(feature = "mediacodec")] #[cfg(feature = "mediacodec")]
pub mod mediacodec; pub mod mediacodec;
pub mod vpxcodec; pub mod vpxcodec;
#[cfg(feature = "vram")]
pub mod vram;
pub use self::convert::*; pub use self::convert::*;
pub const STRIDE_ALIGN: usize = 64; // commonly used in libvpx vpx_img_alloc caller 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 pub const HW_STRIDE_ALIGN: usize = 0; // recommended by av_frame_get_buffer
@ -111,10 +111,10 @@ pub trait TraitCapturer {
#[cfg(windows)] #[cfg(windows)]
fn set_gdi(&mut self) -> bool; fn set_gdi(&mut self) -> bool;
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn device(&self) -> AdapterDevice; fn device(&self) -> AdapterDevice;
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn set_output_texture(&mut self, texture: bool); fn set_output_texture(&mut self, texture: bool);
} }
@ -245,10 +245,10 @@ pub enum CodecName {
VP8, VP8,
VP9, VP9,
AV1, AV1,
H264HW(String), H264RAM(String),
H265HW(String), H265RAM(String),
H264GPU, H264VRAM,
H265GPU, H265VRAM,
} }
#[derive(PartialEq, Debug, Clone, Copy)] #[derive(PartialEq, Debug, Clone, Copy)]
@ -280,8 +280,8 @@ impl From<&CodecName> for CodecFormat {
CodecName::VP8 => Self::VP8, CodecName::VP8 => Self::VP8,
CodecName::VP9 => Self::VP9, CodecName::VP9 => Self::VP9,
CodecName::AV1 => Self::AV1, CodecName::AV1 => Self::AV1,
CodecName::H264HW(_) | CodecName::H264GPU => Self::H264, CodecName::H264RAM(_) | CodecName::H264VRAM => Self::H264,
CodecName::H265HW(_) | CodecName::H265GPU => Self::H265, CodecName::H265RAM(_) | CodecName::H265VRAM => Self::H265,
} }
} }
} }

View File

@ -207,7 +207,7 @@ impl EncoderApi for VpxEncoder {
self.yuvfmt.clone() self.yuvfmt.clone()
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn input_texture(&self) -> bool { fn input_texture(&self) -> bool {
false false
} }

View File

@ -5,24 +5,24 @@ use std::{
}; };
use crate::{ 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, 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::{ use hbb_common::{
allow_err,
anyhow::{anyhow, bail, Context}, anyhow::{anyhow, bail, Context},
bytes::Bytes, bytes::Bytes,
log, log,
message_proto::{EncodedVideoFrame, EncodedVideoFrames, VideoFrame}, message_proto::{EncodedVideoFrame, EncodedVideoFrames, VideoFrame},
ResultType, 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; const OUTPUT_SHARED_HANDLE: bool = false;
@ -35,31 +35,31 @@ lazy_static::lazy_static! {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct GpuEncoderConfig { pub struct VRamEncoderConfig {
pub device: AdapterDevice, pub device: AdapterDevice,
pub width: usize, pub width: usize,
pub height: usize, pub height: usize,
pub quality: Quality, pub quality: Quality,
pub feature: gpucodec::gpu_common::FeatureContext, pub feature: FeatureContext,
pub keyframe_interval: Option<usize>, pub keyframe_interval: Option<usize>,
} }
pub struct GpuEncoder { pub struct VRamEncoder {
encoder: Encoder, encoder: Encoder,
pub format: gpu_common::DataFormat, pub format: DataFormat,
ctx: EncodeContext, ctx: EncodeContext,
bitrate: u32, bitrate: u32,
last_frame_len: usize, last_frame_len: usize,
same_bad_len_counter: usize, same_bad_len_counter: usize,
} }
impl EncoderApi for GpuEncoder { impl EncoderApi for VRamEncoder {
fn new(cfg: EncoderCfg, _i444: bool) -> ResultType<Self> fn new(cfg: EncoderCfg, _i444: bool) -> ResultType<Self>
where where
Self: Sized, Self: Sized,
{ {
match cfg { match cfg {
EncoderCfg::GPU(config) => { EncoderCfg::VRAM(config) => {
let b = Self::convert_quality(config.quality, &config.feature); let b = Self::convert_quality(config.quality, &config.feature);
let base_bitrate = base_bitrate(config.width as _, config.height as _); let base_bitrate = base_bitrate(config.width as _, config.height as _);
let mut bitrate = base_bitrate * b / 100; let mut bitrate = base_bitrate * b / 100;
@ -79,7 +79,7 @@ impl EncoderApi for GpuEncoder {
}, },
}; };
match Encoder::new(ctx.clone()) { match Encoder::new(ctx.clone()) {
Ok(encoder) => Ok(GpuEncoder { Ok(encoder) => Ok(VRamEncoder {
encoder, encoder,
ctx, ctx,
format: config.feature.data_format, format: config.feature.data_format,
@ -88,7 +88,7 @@ impl EncoderApi for GpuEncoder {
same_bad_len_counter: 0, same_bad_len_counter: 0,
}), }),
Err(_) => { Err(_) => {
hbb_common::config::GpucodecConfig::clear(); hbb_common::config::HwCodecConfig::clear_vram();
Err(anyhow!(format!("Failed to create encoder"))) Err(anyhow!(format!("Failed to create encoder")))
} }
} }
@ -138,8 +138,8 @@ impl EncoderApi for GpuEncoder {
..Default::default() ..Default::default()
}; };
match self.format { match self.format {
gpu_common::DataFormat::H264 => vf.set_h264s(frames), DataFormat::H264 => vf.set_h264s(frames),
gpu_common::DataFormat::H265 => vf.set_h265s(frames), DataFormat::H265 => vf.set_h265s(frames),
_ => bail!("{:?} not supported", self.format), _ => bail!("{:?} not supported", self.format),
} }
Ok(vf) Ok(vf)
@ -160,7 +160,7 @@ impl EncoderApi for GpuEncoder {
} }
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn input_texture(&self) -> bool { fn input_texture(&self) -> bool {
true true
} }
@ -181,11 +181,11 @@ impl EncoderApi for GpuEncoder {
} }
fn support_abr(&self) -> bool { 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> { pub fn try_get(device: &AdapterDevice, name: CodecName) -> Option<FeatureContext> {
let v: Vec<_> = Self::available(name) let v: Vec<_> = Self::available(name)
.drain(..) .drain(..)
@ -201,12 +201,12 @@ impl GpuEncoder {
pub fn available(name: CodecName) -> Vec<FeatureContext> { pub fn available(name: CodecName) -> Vec<FeatureContext> {
let not_use = ENOCDE_NOT_USE.lock().unwrap().clone(); let not_use = ENOCDE_NOT_USE.lock().unwrap().clone();
if not_use.values().any(|not_use| *not_use) { 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![]; return vec![];
} }
let data_format = match name { let data_format = match name {
CodecName::H264GPU => gpu_common::DataFormat::H264, CodecName::H264VRAM => DataFormat::H264,
CodecName::H265GPU => gpu_common::DataFormat::H265, CodecName::H265VRAM => DataFormat::H265,
_ => return vec![], _ => return vec![],
}; };
let Ok(displays) = crate::Display::all() else { let Ok(displays) = crate::Display::all() else {
@ -252,27 +252,21 @@ impl GpuEncoder {
pub fn convert_quality(quality: Quality, f: &FeatureContext) -> u32 { pub fn convert_quality(quality: Quality, f: &FeatureContext) -> u32 {
match quality { match quality {
Quality::Best => { Quality::Best => {
if f.driver == gpu_common::EncodeDriver::VPL if f.driver == Driver::VPL && f.data_format == DataFormat::H264 {
&& f.data_format == gpu_common::DataFormat::H264
{
200 200
} else { } else {
150 150
} }
} }
Quality::Balanced => { Quality::Balanced => {
if f.driver == gpu_common::EncodeDriver::VPL if f.driver == Driver::VPL && f.data_format == DataFormat::H264 {
&& f.data_format == gpu_common::DataFormat::H264
{
150 150
} else { } else {
100 100
} }
} }
Quality::Low => { Quality::Low => {
if f.driver == gpu_common::EncodeDriver::VPL if f.driver == Driver::VPL && f.data_format == DataFormat::H264 {
&& f.data_format == gpu_common::DataFormat::H264
{
75 75
} else { } else {
50 50
@ -283,7 +277,7 @@ impl GpuEncoder {
} }
pub fn set_not_use(display: usize, not_use: bool) { 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); ENOCDE_NOT_USE.lock().unwrap().insert(display, not_use);
} }
@ -292,17 +286,11 @@ impl GpuEncoder {
} }
} }
pub struct GpuDecoder { pub struct VRamDecoder {
decoder: Decoder, decoder: Decoder,
} }
#[derive(Default)] impl VRamDecoder {
pub struct GpuDecoders {
pub h264: Option<GpuDecoder>,
pub h265: Option<GpuDecoder>,
}
impl GpuDecoder {
pub fn try_get(format: CodecFormat, luid: Option<i64>) -> Option<DecodeContext> { pub fn try_get(format: CodecFormat, luid: Option<i64>) -> Option<DecodeContext> {
let v: Vec<_> = Self::available(format, luid); let v: Vec<_> = Self::available(format, luid);
if v.len() > 0 { if v.len() > 0 {
@ -315,8 +303,8 @@ impl GpuDecoder {
pub fn available(format: CodecFormat, luid: Option<i64>) -> Vec<DecodeContext> { pub fn available(format: CodecFormat, luid: Option<i64>) -> Vec<DecodeContext> {
let luid = luid.unwrap_or_default(); let luid = luid.unwrap_or_default();
let data_format = match format { let data_format = match format {
CodecFormat::H264 => gpu_common::DataFormat::H264, CodecFormat::H264 => DataFormat::H264,
CodecFormat::H265 => gpu_common::DataFormat::H265, CodecFormat::H265 => DataFormat::H265,
_ => return vec![], _ => return vec![],
}; };
get_available_config() get_available_config()
@ -328,15 +316,13 @@ impl GpuDecoder {
} }
pub fn possible_available_without_check() -> (bool, bool) { pub fn possible_available_without_check() -> (bool, bool) {
if !enable_gpucodec_option() { if !enable_vram_option() {
return (false, false); return (false, false);
} }
let v = get_available_config().map(|c| c.d).unwrap_or_default(); let v = get_available_config().map(|c| c.d).unwrap_or_default();
( (
v.iter() v.iter().any(|d| d.data_format == DataFormat::H264),
.any(|d| d.data_format == gpu_common::DataFormat::H264), v.iter().any(|d| d.data_format == DataFormat::H265),
v.iter()
.any(|d| d.data_format == gpu_common::DataFormat::H265),
) )
} }
@ -346,7 +332,7 @@ impl GpuDecoder {
match Decoder::new(ctx) { match Decoder::new(ctx) {
Ok(decoder) => Ok(Self { decoder }), Ok(decoder) => Ok(Self { decoder }),
Err(_) => { Err(_) => {
hbb_common::config::GpucodecConfig::clear(); hbb_common::config::HwCodecConfig::clear_vram();
Err(anyhow!(format!( Err(anyhow!(format!(
"Failed to create decoder, format: {:?}", "Failed to create decoder, format: {:?}",
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) { 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)), Err(e) => Err(anyhow!(e)),
} }
} }
} }
pub struct GpuDecoderImage<'a> { pub struct VRamDecoderImage<'a> {
pub frame: &'a DecodeFrame, pub frame: &'a DecodeFrame,
} }
impl GpuDecoderImage<'_> {} impl VRamDecoderImage<'_> {}
fn get_available_config() -> ResultType<Available> { 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) { match Available::deserialize(&available) {
Ok(v) => Ok(v), Ok(v) => Ok(v),
Err(_) => Err(anyhow!("Failed to deserialize:{}", available)), Err(_) => Err(anyhow!("Failed to deserialize:{}", available)),
} }
} }
pub fn check_available_gpucodec() { pub(crate) fn check_available_vram() -> String {
let d = DynamicContext { let d = DynamicContext {
device: None, device: None,
width: 1920, width: 1280,
height: 1080, height: 720,
kbitrate: 5000, kbitrate: 5000,
framerate: 60, framerate: 60,
gop: MAX_GOP as _, gop: MAX_GOP as _,
@ -391,54 +377,5 @@ pub fn check_available_gpucodec() {
e: encoders, e: encoders,
d: decoders, d: decoders,
}; };
available.serialize().unwrap_or_default()
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}")
}
}
}
};
});
});
} }

View File

@ -185,7 +185,7 @@ impl Capturer {
self.gdi_capturer.take(); self.gdi_capturer.take();
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
pub fn set_output_texture(&mut self, texture: bool) { pub fn set_output_texture(&mut self, texture: bool) {
self.output_texture = texture; self.output_texture = texture;
} }
@ -620,7 +620,7 @@ impl Display {
) )
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
pub fn adapter_luid(&self) -> Option<i64> { pub fn adapter_luid(&self) -> Option<i64> {
unsafe { unsafe {
if !self.adapter.is_null() { if !self.adapter.is_null() {

View File

@ -1038,9 +1038,9 @@ pub struct VideoHandler {
impl VideoHandler { impl VideoHandler {
/// Create a new video handler. /// Create a new video handler.
pub fn new(format: CodecFormat, _display: usize) -> Self { pub fn new(format: CodecFormat, _display: usize) -> Self {
#[cfg(all(feature = "gpucodec", feature = "flutter"))] #[cfg(all(feature = "vram", feature = "flutter"))]
let luid = crate::flutter::get_adapter_luid(); let luid = crate::flutter::get_adapter_luid();
#[cfg(not(all(feature = "gpucodec", feature = "flutter")))] #[cfg(not(all(feature = "vram", feature = "flutter")))]
let luid = Default::default(); let luid = Default::default();
log::info!("new video handler for display #{_display}, format: {format:?}, luid: {luid:?}"); log::info!("new video handler for display #{_display}, format: {format:?}, luid: {luid:?}");
VideoHandler { VideoHandler {
@ -1097,9 +1097,9 @@ impl VideoHandler {
/// Reset the decoder, change format if it is Some /// Reset the decoder, change format if it is Some
pub fn reset(&mut self, format: Option<CodecFormat>) { pub fn reset(&mut self, format: Option<CodecFormat>) {
#[cfg(all(feature = "flutter", feature = "gpucodec"))] #[cfg(all(feature = "flutter", feature = "vram"))]
let luid = crate::flutter::get_adapter_luid(); let luid = crate::flutter::get_adapter_luid();
#[cfg(not(all(feature = "flutter", feature = "gpucodec")))] #[cfg(not(all(feature = "flutter", feature = "vram")))]
let luid = None; let luid = None;
let format = format.unwrap_or(self.decoder.format()); let format = format.unwrap_or(self.decoder.format());
self.decoder = Decoder::new(format, luid); self.decoder = Decoder::new(format, luid);

View File

@ -410,10 +410,6 @@ pub fn core_main() -> Option<Vec<String>> {
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
scrap::hwcodec::check_available_hwcodec(); scrap::hwcodec::check_available_hwcodec();
return None; return None;
} else if args[0] == "--check-gpucodec-config" {
#[cfg(feature = "gpucodec")]
scrap::gpucodec::check_available_gpucodec();
return None;
} else if args[0] == "--cm" { } else if args[0] == "--cm" {
// call connection manager to establish connections // call connection manager to establish connections
// meanwhile, return true to call flutter window to show control panel // meanwhile, return true to call flutter window to show control panel

View File

@ -4,7 +4,7 @@ use crate::{
ui_session_interface::{io_loop, InvokeUiSession, Session}, ui_session_interface::{io_loop, InvokeUiSession, Session},
}; };
use flutter_rust_bridge::StreamSink; use flutter_rust_bridge::StreamSink;
#[cfg(any(feature = "flutter_texture_render", feature = "gpucodec"))] #[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
use hbb_common::dlopen::{ use hbb_common::dlopen::{
symbor::{Library, Symbol}, symbor::{Library, Symbol},
Error as LibError, Error as LibError,
@ -16,7 +16,7 @@ use hbb_common::{
use serde::Serialize; use serde::Serialize;
use serde_json::json; use serde_json::json;
#[cfg(any(feature = "flutter_texture_render", feature = "gpucodec"))] #[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
use std::os::raw::c_void; use std::os::raw::c_void;
use std::{ use std::{
@ -63,7 +63,7 @@ lazy_static::lazy_static! {
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open_self(); pub static ref TEXTURE_RGBA_RENDERER_PLUGIN: Result<Library, LibError> = Library::open_self();
} }
#[cfg(all(target_os = "windows", feature = "gpucodec"))] #[cfg(all(target_os = "windows", feature = "vram"))]
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref TEXTURE_GPU_RENDERER_PLUGIN: Result<Library, LibError> = Library::open("flutter_gpu_texture_renderer_plugin.dll"); pub static ref TEXTURE_GPU_RENDERER_PLUGIN: Result<Library, LibError> = Library::open("flutter_gpu_texture_renderer_plugin.dll");
} }
@ -168,15 +168,15 @@ pub unsafe extern "C" fn get_rustdesk_app_name(buffer: *mut u16, length: i32) ->
#[derive(Default)] #[derive(Default)]
struct SessionHandler { struct SessionHandler {
event_stream: Option<StreamSink<EventToUI>>, event_stream: Option<StreamSink<EventToUI>>,
#[cfg(any(feature = "flutter_texture_render", feature = "gpucodec"))] #[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
renderer: VideoRenderer, renderer: VideoRenderer,
} }
#[cfg(any(feature = "flutter_texture_render", feature = "gpucodec"))] #[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum RenderType { enum RenderType {
PixelBuffer, PixelBuffer,
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
Texture, Texture,
} }
@ -214,41 +214,41 @@ pub type FlutterRgbaRendererPluginOnRgba = unsafe extern "C" fn(
dst_rgba_stride: c_int, dst_rgba_stride: c_int,
); );
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
pub type FlutterGpuTextureRendererPluginCApiSetTexture = pub type FlutterGpuTextureRendererPluginCApiSetTexture =
unsafe extern "C" fn(output: *mut c_void, texture: *mut c_void); unsafe extern "C" fn(output: *mut c_void, texture: *mut c_void);
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
pub type FlutterGpuTextureRendererPluginCApiGetAdapterLuid = unsafe extern "C" fn() -> i64; pub type FlutterGpuTextureRendererPluginCApiGetAdapterLuid = unsafe extern "C" fn() -> i64;
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
pub(super) type TextureRgbaPtr = usize; pub(super) type TextureRgbaPtr = usize;
#[cfg(any(feature = "flutter_texture_render", feature = "gpucodec"))] #[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
struct DisplaySessionInfo { struct DisplaySessionInfo {
// TextureRgba pointer in flutter native. // TextureRgba pointer in flutter native.
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
texture_rgba_ptr: TextureRgbaPtr, texture_rgba_ptr: TextureRgbaPtr,
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
size: (usize, usize), size: (usize, usize),
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
gpu_output_ptr: usize, gpu_output_ptr: usize,
notify_render_type: Option<RenderType>, notify_render_type: Option<RenderType>,
} }
// Video Texture Renderer in Flutter // Video Texture Renderer in Flutter
#[cfg(any(feature = "flutter_texture_render", feature = "gpucodec"))] #[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
#[derive(Clone)] #[derive(Clone)]
struct VideoRenderer { struct VideoRenderer {
is_support_multi_ui_session: bool, is_support_multi_ui_session: bool,
map_display_sessions: Arc<RwLock<HashMap<usize, DisplaySessionInfo>>>, map_display_sessions: Arc<RwLock<HashMap<usize, DisplaySessionInfo>>>,
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
on_rgba_func: Option<Symbol<'static, FlutterRgbaRendererPluginOnRgba>>, on_rgba_func: Option<Symbol<'static, FlutterRgbaRendererPluginOnRgba>>,
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
on_texture_func: Option<Symbol<'static, FlutterGpuTextureRendererPluginCApiSetTexture>>, on_texture_func: Option<Symbol<'static, FlutterGpuTextureRendererPluginCApiSetTexture>>,
} }
#[cfg(any(feature = "flutter_texture_render", feature = "gpucodec"))] #[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
impl Default for VideoRenderer { impl Default for VideoRenderer {
fn default() -> Self { fn default() -> Self {
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
@ -270,7 +270,7 @@ impl Default for VideoRenderer {
None None
} }
}; };
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
let on_texture_func = match &*TEXTURE_GPU_RENDERER_PLUGIN { let on_texture_func = match &*TEXTURE_GPU_RENDERER_PLUGIN {
Ok(lib) => { Ok(lib) => {
let find_sym_res = unsafe { let find_sym_res = unsafe {
@ -297,13 +297,13 @@ impl Default for VideoRenderer {
is_support_multi_ui_session: false, is_support_multi_ui_session: false,
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
on_rgba_func, on_rgba_func,
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
on_texture_func, on_texture_func,
} }
} }
} }
#[cfg(any(feature = "flutter_texture_render", feature = "gpucodec"))] #[cfg(any(feature = "flutter_texture_render", feature = "vram"))]
impl VideoRenderer { impl VideoRenderer {
#[inline] #[inline]
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
@ -318,7 +318,7 @@ impl VideoRenderer {
DisplaySessionInfo { DisplaySessionInfo {
texture_rgba_ptr: usize::default(), texture_rgba_ptr: usize::default(),
size: (width, height), size: (width, height),
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
gpu_output_ptr: usize::default(), gpu_output_ptr: usize::default(),
notify_render_type: None, notify_render_type: None,
}, },
@ -345,7 +345,7 @@ impl VideoRenderer {
DisplaySessionInfo { DisplaySessionInfo {
texture_rgba_ptr: ptr as _, texture_rgba_ptr: ptr as _,
size: (0, 0), size: (0, 0),
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
gpu_output_ptr: usize::default(), gpu_output_ptr: usize::default(),
notify_render_type: None, notify_render_type: None,
}, },
@ -355,7 +355,7 @@ impl VideoRenderer {
} }
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
pub fn register_gpu_output(&self, display: usize, ptr: usize) { pub fn register_gpu_output(&self, display: usize, ptr: usize) {
let mut sessions_lock = self.map_display_sessions.write().unwrap(); let mut sessions_lock = self.map_display_sessions.write().unwrap();
if ptr == 0 { if ptr == 0 {
@ -434,7 +434,7 @@ impl VideoRenderer {
} }
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
pub fn on_texture(&self, display: usize, texture: *mut c_void) -> bool { pub fn on_texture(&self, display: usize, texture: *mut c_void) -> bool {
let mut write_lock = self.map_display_sessions.write().unwrap(); let mut write_lock = self.map_display_sessions.write().unwrap();
let opt_info = if !self.is_support_multi_ui_session { let opt_info = if !self.is_support_multi_ui_session {
@ -793,7 +793,7 @@ impl InvokeUiSession for FlutterHandler {
} }
#[inline] #[inline]
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn on_texture(&self, display: usize, texture: *mut c_void) { fn on_texture(&self, display: usize, texture: *mut c_void) {
for (_, session) in self.session_handlers.read().unwrap().iter() { for (_, session) in self.session_handlers.read().unwrap().iter() {
if session.renderer.on_texture(display, texture) { if session.renderer.on_texture(display, texture) {
@ -1073,9 +1073,9 @@ pub fn session_add(
Some(switch_uuid.to_string()) Some(switch_uuid.to_string())
}; };
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
let adapter_luid = get_adapter_luid(); let adapter_luid = get_adapter_luid();
#[cfg(not(feature = "gpucodec"))] #[cfg(not(feature = "vram"))]
let adapter_luid = None; let adapter_luid = None;
session.lc.write().unwrap().initialize( session.lc.write().unwrap().initialize(
@ -1453,7 +1453,7 @@ pub fn session_register_pixelbuffer_texture(_session_id: SessionID, _display: us
#[inline] #[inline]
pub fn session_register_gpu_texture(_session_id: SessionID, _display: usize, _output_ptr: usize) { pub fn session_register_gpu_texture(_session_id: SessionID, _display: usize, _output_ptr: usize) {
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
for s in sessions::get_sessions() { for s in sessions::get_sessions() {
if let Some(h) = s if let Some(h) = s
.ui_handler .ui_handler
@ -1468,7 +1468,7 @@ pub fn session_register_gpu_texture(_session_id: SessionID, _display: usize, _ou
} }
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
pub fn get_adapter_luid() -> Option<i64> { pub fn get_adapter_luid() -> Option<i64> {
let get_adapter_luid_func = match &*TEXTURE_GPU_RENDERER_PLUGIN { let get_adapter_luid_func = match &*TEXTURE_GPU_RENDERER_PLUGIN {
Ok(lib) => { Ok(lib) => {

View File

@ -1295,8 +1295,8 @@ pub fn main_has_hwcodec() -> SyncReturn<bool> {
SyncReturn(has_hwcodec()) SyncReturn(has_hwcodec())
} }
pub fn main_has_gpucodec() -> SyncReturn<bool> { pub fn main_has_vram() -> SyncReturn<bool> {
SyncReturn(has_gpucodec()) SyncReturn(has_vram())
} }
pub fn main_supported_hwdecodings() -> SyncReturn<String> { pub fn main_supported_hwdecodings() -> SyncReturn<String> {
@ -1782,7 +1782,7 @@ pub fn main_has_file_clipboard() -> SyncReturn<bool> {
} }
pub fn main_has_gpu_texture_render() -> SyncReturn<bool> { pub fn main_has_gpu_texture_render() -> SyncReturn<bool> {
SyncReturn(cfg!(feature = "gpucodec")) SyncReturn(cfg!(feature = "vram"))
} }
pub fn cm_init() { pub fn cm_init() {

View File

@ -450,8 +450,6 @@ pub async fn start_server(is_server: bool) {
} }
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
scrap::hwcodec::hwcodec_new_check_process(); scrap::hwcodec::hwcodec_new_check_process();
#[cfg(feature = "gpucodec")]
scrap::gpucodec::gpucodec_new_check_process();
#[cfg(windows)] #[cfg(windows)]
hbb_common::platform::windows::start_cpu_performance_monitor(); hbb_common::platform::windows::start_cpu_performance_monitor();

View File

@ -235,7 +235,7 @@ pub struct Connection {
auto_disconnect_timer: Option<(Instant, u64)>, auto_disconnect_timer: Option<(Instant, u64)>,
authed_conn_id: Option<self::raii::AuthedConnID>, authed_conn_id: Option<self::raii::AuthedConnID>,
file_remove_log_control: FileRemoveLogControl, file_remove_log_control: FileRemoveLogControl,
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
supported_encoding_flag: (bool, Option<bool>), supported_encoding_flag: (bool, Option<bool>),
services_subed: bool, services_subed: bool,
delayed_read_dir: Option<(String, bool)>, delayed_read_dir: Option<(String, bool)>,
@ -386,7 +386,7 @@ impl Connection {
auto_disconnect_timer: None, auto_disconnect_timer: None,
authed_conn_id: None, authed_conn_id: None,
file_remove_log_control: FileRemoveLogControl::new(id), file_remove_log_control: FileRemoveLogControl::new(id),
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
supported_encoding_flag: (false, None), supported_encoding_flag: (false, None),
services_subed: false, services_subed: false,
delayed_read_dir: None, delayed_read_dir: None,
@ -691,7 +691,7 @@ impl Connection {
} }
} }
conn.file_remove_log_control.on_timer().drain(..).map(|x| conn.send_to_cm(x)).count(); conn.file_remove_log_control.on_timer().drain(..).map(|x| conn.send_to_cm(x)).count();
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
conn.update_supported_encoding(); conn.update_supported_encoding();
} }
_ = test_delay_timer.tick() => { _ = test_delay_timer.tick() => {
@ -3097,9 +3097,9 @@ impl Connection {
.map(|t| t.0 = Instant::now()); .map(|t| t.0 = Instant::now());
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn update_supported_encoding(&mut self) { fn update_supported_encoding(&mut self) {
let not_use = Some(scrap::gpucodec::GpuEncoder::not_use()); let not_use = Some(scrap::vram::VRamEncoder::not_use());
if !self.authorized if !self.authorized
|| self.supported_encoding_flag.0 && self.supported_encoding_flag.1 == not_use || self.supported_encoding_flag.0 && self.supported_encoding_flag.1 == not_use
{ {

View File

@ -8,7 +8,7 @@ use hbb_common::{
tokio::{self, sync::mpsc}, tokio::{self, sync::mpsc},
ResultType, ResultType,
}; };
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
use scrap::AdapterDevice; use scrap::AdapterDevice;
use scrap::{Capturer, Frame, TraitCapturer, TraitPixelBuffer}; use scrap::{Capturer, Frame, TraitCapturer, TraitPixelBuffer};
use shared_memory::*; use shared_memory::*;
@ -744,12 +744,12 @@ pub mod client {
true true
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn device(&self) -> AdapterDevice { fn device(&self) -> AdapterDevice {
AdapterDevice::default() AdapterDevice::default()
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
fn set_output_texture(&mut self, _texture: bool) {} fn set_output_texture(&mut self, _texture: bool) {}
} }

View File

@ -42,10 +42,10 @@ use hbb_common::{
Mutex as TokioMutex, Mutex as TokioMutex,
}, },
}; };
#[cfg(feature = "gpucodec")]
use scrap::gpucodec::{GpuEncoder, GpuEncoderConfig};
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
use scrap::hwcodec::{HwEncoder, HwEncoderConfig}; use scrap::hwcodec::{HwRamEncoder, HwRamEncoderConfig};
#[cfg(feature = "vram")]
use scrap::vram::{VRamEncoder, VRamEncoderConfig};
#[cfg(not(windows))] #[cfg(not(windows))]
use scrap::Capturer; use scrap::Capturer;
use scrap::{ use scrap::{
@ -430,7 +430,7 @@ fn run(vs: VideoService) -> ResultType<()> {
Ok(x) => encoder = x, Ok(x) => encoder = x,
Err(err) => bail!("Failed to create encoder: {}", err), Err(err) => bail!("Failed to create encoder: {}", err),
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
c.set_output_texture(encoder.input_texture()); c.set_output_texture(encoder.input_texture());
VIDEO_QOS.lock().unwrap().store_bitrate(encoder.bitrate()); VIDEO_QOS.lock().unwrap().store_bitrate(encoder.bitrate());
VIDEO_QOS VIDEO_QOS
@ -490,9 +490,9 @@ fn run(vs: VideoService) -> ResultType<()> {
if Encoder::use_i444(&encoder_cfg) != use_i444 { if Encoder::use_i444(&encoder_cfg) != use_i444 {
bail!("SWITCH"); bail!("SWITCH");
} }
#[cfg(all(windows, feature = "gpucodec"))] #[cfg(all(windows, feature = "vram"))]
if c.is_gdi() && (codec_name == CodecName::H264GPU || codec_name == CodecName::H265GPU) { if c.is_gdi() && (codec_name == CodecName::H264VRAM || codec_name == CodecName::H265VRAM) {
log::info!("changed to gdi when using gpucodec"); log::info!("changed to gdi when using vram");
bail!("SWITCH"); bail!("SWITCH");
} }
check_privacy_mode_changed(&sp, c.privacy_mode_id)?; check_privacy_mode_changed(&sp, c.privacy_mode_id)?;
@ -624,8 +624,8 @@ impl Raii {
impl Drop for Raii { impl Drop for Raii {
fn drop(&mut self) { fn drop(&mut self) {
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
GpuEncoder::set_not_use(self.0, false); VRamEncoder::set_not_use(self.0, false);
VIDEO_QOS.lock().unwrap().set_support_abr(self.0, true); VIDEO_QOS.lock().unwrap().set_support_abr(self.0, true);
} }
} }
@ -637,21 +637,21 @@ fn get_encoder_config(
record: bool, record: bool,
_portable_service: bool, _portable_service: bool,
) -> EncoderCfg { ) -> EncoderCfg {
#[cfg(all(windows, feature = "gpucodec"))] #[cfg(all(windows, feature = "vram"))]
if _portable_service || c.is_gdi() { if _portable_service || c.is_gdi() {
log::info!("gdi:{}, portable:{}", c.is_gdi(), _portable_service); log::info!("gdi:{}, portable:{}", c.is_gdi(), _portable_service);
GpuEncoder::set_not_use(_display_idx, true); VRamEncoder::set_not_use(_display_idx, true);
} }
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
Encoder::update(scrap::codec::EncodingUpdate::Check); Encoder::update(scrap::codec::EncodingUpdate::Check);
// https://www.wowza.com/community/t/the-correct-keyframe-interval-in-obs-studio/95162 // https://www.wowza.com/community/t/the-correct-keyframe-interval-in-obs-studio/95162
let keyframe_interval = if record { Some(240) } else { None }; let keyframe_interval = if record { Some(240) } else { None };
let negotiated_codec = Encoder::negotiated_codec(); let negotiated_codec = Encoder::negotiated_codec();
match negotiated_codec.clone() { match negotiated_codec.clone() {
CodecName::H264GPU | CodecName::H265GPU => { CodecName::H264VRAM | CodecName::H265VRAM => {
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
if let Some(feature) = GpuEncoder::try_get(&c.device(), negotiated_codec.clone()) { if let Some(feature) = VRamEncoder::try_get(&c.device(), negotiated_codec.clone()) {
EncoderCfg::GPU(GpuEncoderConfig { EncoderCfg::VRAM(VRamEncoderConfig {
device: c.device(), device: c.device(),
width: c.width, width: c.width,
height: c.height, height: c.height,
@ -668,7 +668,7 @@ fn get_encoder_config(
keyframe_interval, keyframe_interval,
) )
} }
#[cfg(not(feature = "gpucodec"))] #[cfg(not(feature = "vram"))]
handle_hw_encoder( handle_hw_encoder(
negotiated_codec.clone(), negotiated_codec.clone(),
c.width, c.width,
@ -677,7 +677,7 @@ fn get_encoder_config(
keyframe_interval, keyframe_interval,
) )
} }
CodecName::H264HW(_name) | CodecName::H265HW(_name) => handle_hw_encoder( CodecName::H264RAM(_name) | CodecName::H265RAM(_name) => handle_hw_encoder(
negotiated_codec.clone(), negotiated_codec.clone(),
c.width, c.width,
c.height, c.height,
@ -714,15 +714,15 @@ fn handle_hw_encoder(
let f = || { let f = || {
#[cfg(feature = "hwcodec")] #[cfg(feature = "hwcodec")]
match _name { match _name {
CodecName::H264GPU | CodecName::H265GPU => { CodecName::H264VRAM | CodecName::H265VRAM => {
if !scrap::codec::enable_hwcodec_option() { if !scrap::codec::enable_hwcodec_option() {
return Err(()); return Err(());
} }
let is_h265 = _name == CodecName::H265GPU; let is_h265 = _name == CodecName::H265VRAM;
let best = HwEncoder::best(); let best = HwRamEncoder::best();
if let Some(h264) = best.h264 { if let Some(h264) = best.h264 {
if !is_h265 { if !is_h265 {
return Ok(EncoderCfg::HW(HwEncoderConfig { return Ok(EncoderCfg::HWRAM(HwRamEncoderConfig {
name: h264.name, name: h264.name,
width, width,
height, height,
@ -733,7 +733,7 @@ fn handle_hw_encoder(
} }
if let Some(h265) = best.h265 { if let Some(h265) = best.h265 {
if is_h265 { if is_h265 {
return Ok(EncoderCfg::HW(HwEncoderConfig { return Ok(EncoderCfg::HWRAM(HwRamEncoderConfig {
name: h265.name, name: h265.name,
width, width,
height, height,
@ -743,8 +743,8 @@ fn handle_hw_encoder(
} }
} }
} }
CodecName::H264HW(name) | CodecName::H265HW(name) => { CodecName::H264RAM(name) | CodecName::H265RAM(name) => {
return Ok(EncoderCfg::HW(HwEncoderConfig { return Ok(EncoderCfg::HWRAM(HwRamEncoderConfig {
name, name,
width, width,
height, height,

View File

@ -576,8 +576,8 @@ impl UI {
has_hwcodec() has_hwcodec()
} }
fn has_gpucodec(&self) -> bool { fn has_vram(&self) -> bool {
has_gpucodec() has_vram()
} }
fn get_langs(&self) -> String { fn get_langs(&self) -> String {
@ -701,7 +701,7 @@ impl sciter::EventHandler for UI {
fn get_lan_peers(); fn get_lan_peers();
fn get_uuid(); fn get_uuid();
fn has_hwcodec(); fn has_hwcodec();
fn has_gpucodec(); fn has_vram();
fn get_langs(); fn get_langs();
fn default_video_save_directory(); fn default_video_save_directory();
fn handle_relay_id(String); fn handle_relay_id(String);

View File

@ -210,13 +210,13 @@ class Enhancements: Reactor.Component {
function render() { function render() {
var has_hwcodec = handler.has_hwcodec(); var has_hwcodec = handler.has_hwcodec();
var has_gpucodec = handler.has_gpucodec(); var has_vram = handler.has_vram();
var support_remove_wallpaper = handler.support_remove_wallpaper(); var support_remove_wallpaper = handler.support_remove_wallpaper();
var me = this; var me = this;
self.timer(1ms, function() { me.toggleMenuState() }); self.timer(1ms, function() { me.toggleMenuState() });
return <li>{translate('Enhancements')} return <li>{translate('Enhancements')}
<menu #enhancements-menu> <menu #enhancements-menu>
{(has_hwcodec || has_gpucodec) ? <li #enable-hwcodec><span>{svg_checkmark}</span>{translate("Enable hardware codec")}</li> : ""} {(has_hwcodec || has_vram) ? <li #enable-hwcodec><span>{svg_checkmark}</span>{translate("Enable hardware codec")}</li> : ""}
<li #enable-abr><span>{svg_checkmark}</span>{translate("Adaptive bitrate")} (beta)</li> <li #enable-abr><span>{svg_checkmark}</span>{translate("Adaptive bitrate")} (beta)</li>
<li #screen-recording>{translate("Recording")}</li> <li #screen-recording>{translate("Recording")}</li>
{support_remove_wallpaper ? <li #allow-remove-wallpaper><span>{svg_checkmark}</span>{translate("Remove wallpaper during incoming sessions")}</li> : ""} {support_remove_wallpaper ? <li #allow-remove-wallpaper><span>{svg_checkmark}</span>{translate("Remove wallpaper during incoming sessions")}</li> : ""}

View File

@ -836,8 +836,8 @@ pub fn has_hwcodec() -> bool {
} }
#[inline] #[inline]
pub fn has_gpucodec() -> bool { pub fn has_vram() -> bool {
cfg!(feature = "gpucodec") cfg!(feature = "vram")
} }
#[cfg(feature = "flutter")] #[cfg(feature = "flutter")]
@ -846,14 +846,14 @@ pub fn supported_hwdecodings() -> (bool, bool) {
let decoding = scrap::codec::Decoder::supported_decodings(None, true, None, &vec![]); let decoding = scrap::codec::Decoder::supported_decodings(None, true, None, &vec![]);
#[allow(unused_mut)] #[allow(unused_mut)]
let (mut h264, mut h265) = (decoding.ability_h264 > 0, decoding.ability_h265 > 0); let (mut h264, mut h265) = (decoding.ability_h264 > 0, decoding.ability_h265 > 0);
#[cfg(feature = "gpucodec")] #[cfg(feature = "vram")]
{ {
// supported_decodings check runtime luid // supported_decodings check runtime luid
let gpu = scrap::gpucodec::GpuDecoder::possible_available_without_check(); let vram = scrap::vram::VRamDecoder::possible_available_without_check();
if gpu.0 { if vram.0 {
h264 = true; h264 = true;
} }
if gpu.1 { if vram.1 {
h265 = true; h265 = true;
} }
} }

View File

@ -1350,7 +1350,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn on_voice_call_incoming(&self); fn on_voice_call_incoming(&self);
fn get_rgba(&self, display: usize) -> *const u8; fn get_rgba(&self, display: usize) -> *const u8;
fn next_rgba(&self, display: usize); fn next_rgba(&self, display: usize);
#[cfg(all(feature = "gpucodec", feature = "flutter"))] #[cfg(all(feature = "vram", feature = "flutter"))]
fn on_texture(&self, display: usize, texture: *mut c_void); fn on_texture(&self, display: usize, texture: *mut c_void);
fn set_multiple_windows_session(&self, sessions: Vec<WindowsSession>); fn set_multiple_windows_session(&self, sessions: Vec<WindowsSession>);
} }
@ -1663,7 +1663,7 @@ pub async fn io_loop<T: InvokeUiSession>(handler: Session<T>, round: u32) {
if pixelbuffer { if pixelbuffer {
ui_handler.on_rgba(display, data); ui_handler.on_rgba(display, data);
} else { } else {
#[cfg(all(feature = "gpucodec", feature = "flutter"))] #[cfg(all(feature = "vram", feature = "flutter"))]
ui_handler.on_texture(display, _texture); ui_handler.on_texture(display, _texture);
} }
}, },