CommunityToolkit / Maui.NativeLibraryInterop

Maui.NativeLibraryInterop is a community-created library of binding samples to help .NET MAUI developers interop with native libraries more easily
MIT License
181 stars 28 forks source link

Questions on useability #59

Open danleash opened 3 weeks ago

danleash commented 3 weeks ago

Good evening, I'm trying to access ScreenCaptureKit from Maui MacCatalyst. I believe I have set everything up correctly, however, I continue to get the same issue. I was hoping someone could give me some insight into what I am doing wrong.

My error:

7>Xamarin.Shared.Sdk.targets(1643,3): Error : clang++ exited with code 1: Undefined symbols for architecture arm64: "_OBJCCLASS$_SCStream", referenced from:

"_OBJC_CLASS_$_SCStreamOutput", referenced from: "_OBJC_CLASS_$_ScreenCapture", referenced from: ld: symbol(s) not found for architecture arm64 clang++: error: linker command failed with exit code 1 (use -v to see invocation) I created my framework in XCode with one class to test the initial implementation. `import ScreenCaptureKit @objcMembers @objc(ScreenCapture) public class ScreenCapture: NSObject, SCStreamDelegate, SCStreamOutput { private static var captureCompletion: ((NSData?) -> Void)? private var stream: SCStream? @objc(captureFullScreenWithCompletion:) public static func captureFullScreen(completion: @escaping (NSData?) -> Void) { // Set the completion handler for later use in the delegate method captureCompletion = completion let screenCapture = ScreenCapture() Task { do { // Access the main display for screen capture let shareableContent = try await SCShareableContent.current guard let mainDisplay = shareableContent.displays.first else { completion(nil) return } // Set up the content filter and stream configuration let filter = SCContentFilter(display: mainDisplay, excludingWindows: []) let config = SCStreamConfiguration() config.width = Int(mainDisplay.width) config.height = Int(mainDisplay.height) config.pixelFormat = kCVPixelFormatType_32BGRA // Initialize the stream with the content filter, configuration, and delegate screenCapture.stream = SCStream(filter: filter, configuration: config, delegate: screenCapture) // Set the ScreenCapture class as the output try screenCapture.stream?.addStreamOutput(screenCapture, type: .screen, sampleHandlerQueue: .main) // Start the capture session try await screenCapture.stream?.startCapture() } catch { print("Failed to start screen capture: \(error)") completion(nil) } } } // SCStreamOutput delegate method to handle the frame output @objc public func stream(_ stream: SCStream, didOutput sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType){ guard type == .screen, let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { ScreenCapture.captureCompletion?(nil) ScreenCapture.captureCompletion = nil stream.stopCapture { _ in } return } // Convert CVPixelBuffer to NSData directly let ciImage = CIImage(cvPixelBuffer: imageBuffer) // Render the CIImage to PNG data using Core Image let context = CIContext(options: nil) if let pngData = context.pngRepresentation(of: ciImage, format: .BGRA8, colorSpace: CGColorSpaceCreateDeviceRGB()) { ScreenCapture.captureCompletion?(pngData as NSData) } else { ScreenCapture.captureCompletion?(nil) } // Stop the stream after capturing one frame ScreenCapture.captureCompletion = nil stream.stopCapture { _ in } } // SCStreamDelegate method to handle any errors during the streaming session @objc public func stream(_ stream: SCStream, didStopWithError error: Error) { print("Stream stopped with error: \(error)") ScreenCapture.captureCompletion?(nil) ScreenCapture.captureCompletion = nil } } ` I created the project for binding with the template per the docs. I am also referencing my local xcodeproj for the framework: ` ScreenCaptureFramework ScreenCapture true Framework true ` I created the ApiDefinitions.cs file myself, and am really struggling to get this to work. `#nullable enable using System; using Foundation; using ObjCRuntime; using CoreMedia; using CoreFoundation; // Add this for DispatchQueue namespace Seea.NativeBinding { [BaseType(typeof(NSObject))] interface ScreenCapture { [Static] [Export("captureFullScreenWithCompletion:")] void CaptureFullScreenWithCompletion(Action completion); [Export("stream:didOutput:of:")] void DidOutput(SCStream stream, CMSampleBuffer sampleBuffer, SCStreamOutputType type); [Export("stream:didStopWithError:")] void DidStopWithError(SCStream stream, NSError error); } [BaseType(typeof(NSObject))] interface SCStream { [Export("startCaptureWithCompletionHandler:")] void StartCapture([NullAllowed] Action completionHandler); [Export("stopCaptureWithCompletionHandler:")] void StopCapture([NullAllowed] Action completionHandler); [Export("addStreamOutput:type:sampleHandlerQueue:error:")] bool AddStreamOutput(SCStreamOutput output, SCStreamOutputType type, [NullAllowed] DispatchQueue sampleHandlerQueue, out NSError error); [Export("removeStreamOutput:type:error:")] bool RemoveStreamOutput(SCStreamOutput output, SCStreamOutputType type, out NSError error); } [BaseType(typeof(NSObject))] interface SCStreamOutput { // This method handles the output of a sample buffer in the stream. [Abstract] [Export("stream:didOutput:of:")] void DidOutput(SCStream stream, CMSampleBuffer sampleBuffer, SCStreamOutputType type); } }` I know I am probably doing this wrong somewhere, but I could really use some insight if anyone has had this issue besides myself. Thanks!