macOS屏幕录制开发:ScreenCaptureKit框架详解

发布时间:2026/10/30 3:29:18
macOS屏幕录制开发:ScreenCaptureKit框架详解

1. macOS屏幕录制开发概述

在当今远程协作和内容创作日益普及的环境下,屏幕录制功能已成为各类应用的核心需求。macOS平台上的ScreenCaptureKit框架为开发者提供了高性能、低延迟的屏幕捕获解决方案,相比传统的CGDisplayStream和CGWindowList API,它在性能、隐私保护和功能灵活性方面都有显著提升。

ScreenCaptureKit支持捕获屏幕显示、应用程序窗口以及音频内容,能够以高达屏幕原生分辨率和60fps的帧率进行录制,同时支持48kHz立体声音频采集。这个框架特别适合用于开发视频会议应用、远程协作工具、游戏直播软件以及教育类应用。

重要提示:从macOS 13开始,Apple已明确表示将逐步弃用旧的屏幕捕获API,因此新项目应优先考虑使用ScreenCaptureKit。

2. ScreenCaptureKit核心组件解析

2.1 SCShareableContent:可共享内容管理

SCShareableContent是ScreenCaptureKit中用于管理可捕获内容的中心类。它提供了当前系统中所有可共享的显示、应用程序和窗口的详细信息:

// 获取当前可共享内容 let content = try await SCShareableContent.excludingDesktopWindows( false, onScreenWindowsOnly: true )

这个方法返回的对象包含三个主要属性:

  • displays: 当前连接的物理显示器列表(SCDisplay)
  • applications: 正在运行的应用程序列表(SCRunningApplication)
  • windows: 所有可见窗口列表(SCWindow)

每个SCDisplay对象包含显示器的唯一标识符、尺寸和缩放比例等信息,这对于多显示器环境下的屏幕捕获尤为重要。

2.2 SCContentFilter:内容过滤配置

SCContentFilter决定了实际捕获哪些内容,它支持两种主要过滤模式:

  1. 显示器无关的窗口过滤:捕获特定窗口,即使窗口在不同显示器间移动
  2. 显示器相关的过滤:捕获特定显示器上的内容,可选择包含或排除某些窗口/应用
// 创建内容过滤器,排除当前应用 let excludedApps = content.applications.filter { app in Bundle.main.bundleIdentifier == app.bundleIdentifier } let filter = SCContentFilter(display: display, excludingApplications: excludedApps, exceptingWindows: [])

这种过滤机制可以有效避免"镜厅效应"(即捕获到自己的捕获界面),同时保护敏感信息不被意外录制。

2.3 SCStreamConfiguration:流媒体参数设置

SCStreamConfiguration对象控制捕获流的各项参数,包括:

let streamConfig = SCStreamConfiguration() // 视频参数 streamConfig.width = 1920 // 输出宽度 streamConfig.height = 1080 // 输出高度 streamConfig.minimumFrameInterval = CMTime(value: 1, timescale: 60) // 60fps streamConfig.showsCursor = false // 是否显示鼠标光标 // 音频参数 streamConfig.capturesAudio = true // 启用音频捕获 streamConfig.sampleRate = 48000 // 48kHz采样率 streamConfig.channelCount = 2 // 立体声

开发者可以根据应用场景灵活调整这些参数。例如,文档共享应用可能更注重分辨率而非帧率,而游戏直播则需要更高的帧率保证流畅性。

3. 屏幕与音频捕获实战实现

3.1 创建和启动捕获流

配置好内容和参数后,就可以创建SCStream实例并开始捕获:

// 创建流实例 stream = SCStream(filter: filter, configuration: streamConfig, delegate: self) // 添加输出处理器 try stream?.addStreamOutput(self, type: .screen, sampleHandlerQueue: screenQueue) try stream?.addStreamOutput(self, type: .audio, sampleHandlerQueue: audioQueue) // 开始捕获 try await stream?.startCapture()

3.2 处理视频和音频样本

ScreenCaptureKit通过SCStreamOutput协议回调传递捕获的媒体数据:

