将视网膜图像转换为视频:“CGContextScaleCTM:无效上下文 0x0。这是一个严重错误。”
Posted
技术标签:
【中文标题】将视网膜图像转换为视频:“CGContextScaleCTM:无效上下文 0x0。这是一个严重错误。”【英文标题】:Turning retina images into video: "CGContextScaleCTM: invalid context 0x0. This is a serious error." 【发布时间】:2016-04-04 23:49:12 【问题描述】:目标是将一系列视网膜图像转换为单个视频。
下面的两个函数负责将 UIImage 写入 AVAssetWriterInputPixelBufferAdaptor。它们可以工作,并且代码会从图像中生成看似有效的视频。
但是,Xcode 报错:
CGContextScaleCTM:无效的上下文 0x0。这是一个严重的错误。这 应用程序或其使用的库正在使用无效的上下文并且是 从而导致系统稳定性的整体退化和 可靠性。此通知是出于礼貌:请解决此问题。它 将在即将到来的更新中成为致命错误。
大概是在抱怨fillPixelBufferFromImage
中的CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale)
行。但是,删除 CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale)
会导致问题。视网膜图像最终以视频内一半大小(例如,320x568 而不是 640x1136)呈现。
1) 这是一个需要担心的错误吗?其他 SO 帖子建议不要。
2) 即使是良性的,如何才能让这个错误消失?或者将视网膜图像渲染到 AVAssetWriterInputPixelBufferAdaptor 的正确方法是什么?
func appendPixelBufferForImageAtURL(image: UIImage, pixelBufferAdaptor: AVAssetWriterInputPixelBufferAdaptor, presentationTime: CMTime) -> Bool
var appendSucceeded = false
autoreleasepool
if let pixelBufferPool = pixelBufferAdaptor.pixelBufferPool
let pixelBufferPointer = UnsafeMutablePointer<CVPixelBuffer?>.alloc(1)
let status: CVReturn = CVPixelBufferPoolCreatePixelBuffer(
kCFAllocatorDefault,
pixelBufferPool,
pixelBufferPointer
)
if let pixelBuffer = pixelBufferPointer.memory where status == 0
fillPixelBufferFromImage(image, pixelBuffer: pixelBuffer)
appendSucceeded = pixelBufferAdaptor.appendPixelBuffer(pixelBuffer, withPresentationTime: presentationTime)
pixelBufferPointer.destroy()
else
NSLog("Error: Failed to allocate pixel buffer from pool")
pixelBufferPointer.dealloc(1)
return appendSucceeded
func fillPixelBufferFromImage(image: UIImage, pixelBuffer: CVPixelBufferRef)
/// Lock base address
CVPixelBufferLockBaseAddress(pixelBuffer, 0)
// Set properties for context
let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer)
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let scale = image.scale
let scaledWidth = image.size.width * scale
let scaledHeight = image.size.height * scale
// Create CGBitmapContext
let context = CGBitmapContextCreate(
pixelData,
Int(scaledWidth),
Int(scaledHeight),
8,
CVPixelBufferGetBytesPerRow(pixelBuffer),
rgbColorSpace,
CGImageAlphaInfo.PremultipliedFirst.rawValue
)
// Set scale for context
CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale)
// Draw image into context
CGContextDrawImage(context, CGRectMake(0, 0, scaledWidth, scaledHeight), image.CGImage)
/// Unlock base address
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0)
【问题讨论】:
【参考方案1】:是的,这是您应该担心的错误。错误消息显示“这是一个严重错误”。 “请解决这个问题”不是开玩笑。
这是不正确的:
CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale)
因为这些都不是:
-
您不在 UIView 的
-drawRect:
方法中
您没有调用 UIGraphicsBeginImageContext
来设置上下文
您没有手动调用UIGraphicsPushContext
因此,据 UIKit 所知,没有“当前”上下文,所以UIGraphicsGetCurrentContext()
返回 nil。
您自己创建了位图上下文,因此您应该将比例应用于该上下文:
CGContextScaleCTM(context, scale, scale)
【讨论】:
谢谢,试试这个!但是,删除此行CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale)
会更改渲染图像,使其以 1.0 比例渲染(例如,5S 上的 320x568),而包含它会导致图像以 2.0 比例渲染。不介意解释怎么会有效果呢?
嗯,CGContextScaleCTM(context, scale, scale) 似乎不起作用。它会产生一个太大的图像。甚至尝试将 scaledWidth
和 scaledHeight
更改为不包括比例,因为看起来可能会发生双重效果,但这也失败了。到目前为止,在视频中以正确尺寸(例如 640x1136)渲染图像的唯一内容是 CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale)
。
删除该行会产生影响的唯一方法是UIGraphicsGetCurrentContext
返回一个非零值。有时只打印警告消息吗?当您调用此代码时,您是否在 UIView 的 -drawRect:
方法中?此外,由于您正在缩放 CTM,因此您应该使用未缩放的尺寸绘制图像:CGContextDrawImage(context, CGRectMake(0, 0, image.width, image.height), image.CGImage)
.
(这就是为什么如果你提供一个完整的例子来演示这个问题会很有帮助。你没有在这里显示你的所有代码,所以我必须猜测你调用它的环境.)
你是对的,但过去发布太多代码会引起其他评论者的愤怒,因此很难衡量正确的水平。稍后将发布更多信息。它一致地打印警告消息。不在 drawRect 方法内。以上是关于将视网膜图像转换为视频:“CGContextScaleCTM:无效上下文 0x0。这是一个严重错误。”的主要内容,如果未能解决你的问题,请参考以下文章