programming
UIViewの表示内容をCMSampleBufferにする
任意のUIViewをPinPに利用しようとすると、CMSampleBufferにUIViewの内容を変換する必要があります。
iOSで任意のUIViewをピクチャーインピクチャーするという素晴らしい記事と実装を公開してくださっているのですが、CMSampleBuffer
への変換方法が少し微妙な気がしたので、そこの部分のみ実装を紹介しようと思います。
実装
extension UIView {
func makeSampleBuffer() -> CMSampleBuffer? {
let scale = UIScreen.main.scale
let size = CGSize(width: bounds.width * scale, height: bounds.height * scale)
var pixelBuffer: CVPixelBuffer?
var status = CVPixelBufferCreate(kCFAllocatorDefault,
Int(size.width),
Int(size.height),
kCVPixelFormatType_32ARGB,
[
kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue!,
kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue!,
kCVPixelBufferIOSurfacePropertiesKey: [:] as CFDictionary,
] as CFDictionary,
&pixelBuffer)
if status != kCVReturnSuccess {
assertionFailure("Failed to create CVPixelBuffer: \(status)")
return nil
}
CVPixelBufferLockBaseAddress(pixelBuffer!, [])
defer {
CVPixelBufferUnlockBaseAddress(pixelBuffer!, [])
}
let context = CGContext(data: CVPixelBufferGetBaseAddress(pixelBuffer!),
width: Int(size.width),
height: Int(size.height),
bitsPerComponent: 8,
bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!),
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)!
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: scale, y: -scale)
layer.render(in: context)
var formatDescription: CMFormatDescription?
status = CMVideoFormatDescriptionCreateForImageBuffer(allocator: kCFAllocatorDefault,
imageBuffer: pixelBuffer!,
formatDescriptionOut: &formatDescription)
if status != kCVReturnSuccess {
assertionFailure("Failed to create CMFormatDescription: \(status)")
return nil
}
let now = CMTime(seconds: CACurrentMediaTime(), preferredTimescale: 60)
let timingInfo = CMSampleTimingInfo(duration: .init(seconds: 1, preferredTimescale: 60),
presentationTimeStamp: now,
decodeTimeStamp: now)
do {
return try CMSampleBuffer(imageBuffer: pixelBuffer!, formatDescription: formatDescription!,
sampleTiming: timingInfo)
} catch {
assertionFailure("Failed to create CVSampleBuffer: \(error)")
return nil
}
}
}
実装のポイント
ハマった箇所のみ説明を残しておくと、
kCVPixelBufferIOSurfacePropertiesKey: [:] as CFDictionary
の指定がないと実機で描画されませんUIScreen.main.scale
を利用して、Retinaディスプレイの解像度に耐えるように大きめのサイズでCVPixelBuffer
を作成していますkCVPixelFormatType_32ARGB
色の順番を間違えると色がおかしくなります
記事が気に入ったらチップを送ることができます!
You can give me a cup of coffee :)
Kyash ID: soranoba
Amazon: Wish List
GitHub Sponsor: github.com/sponsors/soranoba
PayPal.Me: paypal.me/soranoba
(Updated: )