
-
Apple Projected Media Profileについて
Apple Projected Media Profile(APMP)の詳細と、Video Extended Usageシグナリングを活用することでQuickTimeファイルやMP4ファイルにおける180度/360度およびWide FoVのプロジェクションを実現する、APMPの機能について解説します。OSに用意されたフレームワークとツールを使用して、APMPを含むメディアの変換、読み書き、編集、エンコードを行う方法のガイドを提供します。また、高度なイマーシブ体験を実現する空間オーディオコンテンツの作成と提供を可能にする、Apple Positional Audio Codec(APAC)の機能についても触れます。
関連する章
- 0:00 - イントロダクション
- 1:12 - 非直線投影ビデオの基本知識
- 3:42 - Apple Projected Media Profileの仕様
- 5:59 - APMPでのコンテンツキャプチャとワークフロー
- 8:33 - アセット変換機能
- 10:45 - APMPビデオの読み込み
- 11:47 - APMPビデオの編集
- 13:42 - APMPビデオの公開
- 16:14 - Apple Positional Audio Codec
リソース
- Apple HEVC Stereo Video Interoperability Profile
- AVFoundation
- Converting projected video to Apple Projected Media Profile
- Core Media
- HTTP Live Streaming
- HTTP Live Streaming (HLS) authoring specification for Apple devices
- QuickTime and ISO Base Media File Formats and Spatial and Immersive Media
- Using Apple’s HTTP Live Streaming (HLS) Tools
関連ビデオ
WWDC25
WWDC22
WWDC21
-
このビデオを検索
こんにちは Jonです Core Media Spatial Technologiesチームの エンジニアを務めています このビデオでは QuickTimeファイルでの 非直線投影ビデオの表示方法の 基礎について説明します またCore Media、Video Toolbox、 AVFoundationの各フレームワークに 導入された新機能を紹介します これらの機能は Apple Projected Media Profile(APMP)ビデオの 読み込み、作成、編集、公開に使用できます 最後に Apple Positional Audio Codecを 使用して投影されるビデオメディアに イマーシブな空間オーディオを 取り入れる方法を解説します このセッションは 180度/360度/ ワイドFoVカメラのベンダーの方、 ビデオ編集ソフトを扱うデベロッパの方、 注目の新しいメディアでの開発に 興味のあるアプリデベロッパの方に 最適な内容です また「Explore video experiences for visionOS」のビデオでは visionOS 26で利用できる イマーシブなビデオプロファイルや ビデオ投影の概念についての 重要な基本情報を説明しています まず 非直線投影ビデオの 基礎を確認しましょう この内容は「Explore video experiences for visionOS」でも紹介されています visionOS 26の新機能である Apple Projected Media Profileは コンシューマー向けカメラで撮影された 180度/360度/ワイドFoVビデオを サポートしています 各種の投影メディアプロファイルの間での 主な相違点の1つは 投影の種別です 2Dビデオ、3Dビデオ、空間ビデオでは 直線投影が使用されます 180度ビデオでは 半正距円筒図法が使用されます 360度ビデオでは正距円筒図法が ワイドFoVビデオでは パラメトリック投影が使用されます 正距円筒図法は 等距円筒図法とも呼ばれ Final Cut Proなど 多くの編集アプリでサポートされています 正距円筒図法では 外接球のピクセル座標は 緯度と経度の角度として表現され 長方形のビデオフレームの行と列に 均等に投影されます 水平軸は -180度から+180度で 経度をマッピングします 垂直軸は -90度から+90度で 緯度をマッピングします 半正距円筒投影も同様ですが ビデオフレーム内のX座標の範囲は -90度から+90度です パラメトリックイマーシブ投影では 広角レンズや魚眼レンズに関連する 内部パラメータや レンズによる歪みのパラメータを使います 内部パラメータは 撮影に使用したレンズシステムの 焦点距離、光学中心、 レンズによる歪みなどの情報を表します これらのパラメータは 3×3の行列として解釈されます この行列は通常 Kと表記され 3次元の世界座標を 画像平面上の2次元座標に 変換するために使用されます さらに パラメトリックイマーシブ投影では 放射状歪みなどの レンズによる 歪みのパラメータを表現できます 放射状歪みのパラメータは 樽型歪みの補正に使用されます 樽型歪みは 光学中心からの距離に比例して 直線が曲がって見えるもので 広角レンズの設計上生じる歪みです この画像では 垣根の柱が レンズの端の近くでは曲がって見えています 他のレンズ歪みの特性には 接線歪み、 投影オフセット、ラジアル角度の制限、 レンズフレームの調整などがありますが パラメトリックイマーシブ投影では それらも指定できます
以上は基本知識の説明でしたが ここからは AppleのAPIを使用して Apple Projected Media Profileコンテンツの 情報を扱う方法を概説します
まず QuickTimeやMP4のムービーファイルで APMPビデオが どのように扱われるかについて説明します Apple Projected Media Profile(APMP)は QuickTimeファイルやMP4ファイルで 180度/360度/ワイドFoVの 信号処理をサポートします QuickTimeファイルの構造は 幅広い種類の メディアデータのコンテナの 階層として構成されています それらの階層には オーディオトラックや ビデオトラックに加え 各トラックの 詳細を記述したデータも格納できます MP4のISO Base Media File Format (ISOBMFF)規格は QuickTimeを元に作られました ISOBMFFファイルにおける データ構造の基本単位はボックスです visionOS 1で導入されたVideo Extended Usage拡張ボックスでは コンテンツが ステレオスコピックかモノスコピックかを Stereo viewの情報で指定できます visionOS 26では Video Extended Usage (VEXU)に新しいボックスが追加され 投影メディアプロファイルの 信号処理が可能になりました Projectionボックスは各種の投影タイプの いずれかの信号に対応します 正距円筒図法、 半正距円筒図法、 パラメトリックイマーシブなどです Lens collectionボックスには パラメトリックイマーシブ投影の 内部パラメータ、外部パラメータ、 レンズによる歪みのパラメータが含まれます View packingボックスには フレームパック画像における 両眼の配置に関する情報 (横並びまたは縦並び)が含まれます これは モノスコピックの正距円筒図法 ファイルにおける最小限の信号処理の例です Projectionボックスの ProjectionKindの値は 正距円筒図法です ステレオスコピックの180度ビデオの ファイルでは Stereo viewボックスが必要で ProjectionKindで指定する信号処理は 半正距円筒図法です これらの構成要素を組み合わせることで ステレオスコピックの360度ビデオなど 他の信号処理も指定できます
QuickTime、ISOBMFF、空間メディア、 イマーシブメディアの規格の詳細や Apple Projected Media Profileが サポートする Projectionボックスおよび その他のボックスの詳細は developer.apple.com/jpでご確認ください 次に APMPコンテンツの撮影方法の概要と APMPの 標準的なワークフローについて説明します APMP対応のコンテンツは 様々な機種のカメラで撮影できます 例えばキヤノンのEOS VRシステムは ステレオスコピック180度ビデオの 撮影と処理が可能です GoPro MAXやInsta360 X5では 360度ビデオを撮影できます GoPro HERO 13やInsta360 Ace Pro 2などの 最新のアクションカメラでは ワイドFoVビデオを撮影できます Final Cut Proは 360度ビデオでのAPMPの 読み込みと書き込みをサポートしています そして 今年後半に登場する カメラビデオ編集ソフトウェアである キヤノンのEOS VR Utilityや GoPro Playerなどでは APMPの信号処理を行うMOVファイルや MP4ファイルのエクスポートが可能です 180度/360度ビデオの場合 スティッチング、手ぶれ補正、 ステレオ画像の補正などの処理には カメラベンダーのソフトウェアを使用します エディターが現時点でAPMP対応の場合 APMPの信号処理に対応した MOV/MP4ファイルとしてエクスポートします 最後に Apple Vision Proへのファイルの 転送には AirDropかiCloudを使用しましょう カメラのソフトウェアがAPMP未対応の場合 180度/360度ビデオとしてエクスポートを 実行するには 球面メタデータを使用し macOSのユーティリティである avconvertをコマンドラインから実行するか Finderで 1つ以上のビデオファイルを選択し controlキー+クリックで実行します 最後に AirDropかiCloudを使って ファイルをApple Vision Proに転送します Apple Projected Media Profileは 撮影、編集、配信を含む メディアワークフロー全体における 投影ビデオの信号処理に適した形式です 次に説明するのは APMPの信号処理を 各ステップで使用できる ステレオスコピックの180度ビデオの ワークフローの例です コンテンツをHEVC、RAW、ProResの コーデックで撮影してから ProResを使用して編集します 3Dコンテンツの撮影と編集に使えるのは フレームパック方式、マルチビュー方式、 片眼ごとの別個のムービーファイル、1つの ムービーファイルとして信号処理される 2つのビデオトラックです この例では 撮影にムービーファイルが2つ必要ですが 編集は横並びの フレームパックのコンテンツで行っています エンコードと公開には マルチビューHEVC (MV-HEVC)コーデックを使うことで visionOSでの効率的な 配信と再生を実現しています ここまで APMPの規格と 標準的なワークフローについて説明しました 次は macOS 26とvisionOS 26向けの 新機能である 既存のメディアAPIによる APMPファイルの処理について説明します まずはアセット変換機能です メディアワークフロー関連アプリの デベロッパがAPMPの信号処理を導入するのは 時間がかかるため Spherical Metadata V1/V2の信号処理を使用する 互換アセットを認識する機能を AVFoundationに追加しました 互換性のある180度/360度コンテンツとは 正距円筒図法による投影を行う ステレオスコピックまたはモノスコピックの フレームパック方式のコンテンツです アセット作成のオプションとして ShouldParseExternalSphericalTagsを渡すと 互換性のある球面コンテンツが認識され 適切なフォーマット記述のExtentionが 合成されます これにより 他のシステムAPIが 当該のアセットを APMPで信号処理される アセットとして扱えるようになります formatDescription.extentionsに convertedFromExternalSphericalTagsが 指定されていれば 球面メタデータが 解析されたことが確認できます visionOS 26には GoProやInsta360などの カメラベンダー向けに レンズ投影パラメータや一般的な視野モードの ネイティブサポートが組み込まれています QuickLookではそれらのファイルを開く際 変換するよう求められます アプリでワイドFoVコンテンツの変換を 有効にするために使用するのは ImmersiveMediaSupportフレームワークの ParametricImmersiveAssetInfoオブジェクトです このオブジェクトは 互換性のあるカメラに対し パラメトリックイマーシブ投影の 投影種別と 内部パラメータおよび レンズ歪みのパラメータを含む ビデオフォーマットの記述を生成します isConvertibleプロパティを使用すると 互換性のあるカメラのメタデータが 検出されたかどうかを判断し ビデオトラックのフォーマット記述を 新しく生成された記述で 置き換えることができます これで このアセットを使用するシステムAPIが コンテンツをワイドFoV APMPと認識します サンプルコード「Converting projected video to Apple Projected Media Profile」では 配信可能なAPMPフォーマットへの 変換方法を確認できます APMPビデオは 広く利用されている システムのメディアAPIで読み込めます CoreMediaフレームワークと AVFoundationフレームワークが更新され 投影メディアの識別と読み込みの サポートが追加されました アセットがAPMPプロファイルに 準拠しているかを確認する必要がある場合 例えば バッジの表示や 個別の再生の設定を行うために 準拠を確認したい場合は AVAssetPlaybackAssistantを使用して nonRectilinearProjectionの 構成オプションをチェックします APMPビデオの再生体験を 構築する方法について詳しくは 「Support immersive video playback in visionOS apps」をご覧ください
より詳細を確認したい場合は まずmediaCharacteristicsを調べ そのビデオトラックで 非直線投影が指定されているか確認します 次にprojectionKindを調べて 適切な投影の信号処理が 指定されているか確認します フォーマット記述Extentionの viewPackingKindにより フレームパックコンテンツか判断できます この場合 横並びと縦並びの フレームパッキングがサポートされます 投影メディアを編集するには AVFoundationフレームワークの AVVideoCompositionオブジェクトを使います また CMTaggedBuffersの理解も必要です CMTaggedDynamicBufferは 複数のAPIにわたって使用され ステレオスコピックコンテンツを処理します 対象のAPIには AVVideoCompositionなど 編集に関するAPIが含まれます CMTaggedDynamicBufferは 基盤となるバッファの CMタグと呼ばれる特定のプロパティを 指定するために使用されます 各CMタグにはカテゴリと値が含まれます この例では CMタグのStereoViewカテゴリは 左眼であることを示しています
CMTaggedDynamicBufferは 関連するバッファごとにグループ化できます この例では ステレオスコピックビデオの CVpixelBufferの左眼と右眼で グループ化しています AVVideoCompositionで ステレオスコピックビデオを編集できるよう 追加したのが コンポジタが生成する タグ付きバッファのフォーマットを 指定するためのAPIと コンポジションリクエストに タグ付きバッファを渡すためのメソッドです outputBufferDescriptionは コンポジタが生成するCMTaggedBuffersの 種類を指定します 合成を開始する前に定義します CMTaggedBufferの ステレオスコピックペアを構築してから finishを呼び出して タグ付きバッファを渡します
Apple Projected Media Profileアセットの 変換、読み込み、編集を 行う方法について説明しました 次は 書き込みのプロセスを説明します
モノスコピックの360度ビデオを書き込む このサンプルコードでは アセットの作成に AVAssetWriterを使用しています CompressionPropertyKeyを使用して ProjectionKindに 半正距円筒図法を指定しています 圧縮のプロパティは AVAssetWriterInputに渡されますが これにはoutputSettingsの辞書プロパティの AVVideoCompressionPropertiesKeyを使います
次に APMPコンテンツの公開に関する 推奨事項を紹介します
これらは visionOSでの再生における 推奨条件です ビデオコーデックのエンコードパラメータは HEVC MainまたはMain 10に準拠させます クロマサンプリングは4:2:0です 推奨されるカラープライマリは Rec.709またはP3-D65です ステレオモードは モノスコピックも ステレオスコピックも可です 10ビットでの推奨解像度は モノスコピックでは7680×3840 ステレオスコピックでは 片眼あたり4320×4320です フレームレートは解像度や ビット深度により異なりますが 推奨値は 10ビットのモノスコピック8K または ステレオスコピック4Kの場合 30fpsです ビットレートのエンコード設定は コンテンツによって異なり 用途に応じて 適切に選択する必要がありますが ピーク時でも150Mbps以下が推奨です Appleが使用している MV-HEVCステレオビデオの詳細は developer.apple.com/jpのドキュメント 「Apple HEVC Stereo Video Interoperability Profile」で 確認できます Advanced Video Quality Tool(AVQT)が アップデートされ 3Dビデオ、空間ビデオ、 APMPの180度/360度コンテンツなど イマーシブフォーマットのサポート追加と 精度向上のためのアルゴリズム強化が 行われました AVQTは 圧縮された映像コンテンツの 知覚上の品質の評価と ビデオエンコーダのパラメータの 微調整に役立ちます また HLSの各ティアにおける ビットレート最適化にも有効です その他の新機能として 正距円筒図法と 半正距円筒図法での投影に対応した 品質メトリックスの算出機能があります HTTP Live Streamingの規格は Apple Projected Media Profileの ストリーミングに対応するよう 強化されており Apple Developer Webサイトで入手できる 最新のHLSツールも APMPの配信をサポートするように アップデートされています これは ステレオスコピック180度アセットの マニフェストの一例です 主な変更点は EXT-X-STREAM-INFタグです REQ-VIDEO-LAYOUT属性は ステレオおよび半正距円筒図法の 投影を指定しています マップセグメントには 半正距円筒図法の 信号処理を示すProjectionと Stereo viewの情報を指定する フォーマット記述のExtentionが必要です HLSのビットレートに関するティアの階層や その他のオーサリングガイドラインに関する 最新情報は Apple Developer Webサイトの 「HLS Authoring Specification」を ご覧ください 空間オーディオは魅力的な イマーシブ体験の構築において 映像と同じくらい重要です 実世界では 音はあらゆる方向から聞こえてきます そのような体験を再現するには 音場全体を表現できる 技術が必要です この目的のために設計されたのが Apple Positional Audio Codecs(APAC)です APACの重要な機能の1つが 音場を高忠実度で再現するための アンビソニック音声のエンコーディングです アンビソニック音声は 全方位の空間オーディオを 録音、ミキシング、再生するための技術です
アンビソニック録音は 特定のスピーカー配置に依存しません 球面調和関数という基底関数を用いて 音場を数学的にエンコードするためです
アンビソニック音声の収録では 3D音響環境の録音用に配置された マイクロフォンアレイを使用します さらに デジタル信号処理によって 各マイクの信号を 球面調和成分に対応する 指向性の信号へと変換します これらすべての信号を組み合わせることで オリジナルの音場を 正確に再現できます アンビソニックスにおける「次数」とは 音声ミックスを表現するために使用される 球面成分の数を指します 1次アンビソニックスは4つの成分 つまり4チャンネルで構成され 全指向性のチャンネル1つと 前後、左右、上下の指向性を持つ 3つのチャンネルに 対応しています 2次アンビソニックスは9つの成分を 3次アンビソニックスは 16の成分を使用します 高次のアンビソニックスは より高い空間分解能を有します Apple Positional Audio Codecは 高効率な空間オーディオコーデックであり APMPビデオとアンビソニックスを使用する 空間オーディオのエンコードにおいて 使用が推奨されます APACは watchOSを除くすべての Appleプラットフォームでデコードされます 組み込みのAPACエンコーダは iOS、 macOS、visionOSの各プラットフォームで AVAssetWriterを通じて利用でき 1次、2次、3次アンビソニックスを サポートします このコードは AVAssetWriterを使用した 1次、2次、3次アンビソニックスの エンコードに必要な 最小限の出力設定を示しています APMP用にAPACにエンコードされた アンビソニックスの推奨ビットレートは 1次の場合で384kbps 3次の場合で768kbpsです APACオーディオは HLSによる セグメント化とストリーミングが可能です この例は APACオーディオで 3次アンビソニックトラックをエンコードした 正距円筒図法を使用する モノスコピックビデオを示しています
Apple Projected Media Profileについての 説明は以上です ご自身のアプリやサービスに APMPのサポートを追加し イマーシブなユーザー生成コンテンツを さっそく再生、編集、共有しましょう カメラベンダーの方は APMPを適宜統合することで Appleのエコシステムでの再生を サポートできます Apple Positional Audio Codecを採用し アンビソニックマイクで収録した音声を イマーシブビデオと組み合わせて 臨場感あふれる音声環境を提供しましょう ご視聴ありがとうございました 私も ステレオスコピック180度ビデオの 撮影にこれからさっそく出かけます
-
-
8:58 - Recognize spherical v1/v2 equirectangular content
// Convert spherical v1/v2 RFC 180/360 equirectangular content import AVFoundation func wasConvertedFromSpherical(url: URL) -> Bool { let assetOptions = [AVURLAssetShouldParseExternalSphericalTagsKey: true] let urlAsset = AVURLAsset(url: url, options: assetOptions) // simplified for sample, assume first video track let track = try await urlAsset.loadTracks(withMediaType: .video).first! // Retrieve formatDescription from video track, simplified for sample assume first format description let formatDescription = try await videoTrack.load(.formatDescriptions).first // Detect if formatDescription includes extensions synthesized from spherical let wasConvertedFromSpherical = formatDescription.extensions[.convertedFromExternalSphericalTags] return wasConvertedFromSpherical }
-
9:54 - Convert wide FOV content from supported cameras
// Convert wide-FOV content from recognized camera models import ImmersiveMediaSupport func upliftIntoParametricImmersiveIfPossible(url: URL) -> AVMutableMovie { let movie = AVMutableMovie(url: url) let assetInfo = try await ParametricImmersiveAssetInfo(asset: movie) if (assetInfo.isConvertible) { guard let newDescription = assetInfo.requiredFormatDescription else { fatalError("no format description for convertible asset") } let videoTracks = try await movie.loadTracks(withMediaType: .video) guard let videoTrack = videoTracks.first, let currentDescription = try await videoTrack.load(.formatDescriptions).first else { fatalError("missing format description for video track") } // presumes that format already compatible for intended use case (delivery or production) // for delivery then if not already HEVC should transcode for example videoTrack.replaceFormatDescription(currentDescription, with: newDescription) } return movie }
-
10:58 - Recognize Projected & Immersive Video
// Determine if an asset contains any tracks with nonRectilinearVideo and if so, whether any are AIV import AVFoundation func classifyProjectedMedia( movieURL: URL ) async -> (containsNonRectilinearVideo: Bool, containsAppleImmersiveVideo: Bool) { let asset = AVMovie(url: movieURL) let assistant = AVAssetPlaybackAssistant(asset: asset) let options = await assistant.playbackConfigurationOptions // Note contains(.nonRectilinearProjection) is true for both APMP & AIV, while contains(.appleImmersiveVideo) is true only for AIV return (options.contains(.nonRectilinearProjection), options.contains(.appleImmersiveVideo)) }
-
11:22 - Perform projection or viewPacking processing
import AVFoundation import CoreMedia // Perform projection or viewPacking specific processing func handleProjectionAndViewPackingKind(_ movieURL: URL) async throws { let movie = AVMovie(url: movieURL) let track = try await movie.loadTracks(withMediaType: .video).first! let mediaCharacteristics = try await track.load(.mediaCharacteristics) // Check for presence of non-rectilinear projection if mediaCharacteristics.contains(.indicatesNonRectilinearProjection) { let formatDescriptions = try await track.load(.formatDescriptions) for formatDesc in formatDescriptions { if let projectionKind = formatDesc.extensions[.projectionKind] { if projectionKind == .projectionKind(.equirectangular) { // handle equirectangular (360) video } else if projectionKind == .projectionKind(.halfEquirectangular) { // handle 180 video } else if projectionKind == .projectionKind(.parametricImmersive) { // handle parametric wfov video } else if projectionKind == .projectionKind(.appleImmersiveVideo) { // handle AIV } } if let viewPackingKind = formatDesc.extensions[.viewPackingKind] { if viewPackingKind == .viewPackingKind(.sideBySide) { // handle side by side } else if viewPackingKind == .viewPackingKind(.overUnder) { // handle over under } } } } }
-
12:51 - Specify outputBufferDescription for a stereoscopic pair
var config = try await AVVideoComposition.Configuration(for: asset) config.outputBufferDescription = [[.stereoView(.leftEye)], [.stereoView(.rightEye)]] let videoComposition = AVVideoComposition(configuration: config)
-
13:01 - Finish an asyncVideoCompositionRequest with tagged buffers
func startRequest(_ asyncVideoCompositionRequest: AVAsynchronousVideoCompositionRequest) { var taggedBuffers: [CMTaggedDynamicBuffer] = [] let MVHEVCLayerIDs = [0, 1] let eyes: [CMStereoViewComponents] = [.leftEye, .rightEye] for (layerID, eye) in zip(MVHEVCLayerIDs, eyes) { // take a monoscopic image and convert it to a z=0 stereo image with identical content for each eye let pixelBuffer = asyncVideoCompositionRequest.sourceReadOnlyPixelBuffer(byTrackID: 0) let tags: [CMTag] = [.videoLayerID(Int64(layerID)), .stereoView(eye)] let buffer = CMTaggedDynamicBuffer(tags: tags, content: .pixelBuffer(pixelBuffer!)) taggedBuffers.append(buffer) } asyncVideoCompositionRequest.finish(withComposedTaggedBuffers: taggedBuffers) }
-