nvfbc 0.2.0

Safe bindings for NVFBC, an NVIDIA API for capturing the front buffer from NVIDIA GPUs.
Documentation
use std::os::raw::c_uint;
use std::{mem::MaybeUninit, ffi::CStr};

use nvfbc_sys::_NVFBCSTATUS_NVFBC_SUCCESS as SUCCESS;
use nvfbc_sys::NVFBC_SESSION_HANDLE;

use crate::CaptureType;
use crate::Error;
use crate::Status;

pub type Handle = NVFBC_SESSION_HANDLE;

pub(crate) fn check_ret(handle: Handle, ret: nvfbc_sys::_NVFBCSTATUS) -> Result<(), Error> {
	if ret != SUCCESS {
		return Err(Error::new(ret, get_last_error(handle)));
	}
	Ok(())
}

pub(crate) fn create_handle() -> Result<nvfbc_sys::NVFBC_SESSION_HANDLE, Error> {
	const MAGIC_PRIVATE_DATA: [u32; 4] = [0xAEF57AC5, 0x401D1A39, 0x1B856BBE, 0x9ED0CEBA];

	let mut params: nvfbc_sys::_NVFBC_CREATE_HANDLE_PARAMS = unsafe { MaybeUninit::zeroed().assume_init() };
	params.dwVersion = nvfbc_sys::NVFBC_CREATE_HANDLE_PARAMS_VER;
	params.privateData = MAGIC_PRIVATE_DATA.as_ptr() as _;
	params.privateDataSize = std::mem::size_of_val(&MAGIC_PRIVATE_DATA) as u32;

	let mut handle = 0;
	let ret = unsafe { nvfbc_sys::NvFBCCreateHandle(
		&mut handle,
		&mut params
	)};
	if ret != SUCCESS {
		return Err(Error::new(ret, None));
	}

	Ok(handle)
}

pub(crate) fn destroy_handle(handle: Handle) -> Result<(), Error> {
	let mut params: nvfbc_sys::_NVFBC_DESTROY_HANDLE_PARAMS = unsafe { MaybeUninit::zeroed().assume_init() };
	params.dwVersion = nvfbc_sys::NVFBC_DESTROY_HANDLE_PARAMS_VER;
	check_ret(handle, unsafe { nvfbc_sys::NvFBCDestroyHandle(handle, &mut params) })
}

pub(crate) fn get_last_error(handle: Handle) -> Option<String> {
	let error = unsafe { nvfbc_sys::NvFBCGetLastErrorStr(handle) };
	let error = unsafe { CStr::from_ptr(error) };
	error.to_str().ok().map(|e| e.to_string())
}

pub(crate) fn status(handle: Handle) -> Result<Status, Error> {
	let mut params: nvfbc_sys::_NVFBC_GET_STATUS_PARAMS = unsafe { MaybeUninit::zeroed().assume_init() };
	params.dwVersion = nvfbc_sys::NVFBC_GET_STATUS_PARAMS_VER;
	check_ret(handle, unsafe { nvfbc_sys::NvFBCGetStatus(handle, &mut params) })?;
	Ok(params.into())
}

pub(crate) fn create_capture_session(handle: Handle, capture_type: CaptureType, sampling_rate: std::time::Duration) -> Result<(), Error> {
	let mut params: nvfbc_sys::_NVFBC_CREATE_CAPTURE_SESSION_PARAMS = unsafe { MaybeUninit::zeroed().assume_init() };
	params.dwVersion = nvfbc_sys::NVFBC_CREATE_CAPTURE_SESSION_PARAMS_VER;
	params.eCaptureType = capture_type as c_uint;
	params.bWithCursor = nvfbc_sys::_NVFBC_BOOL_NVFBC_TRUE;
	params.frameSize = nvfbc_sys::NVFBC_SIZE { w: 0, h: 0 };
	params.eTrackingType = nvfbc_sys::NVFBC_TRACKING_TYPE_NVFBC_TRACKING_DEFAULT;
	params.dwSamplingRateMs = sampling_rate.as_millis() as u32;
	check_ret(handle, unsafe { nvfbc_sys::NvFBCCreateCaptureSession(handle, &mut params) })
}

pub(crate) fn destroy_capture_session(handle: Handle) -> Result<(), Error> {
	let mut params: nvfbc_sys::_NVFBC_DESTROY_CAPTURE_SESSION_PARAMS = unsafe { MaybeUninit::zeroed().assume_init() };
	params.dwVersion = nvfbc_sys::NVFBC_DESTROY_CAPTURE_SESSION_PARAMS_VER;
	check_ret(handle, unsafe { nvfbc_sys::NvFBCDestroyCaptureSession(handle, &mut params) })
}