import Foundation import ForgeGrade import ForgeColor public enum CameraVendor: String, Sendable, Codable { case arri case red case sony case simulated } public enum MetadataField: String, Sendable, Codable, CaseIterable { case clipName case exposureIndex case whiteBalance case tint case fps case timecode case lens } /// What a camera can accept / report. Drivers declare, grade pipeline adapts. public struct CameraCapabilities: Sendable { public var vendor: CameraVendor /// Camera applies ASC CDL natively (RED IPP2, ARRI ALF4). If false, CDL must be baked into LUT. public var supportsNativeCDL: Bool /// Accepted 3D LUT lattice sizes. public var lut3dSizes: [Int] public var metadataFields: [MetadataField] public init(vendor: CameraVendor, supportsNativeCDL: Bool, lut3dSizes: [Int], metadataFields: [MetadataField]) { self.vendor = vendor self.supportsNativeCDL = supportsNativeCDL self.lut3dSizes = lut3dSizes self.metadataFields = metadataFields } } public enum ConnectionStatus: String, Sendable, Equatable { case disconnected case connecting case connected } public struct CameraMetadata: Sendable, Equatable { public var exposureIndex: Int? public var whiteBalance: Int? public var tint: Int? public var fps: Double? public var timecode: String? public var lens: String? public init( exposureIndex: Int? = nil, whiteBalance: Int? = nil, tint: Int? = nil, fps: Double? = nil, timecode: String? = nil, lens: String? = nil ) { self.exposureIndex = exposureIndex self.whiteBalance = whiteBalance self.tint = tint self.fps = fps self.timecode = timecode self.lens = lens } } public struct CameraState: Sendable, Equatable { public var connection: ConnectionStatus public var isRecording: Bool public var clipName: String? public var metadata: CameraMetadata? public init( connection: ConnectionStatus, isRecording: Bool = false, clipName: String? = nil, metadata: CameraMetadata? = nil ) { self.connection = connection self.isRecording = isRecording self.clipName = clipName self.metadata = metadata } } public enum CameraError: Error, Equatable { case connectionFailed(String) case pushFailed(String) case unsupportedLook(String) } /// Hardware seam. One driver instance per physical camera. public protocol CameraDriver: Actor { nonisolated var capabilities: CameraCapabilities { get } nonisolated var state: AsyncStream { get } func connect() async throws func disconnect() async func push(look: FlattenedLook) async throws }