Skip to content

Questions on useability #59

@danleash

Description

@danleash

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:
"OBJC_CLASS$_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:
<ItemGroup> <NLIXcodeProjectReference Include="/path/to/ScreenCaptureFramework/ScreenCaptureFramework.xcodeproj"> <SchemeName>ScreenCaptureFramework</SchemeName> <SharpieNamespace>ScreenCapture</SharpieNamespace> <SharpieBind>true</SharpieBind> <Kind>Framework</Kind> <SmartLink>true</SmartLink> </NLIXcodeProjectReference> </ItemGroup> <ItemGroup>

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<NSData?> 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<NSError> completionHandler);

    [Export("stopCaptureWithCompletionHandler:")]
    void StopCapture([NullAllowed] Action<NSError> 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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs infoRequires more information from issue reporterstaleThe author has not responded recently

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions