#既存の動画ファイルにフィルターをかける
カメラで撮りながらリアルタイムでフィルタをかけるのではなく、
既存の動画ファイルにフィルターをかける方法です。
#画像だけではなく動画にもフィルターをかけたい。しかもフィルターを設定して撮った動画ではなく、撮った後の動画にかけたい。
既存の動画にフィルターをかけられたら、オリジナルビデオを撮影した後で、隠したい部分にモザイクをかけたり、可愛いエフェクトを付け加えることができます。
撮影前にエフェクトを設定してリアルタイムで加工するサンプルはちらほら見かけますが、
元々ある動画にあれこれフィルターをかけるコードはなかなか見つかりませんでした。
###動画の一括処理はうまく動かなかった
アップル公式ドキュメントには、動画ファイルにフィルターをかける二つの方法が見つかりますが、
僕の手元ではうまく動きませんでした。
AVAssetにCIFilterをかけるAVVideoCompositionを作るイニシャライザも動作しなかったし、
CustomAVVideoCompositionクラスも、(ウォーターマークをつける画像合成はできた)CIFilterでは動かなかった。
#コマごとに分解して1枚ずつかけちゃえ
動画をコマごとに分解し、1枚ずつフィルターをかける。
そして、動画として再構成する。
これをすることで、1枚ごとに確実に処理できます。
1枚ずつ処理していたら、ものすごく時間がかかるんじゃないかと思いましたが、動画の長さの実時間程度でした。
メモリをちゃんと解放してあげると、クラッシュすることもありません。
#手法
AVAssetReaderで動画をフレームごとに読み込んで、
コマごとに分解した段階で、CIFilterの処理をはさみます。
そしてAVAssetWriterに書き込みます。
ポイントは、AVAssetWriterInputに直接サンプルバッファーを書き込むのではなく、
AVAssetWriterInputPixelBufferAdaptorというピクセルバッファーの受容器を作って、そこにフィルタリング後のピクセルバッファーを書き込む点です。
let pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: assetWriterVideoInput, sourcePixelBufferAttributes: [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)])
assetWriter.add(assetWriterVideoInput)
...
let presTime = CMSampleBufferGetOutputPresentationTimeStamp(buffer)
pixelBufferAdaptor.append(filteredPixelBuffer, withPresentationTime: presTime)
これでいろんなCIFilterが動画に適用できるようになりました。
🐣
フリーランスエンジニアです。
お仕事のご相談こちらまで
簡単な開発内容をお書き添えの上、お気軽にご連絡ください。
rockyshikoku@gmail.com
Core MLやARKitを使ったアプリを作っています。
機械学習/AR関連の情報を発信しています。