View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

その他のビデオ

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • トランスクリプト
  • コード
  • AVFoundationとVideoToolboxを使ったDecode ProRes

    Mac AppでProResコンテンツをより簡単にデコードおよび表示する方法: AVFoundationとVideoToolboxのデコード機能を活用して、最適なグラフィックパイプラインを実装する方法について学びます。Appのベストプラクティスとパフォーマンスに関する考慮事項を共有し、Afterburnerカードをパイプラインに統合する方法およびMetalを使用してデコードされたフレームを表示する方法について説明します。

    リソース

    • AVFoundation
      • HDビデオ
      • SDビデオ
  • ダウンロード

    こんにちは ようこそWWDCへ “AVFoundationとVideoToolboxを使った Decode ProRes” セッションへ ようこそ 今日の目標は ProResなどの映像ファイルから― アプリケーションへのパスを 最適化することです

    例えばMetalレンダリングエンジンに 映像編集アプリケーションがあるとします ユーザに最高のProResコンテンツを アプリケーション内で提供したいと考えた時

    目指すべきゴールは2つです Afterburnerのような ハードウェアデコーダの活用と 圧縮データのフローや デコーダから出力されたフレーム用に― 最適で効率的なパスを持つことです まずはアプリケーションへ映像を統合する際の いくつかの概要の説明です 次にAVFoundationの機能について話しますが

    この方法が合わない人もいるでしょう そこで圧縮サンプルを 構築する方法を説明します Video Toolboxで 独自にデコードさせる場合です

    そしてVTDecompressionSessionの 使い方の説明 最後はデコードしたビデオフレームを Metalと統合する方法です

    それでは我々のプラットフォームで 映像操作の基本を説明します まず映像デコーダについてお話しします 映像デコーダは様々なソースの ビットストリームの解析を行います ユーザによる管理は完全ではなく 不正な形式のメディアで アプリケーションが不安定になったり ぜい弱性が原因で セキュリティ問題が発生します

    防御策としてVideo Toolboxは sandboxのサーバ内でデコードを実行

    特別なプロセスで実行することで セキュリティが向上し― アプリケーションの安定性も向上します クラッシュ時もアプリケーション全体は壊れず デコードエラーのみで済みます それではmacOSのメディアスタック― 特に映像についてお話しします

    まずはAVKitがあります AVKitはアプリケーションに映像機能を入れる ハイレベルなオプションを提供してくれます 我々は既存のレンダーパイプラインを 使うのでAVKitは使いません AVFoundationが様々なメディアのために 優秀なインターフェイスを提供してくれます いくつかのインターフェイスを紹介する予定です

    引き続きVideo Toolboxについてですが 映像のデコードとエンコードの際に インターフェイスを提供します

    Core Mediaフレームワークは基本的な ビルディングブロックを提供してくれます Core Videoは映像に特化した ビルディングブロックを提供してくれます 今回は3つのフレームワークの インターフェイスに注目します AVFoundationとVideo Toolbox そしてCore Videoです AVFoundationではAVAssetReaderと AVSampleBufferGenerator Video Toolboxでは VTDecompressionSessionに注目します 最後にCore Videoでは CVPixelBuffersと― Metalを使ったCVPixelBufferPoolsに注目します

    異なるAPIレベルを機能させる際の 懸念点を見てみましょう

    現在のOSのバージョンでは― インターフェイスによる自動的な ハードウェアデコードが可能です Afterburnerの有効化も同様です デコードの有効化と無効化は 選択可能ですが― デフォルトではすべて自動なのです

    デコーダの異なるプロセスでの 実行方法は前述しましたが CMSampleBufferが AVFoundationで作成された場合 自動的にフォームになります RPCの境界を越えて 最適化され生成されるのです VTDecompressionSessionを 直接使用する場合 RPCとは関係なくCMSampleBuffersの 生成方法に依存することになります CMSampleBufferの生成については あとで詳しく説明します

    次は用語の説明に移りましょう まずはCVPixelBufferですが 解凍されたラスタ画像データに対する ラッパーとしての役目があります ピクセル形式 高さ 幅 行バイト ピッチなどのプロパティを持つデータです さらにカラータグのような画像データの アタッチメントも含みます

    次にCMBlockBuffer これはCore Mediaフレームワークですが 圧縮されたサンプルデータなど 任意のデータをラップする― 基礎的な役割があります

    そしてCMSampleBuffer これは主に3つの特色を持っています 1つ目は圧縮された映像または 音声データを含む― CMBlockBufferをラップできるということ

    2つ目は非圧縮のラスタ画像データを含む― CVPixelBufferをラップできること

    見てのとおり どちらもCMTimeを含んでいます CMTimeはデコードのタイムスタンプなどを 表すものです さらにSampleBuffer内のフォーマットを示す CMFormatDescriptionもあります

    3つ目の特色は アタッチメントが保持できることで 3種類目のCMSampleBufferとなります CMBlockBufferもCVPixelBufferも 含まない標準のCMSampleBufferです 特殊な条件のメディアパイプラインを通じて 時限化されたアタッチメントが存在します

    次はIOSurfaceです IOSurfaceは画像データに使われる メモリに関する巧妙な抽象化です 先ほどラスタデータの話をしましたが このデータは IOSurfaceのフォームに存在しています

    IOSurfaceはMetalにおける メモリ構造の基礎としても使用可能です

    さらにフレームワーク間のメモリの移動を 効率化することもできます 例えばsandbox化されたデコーダと 皆さんのアプリケーション間の移動 またはGPUが異なるVRAMなど 異なるメモリ領域間でも移動が可能です

    そして最後の用語はCVPixelBufferPoolです これはCore Video由来のオブジェクトで 画像データ用のバッファを 効率的にリサイクルしてくれます

    多くの場合CVPixelBufferは IOSurfaceをラップします CVPixelBufferがプールからリリースされ 使用されない場合 IOSurfaceはCVPixelBufferPoolに戻ります ゆえに次に移動してきたCVPixelBufferが そのメモリを使用できるのです つまりCVPixelBufferPoolはCVPixelBufferと 同様の特徴を持つということです ピクセル形式 高さ 幅 そして行バイトとピッチです

    次にAVFoundationで できることをお話ししましょう やりたいことは何でしたか? ProResの映像ファイルと Metalレンダリングエンジンがあり― 映像からフレームを取得して レンダラーへ移したい AVAssetReaderがすべてを実現します まずサンプルを読み込み― Video Toolbox内で RPC用に最適化します そしてsandbox内で映像データをデコードし― デコードされたCVPixelBufferを 希望のフォーマットで提供します

    AVAssetReaderの構築は とても簡単です まずはURLを使いローカルにある映像への AVAssetを作成

    そのAVAssetを用いて AVAssetReaderを作りますが この状態ではまだ使えません

    AVAssetReaderでデコードデータを 要求するには AVAssetReaderTrackOutputを設定します まず映像トラックが必要です ここではすべての配列を取得しており― 最初のトラックを選択しています この設定は各自で異なるでしょう

    その選択に基づき AVAssetReaderTrackOutputを構築します ここでは16ビット 4:4:4:4 YCbCrアルファ もしくは Y416へ戻すように アウトプットの設定をします これはProRes 4444と共に使用する 優れたネイティブフォーマットです 次にサンプルを戻す際のコピーの回避を AVAssetReaderTrackOutputに設定 これにより効率化を望めますが― 戻されたCMSampleBufferが 別の場所に保管されることもあります これは変更することができません

    最後に このアウトプットを AVAssetReaderに追加します 動作はとてもシンプルです 最も簡単な設定でお見せしましょう まずは 読み込み開始です

    次にcopyNextSampleBufferを 繰り返し実行 デコード済みのアウトプットを設定したので CVImageBufferへの CMSampleBufferデータをチェック 画像バッファのないCMSampleBufferが あっても問題ありません AVAssetReaderを使えば このような単純な反復より― より高度な動作が可能になります もしレンダラーがデコーダに適した フォーマットのバッファを消費できれば 映像パイプラインは最も効率的になります AVAssetReaderはデコーダが サポートしていないフォーマットを指定した場合 アウトプットを 希望のフォーマットに変換します ただしバッファコピーを回避すれば アプリケーションは大幅に改善します 変換不能なアウトプットの選択に関する ガイドラインを紹介します 先ほどのAVAssetReaderOutputの 例を見てみましょう 16ビット 4:4:4:4 YCbCrアルファ またはY416のバッファを元に戻すことにします ProRes 4444を使用する際の 最適なフォーマットです ProRes 422に対しては16ビット 4:2:2 YCbCrもしくはv216が― 最も標準的なデコーダフォーマットです さらにProRes RAWにはRGBA half-float もしくはRGhAが標準的です

    AVAssetReaderにすべてを 委ねたくない場合もあります その場合はCMSampleBufferを Video Toolboxにパスする必要があります 3つのオプションを紹介します 1つ目は先ほどの説明どおり AVAssetReaderを使います しかしデコードせずに 圧縮データを得ることができます 編集とフレームの関係と共に トラックレベルのアクセスが得られます

    2つ目はAVSampleBufferGeneratorです 編集とフレームとは無関係に メディアレベルでサンプルにアクセスできます 3つ目はCMSampleBufferを 自ら構築することです

    AVAssetReaderにサンプルを生成させ AVAssetから圧縮データを得るのです AVAssetReaderでトラックレベルの 読み込みを行い― フレームを表示させるために必要な すべてのサンプルを取得します さらにAVAssetReaderは RPC用に最適化されたサンプルを提供し フレーム送信時の sandboxのオーバーヘッドを削減します

    AVAssetReaderから生の圧縮アウトプットを 得るためには AVAssetReaderを構築するだけでよいのです しかしAVAssetReaderTrackOutputを 構築する際は ピクセル形式のディクショナリは指定せず 出力設定をnilに設定します

    AVSampleBufferGeneratorはAVAssetTrackの メディアからサンプルを提供します AVSampleBufferCursorを使い メディアを読み取る位置を制御します フレームの依存関係は関係ないため ProResの利用も可能になります しかしHEVCやH.264など フレーム間依存のあるコンテンツで― 使用する場合は注意が必要です AVSampleBufferGeneratorの作成過程を 簡単なコードで示します まず サンプルの実行用に AVSampleCursorを作成します AVSampleBufferRequestも 作成しなければなりません 実際のサンプルリクエストを記述します

    AVAssetのソースを使い AVSampleBufferGeneratorを作成

    ここでタイムベースをnilに設定すると 同期が実行されます AVSampleBufferGeneratorの 最適なパフォーマンスには― タイムベースを指定し リクエストを非同期で実行します 最後にcreateSampleBufferForRequestで ループさせます 同時にカーソルを1フレーム進めます 繰り返しますが これは最も単純な同期操作で― 最適なパフォーマンスを得るには 非同期版を使います 最後は自らCMSampleBufferを作成する方法です 独自のファイルを読み込んだり 別のソースからデータを得る場合 サンプルデータはsandbox RPCの変換の際には 最適化されません 先ほどCMSampleBufferの構成要素を 説明しました CMBlockBufferにデータが存在しており CMFormatDescriptionと タイムスタンプがあります まずCMBlockBufferで サンプルデータをパックします

    次にデータ記述のため CMVideoFormatDescriptionを作成 ここに拡張ディクショナリの カラータグを含めます ビデオの色の管理を適切に行うためです

    次にCMSampleTimingInfoの構造に タイムスタンプを作成 最後にCMBlockBufferと CMVideoFormatDescription― CMSampleTimingInfoを使い CMSampleBufferを作成します

    以上で皆さん自身でCMSampleBufferのための ソースを作成できました 次はVideo Toolboxです VTDecompressionSessionの構造を見てみましょう 当然ながら映像デコーダがあります そして別々のsandboxプロセスを実行します このCVPixelBufferPoolは― デコードされたフレームの バッファ作成用に使用されています

    デコーダが提供できる形式と異なる 形式での出力を指定した時のために 変換を行うVTPixelTransferSessionが存在します もしアプリケーションが特殊なデコーダに アクセスする必要がある場合 VTRegisterProfessionalVideoWorkflow VideoDecodersを呼び出す必要があります この操作は1回のみで結構です VTDecompressionSessionの使用はシンプルです まずVTDecompressionSessionを作成 次にVTSessionSetPropertyを通じて VTDecompressionSessionに― 必要なすべての設定を実施します 必要ない場合もあります

    最後にVTDecompressionSessionDecode FrameWithOutputHandlerを記述 単純にVTDecompression SessionDecodeFrameでも結構です

    DecodeFrameの呼び出しで 非同期デコードを有効にすることをお勧めします VTDecompressionSession作成の詳細です 注目すべき3つのオプションがあります まずはvideoFormatDescriptionです VTDecompressionSessionに コーデックを伝える役目を持ち CMSampleBuffer内のフォーマットの 詳細を提供します このフォーマットはCMSampleBufferの― CMVideoFormatDescriptionと 一致させる必要があります

    次にdestinationImageBufferAttributesです pixelBufferの要求を示しています Video Toolboxでサイズ設定する場合に ここに含めることが可能です レンダリングエンジンの要求があれば 特定のピクセル形式も含めることができます 8ビットRGBサンプルの消費方法しか 分からない場合もここで指定します

    Core Animationの出力の要求など 高レベルのディレクティブにもなります

    次はvideoDecoderSpecificationです デコーダの選択にヒントを与えてくれます デフォルト以外のハードウェアデコーダも 指定可能です

    ハードウェアデコーダと言えば 現行バージョンのOSでは― ハードウェアデコーダの使用は サポートされるすべてのフォーマットで有効です これはオプトインだった数年前とは異なります 現在のOSではハードウェアコーデックが オプトインの必要なく使用可能です VTDecompressionSessionに確実に ハードウェアデコーダをセットしたい場合 また失敗した際にエラーを出したい場合は RequireHardwareAcceleratedVideoDecoderの オプションをtrueに設定します

    ハードウェアを無効にして ソフトウェアデコーダを使用する場合は EnableHardwareAcceleratedVideoDecoderの オプションをfalseに設定します 酷似していますね RequireHardwareAcceleratedVideoDecoderと EnableHardwareAcceleratedVideoDecoderです サンプルでVTDecompressionSession作成の 基本を見ましょう まず希望のデータの種類を伝えるための formatDescriptionが必要です CMSampleBufferから 取り出してsessionにパスしましょう 特定のピクセル形式の出力には― pixelBufferAttributesディクショナリの 作成が必要です 先ほどのAVAssetReaderと同様に 16ビット 4:4:4:4 YCbCrアルファを 指定するとします そしてVTDecompressionSessionを作成 3番目のパラメータにはNULLを設定します videoDecoderSpecificationの部分です Video Toolboxがデフォルトで ハードウェアデコーダを選択します

    VTDecompressionSessionができたら DecodeFrameの呼び出しに進みます 最適なパフォーマンスのために デコードフラグとしてKVTDecodeFrameEnable AsynchronousDecompressionフラグを設定します

    VTDecompressionSession DecodeFrameWithOutputHandlerは 圧縮されたサンプルバッファを取得します inFlagsをデコーダの挙動管理として記述し デコード動作の結果として 出力ブロックが呼び出されます VTDecompressionSessionDecodeFrame WithOutputHandlerがエラーにならない限り 出力ブロックはデコードの結果として 呼び出されます CVImageBufferもしくはデコーダエラーです 圧縮アウトプットの注意点ですが デコードのアウトプットはシリアル化されます 一度にデコーダから戻される フレームは1つだけです デコーダアウトプット内のブロックは フレームのアウトプットにも影響があり デコーダを通じて バックプレッシャーが起きます

    動作の実行はアウトプットブロックや コールバックの外で実施してください それではMetalを使った CVPixelBufferの説明に移ります その前にCVPixelBufferPoolの機能を おさらいしましょう 前述のとおりCVPixelBufferPoolから CVPixelBufferがリリースされた時に IOSurfaceはCVPixelBufferPoolに戻ります 次にCVPixelBufferがPoolから移動すると IOSurfaceは再利用され 新たなCVPixelBuffer用に使われます

    Metalで実行する際の失敗を避けるため このことを念頭に置くとよいでしょう Metalで利用する場合 IOSurfaceはリサイクルされません

    アプローチの方法は2通りあります まずはIOSurfaceを介して行う方法です MetalにはIOSurfaceを テクスチャリングに使用する方法があります そのためには特殊なケアが必要です

    次にCore Videoの CVMetalTextureCacheを経由する方法です 確実ではありませんが 簡単で安全な方法なので― パフォーマンス上の利点があります

    MetalでCVPixelBufferからの IOSurfaceを使うのは簡単に見えます しかしMetalで利用した場合 IOSurfaceが再利用されないトリックが あることを認識しましょう

    まずはCVPixelBufferから IOSurfaceを取得します それからMetalのテクスチャを作成します Metalの使用中は IOSurfaceは リサイクルされないことは分かっているので IOSurfaceIncrementUseCountを使います

    Metalが外れ IOSurfaceを リリースしてプールに戻すには MTLCommandBufferを設定し CommandBufferの完了後に実行します さらにIOSurfaceUseCountを デクリメントします

    インターフェイスを処理するために CVMetalTextureCacheを使います IOSurfaceとIOSurfaceUseCountを 手動で追跡する必要性を排除します

    そのため最初にCVMetalTextureCacheを 作成する必要があります ここで関連付けるMetalデバイスを指定

    CVPixelBufferに関連付けられた オブジェクトを作成するため CVMetalTextureCacheCreateTextureFromImageを 呼び出すことができます

    さらにCVMetalTextureCacheから 実際のMetalテクスチャを取得するには CVMetalTextureGetTextureを 呼び出すだけです

    最後にもう一度 注意してほしいのは― Metalコマンドバッファの完了時に ハンドラを設定することです CVMetalTextureをリリースする前に Metalが外れていることを確認します CVMetalTextureCacheは IOSurfaceテクスチャ結合の繰り返しを防ぎます CVPixelBufferPool由来のIOSurfaceが― 再利用され出現することで 少し効率的になります

    トピックのおさらいです ハードウェアデコードの取得タイミングと その制御法 AVAssetReaderを使うことにより― 映像デコーディングが容易に レンダリングパイプラインに統合できること CMSampleBufferの構築方法 AVAssetReaderが適していない場合 Video Toolboxで使用する方法

    最後にMetalでのCVPixelBufferの 使用方法を説明しました 皆さんの映像アプリケーションの向上に つながることを期待します ご視聴ありがとうございました

    • 7:41 - Creating an AVAssetReader is pretty easy

      // Constructing an AVAssetReader
      
      // Create an AVAsset with an URL pointing at a local asset
      AVAsset *sourceMovieAsset = [AVAsset assetWithURL:sourceMovieURL];
      
      // Create an AVAssetReader for the asset
      AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:sourceMovieAsset 
                                                                 error:&error];
    • 7:58 - // Configuring AVAssetReaderTrackOutput

      // Configuring AVAssetReaderTrackOutput
      
      // Copy the array of video tracks from the source movie
      NSArray<AVAssetTrack*>  *tracks = [sourceMovieAsset tracksWithMediaType:AVMediaTypeVideo];
          
      // Get the first video track
      AVAssetTrack *track = [sourceMovieVideoTracks objectAtIndex:0];
      
      // Create the asset reader track output for this video track, requesting ‘y416’ output
      NSDictionary *outputSettings = @{ (id)kCVPixelBufferPixelFormatTypeKey :
                                        @(kCVPixelFormatType_4444AYpCbCr16) };
      
      AVAssetReaderTrackOutput* assetReaderTrackOutput
      = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track
                                                   outputSettings:outputSettings];
      
      // Set the property to instruct the track output to return the samples 
      // without copying them
      assetReaderTrackOutput.alwaysCopiesSampleData = NO;
         
      // Connect the the AVAssetReaderTrackOutput to the AVAssetReader
      [assetReader addOutput:assetReaderTrackOutput];
    • 8:57 - Running AVAssetReader

      // Running AVAssetReader
      
      BOOL success = [assetReader startReading];
      
      if (success) {
         CMSampleBufferRef sampleBuffer = NULL;
              
         // output is a AVAssetReaderOutput
         while ((sampleBuffer = [output copyNextSampleBuffer]))
         {
             CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
                  
             if (imageBuffer)
             {
                // Use the image buffer here
                // if imageBuffer is NULL, this is likely a marker sampleBuffer
             }
          }
      }
    • 11:40 - Prepareing CMSampleBuffers for optimized RPC transfer

      AVAssetReaderTrackOutput* assetReaderTrackOutput
      = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track
                                                   outputSettings:nil];
    • 12:24 - How an AVSampleBufferGenerator is created

      AVSampleCursor* cursor = [assetTrack makeSampleCursorAtFirstSampleInDecodeOrder];
              
      AVSampleBufferRequest* request = [[AVSampleBufferRequest alloc] initWithStartCursor:cursor];
              
      request.direction = AVSampleBufferRequestDirectionForward;
      request.preferredMinSampleCount = 1;
      request.maxSampleCount = 1;
             
      AVSampleBufferGenerator* generator
      = [[AVSampleBufferGenerator alloc] initWithAsset:srcAsset timebase:nil];
      
      BOOL notDone = YES;
          
      while(notDone)
      {
         CMSampleBufferRef sampleBuffer = [generator createSampleBufferForRequest:request];
      
         // do your thing with the sampleBuffer
      
         [cursor stepInDecodeOrderByCount:1];
      }
    • 13:40 - Pack your sample data into a CMBlockBuffer

      CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, sampleData, sizeof(sampleData), 
                                         kCFAllocatorMalloc, NULL, 0, sizeof(sampleData), 0, 
                                         &blockBuffer);
      
      CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_AppleProRes4444, 1920, 
                                     1080, extensionsDictionary, &formatDescription);
      
      CMSampleTimingInfo timingInfo;
      
      timingInfo.duration = CMTimeMake(10, 600);
      timingInfo.presentationTimeStamp = CMTimeMake(frameNumber * 10, 600);
      
      CMSampleBufferCreateReady(kCFAllocatorDefault, blockBuffer, formatDescription, 1, 1, 
                                &timingInfo, 1, &sampleSize, &sampleBuffer);
    • 17:47 - VTDecompressionSession Creation

      // VTDecompressionSession Creation
      
      CMFormatDescriptionRef formatDesc = CMSampleBufferGetFormatDescription(sampleBuffer);
      
      CFDictionaryRef pixelBufferAttributes = (__bridge CFDictionaryRef)@{
          (id)kCVPixelBufferPixelFormatTypeKey :
          @(kCVPixelFormatType_4444AYpCbCr16) };
      
      VTDecompressionSessionRef decompressionSession;
          
      OSStatus err = VTDecompressionSessionCreate(kCFAllocatorDefault, 
                                                  formatDesc, 
                                                  NULL,
                                                  pixelBufferAttributes, 
                                                  NULL, 
                                                  &decompressionSession);
    • 18:30 - Running a VTDecompressionSession

      // Running a VTDecompressionSession
      
      uint32_t inFlags = kVTDecodeFrame_EnableAsynchronousDecompression;
      
      VTDecompressionOutputHandler  outputHandler
       = ^(OSStatus status,
           VTDecodeInfoFlags infoFlags,
           CVImageBufferRef imageBuffer,
           CMTime presentationTimeStamp,
           CMTime presentationDurationVTDecodeInfoFlags)
       {
           // Handle decoder output in this block
           // Status reports any decoder errors
           // imageBuffer contains the decoded frame if there were no errors
       };
      
      VTDecodeInfoFlags outFlags;
      
      OSStatus err = VTDecompressionSessionDecodeFrameWithOutputHandler(decompressionSession,
                                                         sampleBuffer, inFlags, 
                                                         &outFlags, outputHandler);
    • 20:54 - CVPixelBuffer to Metal texture: IOSurface

      // CVPixelBuffer to Metal texture: IOSurface
      
      IOSurfaceRef surface = CVPixelBufferGetIOSurface(imageBuffer);
      
      id <MTLTexture> metalTexture = [metalDevice newTextureWithDescriptor:descriptor
                                                                 iosurface:surface 
                                                                     plane:0];
      
      // Mark the IOSurface as in-use so that it won’t be recycled by the CVPixelBufferPool
      IOSurfaceIncrementUseCount(surface);
      
      // Set up command buffer completion handler to decrement IOSurface use count again
      [cmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
           IOSurfaceDecrementUseCount(surface);
       }];
    • 21:42 - Create a CVMetalTextureCacheRef

      // Create a CVMetalTextureCacheRef
      
      CVMetalTextureCacheRef metalTextureCache = NULL;
      
      id <MTLDevice> metalDevice = MTLCreateSystemDefaultDevice();
          
      CVMetalTextureCacheCreate(kCFAllocatorDefault, NULL, metalDevice, NULL, &metalTextureCache);
      
      // Create a CVMetalTextureRef using metalTextureCache and our pixelBuffer
      CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                                metalTextureCache,
                                                pixelBuffer,
                                                NULL,
                                                pixelFormat,
                                                CVPixelBufferGetWidth(pixelBuffer),
                                                CVPixelBufferGetHeight(pixelBuffer),
                                                0,
                                                &cvTexture);
      
      id <MTLTexture>  texture = CVMetalTextureGetTexture(cvTexture);
      // Be sure to release the cvTexture object when the Metal command buffer completes!
  • 特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。

    クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。

Developer Footer

  • ビデオ
  • WWDC20
  • AVFoundationとVideoToolboxを使ったDecode ProRes
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン