WWDC Quick Look 💓 By SwiftGGTeam
What's new in ScreenCaptureKit

What's new in ScreenCaptureKit

元の動画を見る

ハイライト

macOS 14 の ScreenCaptureKit には、Presenter Overlay スピーカー オーバーレイ エフェクト、SCContentSharingPicker システム レベル コンテンツ セレクター、および SCScreenshotManager 高解像度スクリーンショット API が追加されており、これにより、画面共有アプリケーションは、独自に構築した UI を構築することなく、システムで一貫したエクスペリエンスを得ることができます。

主な内容

画面共有 UI のジレンマ

ビデオ会議ツールや画面録画ツールを作成する場合、コンテンツ選択インターフェイスが面倒になることがあります。すべてのウィンドウとアプリケーションを列挙するには、さまざまなエッジ ケースを処理する選択パネルを描画します。アプリケーションごとに選択インターフェイスの外観が異なるため、ユーザーは毎回それを学び直す必要があります。

SCContentSharingPicker がこの負担を引き継ぎます。これは、macOS ネイティブと一致するウィンドウ/アプリケーション/ディスプレイの選択エクスペリエンスを提供するシステム レベルのシングルトンであり、ユーザーがビデオ メニュー バー、アプリ内ボタン、またはウィンドウを直接クリックすることによってトリガーできます。

プレゼンター オーバーレイ: 自動スピーカー効果

リモート会議で画面を共有する場合、発言者のポートレートとコンテンツは分離されます。プレゼンター オーバーレイは、高度なセグメンテーション アルゴリズムを通じて共有コンテンツにスピーカーを埋め込みます。

スモール オーバーレイ モードでは、移動可能な円形ウィンドウ内にスピーカーが配置されます。ラージ オーバーレイ モードは、スピーカーを背景から分離し、スピーカーと背景の間に画面コンテンツを配置して、天気予報に似た没入型効果を作り出します。

重要なのは、この効果は ScreenCaptureKit を使用するアプリケーションに対して自動的に有効になるということです。アプリがカメラとスクリーン キャプチャ ストリームの両方を使用している限り、コントロールはビデオ メニュー バーに表示され、ScreenCaptureKit は合成されたフレームをストリームに直接プッシュします。

ビデオ ストリームからネイティブ スクリーンショットにフレームをキャプチャします

以前は、画面のコンテンツをキャプチャするには、SCStream からフレームを取得するか、CGWindowListCreateImage を使用する必要がありました。前者はストリームを維持する必要がありますが、後者は機能が制限されています。

SCScreenshotManager は、非同期スクリーンショット API を提供し、CGImage と CMSampleBuffer の 2 つの出力形式をサポートし、ScreenCaptureKit のフィルタリングおよび構成機能を再利用します。

##詳細

プレゼンターオーバーレイステータス検出

03:32

アプリは、UI を調整できるように、プレゼンター オーバーレイがいつ有効になっているかを知る必要があります。

let stream = SCStream(filter: filter, configuration: config, delegate: self)

// SCStreamDelegate コールバックを実装
func stream(_ stream: SCStream, outputEffectDidStart didStart: Bool) {
    if didStart {
        presentBanner()
        turnOffCamera() // ローカルカメラのタイルを非表示にする
    } else {
        turnOnCamera()
    }
}

キーポイント:

  • outputEffectDidStartプレゼンターのオーバーレイが有効/無効になったときにトリガーされます
  • 有効にすると、カメラがオーバーレイによって直接使用されるため、AVCaptureSession は通常のカメラ ストリームを出力しなくなります
  • ビデオ通話アプリケーションはオーディオとビデオの同期を調整し、発言者のローカル カメラ タイルを非表示にする必要があります。
  • オーバーレイにはリアルタイムの分割レンダリングが含まれるため、より高いフレーム レートに最適化することをお勧めします。

システムレベルのコンテンツセレクター

06:48

SCContentSharingPicker は、独自に構築されたコンテンツ選択インターフェイスを置き換えます。

let picker = SCContentSharingPicker.shared()
picker.addObserver(self)
picker.isActive = true

// アプリ内ボタンでシステムピッカーを表示
func showSystemPicker(sender: UIButton) {
    picker.present(for: nil, using: .window)
}

// 選択完了時のコールバック
func contentSharingPicker(_ picker: SCContentSharingPicker,
                          didUpdateWith filter: SCContentFilter,
                          for stream: SCStream?) {
    if let stream = stream {
        stream.updateContentFilter(filter)
    } else {
        let newStream = SCStream(filter: filter, configuration: config, delegate: self)
        // 新しいストリームを開始
    }
}

// 失敗とキャンセルのコールバック
func contentSharingPicker(_ picker: SCContentSharingPicker,
                          didCancelFor stream: SCStream?) {
    if let stream = stream {
        resetStateForStream(stream: stream)
    }
}

func contentSharingPickerStartDidFailWithError(_ error: Error) {
    presentNotification(error: error)
}

