1use std::ffi::c_void;
2use std::mem::MaybeUninit;
3use std::ptr::null_mut;
4
5use nvfbc_sys::{
6 NVFBC_TOCUDA_FLAGS_NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT,
7 NVFBC_TOCUDA_FLAGS_NVFBC_TOCUDA_GRAB_FLAGS_NOFLAGS,
8 NVFBC_TOCUDA_FLAGS_NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY
9};
10
11use crate::{
12 BufferFormat,
13 CaptureType,
14 Error,
15 Status,
16};
17
18use crate::common::{
19 Handle,
20 check_ret,
21 create_capture_session,
22 create_handle,
23 destroy_capture_session,
24 destroy_handle,
25 status,
26};
27
28pub enum CaptureMethod {
29 NoWait = NVFBC_TOCUDA_FLAGS_NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT as isize,
35
36 NoWaitIfNewFrame = NVFBC_TOCUDA_FLAGS_NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY as isize,
39
40 Blocking = NVFBC_TOCUDA_FLAGS_NVFBC_TOCUDA_GRAB_FLAGS_NOFLAGS as isize,
42}
43
44#[derive(Copy, Clone)]
46pub struct CudaFrameInfo {
47 pub device_buffer: usize,
51 pub device_buffer_len: u32,
53 pub width: u32,
55 pub height: u32,
57 pub current_frame: u32,
61}
62
63impl std::fmt::Debug for CudaFrameInfo {
64 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
65 f.debug_struct("CudaFrameInfo")
66 .field("device_buffer", &(&self.device_buffer as *const usize))
67 .field("device_buffer_len", &self.device_buffer_len)
68 .field("width", &self.width)
69 .field("height", &self.height)
70 .field("current_frame", &self.current_frame)
71 .finish()
72 }
73}
74
75pub struct CudaCapturer {
77 handle: Handle,
79}
80
81impl CudaCapturer {
82 pub fn new() -> Result<Self, Error> {
86 Ok(Self { handle: create_handle()? })
87 }
88
89 pub fn status(&self) -> Result<Status, Error> {
91 status(self.handle)
92 }
93
94 pub fn start(&self, buffer_format: BufferFormat, fps: u32) -> Result<(), Error> {
96 create_capture_session(
97 self.handle,
98 CaptureType::SharedCuda,
99 std::time::Duration::from_millis(1000 / fps as u64),
100 )?;
101
102 let mut params: nvfbc_sys::NVFBC_TOCUDA_SETUP_PARAMS = unsafe { MaybeUninit::zeroed().assume_init() };
103 params.dwVersion = nvfbc_sys::NVFBC_TOCUDA_SETUP_PARAMS_VER;
104 params.eBufferFormat = buffer_format as u32;
105 check_ret(self.handle, unsafe { nvfbc_sys::NvFBCToCudaSetUp(self.handle, &mut params) })
106 }
107
108 pub fn stop(&self) -> Result<(), Error> {
110 destroy_capture_session(self.handle)
111 }
112
113 pub fn next_frame(&mut self, capture_method: CaptureMethod) -> Result<CudaFrameInfo, Error> {
115 let mut device_buffer: *mut c_void = null_mut();
116 let mut frame_info: nvfbc_sys::NVFBC_FRAME_GRAB_INFO = unsafe { MaybeUninit::zeroed().assume_init() };
117 let mut params: nvfbc_sys::NVFBC_TOCUDA_GRAB_FRAME_PARAMS = unsafe { MaybeUninit::zeroed().assume_init() };
118 params.dwVersion = nvfbc_sys::NVFBC_TOCUDA_GRAB_FRAME_PARAMS_VER;
119 params.dwFlags = capture_method as u32;
120 params.pFrameGrabInfo = &mut frame_info;
121 params.pCUDADeviceBuffer = &mut device_buffer as *mut _ as *mut c_void;
122 check_ret(self.handle, unsafe { nvfbc_sys::NvFBCToCudaGrabFrame(self.handle, &mut params) })?;
123
124 Ok(CudaFrameInfo {
125 device_buffer: device_buffer as usize,
126 device_buffer_len: frame_info.dwByteSize,
127 width: frame_info.dwWidth,
128 height: frame_info.dwHeight,
129 current_frame: frame_info.dwCurrentFrame,
130 })
131 }
132
133 pub fn release_context(&self) -> Result<(), Error> {
140 let mut params: nvfbc_sys::NVFBC_RELEASE_CONTEXT_PARAMS = unsafe { MaybeUninit::zeroed().assume_init() };
141 params.dwVersion = nvfbc_sys::NVFBC_RELEASE_CONTEXT_PARAMS_VER;
142 check_ret(
143 self.handle,
144 unsafe { nvfbc_sys::NvFBCReleaseContext(self.handle, &mut params) }
145 )
146 }
147
148 pub fn bind_context(&self) -> Result<(), Error> {
165 let mut params: nvfbc_sys::NVFBC_BIND_CONTEXT_PARAMS = unsafe { MaybeUninit::zeroed().assume_init() };
166 params.dwVersion = nvfbc_sys::NVFBC_BIND_CONTEXT_PARAMS_VER;
167 check_ret(
168 self.handle,
169 unsafe { nvfbc_sys::NvFBCBindContext(self.handle, &mut params) }
170 )
171 }
172}
173
174impl Drop for CudaCapturer {
175 fn drop(&mut self) {
176 destroy_handle(self.handle).ok();
178 }
179}