Skip to content

Commit

Permalink
Handle Size Change 🎈
Browse files Browse the repository at this point in the history
	modified:   src/capture.rs
	modified:   src/d3d11.rs
	modified:   src/frame.rs
  • Loading branch information
NiiightmareXD committed Sep 23, 2023
1 parent 24fdd99 commit 931ef8e
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 50 deletions.
93 changes: 47 additions & 46 deletions src/capture.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::sync::Arc;

use log::{info, warn};
use parking_lot::Mutex;
use thiserror::Error;
use windows::{
Expand All @@ -10,9 +11,11 @@ use windows::{
DirectX::DirectXPixelFormat,
},
Win32::{
Graphics::Direct3D11::{
ID3D11Texture2D, D3D11_CPU_ACCESS_READ, D3D11_MAPPED_SUBRESOURCE, D3D11_MAP_READ,
D3D11_TEXTURE2D_DESC, D3D11_USAGE_STAGING,
Graphics::{
Direct3D11::{
ID3D11Texture2D, D3D11_CPU_ACCESS_READ, D3D11_TEXTURE2D_DESC, D3D11_USAGE_STAGING,
},
Dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM,
},
System::WinRT::{
CreateDispatcherQueueController, Direct3D11::IDirect3DDxgiInterfaceAccess,
Expand All @@ -25,7 +28,7 @@ use windows::{
},
};

use crate::monitor::Monitor;
use crate::{d3d11::SendDirectX, monitor::Monitor};

use super::{
d3d11::{create_d3d_device, create_direct3d_device},
Expand Down Expand Up @@ -71,8 +74,7 @@ where

/// Internal Capture Struct
pub struct WindowsCapture {
_item: GraphicsCaptureItem,
frame_pool: Option<Direct3D11CaptureFramePool>,
frame_pool: Option<Arc<Direct3D11CaptureFramePool>>,
session: Option<GraphicsCaptureSession>,
started: bool,
}
Expand Down Expand Up @@ -104,6 +106,8 @@ impl WindowsCapture {
let trigger = Arc::new(Mutex::new(trigger));
let trigger_item = trigger.clone();
let trigger_frame_pool = trigger;
let frame_pool = Arc::new(frame_pool);
let device = SendDirectX::new(device);

// Set CaptureItem Closed Event
_item.Closed(
Expand All @@ -119,14 +123,20 @@ impl WindowsCapture {
)?;

// Set FramePool FrameArrived Event
let context = unsafe { d3d_device.GetImmediateContext()? };
frame_pool.FrameArrived(
&TypedEventHandler::<Direct3D11CaptureFramePool, IInspectable>::new({
let context = unsafe { d3d_device.GetImmediateContext()? };
let frame_pool = frame_pool.clone();
let mut last_size = _item.Size()?;

move |frame, _| {
// Get Frame
let frame = frame.as_ref().unwrap();
let frame = frame.TryGetNextFrame()?;

// Get Frame Content Size
let frame_content_size = frame.ContentSize()?;

// Get Frame Surface
let surface = frame.Surface()?;

Expand All @@ -142,48 +152,39 @@ impl WindowsCapture {
texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ.0 as u32;
texture_desc.MiscFlags = 0;

// Create A Temp Texture To Process On
let mut texture_copy = None;
unsafe {
d3d_device.CreateTexture2D(&texture_desc, None, Some(&mut texture_copy))?
};
let texture_copy = texture_copy.unwrap();

// Copy The Real Texture To Temp Texture
unsafe { context.CopyResource(&texture_copy, &texture) };

// Map The Texture To Enable CPU Access
let mut mapped_resource = D3D11_MAPPED_SUBRESOURCE::default();
unsafe {
context.Map(
&texture_copy,
0,
D3D11_MAP_READ,
0,
Some(&mut mapped_resource),
)?
};

// Create A Slice From The Bits
let slice: &[u8] = unsafe {
std::slice::from_raw_parts(
mapped_resource.pData as *const u8,
(texture_desc.Height * mapped_resource.RowPitch) as usize,
)
};

let frame = Frame::new(slice, texture_desc.Width, texture_desc.Height);

// Send The Frame To Trigger Struct
trigger_frame_pool.lock().on_frame_arrived(frame);
if texture_desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM {
// Check If The Size Has Been Changed
if frame_content_size.Width != last_size.Width
|| frame_content_size.Height != last_size.Height
{
info!("Size Changed Recreating Device");
let device = &device;
frame_pool
.Recreate(
&device.inner,
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2,
frame_content_size,
)
.unwrap();

last_size = frame_content_size;
} else {
let frame = Frame::new(&surface, &d3d_device, &context);

// Send The Frame To Trigger Struct
trigger_frame_pool.lock().on_frame_arrived(&frame);
}
} else {
warn!("Wrong Pixel Type");
}

Result::Ok(())
}
}),
)?;

Ok(Self {
_item,
frame_pool: Some(frame_pool),
session: Some(session),
started: false,
Expand Down Expand Up @@ -294,12 +295,12 @@ pub trait WindowsCaptureHandler: Sized {
}
}

// Uninit WinRT
unsafe { RoUninitialize() };

// Stop Capturing
capture.stop_capture();

// Uninit WinRT
unsafe { RoUninitialize() };

Ok(())
}

Expand All @@ -308,7 +309,7 @@ pub trait WindowsCaptureHandler: Sized {
fn new(flags: Self::Flags) -> Self;

/// Called Every Time A New Frame Is Available
fn on_frame_arrived(&mut self, frame: Frame);
fn on_frame_arrived(&mut self, frame: &Frame);

/// Called If The Capture Item Closed Usually When The Window Closes
fn on_closed(&mut self);
Expand Down
13 changes: 13 additions & 0 deletions src/d3d11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ use windows::{
},
};

pub struct SendDirectX<T> {
pub inner: T,
}

impl<T> SendDirectX<T> {
pub fn new(device: T) -> Self {
Self { inner: device }
}
}

unsafe impl<T> Send for SendDirectX<T> {}

pub fn create_d3d_device() -> Result<ID3D11Device, Box<dyn std::error::Error>> {
// Try To Build A Hardware Device
let mut d3d_device = None;
Expand Down Expand Up @@ -64,5 +76,6 @@ pub fn create_direct3d_device(
let dxgi_device: IDXGIDevice = d3d_device.cast()?;
let inspectable = unsafe { CreateDirect3D11DeviceFromDXGIDevice(&dxgi_device)? };
let device: IDirect3DDevice = inspectable.cast()?;

Ok(device)
}
99 changes: 95 additions & 4 deletions src/frame.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
use windows::{
core::ComInterface,
Graphics::DirectX::Direct3D11::IDirect3DSurface,
Win32::{
Graphics::Direct3D11::{
ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D, D3D11_CPU_ACCESS_READ,
D3D11_MAPPED_SUBRESOURCE, D3D11_MAP_READ, D3D11_TEXTURE2D_DESC, D3D11_USAGE_STAGING,
},
System::WinRT::Direct3D11::IDirect3DDxgiInterfaceAccess,
},
};

/// Pixels Color Representation
#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(C)]
Expand All @@ -10,13 +22,92 @@ pub struct BGRA {

/// Frame Struct Used To Crop And Get The Frame Buffer
pub struct Frame<'a> {
surface: &'a IDirect3DSurface,
d3d_device: &'a ID3D11Device,
context: &'a ID3D11DeviceContext,
}

impl<'a> Frame<'a> {
/// Craete A New Frame
pub fn new(
surface: &'a IDirect3DSurface,
d3d_device: &'a ID3D11Device,
context: &'a ID3D11DeviceContext,
) -> Self {
Self {
surface,
d3d_device,
context,
}
}

/// Get The Frame Buffer
pub fn buffer(&self) -> Result<FrameBuffer, Box<dyn std::error::Error>> {
// Convert Surface To Texture
let access = self.surface.cast::<IDirect3DDxgiInterfaceAccess>()?;
let texture = unsafe { access.GetInterface::<ID3D11Texture2D>()? };

// Texture Settings
let mut texture_desc = D3D11_TEXTURE2D_DESC::default();
unsafe { texture.GetDesc(&mut texture_desc) }
texture_desc.Usage = D3D11_USAGE_STAGING;
texture_desc.BindFlags = 0;
texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ.0 as u32;
texture_desc.MiscFlags = 0;

// Create A Temp Texture To Process On
let mut texture_copy = None;
unsafe {
self.d3d_device
.CreateTexture2D(&texture_desc, None, Some(&mut texture_copy))?
};
let texture_copy = texture_copy.unwrap();

// Copy The Real Texture To Temp Texture
unsafe { self.context.CopyResource(&texture_copy, &texture) };

// Map The Texture To Enable CPU Access
let mut mapped_resource = D3D11_MAPPED_SUBRESOURCE::default();
unsafe {
self.context.Map(
&texture_copy,
0,
D3D11_MAP_READ,
0,
Some(&mut mapped_resource),
)?
};

// Create A Slice From The Bits
let slice: &[u8] = unsafe {
std::slice::from_raw_parts(
mapped_resource.pData as *const u8,
(texture_desc.Height * mapped_resource.RowPitch) as usize,
)
};

Ok(FrameBuffer {
slice,
width: texture_desc.Width,
height: texture_desc.Height,
})
}

/// Get The Raw IDirect3DSurface
pub fn get_raw_surface(&self) -> &'a IDirect3DSurface {
self.surface
}
}

/// FrameBuffer Struct Used To Crop And Get The Buffer
pub struct FrameBuffer<'a> {
slice: &'a [u8],
width: u32,
height: u32,
}

impl<'a> Frame<'a> {
/// Create A New Frame
impl<'a> FrameBuffer<'a> {
/// Create A New FrameBuffer
pub const fn new(slice: &'a [u8], width: u32, height: u32) -> Self {
Self {
slice,
Expand All @@ -25,7 +116,7 @@ impl<'a> Frame<'a> {
}
}

/// Get The Cropped Version Of The Frame
/// Get The Cropped Version Of The Frame Buffer
pub fn get_cropped(
&self,
start_width: u32,
Expand All @@ -46,7 +137,7 @@ impl<'a> Frame<'a> {
cropped_pixels
}

/// Get The Frame
/// Get The Frame Buffer
pub const fn get(&self) -> &'a [BGRA] {
let pixel_slice: &[BGRA] = unsafe {
std::slice::from_raw_parts(
Expand Down

0 comments on commit 931ef8e

Please sign in to comment.