【发布时间】:2021-11-25 03:25:03
【问题描述】:
我需要使用 MTKView 在 HDR10(kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange / BT2020 PQ 颜色空间)中显示 CVPixelBuffers。我有以下代码要显示,但它会产生失真的图像,我无法确定它是显示 10 位颜色还是钳位颜色。还有是bgra10_xr还是bgra10_xr_srgb应该是colorPixelFormat的正确选择以及两者的区别。
class CIImageView: MTKView {
var image: CIImage? {
didSet {
self.draw()
}
}
var originalImageExtent: CGRect = CGRect.zero
var scale: CGFloat {
return max(self.frame.width / originalImageExtent.width, self.frame.height / originalImageExtent.height)
}
func update() {
guard let img = image, destRect.size.width <= img.extent.size.width && destRect.size.height <= img.extent.size.height else {
return
}
self.draw()
}
let context: CIContext
let commandQueue: MTLCommandQueue
convenience init(frame: CGRect) {
let device = MetalCamera.metalDevice
self.init(frame: frame, device: device)
colorPixelFormat = .bgra10_xr_srgb
}
override init(frame frameRect: CGRect, device: MTLDevice?) {
guard let device = device else {
fatalError("Can't use Metal")
}
guard let cmdQueue = device.makeCommandQueue(maxCommandBufferCount: 5) else {
fatalError("Can't make Command Queue")
}
commandQueue = cmdQueue
context = CIContext(mtlDevice: device, options: [CIContextOption.cacheIntermediates: false])
super.init(frame: frameRect, device: device)
self.framebufferOnly = false
self.enableSetNeedsDisplay = false
self.isPaused = true
self.clearColor = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 0)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
guard let image = self.image else {
return
}
let dRect = destRect
let drawImage: CIImage
if dRect == image.extent {
drawImage = image
} else {
let scale = max(dRect.height / image.extent.height, dRect.width / image.extent.width)
drawImage = image.transformed(by: CGAffineTransform(scaleX: scale, y: scale))
}
let commandBuffer = commandQueue.makeCommandBufferWithUnretainedReferences()
guard let texture = self.currentDrawable?.texture else {
return
}
let colorSpace = drawImage.colorSpace ?? CGColorSpaceCreateDeviceRGB()
context.render(drawImage, to: texture, commandBuffer: commandBuffer, bounds: dRect, colorSpace: colorSpace)
commandBuffer?.present(self.currentDrawable!)
commandBuffer?.commit()
}
private var destRect: CGRect {
let scale: CGFloat
if UIScreen.main.scale == 3 {
// BUG?
scale = 2.0 * (2.0 / UIScreen.main.scale) * 2
} else {
scale = UIScreen.main.scale
}
let destRect = self.bounds.applying(CGAffineTransform(scaleX: scale, y: scale))
return destRect
}
func displayPixelBuffer(_ pixelBuffer: CVPixelBuffer, flip:FlipDirection) {
self.image = CIImage(cvImageBuffer: pixelBuffer)
}
编辑:我尝试了手动设置 colorSpace 的建议,但颜色被洗掉了。
这是 iPhone 上使用 AVCaptureVideoPreviewLayer 的同一场景的屏幕截图。
【问题讨论】:
-
您能否尝试使用此颜色空间:
CGColorSpace(name: CGColorSpace.itur_2100_PQ)(incontext.render(…)) -
我必须明确指定颜色空间吗,drawImage.colorSpace 不是已经有正确的颜色空间了吗?
-
A
CIImage只有在直接从具有颜色空间的源加载时才有colorSpace。但是您(可能)正在对其应用转换,因此它会丢失源的颜色空间信息。 -
让我试着回复你
-
颜色似乎被洗掉了。我将使用示例图像更新问题
标签: ios metal core-image ciimage mtkview