func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) { switch type { case .screen: processVideoSample(sampleBuffer) case .audio: processAudioSample(sampleBuffer) } } private func processVideoSample(_ sampleBuffer: CMSampleBuffer) { guard let attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, createIfNecessary: false) as? [[SCStreamFrameInfo: Any]], let info = attachments.first?[.status] as? SCStreamFrameInfo else { return } if info == .complete, let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) { // 处理完整的视频帧 } }

视频样本以CVPixelBuffer形式提供,可以直接用于显示、编码或进一步处理。每个样本都附带帧状态信息(.complete或.idle),帮助开发者优化处理逻辑。

3.3 音频采集的特殊处理

音频采集需要特别注意以下几点:

  1. 音频格式:ScreenCaptureKit输出的音频样本格式为LPCM,采样率和通道数由SCStreamConfiguration决定
  2. 音频同步:视频和音频样本可能在不同时间到达,需要实现自己的同步机制
  3. 音频混合:当捕获多个应用的音频时,框架会自动混合,无法单独控制每个应用的音量
private func processAudioSample(_ sampleBuffer: CMSampleBuffer) { guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) else { return } var audioBufferList = AudioBufferList() var length = 0 CMBlockBufferGetDataPointer(blockBuffer, atOffset: 0, lengthAtOffsetOut: &length, totalLengthOut: nil, dataPointerOut: &audioBufferList.mBuffers.mData) // 处理音频数据... }

4. 高级功能与性能优化

4.1 动态调整捕获参数

ScreenCaptureKit支持实时更新捕获参数,无需重新创建流:

// 动态调整分辨率 streamConfig.width = 1280 streamConfig.height = 720 try await stream?.updateConfiguration(streamConfig) // 动态切换捕获内容 let newFilter = SCContentFilter(display: anotherDisplay) try await stream?.updateContentFilter(newFilter)

这一特性特别适合需要根据网络状况动态调整质量的远程协作应用。

4.2 多流管理

一个应用可以同时创建多个SCStream实例,分别捕获不同的内容:

// 主显示器捕获流 let mainStream = SCStream(filter: mainFilter, configuration: mainConfig, delegate: self) // 第二显示器捕获流 let secondStream = SCStream(filter: secondFilter, configuration: secondConfig, delegate: self) // 分别启动 try await mainStream.startCapture() try await secondStream.startCapture()

每个流可以独立配置和管理,但需要注意系统资源消耗。

4.3 性能优化技巧

  1. 帧率与分辨率平衡:高分辨率(如4K)下适当降低帧率(如15-30fps)
  2. 像素格式选择:BGRA格式处理效率最高,适合直接显示;如需编码,考虑使用NV12
  3. 队列管理:为视频和音频处理使用不同的DispatchQueue,避免相互阻塞
  4. 内存优化:及时释放不再需要的CMSampleBuffer和CVPixelBuffer

5. 常见问题与解决方案

5.1 权限问题处理

ScreenCaptureKit需要用户授权屏幕录制权限,应用应妥善处理权限相关错误:

func stream(_ stream: SCStream, didStopWithError error: Error) { if let scError = error as? SCStreamError, scError.code == .userDeclined { // 引导用户前往系统设置开启权限 showPermissionAlert() } }

5.2 音频捕获失败排查

如果音频无法正常捕获,检查以下方面:

  1. 确保streamConfig.capturesAudio = true
  2. 确认应用有麦克风使用权限
  3. 检查系统音频设置,确保没有静音或音量过低

5.3 性能问题诊断

当遇到高CPU使用率或帧率不稳定时:

  1. 使用Instruments工具分析性能瓶颈
  2. 考虑降低输出分辨率或帧率
  3. 检查是否有不必要的样本拷贝操作

5.4 多显示器环境下的特殊考虑

在多显示器环境下:

  1. 每个显示器可能有不同的缩放比例,需要手动调整输出分辨率
  2. 窗口跨显示器移动时,显示器无关的窗口过滤器能保持捕获连续性
  3. 不同显示器可能支持不同的最大刷新率

6. 实际应用场景扩展

6.1 视频会议应用集成

在视频会议应用中,ScreenCaptureKit可用于:

  1. 共享特定应用窗口而非整个屏幕
  2. 动态切换共享内容
  3. 实现标注、高亮等协作功能
// 会议应用中动态切换共享窗口 func switchToSharedWindow(_ window: SCWindow) { let newFilter = SCContentFilter(desktopIndependentWindow: window) Task { try await stream?.updateContentFilter(newFilter) } }

6.2 教育类应用开发

教育类应用可以利用ScreenCaptureKit实现:

  1. 课件录制与直播
  2. 学生屏幕监控
  3. 互动教学工具

6.3 游戏直播实现

对于游戏直播场景:

  1. 优先保证高帧率(60fps)
  2. 使用硬件编码器减少CPU负载
  3. 实现低延迟的音频视频同步
// 游戏直播专用配置 let gameConfig = SCStreamConfiguration() gameConfig.width = 1920 gameConfig.height = 1080 gameConfig.minimumFrameInterval = CMTime(value: 1, timescale: 60) gameConfig.capturesAudio = true gameConfig.sampleRate = 48000 gameConfig.channelCount = 2

ScreenCaptureKit为macOS屏幕录制开发提供了强大而灵活的工具集。通过合理配置和优化,开发者可以构建出满足各种场景需求的高性能屏幕录制功能。在实际开发中,建议从简单配置开始,逐步添加复杂功能,并始终关注性能和用户体验的平衡。