0
0

CVPixelBufferからCMSampleBufferに変換

Posted at

実現したかった内容

  1. Flutterでリアルタイムに取得した画像をUint8形式へ変換
  2. 画像ごとにMethodChannelでプラットフォーム(Swift)に送る
  3. 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)
    }   
}

恐らくもっとスマートなやり方があると思うのですが、困っている方の参考になれば幸いです。

0
0
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
0
0