update hwcodec, add windows ffmpeg vram encoding (#7876)
* windows add ffmpeg vram encoding * windows add missing nvenc and qsv ram encoding, linux add vaapi, current codec table: https://github.com/21pages/hwcodec?tab=readme-ov-file#codec Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
parent
f74374e759
commit
34c7c25908
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -3038,8 +3038,8 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hwcodec"
|
||||
version = "0.4.3"
|
||||
source = "git+https://github.com/21pages/hwcodec#db7c2d4afcb4947bfb452213ef7e9ba647578b43"
|
||||
version = "0.4.5"
|
||||
source = "git+https://github.com/21pages/hwcodec#dd8fedeee4d33c8f5a8ffd3357c652329a9bfd34"
|
||||
dependencies = [
|
||||
"bindgen 0.59.2",
|
||||
"cc",
|
||||
|
@ -248,13 +248,12 @@ mod hw {
|
||||
use super::*;
|
||||
|
||||
pub fn test(c: &mut Capturer, width: usize, height: usize, quality: Q, yuv_count: usize) {
|
||||
let best = HwRamEncoder::best();
|
||||
let mut h264s = Vec::new();
|
||||
let mut h265s = Vec::new();
|
||||
if let Some(info) = best.h264 {
|
||||
if let Some(info) = HwRamEncoder::try_get(CodecFormat::H264) {
|
||||
test_encoder(width, height, quality, info, c, yuv_count, &mut h264s);
|
||||
}
|
||||
if let Some(info) = best.h265 {
|
||||
if let Some(info) = HwRamEncoder::try_get(CodecFormat::H265) {
|
||||
test_encoder(width, height, quality, info, c, yuv_count, &mut h265s);
|
||||
}
|
||||
test_decoder(CodecFormat::H264, &h264s);
|
||||
|
@ -208,12 +208,13 @@ impl Encoder {
|
||||
let mut h265hw_encoding = None;
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if enable_hwcodec_option() {
|
||||
let best = HwRamEncoder::best();
|
||||
if _all_support_h264_decoding {
|
||||
h264hw_encoding = best.h264.map_or(None, |c| Some(c.name));
|
||||
h264hw_encoding =
|
||||
HwRamEncoder::try_get(CodecFormat::H264).map_or(None, |c| Some(c.name));
|
||||
}
|
||||
if _all_support_h265_decoding {
|
||||
h265hw_encoding = best.h265.map_or(None, |c| Some(c.name));
|
||||
h265hw_encoding =
|
||||
HwRamEncoder::try_get(CodecFormat::H265).map_or(None, |c| Some(c.name));
|
||||
}
|
||||
}
|
||||
let h264_useable =
|
||||
@ -317,9 +318,8 @@ impl Encoder {
|
||||
};
|
||||
#[cfg(feature = "hwcodec")]
|
||||
if enable_hwcodec_option() {
|
||||
let best = HwRamEncoder::best();
|
||||
encoding.h264 |= best.h264.is_some();
|
||||
encoding.h265 |= best.h265.is_some();
|
||||
encoding.h264 |= HwRamEncoder::try_get(CodecFormat::H264).is_some();
|
||||
encoding.h265 |= HwRamEncoder::try_get(CodecFormat::H265).is_some();
|
||||
}
|
||||
#[cfg(feature = "vram")]
|
||||
if enable_vram_option() {
|
||||
@ -410,9 +410,16 @@ impl Decoder {
|
||||
};
|
||||
#[cfg(feature = "hwcodec")]
|
||||
{
|
||||
let best = HwRamDecoder::best();
|
||||
decoding.ability_h264 |= if best.h264.is_some() { 1 } else { 0 };
|
||||
decoding.ability_h265 |= if best.h265.is_some() { 1 } else { 0 };
|
||||
decoding.ability_h264 |= if HwRamDecoder::try_get(CodecFormat::H264).is_some() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
decoding.ability_h265 |= if HwRamDecoder::try_get(CodecFormat::H265).is_some() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
#[cfg(feature = "vram")]
|
||||
if enable_vram_option() && _flutter {
|
||||
|
@ -19,7 +19,7 @@ use hwcodec::{
|
||||
ffmpeg_ram::{
|
||||
decode::{DecodeContext, DecodeFrame, Decoder},
|
||||
encode::{EncodeContext, EncodeFrame, Encoder},
|
||||
CodecInfo, CodecInfos,
|
||||
CodecInfo,
|
||||
Quality::{self, *},
|
||||
RateControl::{self, *},
|
||||
},
|
||||
@ -188,11 +188,25 @@ impl EncoderApi for HwRamEncoder {
|
||||
}
|
||||
|
||||
impl HwRamEncoder {
|
||||
pub fn best() -> CodecInfos {
|
||||
get_config().map(|c| c.e).unwrap_or(CodecInfos {
|
||||
h264: None,
|
||||
h265: None,
|
||||
})
|
||||
pub fn try_get(format: CodecFormat) -> Option<CodecInfo> {
|
||||
let mut info = None;
|
||||
if let Ok(hw) = get_config().map(|c| c.e) {
|
||||
let best = CodecInfo::prioritized(hw);
|
||||
match format {
|
||||
CodecFormat::H264 => {
|
||||
if let Some(v) = best.h264 {
|
||||
info = Some(v);
|
||||
}
|
||||
}
|
||||
CodecFormat::H265 => {
|
||||
if let Some(v) = best.h265 {
|
||||
info = Some(v);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
info
|
||||
}
|
||||
|
||||
pub fn encode(&mut self, yuv: &[u8]) -> ResultType<Vec<EncodeFrame>> {
|
||||
@ -223,15 +237,37 @@ pub struct HwRamDecoder {
|
||||
}
|
||||
|
||||
impl HwRamDecoder {
|
||||
pub fn best() -> CodecInfos {
|
||||
let mut info = CodecInfo::soft();
|
||||
pub fn try_get(format: CodecFormat) -> Option<CodecInfo> {
|
||||
let mut info = None;
|
||||
let soft = CodecInfo::soft();
|
||||
match format {
|
||||
CodecFormat::H264 => {
|
||||
if let Some(v) = soft.h264 {
|
||||
info = Some(v);
|
||||
}
|
||||
}
|
||||
CodecFormat::H265 => {
|
||||
if let Some(v) = soft.h265 {
|
||||
info = Some(v);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if enable_hwcodec_option() {
|
||||
if let Ok(hw) = get_config().map(|c| c.d) {
|
||||
if let Some(h264) = hw.h264 {
|
||||
info.h264 = Some(h264);
|
||||
}
|
||||
if let Some(h265) = hw.h265 {
|
||||
info.h265 = Some(h265);
|
||||
let best = CodecInfo::prioritized(hw);
|
||||
match format {
|
||||
CodecFormat::H264 => {
|
||||
if let Some(v) = best.h264 {
|
||||
info = Some(v);
|
||||
}
|
||||
}
|
||||
CodecFormat::H265 => {
|
||||
if let Some(v) = best.h265 {
|
||||
info = Some(v);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -239,24 +275,10 @@ impl HwRamDecoder {
|
||||
}
|
||||
|
||||
pub fn new(format: CodecFormat) -> ResultType<Self> {
|
||||
log::info!("try create {format:?} ram decoder");
|
||||
let best = HwRamDecoder::best();
|
||||
let info = match format {
|
||||
CodecFormat::H264 => {
|
||||
if let Some(info) = best.h264 {
|
||||
info
|
||||
} else {
|
||||
bail!("no h264 decoder, should not be here");
|
||||
}
|
||||
}
|
||||
CodecFormat::H265 => {
|
||||
if let Some(info) = best.h265 {
|
||||
info
|
||||
} else {
|
||||
bail!("no h265 decoder, should not be here");
|
||||
}
|
||||
}
|
||||
_ => bail!("unsupported format: {:?}", format),
|
||||
let info = HwRamDecoder::try_get(format);
|
||||
log::info!("try create {info:?} ram decoder");
|
||||
let Some(info) = info else {
|
||||
bail!("unsupported format: {:?}", format);
|
||||
};
|
||||
let ctx = DecodeContext {
|
||||
name: info.name.clone(),
|
||||
@ -339,8 +361,8 @@ impl HwRamDecoderImage<'_> {
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||
struct Available {
|
||||
e: CodecInfos,
|
||||
d: CodecInfos,
|
||||
e: Vec<CodecInfo>,
|
||||
d: Vec<CodecInfo>,
|
||||
}
|
||||
|
||||
fn get_config() -> ResultType<Available> {
|
||||
@ -368,11 +390,9 @@ pub fn check_available_hwcodec() {
|
||||
let vram = crate::vram::check_available_vram();
|
||||
#[cfg(not(feature = "vram"))]
|
||||
let vram = "".to_owned();
|
||||
let encoders = CodecInfo::prioritized(Encoder::available_encoders(ctx, Some(vram.clone())));
|
||||
let decoders = CodecInfo::prioritized(Decoder::available_decoders(Some(vram.clone())));
|
||||
let ram = Available {
|
||||
e: encoders,
|
||||
d: decoders,
|
||||
e: Encoder::available_encoders(ctx, Some(vram.clone())),
|
||||
d: Decoder::available_decoders(Some(vram.clone())),
|
||||
};
|
||||
if let Ok(ram) = serde_json::to_string_pretty(&ram) {
|
||||
HwCodecConfig { ram, vram }.store();
|
||||
|
@ -179,7 +179,7 @@ impl EncoderApi for VRamEncoder {
|
||||
}
|
||||
|
||||
fn support_abr(&self) -> bool {
|
||||
self.ctx.f.driver != Driver::VPL
|
||||
self.ctx.f.driver != Driver::MFX
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,6 +190,10 @@ impl VRamEncoder {
|
||||
.filter(|e| e.luid == device.luid)
|
||||
.collect();
|
||||
if v.len() > 0 {
|
||||
// prefer ffmpeg
|
||||
if let Some(ctx) = v.iter().find(|c| c.driver == Driver::FFMPEG) {
|
||||
return Some(ctx.clone());
|
||||
}
|
||||
Some(v[0].clone())
|
||||
} else {
|
||||
None
|
||||
@ -250,21 +254,21 @@ impl VRamEncoder {
|
||||
pub fn convert_quality(quality: Quality, f: &FeatureContext) -> u32 {
|
||||
match quality {
|
||||
Quality::Best => {
|
||||
if f.driver == Driver::VPL && f.data_format == DataFormat::H264 {
|
||||
if f.driver == Driver::MFX && f.data_format == DataFormat::H264 {
|
||||
200
|
||||
} else {
|
||||
150
|
||||
}
|
||||
}
|
||||
Quality::Balanced => {
|
||||
if f.driver == Driver::VPL && f.data_format == DataFormat::H264 {
|
||||
if f.driver == Driver::MFX && f.data_format == DataFormat::H264 {
|
||||
150
|
||||
} else {
|
||||
100
|
||||
}
|
||||
}
|
||||
Quality::Low => {
|
||||
if f.driver == Driver::VPL && f.data_format == DataFormat::H264 {
|
||||
if f.driver == Driver::MFX && f.data_format == DataFormat::H264 {
|
||||
75
|
||||
} else {
|
||||
50
|
||||
|
@ -53,7 +53,7 @@ use scrap::{
|
||||
codec::{Encoder, EncoderCfg, Quality},
|
||||
record::{Recorder, RecorderContext},
|
||||
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
|
||||
CodecName, Display, Frame, TraitCapturer,
|
||||
CodecFormat, CodecName, Display, Frame, TraitCapturer,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use std::sync::Once;
|
||||
@ -715,29 +715,19 @@ fn handle_hw_encoder(
|
||||
#[cfg(feature = "hwcodec")]
|
||||
match _name {
|
||||
CodecName::H264VRAM | CodecName::H265VRAM => {
|
||||
let is_h265 = _name == CodecName::H265VRAM;
|
||||
let best = HwRamEncoder::best();
|
||||
if let Some(h264) = best.h264 {
|
||||
if !is_h265 {
|
||||
return Ok(EncoderCfg::HWRAM(HwRamEncoderConfig {
|
||||
name: h264.name,
|
||||
width,
|
||||
height,
|
||||
quality,
|
||||
keyframe_interval,
|
||||
}));
|
||||
}
|
||||
}
|
||||
if let Some(h265) = best.h265 {
|
||||
if is_h265 {
|
||||
return Ok(EncoderCfg::HWRAM(HwRamEncoderConfig {
|
||||
name: h265.name,
|
||||
width,
|
||||
height,
|
||||
quality,
|
||||
keyframe_interval,
|
||||
}));
|
||||
}
|
||||
let format = if _name == CodecName::H265VRAM {
|
||||
CodecFormat::H265
|
||||
} else {
|
||||
CodecFormat::H264
|
||||
};
|
||||
if let Some(hw) = HwRamEncoder::try_get(format) {
|
||||
return Ok(EncoderCfg::HWRAM(HwRamEncoderConfig {
|
||||
name: hw.name,
|
||||
width,
|
||||
height,
|
||||
quality,
|
||||
keyframe_interval,
|
||||
}));
|
||||
}
|
||||
}
|
||||
CodecName::H264RAM(name) | CodecName::H265RAM(name) => {
|
||||
|
Loading…
Reference in New Issue
Block a user