【发布时间】:2019-04-07 12:38:44
【问题描述】:
我很难想出在任何 iOS 设备上可靠地复制 CVPixelBuffer 的代码。在我在 iPad Pro 上尝试之前,我的第一次尝试效果很好:
extension CVPixelBuffer {
func deepcopy() -> CVPixelBuffer? {
let width = CVPixelBufferGetWidth(self)
let height = CVPixelBufferGetHeight(self)
let format = CVPixelBufferGetPixelFormatType(self)
var pixelBufferCopyOptional:CVPixelBuffer?
CVPixelBufferCreate(nil, width, height, format, nil, &pixelBufferCopyOptional)
if let pixelBufferCopy = pixelBufferCopyOptional {
CVPixelBufferLockBaseAddress(self, kCVPixelBufferLock_ReadOnly)
CVPixelBufferLockBaseAddress(pixelBufferCopy, 0)
let baseAddress = CVPixelBufferGetBaseAddress(self)
let dataSize = CVPixelBufferGetDataSize(self)
let target = CVPixelBufferGetBaseAddress(pixelBufferCopy)
memcpy(target, baseAddress, dataSize)
CVPixelBufferUnlockBaseAddress(pixelBufferCopy, 0)
CVPixelBufferUnlockBaseAddress(self, kCVPixelBufferLock_ReadOnly)
}
return pixelBufferCopyOptional
}
}
由于CVPixelBufferGetDataSize(self) 比CVPixelBufferGetDataSize(pixelBufferCopy) 稍大,所以上述情况在 iPad Pro 上崩溃,因此 memcpy 会写入未分配的内存。
所以我放弃了,尝试了这个:
func copy() -> CVPixelBuffer?
{
precondition(CFGetTypeID(self) == CVPixelBufferGetTypeID(), "copy() cannot be called on a non-CVPixelBuffer")
var _copy: CVPixelBuffer?
CVPixelBufferCreate(
nil,
CVPixelBufferGetWidth(self),
CVPixelBufferGetHeight(self),
CVPixelBufferGetPixelFormatType(self),
CVBufferGetAttachments(self, .shouldPropagate),
&_copy)
guard let copy = _copy else { return nil }
CVPixelBufferLockBaseAddress(self, .readOnly)
CVPixelBufferLockBaseAddress(copy, [])
defer
{
CVPixelBufferUnlockBaseAddress(copy, [])
CVPixelBufferUnlockBaseAddress(self, .readOnly)
}
for plane in 0 ..< CVPixelBufferGetPlaneCount(self)
{
let dest = CVPixelBufferGetBaseAddressOfPlane(copy, plane)
let source = CVPixelBufferGetBaseAddressOfPlane(self, plane)
let height = CVPixelBufferGetHeightOfPlane(self, plane)
let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(self, plane)
memcpy(dest, source, height * bytesPerRow)
}
return copy
}
这在我的两个测试设备上都有效,但它刚刚接触到实际客户,结果证明它在 iPad 6 上崩溃了(到目前为止只有那个设备)。再次调用memcpy() 时是EXC_BAD_ACCESS。
考虑到让它可靠地工作似乎是多么困难,没有一个简单的 API 调用来解决这个问题似乎很疯狂。还是我让它变得比需要的更难?感谢您的建议!
【问题讨论】:
-
第二个实现看起来相当可靠。我能想象的唯一问题是新像素缓冲区中的平面分配有不同的步长(每行字节数)。步长基于宽度×(每像素字节数),然后以未指定的方式四舍五入以实现最佳内存访问。所以检查
CVPixelBufferGetBytesPerRowOfPlane(self, plane) == CVPixelBufferGetBytesPerRowOfPlane(copy, plane)。如果没有,则逐行复制像素平面。 -
谢谢,你想把它作为答案发布吗?
-
它能解决崩溃问题吗?
-
不幸的是,它在第 6 代 iPad 上崩溃而没有其他问题,直到我在 App Store 上发布后才知道。
-
有效!没有崩溃了。
标签: ios cvpixelbuffer