キーポイント:

  • isActive = trueこのアプリをビデオ メニュー バーに含めるには必須です
  • present(for:using:)contentStyleオプション.window.application.display
  • コールバックによって返されるSCContentFilterストリームの作成または更新に直接使用できます
  • セレクターの動作はストリームごとに個別に設定可能

ストリームごとにセレクターを構成する

08:41

let pickerConfig = SCContentSharingPickerConfiguration()
pickerConfig.allowedPickingModes = [.window, .application]
pickerConfig.excludedBundleIDs = ["com.foo.myApp", "com.foo.myApp2"]
pickerConfig.allowsRepicking = false

picker.setConfiguration(pickerConfig, for: stream)

キーポイント:

  • allowedPickingModesユーザーが選択できるコンテンツの種類を制限する
  • excludedBundleIDsそしてexcludedWindowIDs機密性の高いアプリやウィンドウを非表示にする
  • allowsRepicking = falseユーザーが選択したコンテンツを変更できないようにする
  • 各ストリームは異なる構成を持つことができます

HD スクリーンショット API

12:26

// 方法 1: CGImage 出力
if let screenshot = try? await SCScreenshotManager.captureImage(
    contentFilter: myContentFilter,
    configuration: myConfiguration
) {
    // screenshot は CGImage で、NSImage/UIImage に直接使用できます
}

// 方法 2: CMSampleBuffer 出力
if let sampleBuffer = try? await SCScreenshotManager.captureSampleBuffer(
    contentFilter: myContentFilter,
    configuration: myConfiguration
) {
    // より多くのピクセル形式に対応し、動画処理フローに適しています
}

完全な使用プロセス:

// 1. 共有可能なコンテンツを取得
let content = try await SCShareableContent.current

// 2. コンテンツフィルターを作成(ピッカーまたは手動で指定可能)
let filter = SCContentFilter(display: content.displays.first!,
                             excludingApplications: [],
                             exceptingWindows: [])

// 3. スクリーンショットのパラメータを設定
let configuration = SCStreamConfiguration()
configuration.width = 1920
configuration.height = 1080
configuration.showsCursor = true

// 4. スクリーンショット API を呼び出す
if let screenshot = try? await SCScreenshotManager.captureImage(
    contentFilter: filter,
    configuration: configuration
) {
    print("スクリーンショットに成功、サイズ: \(screenshot.width) x \(screenshot.height)")
}

キーポイント:

  • captureImage直接表示または保存に適した CGImage を返します。
  • captureSampleBufferCMSampleBuffer を返し、より多くのピクセル形式をサポートします
  • カーソル表示、解像度、色空間などの設定オプションは基本的に SCStream と同じです。
  • CGWindowListCreateImageから移行する場合、ウィンドウ階層オプションはSCShareableContentで取得されます。

重要ポイント

  1. ワンクリック画面録画ツール
  • やるべきこと: メニュー バー ウィジェットを作成し、クリックしてシステム セレクターをポップアップし、ウィンドウを選択して GIF/ビデオの録画を開始します。
  • 実行する価値がある理由: SCContentSharingPicker は完全な選択 UI を提供します。自分で構築する必要はなく、わずか数行のコードでプロ レベルの画面記録を実現できます。
  • 開始方法: を使用しますSCContentSharingPicker.shared()コールバックで作成されたセレクターを取得しますSCStream出力先AVAssetWriter
  1. スマートなスクリーンショットメモアプリケーション
  • 対処方法: スクリーンショットを撮った後、OCR でテキストを自動的に認識し、アプリケーション分類ごとにアーカイブします。
  • 実行する価値がある理由:SCScreenshotManager特定のウィンドウを正確にキャプチャし、連携することができます。excludedBundleIDsプライベートコンテンツをフィルタリングする
  • 開始方法: を使用しますSCShareableContentウィンドウリストを取得して作成するSCContentFilter対象ウィンドウを指定して呼び出しますcaptureImage
  1. リモート コラボレーション ホワイトボード
  • 内容: 画面共有時にスピーカーのジェスチャーとレーザー ポインター マークを自動的にオーバーレイします。
  • 実行する価値がある理由: プレゼンター オーバーレイはすでに話者のセグメンテーションを処理しているため、アプリケーションは受信側でカスタム アノテーション レイヤーをオーバーレイするだけで済みます。
  • 開始方法: 検出outputEffectDidStartコールバック、UIレイアウトの調整、共有画面へのCAShapeLayer描画マークの重畳
  1. アプリケーション使用状況分析ツール
  • 何をすべきか: ユーザーのアクティブなウィンドウを定期的に傍受し、毎日のアプリケーション使用時間の視覚的なレポートを生成します。
  • 実行する価値がある理由: スクリーンショット API はアプリケーションごとに正確にフィルタリングできます。SCShareableContentウィンドウレベルの情報
  • 開始方法: を使用しますSCShareableContent.currentアプリケーションリストを取得し、アプリケーションごとにフィルターを作成し、定期的に呼び出します。captureSampleBufferピクセルの変化を分析してアクティビティを判断する

関連セッション

コメント

GitHub Issues · utterances