実現したかった内容
- Flutterでリアルタイムに取得した画像をUint8形式へ変換
- 画像ごとにMethodChannelでプラットフォーム(Swift)に送る
- SwiftでUint8からCMSampleBufferに変換する
というような処理を作成していました。その際、Uint8からCVPixelBufferまでの変換は調べると沢山の例が出てきたのですが、CVPixelBufferをCMSampleBufferに変換する例は少なく、実装するのに苦労していました。
今回は自分で作ってみてひとまず動いた例を紹介します。
変換に必要な物
- CVPixelBuffer(用意済み)
- CMSampleTimingInfo
- CMVideoFormatDescription
CMSampleTimingInfoを用意
画像の時間情報を生成します。単位はナノ秒を使用し、Dateを拡張してタイムスタンプを生成しています。
let timeScale = CMTimeScale(NSEC_PER_SEC)
let pts = CMTime(value:CMTimeValue(Date().currentTimeNanoSec()),
timescale: timeScale)
var timingInfo: CMSampleTimingInfo = CMSampleTimingInfo(duration: CMTime.invalid,
presentationTimeStamp: pts,
decodeTimeStamp: CMTime.invalid)
extension Date {
func currentTimeNanoSec() -> Int64 {
return Int64(self.timeIntervalSince1970*1000000000)
}
}
CMVideoFormatDescriptionを用意
フォーマットの情報を生成します。
var videoInfo: CMVideoFormatDescription?
CMVideoFormatDescriptionCreateForImageBuffer(allocator: nil,
imageBuffer: cvPixelBuffer,
formatDescriptionOut: &videoInfo)
CMSampleBufferを生成
var cmSampleBuffer: CMSampleBuffer?
CMSampleBufferCreateForImageBuffer(allocator: kCFAllocatorDefault,
imageBuffer: cvPixelBuffer,
dataReady: true,
makeDataReadyCallback: nil,
refcon: nil,
formatDescription: videoInfo!,
sampleTiming: &timingInfo,
sampleBufferOut: &cmSampleBuffer)
記述したコード全体
let timeScale = CMTimeScale(NSEC_PER_SEC)
let pts = CMTime(value:CMTimeValue(Date().currentTimeNanoSec()),
timescale: timeScale)
var timingInfo: CMSampleTimingInfo = CMSampleTimingInfo(duration: CMTime.invalid,
presentationTimeStamp: pts,
decodeTimeStamp: CMTime.invalid)
var videoInfo: CMVideoFormatDescription?
CMVideoFormatDescriptionCreateForImageBuffer(allocator: nil,
imageBuffer: cvPixelBuffer,
formatDescriptionOut: &videoInfo)
var cmSampleBuffer: CMSampleBuffer?
CMSampleBufferCreateForImageBuffer(allocator: kCFAllocatorDefault,
imageBuffer: cvPixelBuffer,
dataReady: true,
makeDataReadyCallback: nil,
refcon: nil,
formatDescription: videoInfo!,
sampleTiming: &timingInfo,
sampleBufferOut: &cmSampleBuffer)
extension Date {
func currentTimeNanoSec() -> Int64 {
return Int64(self.timeIntervalSince1970*1000000000)
}
}
恐らくもっとスマートなやり方があると思うのですが、困っている方の参考になれば幸いです。