ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Core Media IOでカメラExtensionを作成する
Core Media IOを使用して、ソフトウェアカメラ、ハードウェアカメラ、クリエイティブカメラのmacOSシステム拡張機能を簡単に作成する方法をご覧ください。従来のDALプラグインに代わる最新機能を紹介します。このExtensionには、カメラ入力を使用するAppと完全な互換性があり、安全性や高速性にも優れています。さらに、Core Media IO APIについて解説し、カメラメーカー、特殊効果機能付きテレビ会議App、クリエイティブAppのアイデアなどをサポートする方法も紹介します。
リソース
- Capture setup
- Core Media I/O
- Creating a camera extension with Core Media I/O
- Overriding the default USB video class extension
- System Extensions and DriverKit
関連ビデオ
WWDC19
-
ダウンロード
(音楽)
皆さん ようこそ Camera Software Engineeringチームの Brad Fordです このセッションでご紹介する カメラExtensionでは macOS用の最新カメラドライバ アーキテクチャとして DAL plug-insに取って代わる CoreMedia IOを紹介します
DAL plug-insは Macに接続するハードウェアのカメラや 仮想カメラのドライバを作るための物です macOS 10.7の時以来ずっと使われてきました
macOSを拡張してリッチな メディアプラットフォームとし サードパーティのカメラ製品の サポートを提供します
Macを Macにしてくれるテクノロジーです
ですが DAL plug-inには問題があります 信用できないコードを直接 Appのプロセスに取り込むため プラグインにバグがあったり マルウェア攻撃があると クラッシュしやすくなってしまうのです そのために AppleのAppに使えない場合があり その例が FaceTimeや QuickTime Playerや PhotoBoothです また多くのサードパーティ製カメラAppでは ライブラリ検証を意図的に無効にするか ユーザーがシステム整合性保護を オフにしない限り動作しません。 どちらも勧められない対処方法であり システムの安全性と安定性を下げてしまいます また 開発も困難です 2011年頃のC APIを使い C++ヘルパークラスの分厚いSDKも 学ばなければなりません それに加えてドキュメントもバラバラです
そろそろアップグレードをするべきでしょう macOS 12.3が導入するCamera Extensionsは DAL plug-inに取って代わる最新のもので…
ユーザーの安全性を最優先する アーキテクチャです その使い方を見ていきましょう まずはテクノロジーの概要を 皆さんに提供します そして一からカメラのExtensionを 作る方法をお見せします その次に APIの主なクラスや 機能について紹介します CoreMedia IO Extensionsを 出力デバイスとして使う方法を説明します 最後は DAL plug-in非奨励の予定に ついてお話します それでは始めましょう CoreMedia IO extensionsの名で 知られているカメラExtensionは カメラドライバをまとめて MacのAppに届ける新たな方法です
とても安全です Extensionのコードが封鎖される 独自のデーモンプロセスは サンドボックス化されていて ロールユーザーとして実行されます Extensionが提供する全てのバッファは Appに配信する前に 検証されています そして速いです ExtensionとApp間の IPCレイヤーを パフォーマンスを重視しながら フレームワークが扱います 複数の同時クライアントへのバッファの配信も フレームワークが行なえます そして最新です SwiftまたはObjective-cで書くこともできます
そしてシンプルです 学ぶべきクラスも少なく わずかなプロトコル実装で 立ち上げて稼働できます ボイラープレートコードも フレームワークの担当です
デプロイも簡単です App StoreでAppとして配信できます
そして既存の AVFoundationキャプチャAPIと 100%の後方互換性を持っています
Camera Extensionsは Appleを含む全てのカメラAppに 内蔵カメラと同じように表示されます 例えば Face Timeでのカメラの選択画面では カメラExtensionはこのように表示されます カメラExtensionでどのような 体験が可能になるでしょうか? 3つのよくある用途を見ていきましょう シンプルな用途としては ソフトウェア専用カメラで 表示するものはカラーバーや 独自のテストパターンや 多様なフレームレートや解像度で プログラム生成された画像か あるいは音声と映像の同期を 確認するための動画フレームなど レンダリング済みののコンテンツを ストリームするカメラです
2つ目のユースケースは 物理的またはワイヤレスで Macに接続するカメラのドライバです Camera Extensionsはホットプラグや アンプラグをフルサポートします ハードウェアの対応方法はいくつかあります お勧めは DriverKit Extension略して DEXTで 完全にユーザースペースで実行されます カーネルレベルでの 対応が必要なハードウェアには 旧来の IOVideoFamily kextのパスが使えます kextコードの新開発はやめましょう kextは本質的に安全性が低く システムの不安定さに繋がります
Appleの提供するクラス準拠のExtensionは USBビデオクラス 略してUVCのカメラに使えます UVCスペックに準拠するカメラに 非常に適しています
ですが 非標準プロトコルを使っていて UVCスペック以外の追加機能がある USBカメラをサポートする必要がある場合には AppleのUVC Extensionを上書きする カメラExtensionを作って 特定の製品やベンダーIDのデバイスを 操作することができます この件に関してさらに詳細を知りたい場合は 今 画面に表示されている developer.apple.com の記事をご覧ください 最小限の DEXTバンドルの作成方法や Info.plistでの上書きに必要な IOKitPersonalitiesキーが出ています
3つ目の用途はクリエイティブカメラで ソフトウェアとハードウェアの ハイブリッドです
Macに繋げられた物理的な別のカメラから Extensionが動画にアクセスし バッファにエフェクトを適用し 新しい動画としてクライアントに配信します
または複数のカメラの動画に アクセスする場合は それを合成してAppに送り込みます
このようなものは合成制御や フィルターのパラメータ化の コンフィグレーションAppを使うかもしれません クリエイティブカメラは可能性が尽きません
主要なユースケースを見ましたので CoreMedia IO Extensionの 内部構造を見てみましょう “CoreMedia IO”の部分から始めましょう
CoreMedia IOはカメラドライバの パブリッシュや発見のための 低レベルのフレームワークです ご存知のように旧来の DAL APIと その代替になる新しい カメラExtension APIを含みます ですが低レベルの C APIの 力強いセットも含むので システム上でカメラを見つけ 検査することができます
では“Extension”の部分はどうでしょうか?
CoreMedia IO Extensionsの土台 SystemExtensionsフレームワークは macOS Catalinaで初めて登場しました 使い捨てのインストーラを不要にして 代わりにApp内にExtensionを装備します Extensionの実行ファイルが Appのバンドル内にあるわけです SystemExtensionsフレームワークに 呼び出しをかければ システム上の全ユーザー向けに Extensionをインストールしたり アップグレードやダウングレード したりできます アンインストールも一瞬です Appの削除でSystemExtensionsフレームワークが 全ユーザーのカメラExtensionを アンインストールします この配信メカニズムは App Storeでも承認されていて カメラExtensionを用意に幅広く 配備することができます
システムExtensionフレームワークについての詳細は developer.apple.com/ documentation/systemextensions のドキュメンテーションをご覧ください
そして WWDC 2019の動画 「System ExtensionとDriverKit」 もお忘れなく
カメラExtensionのテクノロジーの 概要は以上です では実際に作ってみましょう カメラExtensionをほんの数分で 立ち上げ起動する デモをご覧ください
ExampleCamと言う macOS Appを Xcodeで作りました ここではまだ数行の コードしか追加していません
App Delegateは未変更です メインのストーリーボードに 2つのボタンを加えました 1つはExtensionのインストール用 もう1つはアンインストール用で 状況表示用のテキストフィールドもあります
ViewControllerクラスにはIBActionsを追加し インストールとアンインストールの ボタンと繋げます
これらの機能が作り出す OSSystemExtensionRequestsで Appのバンドル内のExtensionを 有効にしたり無効にすることができます 一番下に付けたのは OSSystemExtensionRequestDelegateの 骨組みで ステータスをログに記録します
Appのエンタイトルメントファイルは 通常の App Sandbox=YESで AppGroupを定義します
追加した新しいキーは1つで “System Extension”キーのみ システムExtensionのインストール時に Appが必要とするものです この時点でAppを実行し “Install Extension”を押すと 致命的エラーが出ますがそれは Appがまだ存在しないExtensionを バンドル内で探すからです
システムExtensionを作って埋め込むには Fileに行き New… Target… そして macOSで一番下までスクロールすると “System Extensions”があります “Camera Extension”を選んでから次に進み 名前を”Extension”にしますね “Embedded in Application”と なっているのを確認して Finishボタンを押します 新しいExtensionフォルダの中に 4つの新ファイルができました Info.plistは MachServiceNameを 定義することで CMIOExtensionとして識別します
これは非常に重要な情報です CoreMedia IOの registerassistantは これが無いとExtensionを起動しません
せっかくなのでここで 使用法の説明をしましょう システムExtensionについてですね エンタイトルメントファイルでは App Sandboxedとなっています 検証に合格するためには ExtensionのAppグループに MachServiceNameのプレフィックスが必要です
ですからApp Extensionからそれをコビーして Extensionエンタイトルメントファイルに ペーストします できました
main.swiftファイルが Extensionのエントリーポイントで サービスを開始します そして ExtensionProvider.swiftファイルで 完全に機能するカメラができあがります 含まれるのは DeviceSource StreamSourceと ProviderSourceで 純粋なソフトウェアカメラを 作るのにはこれで十分です なかなかのテンプレートですね
このファイル内で検索するのが “SampleCapture”で それを“ExampleCam”に置き換えると カメラの名前とモデルと 製作者に適切な名前がつきます
これだけですコンパイルして実行しましょう
インストールボタンを押すと… おっと 失敗です それはシステムExtensionを インストールできるのは /Applicationsの中のAppだけだからです 移動して もう一度やってみましょう
今度は… 成功です インストールをブロックされたAppの許可は システム環境設定で認証することで可能であり セキュリティとプライバシーを開けてから “許可”をクリックします
パスワードで認証すれば 結果は0になりエラー無しという事です systemextensionsctl listツールを使うなら 成功したことを確認し システム上で1つのExtensionが 有効になりました これであらゆるカメラAppを開き 出来栄えを楽しめます
FaceTimeを起動しましょう ExampleCamがカメラの選択肢に現れます 70年代の懐かしいポンゲームのような感じで 水平な白い線が毎秒60フレームの速さで フレームを上下に動きます
このカメラを排除するには Appを削除するだけです
Appの削除によってExtensionも アンインストールされる事を システムが確認してきます
ソフトウェアカメラの作成は 簡単だという事が分かりましたね ではワンランクアップして ソフトウェアカメラを クリエイティブカメラにしてみましょう
この2つ目の例の名前をCIFilterCamとします CIが意味するのは CoreImageで 静止画や動画に適用できる あらゆる効果フィルターを持つ フレームワークです
CIFilterCamを作るのに ExampleCamシェルで始めましたが インストーラに加えて コンフィグレーションAppも 付けようと思いました カメラ選択ボタンとフィルター選択ボタンと 効果バイパスボタンを加えました ライブ動画プレビューの表示も加えました この標準ビューは AVCaptureVideoPreviewLayerによるもので フィルターカメラの様子を示しています バイパスボタンのチェックを外すと 動画に適用されている 様々なフィルターが分かります 色彩効果から… ディストーションフィルターまで
バンプ歪みが一部だけかかっていますね
これらは搭載済みのFaceTimeカメラや Macに接続された普通のカメラに適用できます
近くにある iPhoneを Continuity Cameraにしてあります
使ってみましょう
CIFilterCamAppはそれ自体ではごく普通です ただの効果用カメラAppです ですが 全てのAppが使える 仮想フィルターカメラの フロントエンドになると面白くなってきます FaceTimeと PhotoBoothを起動し 両方とも CIFilterCamの方に向けておきます コンフィグレーションAppで フィルターを替えると CIFilterCamを使う全Appが並行して変わります
違うソースカメラを選べば 全てのカメラが変更を反映します
Appのボタンを押すたびに フィルターカメラExtensionに 伝達するわけです“このカメラを使え”とか “いや こっちのフィルターだ”
“こっちのフィルターだよ”
“いや こっちだ”
Extension内のハードウェアカメラの 実行に対するサポートには macOS Venturaが必要です Extensionのエンタイトルメントファイルに com.apple.security.device.camera キーも必要です 他のカメラを使う事を示しているわけです ユーザーはExtensionがカメラを使用する 許可を求められるため Info.plist の中に NSCameraUsageDescriptionを 必ず提供しましょう
カメラExtension作成の基本はこれで終了です では次は APIについてです
スタックの一番下がデーモンプロセスで カメラExtension 1つに1つずつあります
カメラAppの処理には複数のレイヤーが動作し カメラExtensionに IPCで通信する プライベートのフレームワーク コードで始まります 1つ上はもう1つのプレイベートレイヤーで CoreMedia IO Extensionのコールを 旧来のDAL plug−inコールに変換します
もう1つ上は DAL plug−inを作成する CoreMedia IOのAPIです このインターフェイスのクライアントにとって 両者の間に違いはありません すべてDAL plug−inに見えるわけです そして一番上にはAVFoundationで CoreMedia IOのクライアントです AVCaptureDevicesとして再発行します
これと反対なのが旧来の DALplug−inアーキテクチャです デーモンもあったり無かったりですが すべてCoreMedia IOの フレームワークで取り込んだコードを Appの処理で直接 実行します そのためAppがマルウェアに 脆弱になってしまいます Camera Extentionsは この攻撃ベクトルを全て排除します Extensionは App sandboxedでなければ 実行が許可されません
Appleの registerassistantserviceが CMIOExtensionMachServiceNameで それを識別して _cmiodalassistantsという ロールユーザーアカウントとして起動します Sandboxdはカスタマイズされた sandboxプロファイルをプロセスに適用します カメラのユースケース用に作られたものです
カスタムの sandboxプロファイルで 期待される通常のハードウェアの インターフェイスで通信ができるのです USBや Bluetoothや WiFi… WiFiはクライアントで ポートを開くサーバーではありません そして Firewireもです そしてExtensionに コンテナや tmpからの 読み書きも許可します
カメラExtensionの sandboxプロファイルは 通常のAppより制限されています できない事の例を挙げると fork・exec・子プロセスの posix spawn ウィンドウサーバーへのアクセス フォアグラウンドユーザーアカウントとの接続 自分の machサービスを グローバル名前空間に登録する事です
Extensionの開発を行う際に 正当なキャプチャのケースに対し sandbox の制限が厳しすぎると感じたら Feedback Assistantを通して フィードバックを送ってください 制限の緩和を 注意深く検討させていただきます 先程のアーキテクチャダイアグラムで カメラExtensionのデーモンが 直接Appのレイヤーに バッファを送ると分かりました 実はもう1つのレイヤーが セキュリティのために存在します
デーモンとAppの間にあるプロキシサービスは registerassistantserviceで 透明性と同意と制御ポリシーを 強化執行するものです Appがカメラを初めて使おうとする時に システムがユーザーに確認を取ります 同意はすべてのカメラに承認される必要があり 搭載済みのカメラだけではありません プロキシサービスはこの同意を 代わりに取り扱ってくれます カメラへのアクセスをユーザーが拒否した場合 そのAppにバッファが送られるのを プロキシが阻止します また特定のカメラが 特定のAppによって使用されていることを システムに知らせることで デーモンが消費した電力を カメラを使用しているAppに まとめることができます
CoreMedia IO Extensionsには 4つの主要クラスがあります Provider Device Stream です
ProviderにDeviceがあり DeviceにStreamがあり 3つの全てにプロパティがあります
この3つの主要クラスのそれぞれを作るのに ソースを提供しますが それぞれ ProviderSourceと DeviceSourceと StreamSourceです
ExtensionProviderは 最も低いレベルのオブジェクトです ホットプラグの時などの必要に応じて デバイスの追加や削除ができます
接続を試みるとクライアント処理が報告され デバイスが特定のAppに公開されるのを 制限する機会が生じます またプロバイダソースに プロパティ実行の相談もします
Extensionの主要エントリーポイントの 例をお見せします 自分の ExtensionProvider Sourceを作りますが CMIOExtensionProviderSource プロトコルに準拠し ExtensionProviderを作ります サービスの開始には プロバイダクラスメソッドの startServiceを呼び プロバイダインスタンスを送ります
ExtensionProviderが実行する 2つのプロパティは Extensionの働きを変えないように読み取り専用です 製作者とプロバイダの名前です これはどちらも文字列です
次は CMIOExtensionDeviceです ストリームの管理をし 必要に応じて追加や削除をします デバイスは複数のストリームを見せられますが AVFoundationは最初の入力ストリーム 以外は無視する事をお忘れなく
デバイスを作る時に提供するのは デバイスソースと ローカライズされた名前と デバイスID 略してUUIDと オプションとしてレガシーIDの文字列です これらは AVFoundationまで浸透していきます
デバイスの localizedNameは AVCaptureDeviceのlocalizedNameになります 指定の deviceIDは legacyDeviceIDも与えない限り AVCapture Deviceの uniqueIdentifierになります これは DAL plug-inをモダン化し 以前送った uniqueIdentifierと 後方互換性を維持する事が 必要な時だけ提供すればいいものです
legacyDeviceIDを提供すれば AVCaptureDeviceはそれを uniqueIdentifierとして使います
CMIOExtensionDeviceの作成に使う CMIOExtensionDeviceSourceは 他のプロパティをオプション的に 実行することがあり 例えば deviceModelで 同じモデルのすべてのカメラに同様のはずです isSuspendedはデバイスが一時停止状態に 入ることができる場合に実行されるべきです Appleのラップトップの内蔵カメラは クラムシェルが閉じていると 一時停止状態に入ります デバイスの転送タイプで接続方法が分かります UBSか BluetoothかFirewireかなどですね
そしてカメラに物理的に ペアリングしたマイクがあれば 接続デバイスに当てはまります これらのプロパティはすべて読み取り専用です 次は極めて重要なCMIOExtensionStreamで CMIOExtensionでの力仕事を担当しています 動画フォーマットを作成し 有効なフレームレートを決め アクティブフォーマットを設定します ホストのタイムレコーダーのような 標準時計を使うか 独自のカスタム時計を提供して 作り出すバッファの1つ1つの タイミングを操作します 最も重要なのは サンプルのバッファを クライアントに送ることです
Extensionのストリームソースが作成するのは CMIOExtensionStreamFormatsです それが AVCaptureDevice Formatsになります クライアントはアクティブフォーマットの インデックスを読み書きし アクティブフォーマットを変更します
フレームの長さは 最大フレームレートと同じですが 最大のフレームの長さは 最小フレームレートと同じです
DAL plug-inでは DALコントロールという 4つ目のインターフェイスがあります Plug-inのデベロッパはこれを使い自動露出や 輝度や鮮明度やパンやズームなどの 機能を生み出します パワフルですが一貫性をもって 実行できないために Appのデベロッパには 使い難いという問題があります CMIOExtensionのアーキテクチャには DALコントロールの代替品はありません 代わりに すべてがプロパティです
プロバイダのやデバイスや ストリームのレベルで 多くの標準プロパティについて学びました 自分のカスタムのプロパティを作り Appのレイヤーに プロパゲートすることもできます
CoreMedia IOの Cプロパティ インターフェイスは Cのstructを使い プロパティのセレクターや スコープやエレメントを識別します これらはそのアドレスです
セレクターはプロパティ名の4文字コードで カスタムには custという具合です スコープはグローバル 入力または出力のいずれかで エレメントは何でもお好きな番号で構いません メインのエレメントはいつでもゼロです CMIOExtensionsはプロパティ アドレスエレメントを カスタムのプロパティ名にコード化し 旧来のやり方が可能になります まずは 文字の 4cc_で 次にセレクターとスコープとエレメントが 4文字コードでアンダースコアにより 分けられています この方法なら どんな文字列やデータ値も Appのレイヤーに伝えられます
AVFoundationはカスタムの プロパティでは使えないので コンフィグレーションAppが カスタムのプロパティを扱うなら CoreMedia IO C APIを使わなければなりません かなり高度な APIのお話でした それでは出力デバイスについてです
DAL plug-inの機能であまり知られていないのは カメラの反対 つまり 出力デバイスを提示する機能で Appから動画をリアルタイムで吸収するものです これが CoreMedia IOの“O”の部分です インプットとアウトプットです 出力デバイスはプロビデオの 世界では馴染みのあるものです 一般的な用途には ビデオ信号が 外部レコーダーに送られるprint-to-tapeや SDI入力を持つ放送機材である リアルタイムプレビューモニターです
出力デバイスについて1つ覚えておきたいのは AVFoundation APIに 相当するものがないという事です 出力デバイスにフレームを送るには CoreMedia IO C APIを 直接使わなければなりません
CMIOExtensionストリームはソースかシンクの どちらかの指示で作成されます シンクストリームはAppからデータを摂取します クライアントがサンプルバッファをシンプルキューに 挿入し シンクストリームをフィードします それがExtensionでは consumeSampleBufferコールに変換され そのバッファを摂取すると notifyScheduledOutputChangedで クライアントに通知するわけです
出力デバイスに特化した ストリームプロパティはたくさんあります 主な例は キューの選別や スタート前のバッファへのフレーム数 そして全データが摂取された時の合図などです
それでは本日最後の5つ目のトピックに入ります
先ほどDAL plug−inのアーキテクチャの ダイアグラムをお見せした時 その安全性の問題の多さを強調しましたね Camera Extentionsでこの欠点に向き合い 我々は今も全力を上げて開発を続けています これから進むべき道です DAL plug−inはどうなるのでしょうか? 終りが近いという事です
macOS 12.3からDAL plug-insは既に非奨励で 作成時にコンパイル警告が出ます 良い方向に行っていますがまだ不十分です 旧来の DAL plug-inの取り込みが 許可されている限り カメラAppは今でもリスクを負っています
セキュリティの脆弱性に取り組み システムを全ユーザーにとって屈強にするに macOS Ventura後の次のメジャーリリースで DAL plug-inを完全に無効にする予定です
つまり今後どうすべきでしょう? それは明らかだと思います 今現在 DAL plug-inを使用されているなら 今こそコードを Camera Extensionに 移し始めましょう
そして問題が発生した場合はお知らせください 問題解決に取り組み リッチな機能セットを提供していきます 皆さんと一緒に取り組んでいきたいと思います macOSのためのカメラExtensionについて 本日の発表はこれで終了です Macに新しくクリエイティブな カメラExtensionが生まれるのを 非常に楽しみにしています
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。