📷
iPadのセンターフレーム (Center Stage)のAPIを使う
センターフレーム (Center Stage) とは
インカメラで人が映っている時に広角カメラの画角を自動で調整して人をフレーム内に収めてくれる機能です。
iOS 14.5以上で使える機能で、対応した端末でのみ使えます。
英語では "Center Stage" ですが、日本語では「センターフレーム」と呼ぶようです。
APIを使ってみる
まだほとんどドキュメントがないですが、AVFoundationの普通の使い方をしつつ、フラグを設定するだけで機能が使えます。
そのフラグは AVCaptureDevice.centerStageControlMode
です。
このフラグを設定すると設定アプリの権限ページにセンターフレームのOn/Offを切り替えるスイッチが追加されます。
このスイッチは他のカメラなどの許諾とは異なり、アプリ側からONに切り替えたり、設定アプリからOffにできないようすることもできます。
// 設定アプリでの設定でセンターフレームを使うかを決定する
AVCaptureDevice.centerStageControlMode = .user
// 起動時は設定アプリでの設定に従い、アプリ側からセンターフレームのOn/Offを切り替えると
// 設定アプリの状態も同期される
AVCaptureDevice.centerStageControlMode = .cooperative
// 設定アプリからは変更できないようにし、アプリ内の設定に従わせる
AVCaptureDevice.centerStageControlMode = .app
cooperative
やapp
に設定した場合は下記のフラグでセンターフレームの有効性を切り替えられます。
AVCaptureDevice.isCenterStageEnabled = true
app
に設定した場合、設定アプリのスイッチがdisabledになり、切り替えられなくなります。
ソースコード
センターフレームの機能を試すコードはこちらです。
import AVFoundation
import SwiftUI
final class VideoCaptureViewModel: ObservableObject {
private lazy var captureSession = AVCaptureSession()
lazy var previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
override init() {
super.init()
configure()
}
private func configure() {
captureSession.sessionPreset = .photo
guard let captureDevice = AVCaptureDevice.DiscoverySession(
deviceTypes: [.builtInWideAngleCamera],
mediaType: .video,
position: .front).devices.first else { return }
do {
let input = try AVCaptureDeviceInput(device: captureDevice)
captureSession.addInput(input)
} catch {}
captureSession.commitConfiguration()
previewLayer.videoGravity = .resizeAspectFill
previewLayer.backgroundColor = UIColor.black.cgColor
previewLayer.connection?.videoOrientation =
.init(rawValue: UIDevice.current.orientation.rawValue)!
// ここがポイント #############################################################
if #available(iOS 14.5, *) {
// センターフレームを有効にする
AVCaptureDevice.centerStageControlMode = .cooperative
AVCaptureDevice.isCenterStageEnabled = true
// センターフレームが使えるフォーマットをアクティブにする
let width = \AVCaptureDevice.Format.formatDescription.dimensions.width
if let format = captureDevice.formats
.filter(\.isCenterStageSupported)
.max(by: { $0[keyPath: width] < $1[keyPath: width] }) {
do {
try captureDevice.lockForConfiguration()
captureDevice.activeFormat = format
captureDevice.unlockForConfiguration()
} catch {}
}
}
// ##########################################################################
}
func startRunning() {
if captureSession.isRunning { return }
captureSession.startRunning()
}
func stopRunning() {
if !captureSession.isRunning { return }
captureSession.stopRunning()
}
}
// SwiftUIでカメラの映像を表示する
struct CenterStageView: View {
@StateObject var viewModel = VideoCaptureViewModel()
var body: some View {
ZStack(alignment: .top) {
CALayerView(caLayer: viewModel.previewLayer)
.edgesIgnoringSafeArea(.all)
.onAppear(perform: viewModel.startRunning)
.onDisappear(perform: viewModel.stopRunning)
if #available(iOS 14.5, *) {
Toggle(isOn: .init(get: { AVCaptureDevice.isCenterStageEnabled },
set: { AVCaptureDevice.isCenterStageEnabled = $0 })) {
Text("🕺Center Stage💃")
.font(.system(size: 120, weight: .heavy))
.foregroundColor(.red)
}
}
}
}
}
UIKitのラップ部分 (本質じゃない)
struct CALayerView: UIViewControllerRepresentable {
var caLayer: CALayer
func makeUIViewController(context: Context) -> LayerViewController {
LayerViewController(caLayer: caLayer)
}
func updateUIViewController(_ uiViewController: LayerViewController,
context: Context) {}
final class LayerViewController: UIViewController {
let caLayer: CALayer
init(caLayer: CALayer) {
self.caLayer = caLayer
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.layer.addSublayer(caLayer)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
caLayer.frame = view.layer.bounds
}
}
}
まとめ
フラグの制御だけで簡単に人のトラッキングができて便利。
顔を隠すとトラッキングしなくなるのでフェイストラッキング的なことをやってるのかな。
蛇足
センターフレームを有効にするとズームできる量に制限が出たり、デプスや geometricDistortionCorrectionEnabled
を使うとセンターフレームが無効になる仕様のようです。
また、英語だと設定ページはこんな表記。
日本語でも英語でも「ビデオ通話」という文言が入ってるけど、特に通話してなくても使えるので気になってます。
検証環境
- iPad Pro 12.9 インチ (第 5 世代)
- iPadOS 14.6
Discussion