2024-01-02 16:58:10 +08:00
|
|
|
use std::{
|
2024-06-06 22:52:31 +08:00
|
|
|
collections::{HashMap, HashSet},
|
2024-01-02 16:58:10 +08:00
|
|
|
ffi::c_void,
|
|
|
|
sync::{Arc, Mutex},
|
|
|
|
};
|
|
|
|
|
|
|
|
use crate::{
|
2024-04-12 17:26:24 +08:00
|
|
|
codec::{base_bitrate, enable_vram_option, EncoderApi, EncoderCfg, Quality},
|
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.
when start check process: ipc server process start or option changed
from disable to enable
when get config: main window start or option changed from disable to
enable, start_video_audio_threads.
Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.
Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-12 20:40:35 +08:00
|
|
|
hwcodec::HwCodecConfig,
|
2024-05-08 20:31:39 +08:00
|
|
|
AdapterDevice, CodecFormat, EncodeInput, EncodeYuvFormat, Pixfmt,
|
2024-01-02 16:58:10 +08:00
|
|
|
};
|
|
|
|
use hbb_common::{
|
|
|
|
anyhow::{anyhow, bail, Context},
|
|
|
|
bytes::Bytes,
|
|
|
|
log,
|
|
|
|
message_proto::{EncodedVideoFrame, EncodedVideoFrames, VideoFrame},
|
|
|
|
ResultType,
|
|
|
|
};
|
2024-04-12 17:26:24 +08:00
|
|
|
use hwcodec::{
|
2024-05-06 10:59:25 +08:00
|
|
|
common::{AdapterVendor::*, DataFormat, Driver, MAX_GOP},
|
2024-04-25 20:16:48 +08:00
|
|
|
vram::{
|
2024-04-12 17:26:24 +08:00
|
|
|
decode::{self, DecodeFrame, Decoder},
|
|
|
|
encode::{self, EncodeFrame, Encoder},
|
|
|
|
Available, DecodeContext, DynamicContext, EncodeContext, FeatureContext,
|
|
|
|
},
|
|
|
|
};
|
2024-01-02 16:58:10 +08:00
|
|
|
|
|
|
|
// https://www.reddit.com/r/buildapc/comments/d2m4ny/two_graphics_cards_two_monitors/
|
|
|
|
// https://www.reddit.com/r/techsupport/comments/t2v9u6/dual_monitor_setup_with_dual_gpu/
|
|
|
|
// https://cybersided.com/two-monitors-two-gpus/
|
|
|
|
// https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-getadapterluid#remarks
|
|
|
|
lazy_static::lazy_static! {
|
|
|
|
static ref ENOCDE_NOT_USE: Arc<Mutex<HashMap<usize, bool>>> = Default::default();
|
2024-06-06 22:52:31 +08:00
|
|
|
static ref FALLBACK_GDI_DISPLAYS: Arc<Mutex<HashSet<usize>>> = Default::default();
|
2024-01-02 16:58:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
2024-04-12 17:26:24 +08:00
|
|
|
pub struct VRamEncoderConfig {
|
2024-01-02 16:58:10 +08:00
|
|
|
pub device: AdapterDevice,
|
|
|
|
pub width: usize,
|
|
|
|
pub height: usize,
|
|
|
|
pub quality: Quality,
|
2024-04-12 17:26:24 +08:00
|
|
|
pub feature: FeatureContext,
|
2024-01-02 16:58:10 +08:00
|
|
|
pub keyframe_interval: Option<usize>,
|
|
|
|
}
|
|
|
|
|
2024-04-12 17:26:24 +08:00
|
|
|
pub struct VRamEncoder {
|
2024-01-02 16:58:10 +08:00
|
|
|
encoder: Encoder,
|
2024-04-12 17:26:24 +08:00
|
|
|
pub format: DataFormat,
|
2024-01-02 16:58:10 +08:00
|
|
|
ctx: EncodeContext,
|
|
|
|
bitrate: u32,
|
|
|
|
last_frame_len: usize,
|
|
|
|
same_bad_len_counter: usize,
|
2024-05-06 10:59:25 +08:00
|
|
|
config: VRamEncoderConfig,
|
2024-01-02 16:58:10 +08:00
|
|
|
}
|
|
|
|
|
2024-04-12 17:26:24 +08:00
|
|
|
impl EncoderApi for VRamEncoder {
|
2024-01-02 16:58:10 +08:00
|
|
|
fn new(cfg: EncoderCfg, _i444: bool) -> ResultType<Self>
|
|
|
|
where
|
|
|
|
Self: Sized,
|
|
|
|
{
|
|
|
|
match cfg {
|
2024-04-12 17:26:24 +08:00
|
|
|
EncoderCfg::VRAM(config) => {
|
2024-01-02 16:58:10 +08:00
|
|
|
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;
|
|
|
|
if base_bitrate <= 0 {
|
|
|
|
bitrate = base_bitrate;
|
|
|
|
}
|
|
|
|
let gop = config.keyframe_interval.unwrap_or(MAX_GOP as _) as i32;
|
|
|
|
let ctx = EncodeContext {
|
|
|
|
f: config.feature.clone(),
|
|
|
|
d: DynamicContext {
|
|
|
|
device: Some(config.device.device),
|
|
|
|
width: config.width as _,
|
|
|
|
height: config.height as _,
|
|
|
|
kbitrate: bitrate as _,
|
|
|
|
framerate: 30,
|
|
|
|
gop,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
match Encoder::new(ctx.clone()) {
|
2024-04-12 17:26:24 +08:00
|
|
|
Ok(encoder) => Ok(VRamEncoder {
|
2024-01-02 16:58:10 +08:00
|
|
|
encoder,
|
|
|
|
ctx,
|
|
|
|
format: config.feature.data_format,
|
|
|
|
bitrate,
|
|
|
|
last_frame_len: 0,
|
|
|
|
same_bad_len_counter: 0,
|
2024-05-06 10:59:25 +08:00
|
|
|
config,
|
2024-01-02 16:58:10 +08:00
|
|
|
}),
|
2024-05-09 09:02:25 +08:00
|
|
|
Err(_) => Err(anyhow!(format!("Failed to create encoder"))),
|
2024-01-02 16:58:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => Err(anyhow!("encoder type mismatch")),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn encode_to_message(
|
|
|
|
&mut self,
|
|
|
|
frame: EncodeInput,
|
|
|
|
_ms: i64,
|
|
|
|
) -> ResultType<hbb_common::message_proto::VideoFrame> {
|
|
|
|
let texture = frame.texture()?;
|
|
|
|
let mut vf = VideoFrame::new();
|
|
|
|
let mut frames = Vec::new();
|
|
|
|
for frame in self.encode(texture).with_context(|| "Failed to encode")? {
|
|
|
|
frames.push(EncodedVideoFrame {
|
|
|
|
data: Bytes::from(frame.data),
|
|
|
|
pts: frame.pts as _,
|
|
|
|
key: frame.key == 1,
|
|
|
|
..Default::default()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if frames.len() > 0 {
|
|
|
|
// This kind of problem is occurred after a period of time when using AMD encoding,
|
|
|
|
// the encoding length is fixed at about 40, and the picture is still
|
|
|
|
const MIN_BAD_LEN: usize = 100;
|
|
|
|
const MAX_BAD_COUNTER: usize = 30;
|
|
|
|
let this_frame_len = frames[0].data.len();
|
|
|
|
if this_frame_len < MIN_BAD_LEN && this_frame_len == self.last_frame_len {
|
|
|
|
self.same_bad_len_counter += 1;
|
|
|
|
if self.same_bad_len_counter >= MAX_BAD_COUNTER {
|
|
|
|
log::info!(
|
|
|
|
"{} times encoding len is {}, switch",
|
|
|
|
self.same_bad_len_counter,
|
|
|
|
self.last_frame_len
|
|
|
|
);
|
|
|
|
bail!(crate::codec::ENCODE_NEED_SWITCH);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.same_bad_len_counter = 0;
|
|
|
|
}
|
|
|
|
self.last_frame_len = this_frame_len;
|
|
|
|
let frames = EncodedVideoFrames {
|
|
|
|
frames: frames.into(),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
match self.format {
|
2024-04-12 17:26:24 +08:00
|
|
|
DataFormat::H264 => vf.set_h264s(frames),
|
|
|
|
DataFormat::H265 => vf.set_h265s(frames),
|
2024-01-02 16:58:10 +08:00
|
|
|
_ => bail!("{:?} not supported", self.format),
|
|
|
|
}
|
|
|
|
Ok(vf)
|
|
|
|
} else {
|
|
|
|
Err(anyhow!("no valid frame"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn yuvfmt(&self) -> EncodeYuvFormat {
|
|
|
|
// useless
|
|
|
|
EncodeYuvFormat {
|
|
|
|
pixfmt: Pixfmt::BGRA,
|
|
|
|
w: self.ctx.d.width as _,
|
|
|
|
h: self.ctx.d.height as _,
|
|
|
|
stride: Vec::new(),
|
|
|
|
u: 0,
|
|
|
|
v: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-12 17:26:24 +08:00
|
|
|
#[cfg(feature = "vram")]
|
2024-01-02 16:58:10 +08:00
|
|
|
fn input_texture(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_quality(&mut self, quality: Quality) -> ResultType<()> {
|
|
|
|
let b = Self::convert_quality(quality, &self.ctx.f);
|
|
|
|
let bitrate = base_bitrate(self.ctx.d.width as _, self.ctx.d.height as _) * b / 100;
|
|
|
|
if bitrate > 0 {
|
|
|
|
if self.encoder.set_bitrate((bitrate) as _).is_ok() {
|
|
|
|
self.bitrate = bitrate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bitrate(&self) -> u32 {
|
|
|
|
self.bitrate
|
|
|
|
}
|
|
|
|
|
|
|
|
fn support_abr(&self) -> bool {
|
2024-05-06 10:59:25 +08:00
|
|
|
self.config.device.vendor_id != ADAPTER_VENDOR_INTEL as u32
|
2024-01-02 16:58:10 +08:00
|
|
|
}
|
2024-05-13 12:39:04 +08:00
|
|
|
|
|
|
|
fn support_changing_quality(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn latency_free(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
2024-05-28 12:43:13 +08:00
|
|
|
|
|
|
|
fn is_hardware(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
2024-06-12 23:37:51 +08:00
|
|
|
|
|
|
|
fn disable(&self) {
|
|
|
|
HwCodecConfig::clear(true, true);
|
|
|
|
}
|
2024-01-02 16:58:10 +08:00
|
|
|
}
|
|
|
|
|
2024-04-12 17:26:24 +08:00
|
|
|
impl VRamEncoder {
|
2024-05-07 20:34:23 +08:00
|
|
|
pub fn try_get(device: &AdapterDevice, format: CodecFormat) -> Option<FeatureContext> {
|
|
|
|
let v: Vec<_> = Self::available(format)
|
2024-01-02 16:58:10 +08:00
|
|
|
.drain(..)
|
|
|
|
.filter(|e| e.luid == device.luid)
|
|
|
|
.collect();
|
|
|
|
if v.len() > 0 {
|
2024-05-01 00:07:09 +08:00
|
|
|
// prefer ffmpeg
|
|
|
|
if let Some(ctx) = v.iter().find(|c| c.driver == Driver::FFMPEG) {
|
|
|
|
return Some(ctx.clone());
|
|
|
|
}
|
2024-01-02 16:58:10 +08:00
|
|
|
Some(v[0].clone())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-07 20:34:23 +08:00
|
|
|
pub fn available(format: CodecFormat) -> Vec<FeatureContext> {
|
2024-06-06 22:52:31 +08:00
|
|
|
let fallbacks = FALLBACK_GDI_DISPLAYS.lock().unwrap().clone();
|
|
|
|
if !fallbacks.is_empty() {
|
|
|
|
log::info!("fallback gdi displays not empty: {fallbacks:?}");
|
|
|
|
return vec![];
|
|
|
|
}
|
2024-01-02 16:58:10 +08:00
|
|
|
let not_use = ENOCDE_NOT_USE.lock().unwrap().clone();
|
|
|
|
if not_use.values().any(|not_use| *not_use) {
|
2024-04-12 17:26:24 +08:00
|
|
|
log::info!("currently not use vram encoders: {not_use:?}");
|
2024-01-02 16:58:10 +08:00
|
|
|
return vec![];
|
|
|
|
}
|
2024-05-07 20:34:23 +08:00
|
|
|
let data_format = match format {
|
|
|
|
CodecFormat::H264 => DataFormat::H264,
|
|
|
|
CodecFormat::H265 => DataFormat::H265,
|
2024-01-02 16:58:10 +08:00
|
|
|
_ => return vec![],
|
|
|
|
};
|
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.
when start check process: ipc server process start or option changed
from disable to enable
when get config: main window start or option changed from disable to
enable, start_video_audio_threads.
Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.
Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-12 20:40:35 +08:00
|
|
|
let v: Vec<_> = crate::hwcodec::HwCodecConfig::get()
|
|
|
|
.vram_encode
|
2024-01-02 16:58:10 +08:00
|
|
|
.drain(..)
|
|
|
|
.filter(|c| c.data_format == data_format)
|
|
|
|
.collect();
|
2024-05-09 09:02:25 +08:00
|
|
|
if crate::hwcodec::HwRamEncoder::try_get(format).is_some() {
|
|
|
|
// has fallback, no need to require all adapters support
|
2024-01-02 16:58:10 +08:00
|
|
|
v
|
|
|
|
} else {
|
2024-05-09 09:02:25 +08:00
|
|
|
let Ok(displays) = crate::Display::all() else {
|
|
|
|
log::error!("failed to get displays");
|
|
|
|
return vec![];
|
|
|
|
};
|
|
|
|
if displays.is_empty() {
|
|
|
|
log::error!("no display found");
|
|
|
|
return vec![];
|
|
|
|
}
|
|
|
|
let luids = displays
|
|
|
|
.iter()
|
|
|
|
.map(|d| d.adapter_luid())
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
if luids
|
|
|
|
.iter()
|
|
|
|
.all(|luid| v.iter().any(|f| Some(f.luid) == *luid))
|
|
|
|
{
|
|
|
|
v
|
|
|
|
} else {
|
|
|
|
log::info!("not all adapters support {data_format:?}, luids = {luids:?}");
|
|
|
|
vec![]
|
|
|
|
}
|
2024-01-02 16:58:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn encode(&mut self, texture: *mut c_void) -> ResultType<Vec<EncodeFrame>> {
|
|
|
|
match self.encoder.encode(texture) {
|
|
|
|
Ok(v) => {
|
|
|
|
let mut data = Vec::<EncodeFrame>::new();
|
|
|
|
data.append(v);
|
|
|
|
Ok(data)
|
|
|
|
}
|
|
|
|
Err(_) => Ok(Vec::<EncodeFrame>::new()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn convert_quality(quality: Quality, f: &FeatureContext) -> u32 {
|
|
|
|
match quality {
|
|
|
|
Quality::Best => {
|
2024-05-01 00:07:09 +08:00
|
|
|
if f.driver == Driver::MFX && f.data_format == DataFormat::H264 {
|
2024-01-02 16:58:10 +08:00
|
|
|
200
|
|
|
|
} else {
|
|
|
|
150
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Quality::Balanced => {
|
2024-05-01 00:07:09 +08:00
|
|
|
if f.driver == Driver::MFX && f.data_format == DataFormat::H264 {
|
2024-01-02 16:58:10 +08:00
|
|
|
150
|
|
|
|
} else {
|
|
|
|
100
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Quality::Low => {
|
2024-05-01 00:07:09 +08:00
|
|
|
if f.driver == Driver::MFX && f.data_format == DataFormat::H264 {
|
2024-01-02 16:58:10 +08:00
|
|
|
75
|
|
|
|
} else {
|
|
|
|
50
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Quality::Custom(b) => b,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_not_use(display: usize, not_use: bool) {
|
2024-04-12 17:26:24 +08:00
|
|
|
log::info!("set display#{display} not use vram encode to {not_use}");
|
2024-01-02 16:58:10 +08:00
|
|
|
ENOCDE_NOT_USE.lock().unwrap().insert(display, not_use);
|
|
|
|
}
|
2024-06-06 22:52:31 +08:00
|
|
|
|
|
|
|
pub fn set_fallback_gdi(display: usize, fallback: bool) {
|
|
|
|
if fallback {
|
|
|
|
FALLBACK_GDI_DISPLAYS.lock().unwrap().insert(display);
|
|
|
|
} else {
|
|
|
|
FALLBACK_GDI_DISPLAYS.lock().unwrap().remove(&display);
|
|
|
|
}
|
|
|
|
}
|
2024-01-02 16:58:10 +08:00
|
|
|
}
|
|
|
|
|
2024-04-12 17:26:24 +08:00
|
|
|
pub struct VRamDecoder {
|
2024-01-02 16:58:10 +08:00
|
|
|
decoder: Decoder,
|
|
|
|
}
|
|
|
|
|
2024-04-12 17:26:24 +08:00
|
|
|
impl VRamDecoder {
|
2024-01-22 20:01:17 +08:00
|
|
|
pub fn try_get(format: CodecFormat, luid: Option<i64>) -> Option<DecodeContext> {
|
|
|
|
let v: Vec<_> = Self::available(format, luid);
|
2024-01-02 16:58:10 +08:00
|
|
|
if v.len() > 0 {
|
2024-04-25 20:16:48 +08:00
|
|
|
// prefer ffmpeg
|
|
|
|
if let Some(ctx) = v.iter().find(|c| c.driver == Driver::FFMPEG) {
|
|
|
|
return Some(ctx.clone());
|
|
|
|
}
|
2024-01-02 16:58:10 +08:00
|
|
|
Some(v[0].clone())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-22 20:01:17 +08:00
|
|
|
pub fn available(format: CodecFormat, luid: Option<i64>) -> Vec<DecodeContext> {
|
2024-01-02 16:58:10 +08:00
|
|
|
let luid = luid.unwrap_or_default();
|
2024-01-22 20:01:17 +08:00
|
|
|
let data_format = match format {
|
2024-04-12 17:26:24 +08:00
|
|
|
CodecFormat::H264 => DataFormat::H264,
|
|
|
|
CodecFormat::H265 => DataFormat::H265,
|
2024-01-02 16:58:10 +08:00
|
|
|
_ => return vec![],
|
|
|
|
};
|
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.
when start check process: ipc server process start or option changed
from disable to enable
when get config: main window start or option changed from disable to
enable, start_video_audio_threads.
Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.
Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-12 20:40:35 +08:00
|
|
|
crate::hwcodec::HwCodecConfig::get()
|
|
|
|
.vram_decode
|
2024-01-02 16:58:10 +08:00
|
|
|
.drain(..)
|
2024-02-09 16:53:15 +08:00
|
|
|
.filter(|c| c.data_format == data_format && c.luid == luid && luid != 0)
|
2024-01-02 16:58:10 +08:00
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn possible_available_without_check() -> (bool, bool) {
|
2024-04-12 17:26:24 +08:00
|
|
|
if !enable_vram_option() {
|
2024-01-02 16:58:10 +08:00
|
|
|
return (false, false);
|
|
|
|
}
|
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.
when start check process: ipc server process start or option changed
from disable to enable
when get config: main window start or option changed from disable to
enable, start_video_audio_threads.
Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.
Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-12 20:40:35 +08:00
|
|
|
let v = crate::hwcodec::HwCodecConfig::get().vram_decode;
|
2024-01-02 16:58:10 +08:00
|
|
|
(
|
2024-04-12 17:26:24 +08:00
|
|
|
v.iter().any(|d| d.data_format == DataFormat::H264),
|
|
|
|
v.iter().any(|d| d.data_format == DataFormat::H265),
|
2024-01-02 16:58:10 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-01-22 20:01:17 +08:00
|
|
|
pub fn new(format: CodecFormat, luid: Option<i64>) -> ResultType<Self> {
|
|
|
|
let ctx = Self::try_get(format, luid).ok_or(anyhow!("Failed to get decode context"))?;
|
2024-04-26 19:42:47 +08:00
|
|
|
log::info!("try create vram decoder: {ctx:?}");
|
2024-01-02 16:58:10 +08:00
|
|
|
match Decoder::new(ctx) {
|
|
|
|
Ok(decoder) => Ok(Self { decoder }),
|
2024-01-22 20:01:17 +08:00
|
|
|
Err(_) => {
|
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.
when start check process: ipc server process start or option changed
from disable to enable
when get config: main window start or option changed from disable to
enable, start_video_audio_threads.
Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.
Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-12 20:40:35 +08:00
|
|
|
HwCodecConfig::clear(true, false);
|
2024-01-22 20:01:17 +08:00
|
|
|
Err(anyhow!(format!(
|
|
|
|
"Failed to create decoder, format: {:?}",
|
|
|
|
format
|
|
|
|
)))
|
|
|
|
}
|
2024-01-02 16:58:10 +08:00
|
|
|
}
|
|
|
|
}
|
2024-04-12 17:26:24 +08:00
|
|
|
pub fn decode(&mut self, data: &[u8]) -> ResultType<Vec<VRamDecoderImage>> {
|
2024-01-02 16:58:10 +08:00
|
|
|
match self.decoder.decode(data) {
|
2024-04-12 17:26:24 +08:00
|
|
|
Ok(v) => Ok(v.iter().map(|f| VRamDecoderImage { frame: f }).collect()),
|
2024-01-02 16:58:10 +08:00
|
|
|
Err(e) => Err(anyhow!(e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-12 17:26:24 +08:00
|
|
|
pub struct VRamDecoderImage<'a> {
|
2024-01-02 16:58:10 +08:00
|
|
|
pub frame: &'a DecodeFrame,
|
|
|
|
}
|
|
|
|
|
2024-04-12 17:26:24 +08:00
|
|
|
impl VRamDecoderImage<'_> {}
|
2024-01-02 16:58:10 +08:00
|
|
|
|
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.
when start check process: ipc server process start or option changed
from disable to enable
when get config: main window start or option changed from disable to
enable, start_video_audio_threads.
Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.
Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-12 20:40:35 +08:00
|
|
|
pub(crate) fn check_available_vram() -> (Vec<FeatureContext>, Vec<DecodeContext>, String) {
|
2024-01-02 16:58:10 +08:00
|
|
|
let d = DynamicContext {
|
|
|
|
device: None,
|
2024-04-12 17:26:24 +08:00
|
|
|
width: 1280,
|
|
|
|
height: 720,
|
2024-01-02 16:58:10 +08:00
|
|
|
kbitrate: 5000,
|
|
|
|
framerate: 60,
|
|
|
|
gop: MAX_GOP as _,
|
|
|
|
};
|
|
|
|
let encoders = encode::available(d);
|
2024-04-26 19:42:47 +08:00
|
|
|
let decoders = decode::available();
|
2024-01-02 16:58:10 +08:00
|
|
|
let available = Available {
|
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.
when start check process: ipc server process start or option changed
from disable to enable
when get config: main window start or option changed from disable to
enable, start_video_audio_threads.
Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.
Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-12 20:40:35 +08:00
|
|
|
e: encoders.clone(),
|
|
|
|
d: decoders.clone(),
|
2024-01-02 16:58:10 +08:00
|
|
|
};
|
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.
when start check process: ipc server process start or option changed
from disable to enable
when get config: main window start or option changed from disable to
enable, start_video_audio_threads.
Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.
Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-12 20:40:35 +08:00
|
|
|
(
|
|
|
|
encoders,
|
|
|
|
decoders,
|
|
|
|
available.serialize().unwrap_or_default(),
|
|
|
|
)
|
2024-01-02 16:58:10 +08:00
|
|
|
}
|