62
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Metalでカメラからの動画入力をリアルタイム処理する

Last updated at Posted at 2016-12-21

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);

deviceMTLDevice

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 を生成します。

swift
let width = CVPixelBufferGetWidth(imageBuffer)
let height = CVPixelBufferGetHeight(imageBuffer)
    
var imageTexture: CVMetalTexture?
    
let result = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textureCache, imageBuffer, nil, pixelFormat, width, height, 0, &imageTexture)
objc
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 を取り出します。

swift
let texture = CVMetalTextureGetTexture(imageTexture)
objc
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を使う際にも活きてくる予定です。

近日中に記事を書く予定です。

62
47
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?