diff --git a/Cargo.toml b/Cargo.toml index cc59bab..dd218a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,5 @@ members = [ "graphic-offsets", "inject-helper", "obs-client", + "obs-client-ffi", ] \ No newline at end of file diff --git a/obs-client-ffi/Cargo.toml b/obs-client-ffi/Cargo.toml new file mode 100644 index 0000000..b5f0e80 --- /dev/null +++ b/obs-client-ffi/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "obs-client-ffi" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +name = "obs_client_ffi" +crate-type = ["lib", "cdylib", "staticlib"] + +[dependencies] +obs-client = { path = "../obs-client" } \ No newline at end of file diff --git a/obs-client-ffi/README.md b/obs-client-ffi/README.md new file mode 100644 index 0000000..9707994 --- /dev/null +++ b/obs-client-ffi/README.md @@ -0,0 +1,15 @@ +# obs-client-ffi + +## Requirements + +``` +cargo +nightly install cbindgen +``` + +## Headers + +Generate with: +``` +cbindgen --config cbindgen.toml --crate obs-client-ffi --output obs-client.h -l C +cbindgen --config cbindgen.toml --crate obs-client-ffi --output obs-client.hpp -l C++ +``` \ No newline at end of file diff --git a/obs-client-ffi/cbindgen.toml b/obs-client-ffi/cbindgen.toml new file mode 100644 index 0000000..dcd1ba8 --- /dev/null +++ b/obs-client-ffi/cbindgen.toml @@ -0,0 +1,14 @@ +language = "C++" + +include_guard = "OBS_CLIENT_H" +tab_width = 4 +style = "both" +cpp_compat = true + +after_includes = "typedef void *Capture;" + +[fn] +sort_by = "None" + +[enum] +prefix_with_name = true \ No newline at end of file diff --git a/obs-client-ffi/obs-client.h b/obs-client-ffi/obs-client.h new file mode 100644 index 0000000..86734c5 --- /dev/null +++ b/obs-client-ffi/obs-client.h @@ -0,0 +1,32 @@ +#ifndef OBS_CLIENT_H +#define OBS_CLIENT_H + +#include +#include +#include +#include +typedef void *Capture; + +typedef struct Frame { + uintptr_t width; + uintptr_t height; + uint8_t *data; +} Frame; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +Capture *create_capture(const char *name_str); + +void free_capture(Capture *capture); + +bool try_launch_capture(Capture *capture); + +struct Frame *capture_frame(Capture *capture); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* OBS_CLIENT_H */ diff --git a/obs-client-ffi/obs-client.hpp b/obs-client-ffi/obs-client.hpp new file mode 100644 index 0000000..45611b5 --- /dev/null +++ b/obs-client-ffi/obs-client.hpp @@ -0,0 +1,29 @@ +#ifndef OBS_CLIENT_H +#define OBS_CLIENT_H + +#include +#include +#include +#include +#include +typedef void *Capture; + +struct Frame { + uintptr_t width; + uintptr_t height; + uint8_t *data; +}; + +extern "C" { + +Capture *create_capture(const char *name_str); + +void free_capture(Capture *capture); + +bool try_launch_capture(Capture *capture); + +Frame *capture_frame(Capture *capture); + +} // extern "C" + +#endif // OBS_CLIENT_H diff --git a/obs-client-ffi/src/lib.rs b/obs-client-ffi/src/lib.rs new file mode 100644 index 0000000..68f3e73 --- /dev/null +++ b/obs-client-ffi/src/lib.rs @@ -0,0 +1,63 @@ +use obs_client::Capture; +use std::ffi::{c_char, CStr}; + +#[no_mangle] +pub extern "C" fn create_capture(name_str: *const c_char) -> *mut Capture { + let name = unsafe { CStr::from_ptr(name_str).to_string_lossy().into_owned() }; + + let capture = Capture::new(name.as_str()); + Box::into_raw(Box::new(capture)) +} + +#[no_mangle] +pub extern "C" fn free_capture(capture: *mut Capture) { + if capture.is_null() { + return; + } + let capture = unsafe { Box::from_raw(capture) }; + core::mem::drop(capture); +} + +#[no_mangle] +pub extern "C" fn try_launch_capture(capture: *mut Capture) -> bool { + if capture.is_null() { + return false; + } + + if let Err(e) = unsafe { (*capture).try_launch() } { + eprintln!("Failed to launch capture: {:?}", e); + false + } else { + true + } +} + +#[repr(C)] +pub struct Frame { + width: usize, + height: usize, + data: *mut u8, +} + +#[no_mangle] +pub extern "C" fn capture_frame(capture: *mut Capture) -> *mut Frame { + if capture.is_null() { + return std::ptr::null_mut(); + } + + let frame = unsafe { (*capture).capture_frame() }; + let (data, (width, height)) = match frame { + Ok(frame) => frame, + Err(e) => { + eprintln!("Failed to capture frame: {:?}", e); + return std::ptr::null_mut(); + } + }; + + let frame = Frame { + width, + height, + data: data.as_mut_ptr(), + }; + Box::into_raw(Box::new(frame)) +} diff --git a/obs-client/src/lib.rs b/obs-client/src/lib.rs index 0348160..06959a6 100644 --- a/obs-client/src/lib.rs +++ b/obs-client/src/lib.rs @@ -1,6 +1,3 @@ -#![feature(bool_to_option)] -#![feature(cstring_from_vec_with_nul)] - use crate::{ error::ObsError, hook_info::{