LoginSignup
2
1

More than 1 year has passed since last update.

iOSでアルファチャンネル付きで動画を作成する

Posted at

iOS でアルファチャンネル付きで動画を作成する

  • AVAssetWriter を使うと、iOS で透過情報付きの動画を作成する事が可能です
  • iOS の写真アプリは透過付きの動画を再生可能です
  • ツールバーの表示/非表示で背景色が変わったり、プルダウンすることで後ろの画像が見えるので、動画の背景が透過されている事がわかります

サンプルアプリ

  • リポジトリはこちらです

  • Examples/NativeExamples/NativeExamples.xcodeprojCrossMetal iOS ターゲットです
  • Xcode の Metal の Game アプリをベースにしています

透過情報付きで保存するポイント

  • AVAssetWriterInput の生成時の settings で、hevcWithAlpha を指定します
let videoConfigs: [String: Any] = [AVVideoCodecKey : AVVideoCodecType.hevcWithAlpha,
                                   AVVideoWidthKey : 1920,
                                   AVVideoHeightKey :1080]
let videoAssetWriterInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoConfigs)
  • 書き込む CMSampleBuffer の CVPixelBuffer のフォーマットとして kCVPixelFormatType_32BGRA を選択します
let options = [kCVPixelBufferIOSurfacePropertiesKey: [:]] as [String : Any]            
let status = CVPixelBufferCreate(nil, width, height,
                                 kCVPixelFormatType_32BGRA,
                                 options as CFDictionary,
                                 &pixelBuffer)
  • 透過情報付きの画像データを生成し、AVAssetWriterInput に書き込むことで、アルファチャンネル付きの動画を取得可能です

実装

録画開始

  • ファイルタイプは mov を指定しました
  • hevcWithAlpha が保存できるコンテナであれば良いと思います
let assetWriter = try! AVAssetWriter(outputURL: url, fileType: AVFileType.mov)

let videoConfigs: [String: Any] = [AVVideoCodecKey : AVVideoCodecType.hevcWithAlpha,
                                   AVVideoWidthKey : 1920,
                                   AVVideoHeightKey : 1080]
let videoAssetWriterInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoConfigs)
videoAssetWriterInput.expectsMediaDataInRealTime = true
assetWriter.add(videoAssetWriterInput)
  • 元の画像を Metal でレンダリングしているので、MTLTexture と描画時刻を受け取ります
  • MTLTexture -> CIImage -> CVPixelBuffer -> CMSampleBuffer の順番に変換します
func make(mtlTexture: MTLTexture, time: CMTime) -> CMSampleBuffer? {
    let ci = CIImage(mtlTexture: mtlTexture, options: nil)!
    CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
    context.render(ci, to: pixelBuffer)
    var res: CMSampleBuffer? = nil
    var sampleTiming = CMSampleTimingInfo()
    sampleTiming.presentationTimeStamp = time
    let _ = CMSampleBufferCreateForImageBuffer(allocator: kCFAllocatorDefault,
                                               imageBuffer: pixelBuffer,
                                               dataReady: true,
                                               makeDataReadyCallback: nil,
                                               refcon: nil,
                                               formatDescription: formatDescription,
                                               sampleTiming: &sampleTiming,
                                               sampleBufferOut: &res)
    CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
    return res
}
  • 作成した CMSampleBuffer を videoAssetWriterInput に書き込みます
videoAssetWriterInput.append(sample)

録画終了

  • finishWriting することで mov ファイルが作成されています
assetWriter.finishWriting(completionHandler: { })

保存

  • 指定した url に動画が保存されているので、必要に応じて保存します
  • ALAssetsLibrary は deprecated なので Photos framework を使った方が良さそうです
ALAssetsLibrary()
    .writeVideoAtPath(toSavedPhotosAlbum: url) { (url: URL?, error: Error?) in
        print("url: \(String(describing: url)), error: \(String(describing: error))")
    }

おわりに

  • アルファチャンネル付きの動画を保存可能になると、汎用性が高そうです
  • 例えば、LiDAR のデプスをアルファチャンネルに入れて保存するなど活用できそうです
  • Unity でも R8G8B8A8_UNorm など、alpha チャンネルがあるテクスチャを渡すことで、透過情報付きの動作を作成する事が可能です
2
1
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
2
1