add zero copy mode hareware codec for windows (#6778)

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages
2024-01-02 16:58:10 +08:00
committed by GitHub
parent f47faa548b
commit 89150317e1
55 changed files with 2540 additions and 429 deletions

View File

@@ -22,6 +22,9 @@ use winapi::{
use crate::RotationMode::*;
use crate::{AdapterDevice, Frame, PixelBuffer};
use std::ffi::c_void;
pub struct ComPtr<T>(*mut T);
impl<T> ComPtr<T> {
fn is_null(&self) -> bool {
@@ -45,12 +48,15 @@ pub struct Capturer {
duplication: ComPtr<IDXGIOutputDuplication>,
fastlane: bool,
surface: ComPtr<IDXGISurface>,
texture: ComPtr<ID3D11Texture2D>,
width: usize,
height: usize,
rotated: Vec<u8>,
gdi_capturer: Option<CapturerGDI>,
gdi_buffer: Vec<u8>,
saved_raw_data: Vec<u8>, // for faster compare and copy
output_texture: bool,
adapter_desc1: DXGI_ADAPTER_DESC1,
}
impl Capturer {
@@ -60,12 +66,14 @@ impl Capturer {
let mut duplication = ptr::null_mut();
#[allow(invalid_value)]
let mut desc = unsafe { mem::MaybeUninit::uninit().assume_init() };
#[allow(invalid_value)]
let mut adapter_desc1 = unsafe { mem::MaybeUninit::uninit().assume_init() };
let mut gdi_capturer = None;
let mut res = if display.gdi {
wrap_hresult(1)
} else {
wrap_hresult(unsafe {
let res = wrap_hresult(unsafe {
D3D11CreateDevice(
display.adapter.0 as *mut _,
D3D_DRIVER_TYPE_UNKNOWN,
@@ -78,7 +86,12 @@ impl Capturer {
ptr::null_mut(),
&mut context,
)
})
});
if res.is_ok() {
wrap_hresult(unsafe { (*display.adapter.0).GetDesc1(&mut adapter_desc1) })
} else {
res
}
};
let device = ComPtr(device);
let context = ComPtr(context);
@@ -145,6 +158,7 @@ impl Capturer {
duplication: ComPtr(duplication),
fastlane: desc.DesktopImageInSystemMemory == TRUE,
surface: ComPtr(ptr::null_mut()),
texture: ComPtr(ptr::null_mut()),
width: display.width() as usize,
height: display.height() as usize,
display,
@@ -152,6 +166,8 @@ impl Capturer {
gdi_capturer,
gdi_buffer: Vec::new(),
saved_raw_data: Vec::new(),
output_texture: false,
adapter_desc1,
})
}
@@ -169,6 +185,11 @@ impl Capturer {
self.gdi_capturer.take();
}
#[cfg(feature = "gpucodec")]
pub fn set_output_texture(&mut self, texture: bool) {
self.output_texture = texture;
}
unsafe fn load_frame(&mut self, timeout: UINT) -> io::Result<(*const u8, i32)> {
let mut frame = ptr::null_mut();
#[allow(invalid_value)]
@@ -230,7 +251,21 @@ impl Capturer {
Ok(surface)
}
pub fn frame<'a>(&'a mut self, timeout: UINT) -> io::Result<&'a [u8]> {
pub fn frame<'a>(&'a mut self, timeout: UINT) -> io::Result<Frame<'a>> {
if self.output_texture {
Ok(Frame::Texture(self.get_texture(timeout)?))
} else {
let width = self.width;
let height = self.height;
Ok(Frame::PixelBuffer(PixelBuffer::new(
self.get_pixelbuffer(timeout)?,
width,
height,
)))
}
}
fn get_pixelbuffer<'a>(&'a mut self, timeout: UINT) -> io::Result<&'a [u8]> {
unsafe {
// Release last frame.
// No error checking needed because we don't care.
@@ -293,6 +328,34 @@ impl Capturer {
}
}
fn get_texture(&mut self, timeout: UINT) -> io::Result<*mut c_void> {
unsafe {
if self.duplication.0.is_null() {
return Err(std::io::ErrorKind::AddrNotAvailable.into());
}
(*self.duplication.0).ReleaseFrame();
let mut frame = ptr::null_mut();
#[allow(invalid_value)]
let mut info = mem::MaybeUninit::uninit().assume_init();
wrap_hresult((*self.duplication.0).AcquireNextFrame(timeout, &mut info, &mut frame))?;
let frame = ComPtr(frame);
if info.AccumulatedFrames == 0 || *info.LastPresentTime.QuadPart() == 0 {
return Err(std::io::ErrorKind::WouldBlock.into());
}
let mut texture: *mut ID3D11Texture2D = ptr::null_mut();
(*frame.0).QueryInterface(
&IID_ID3D11Texture2D,
&mut texture as *mut *mut _ as *mut *mut _,
);
let texture = ComPtr(texture);
self.texture = texture;
Ok(self.texture.0 as *mut c_void)
}
}
fn unmap(&self) {
unsafe {
(*self.duplication.0).ReleaseFrame();
@@ -305,6 +368,15 @@ impl Capturer {
}
}
}
pub fn device(&self) -> AdapterDevice {
AdapterDevice {
device: self.device.0 as _,
vendor_id: self.adapter_desc1.VendorId,
luid: ((self.adapter_desc1.AdapterLuid.HighPart as i64) << 32)
| self.adapter_desc1.AdapterLuid.LowPart as i64,
}
}
}
impl Drop for Capturer {
@@ -547,6 +619,22 @@ impl Display {
self.desc.DesktopCoordinates.top,
)
}
#[cfg(feature = "gpucodec")]
pub fn adapter_luid(&self) -> Option<i64> {
unsafe {
if !self.adapter.is_null() {
#[allow(invalid_value)]
let mut adapter_desc1 = mem::MaybeUninit::uninit().assume_init();
if wrap_hresult((*self.adapter.0).GetDesc1(&mut adapter_desc1)).is_ok() {
let luid = ((adapter_desc1.AdapterLuid.HighPart as i64) << 32)
| adapter_desc1.AdapterLuid.LowPart as i64;
return Some(luid);
}
}
None
}
}
}
fn wrap_hresult(x: HRESULT) -> io::Result<()> {