Metalのパフォーマンスがわかりやすく活きる例としては、動画のリアルタイム処理です。動画撮影中に30fpsなり60fpsなりで渡されてくるカメラからの入力をMetalで画像処理し、Metalで描画する、ということをやります。
##カメラからの入力を取得する
カメラからの入力をリアルタイムに受け取るようにする実装は、何も新しいことはないのでここでは省略します。AVFoundationのAVCaptureSession
を用いるおなじみのものです。iOS-10-Samplerにもそういう実装があるので必要に応じてご参照ください。
関連:
AVCaptureVideoDataOutputSampleBufferDelegate
プロトコルの captureOutput:didOutputSampleBuffer:fromConnection:
メソッドで、カメラからの入力がCMSampleBuffer
として渡されてきます。
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!)
ここから CMSampleBufferGetImageBuffer()
を用いて、 CVImageBuffer
(CVPixelBuffer
)を取り出します。
let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
ここまではiOSデバイスでカメラ入力に対して何かやりたいときには必ず通る、おなじみの手順かと思います。
##CVImageBuffer -> MTLTexture
ここからが本番で、Metalで処理するために、 CVImageBuffer
(CVPixelBuffer
) からMTLTextureを生成します。
###1.CVMetalTextureCache
を生成
まず、CVMetalTextureCache
を用意しておきます。
(Swift)
var textureCache : CVMetalTextureCache?
CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, device, nil, &textureCache)
(ObjC)
CVMetalTextureCacheRef textureCache;
CVMetalTextureCacheCreate(kCFAllocatorDefault,
nil,
device,
nil,
&textureCache);
(device
はMTLDevice
)
CVMetalTextureCache
は、CVMetalTexture
型のテクスチャを生成・管理するためのクラスです。以下リファレンスより引用。
A CoreVideo Metal texture cache creates and manages CVMetalTexture textures. You use a CVMetalTextureCache object to directly read from or write to GPU-based CoreVideo image buffers in rendering or GPU compute tasks that use the Metal framework.
テクスチャをつくるたびに生成しなおす必要はありません。
###2. CVImageBuffer -> CVMetalTexture
ここからは、カメラからの入力(CMSampleBuffer)を得るたびに行う処理です。
CVMetalTextureCache
を用いて、 CVImageBuffer
から、 CVMetalTexture
を生成します。
let width = CVPixelBufferGetWidth(imageBuffer)
let height = CVPixelBufferGetHeight(imageBuffer)
var imageTexture: CVMetalTexture?
let result = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textureCache, imageBuffer, nil, pixelFormat, width, height, 0, &imageTexture)
CVMetalTextureRef imageTexture;
CVReturn result = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
textureCache,
imageBuffer,
nil,
MTLPixelFormatBGRA8Unorm,
width, height, 0,
&imageTexture);
成功すれば、戻り値は kCVReturnSuccess
となります。
ちなみに、CVMetalTexture
とはどういうものかというと、「Metalで利用するためのtexture-basedなイメージバッファ」とのことです。
A texture-based image buffer that supplies source image data for use with the Metal framework.
###3. CVMetalTexture -> MTLTexture
イメージバッファから、MTLTexture
を取り出します。
let texture = CVMetalTextureGetTexture(imageTexture)
id<MTLTexture> texture = CVMetalTextureGetTexture(imageTexture);
CFRelease(imageTexture);
Objective-Cの場合は明示的にCVMetalTextureを解放する必要がある点に注意。
##MTLTexture -> Metalで処理
Metalのシェーダで何かしらの処理を行う話は以下の記事に、
また、Metal Performance Shadersでリサイズやブラー処理を行う話はこちらに、
MTLTextureに対して**(Metalでシームレスに)Core Imageで画像処理**を行う話は下記記事に書きました。
##MTLTexture -> MTKViewで表示(描画)
MTLTextureをMTKViewで描画する方法については、下記記事にまとめました。
##出来上がり
(AnimatedGIFを載せる予定)
##今後の展望
このへんの知見は、Metal Performance ShadersでのCNNを使う際にも活きてくる予定です。
近日中に記事を書く予定です。