# SGRVision (iOS / macOS) — LLM / Coding-Agent Guide > 이 문서는 코딩 에이전트가 iOS·macOS 네이티브 SDK 를 정확히 사용하도록 돕는 압축 레퍼런스입니다. > 사람용 소개는 vision-sdk-ios/README.md, 실행 예제는 example/ios 를 참고하세요. > 웹 SDK 가이드는 llms.txt. 두 SDK 는 동일한 옵션·프로필·라이선스 계약을 공유합니다. ## What it is Metal 기반 iOS/macOS 네이티브 SDK. `AVPlayer` 가 재생하는 영상 프레임을 (`AVPlayerItemVideoOutput` → `CVMetalTextureCache` → Metal 패스 체인 → `MTKView`) 실시간으로 화질 개선해 출력한다. **재생은 사용자의 `AVPlayer` 가 담당하고, SDK 는 그 프레임의 화면 출력만 개선한다.** 웹 SDK 의 `enhance()`(overlay ``)에 대응하는 네이티브 포트. 핵심 API 2개: - `VisionVideoView` — SwiftUI 뷰(권장). 웹 overlay canvas 대응. 라이선스 게이팅 내장. - `VisionEnhancer` — 명령형 컨트롤러. 웹 `enhance()` 핸들 대응. ## Install (Swift Package Manager) ```swift .package(url: "https://github.com/SGRsoft-Dev/vision-ios-sdk.git", from: "0.1.9") ``` - 배포: XCFramework `binaryTarget`(컴파일 바이너리). 지원 **iOS 15+ · macOS 12+** (arm64 기기 / arm64·x86_64 시뮬레이터 / arm64·x86_64 macOS). - `import SGRVision`. 리소스(profiles.json + 컴파일된 default.metallib)는 프레임워크에 내장. ## Primary API — SwiftUI (권장) ```swift import SGRVision import AVFoundation let player = AVPlayer(url: hlsURL) // 사용자가 재생 제어 VisionVideoView( player: player, options: VisionOptions(profile: .default, licenseKey: "VSK-…"), onLicense: { state in /* .pending → .ok / .invalid */ } ) .aspectRatio(16.0/9.0, contentMode: .fit) // 비율은 호출측 책임 ``` - `onLicense`: `licenseKey` 지정 시에만 호출(메인스레드). 효과 적용 2초 후 검증 → 실패 시 원본 복귀. - 옵션 변경 반영: 현재 `updateUIView` 는 비어 있어, SwiftUI `.id(...)` 를 바꿔 뷰를 재생성하면 새 옵션이 적용됨(데모 방식). 라이브 갱신이 필요하면 `VisionEnhancer`/`updateUniforms` 사용. - `AVPlayer.currentItem` 교체(`replaceCurrentItem`)를 KVO 로 감지해 자동 재연결 → 소스 전환/지연 로드에도 프레임 안 끊김. 빈 `AVPlayer()` 먼저 만들고 나중에 아이템을 넣어도 OK. ## Imperative API ```swift let enhancer = VisionEnhancer(player: player, options: VisionOptions(profile: .ott)) enhancer.update(VisionOptions(profile: .cctv, contrast: 0.4)) enhancer.setEnabled(false) // 효과 on/off let state = enhancer.getState() // VisionState enhancer.destroy() // VisionState: { enabled, profile, rendererKind:"metal"|"none", license:LicenseState, uniforms } ``` ## VisionOptions (전체 — 웹 VideoEnhancementOptions 미러, 동일 필드명) ```swift VisionOptions( enabled: Bool = true, profile: VisionProfile? = .default, // off/default/detail/ott/education/cctv/anime/oled/retro // 개별 강도 — 명시 시 profile 기본값을 덮어씀 sharpen: Double? = nil, // 0..1 언샤프 선명도 contrast: Double? = nil, // 0..1 글로벌 S-curve cleanup: Double? = nil, // 0..1 압축 노이즈/블록 제거 anime: Double? = nil, // 0..1 라인 강조 + 색면 평탄화 gamma: Double? = nil, // 0.5..2.0 (기본 1.0) localContrast: Double? = nil, // 0..1 와이드 radius 언샤프 darkLift: Double? = nil, // 0..1 암부만 lift scanline: ScanlineParams? = nil, // enabled/intensity/spacing upscale: UpscaleParams? = nil, // 아래 edgeEnhancement: EdgeEnhancementParams? = nil, // enabled/algorithm(.off/.classic/.rcas)/strength cnn1: Cnn1Params? = nil, // 1-layer CNN(compute) cnn: CnnParams? = nil, // multi-layer CNN(compute, layers:[CnnLayer] 81 floats/layer) renderer: VisionRenderer? = nil, // .auto/.metal (iOS 단일 백엔드) autoReduceOnLowEnd: Bool? = nil, // 저사양 기기 강도 자동 감쇠(기본 true) licenseKey: String? = nil // 지정 시 효과 즉시 적용→2초 후 검증, 실패 시 효과 OFF(원본) ) // UpscaleParams(enabled:Bool?, algorithm:UpscaleAlgorithm?, target:UpscaleTarget?, width:Int?, height:Int?, sharpness:Double?) // UpscaleAlgorithm: .none/.nearest/.bilinear/.lanczos/.fsr // UpscaleTarget: .source/.p720("720p")/.p1080("1080p")/.p1440("1440p")/.x2/.x3/.custom ``` ## Profiles (한 줄 의미) - default: Cinematic, 실사용 메인 / detail: Ultra Detail, 시연용 - ott: 저비트레이트 스트리밍 cleanup / education: 텍스트·판서 가독성 - cctv: 야간·저조도 대비 / anime: 라인+색면 평탄화 - oled: 깊은 black+영화적 대비 / retro: CRT scanline+warm / off: 비활성 ## Upscale (UpscaleParams 로 직접 구성 — 권장 조합 예시) ```swift // 비활성 → upscale 생략(nil) let stable = UpscaleParams(enabled: true, algorithm: .lanczos, target: .p1080, sharpness: 0.04) let quality = UpscaleParams(enabled: true, algorithm: .fsr, target: .p1080, sharpness: 0.06) let strong = UpscaleParams(enabled: true, algorithm: .fsr, target: .p1080, sharpness: 0.10) let lowPower = UpscaleParams(enabled: true, algorithm: .bilinear, target: .p720, sharpness: 0.03) ``` ## License (네이티브 = 번들 ID 바인딩, 낙관적 게이팅) - **낙관적 라이프사이클**: `licenseKey` 지정 시 효과가 **즉시 적용**되고, **2초 후** 검증한다. 통과면 그대로 유지, 실패(없음/만료/폐기/번들ID불일치/네트워크)면 효과를 끄고 **원본으로 되돌림**. 결과는 프로세스 내 캐시(뷰 재생성 시 재요청 X). 웹/Android 와 동일한 동작. - 상태: `LicenseState` = `.none|.pending|.ok|.invalid`. - SwiftUI: `VisionVideoView(onLicense: { state in ... })` - 명령형: `enhancer.getState().license` / `enhancer.licenseState` - **웹과 차이**: 네이티브는 도메인(Origin) 대신 **번들 ID** 를 `app` 으로 서버에 전송한다. 라이선스의 `allowedOrigins` 에 앱의 **번들 ID** 가 포함돼야 통과(웹 도메인과 같은 리스트에 함께). - **개발 빌드 면제**(웹 localhost 대응): 시뮬레이터이거나 `embedded.mobileprovision` 이 있는 개발/Ad-hoc 빌드는 검증을 건너뛰고 바로 구동된다(licenseState=.ok). **App Store·TestFlight 등 릴리스 빌드만 검증.** 출시 빌드는 이 신호를 위조할 수 없어(스토어가 임의 프로비저닝 차단) 면제 악용 불가. - **번들 ID 위변조 방지**: app 식별자는 SDK 가 `Bundle.main.bundleIdentifier`(Info.plist, 빌드/서명 시 고정)에서 **직접** 읽는다. 개발자가 주입·조작할 수 있는 파라미터가 없다(LicenseClient 에 bundleId 인자 없음). - 체험 키 `VSK-ZP02Z-K3FJ9-4C4DQ-8EM6A` 는 번들 ID **`com.sgr.vision.ios.example`** 에만 바인딩됨 (example/ios 데모용). 본인 앱은 번들 ID 를 origins 에 추가한 키를 support@sgrsoft.com 으로 발급. - 검증 서버 주소는 SDK 에 고정 내장(변경 불가). ## Exports (public) - 뷰/컨트롤러: `VisionVideoView`(SwiftUI), `VisionEnhancer`, `VisionMetalView`(MTKView), `MetalRenderer` - 옵션/타입: `VisionOptions`, `VisionProfile`, `VisionRenderer`, `UpscaleAlgorithm`, `UpscaleTarget`, `EdgeAlgorithm`, `ScanlineParams`, `UpscaleParams`, `EdgeEnhancementParams`, `Cnn1Params`, `CnnParams`, `CnnLayer`, `CnnWeights`, `EnhancementUniforms`, `VisionState`, `LicenseState`, `LicenseResult`, `LicenseClient` - Multi-layer CNN 가중치: `CnnWeights.load(from: url, layerCount:)`(async) 또는 `CnnWeights.parse(data, layerCount:)` 로 .bin(LE f32, 81 floats/layer)을 `[CnnLayer]` 로 만들어 `VisionOptions(cnn: CnnParams(enabled: true, layers:))` 에 주입. - 네임스페이스: `VisionSDK.version`, `VisionSDK.specVersion`, `VisionSDK.profiles` (주의: 모듈명과 충돌하므로 네임스페이스 enum 은 `SGRVision` 이 아니라 `VisionSDK`) ## Behavior & constraints (에이전트 주의) - `VisionVideoView` 가 권장 진입점. `VisionEnhancer` 는 명령형/상태 미러. - 비율(aspectRatio)·레이아웃·전체화면은 호출측 책임. SDK 는 **영상 해상도**에서 패스 체인을 처리한 뒤 출력 drawable 로 스케일한다(0.1.6+). 뷰가 영상보다 작아도 선명도가 유지된다(웹/Android 와 동일). - `enabled:false` 또는 `profile:.off` 또는 모든 강도 0 이면 passthrough(원본) 출력. - 낙관적 게이팅: 효과가 먼저 적용되고 2초 후 검증 → 실패 시에만 원본으로 되돌린다(뷰 재생성 불필요). - 소스 전환: 같은 `AVPlayer` 에 `replaceCurrentItem` → 자동 재연결(currentItem KVO). - DRM(FairPlay) 보호 콘텐츠는 프레임 캡처가 차단돼 개선 적용 불가. 단, SDK 가 자동 감지 (`asset.hasProtectedContent` + 재생 1초 후 프레임 미수신 안전망)해 **검정 대신 원본을 그대로 재생**한다 (`AVPlayerLayer` 폴백 → Metal 정지, `VisionMetalView.isDrmFallback`). 소스가 클리어로 바뀌면 자동 복귀. - Xcode 빌드(시뮬/실기기)는 `Shaders.metal` 을 `default.metallib` 로 컴파일 → 최초 1회 `xcodebuild -downloadComponent MetalToolchain` 필요할 수 있음(`cannot execute tool 'metal'` 시). `MetalRenderer` 는 metallib(Xcode) / `.metal` 소스(SwiftPM) 양쪽 로드 지원. - 렌더러 생성 실패 시 `VisionVideoView` 는 빈 뷰로 폴백(원본 재생 X, 화면 비어 보일 수 있음) — 보통 리소스 누락 시 발생하므로 SPM/번들 구성을 의심. - macOS 도 동일 SwiftUI 코드 동작(NSViewRepresentable). `swift run` 으로 즉시 테스트 가능. ## Common agent tasks - "영상에 화질 개선" → `VisionVideoView(player: player, options: VisionOptions(profile: .default))` - "라이선스 적용" → `VisionVideoView(player:, options: VisionOptions(profile:.default, licenseKey:"VSK-…"), onLicense:{ s in })` (체험 키는 번들 ID `com.sgr.vision.ios.example` 한정 — 본인 앱은 번들 ID 등록 키 발급) - "끄기/켜기" → 명령형 `enhancer.setEnabled(bool)`; SwiftUI 는 options.enabled 바꾸고 `.id` 갱신 - "프로필 변경" → options.profile 교체 후 뷰 `.id` 갱신(또는 `enhancer.update`) - "업스케일" → options.upscale 에 위 preset 중 하나(quality 권장: 1080p+FSR) - "소스 전환" → 같은 player 에 `player.replaceCurrentItem(with:)` (뷰 재구성 불필요, 자동 재연결) - "원본 vs 개선 동시 비교" → 두 VisionVideoView(enabled:false / true)를 ZStack 으로 겹치고 mask 로 좌/우 분할 (example/ios ContentView '동시 비교' 참고) - "정리" → 명령형 사용 시 `enhancer.destroy()`. SwiftUI 는 뷰 소멸 시 자동. ## Links - 배포(SPM): https://github.com/SGRsoft-Dev/vision-ios-sdk (XCFramework, from: "0.1.9") - 예제 앱: example/ios (VisionDemo — 웹 demo.html 구성 + 전체화면) - README(상세): vision-sdk-ios/README.md - 웹 SDK 가이드: llms.txt