Ios 将图像转换为帧时会消耗大量内存
我正在尝试从一系列图像中创建视频,它正在工作,但只在模拟器中。看来主要的问题是内存使用。我已经对阵列进行了优化,但这显然是不够的,我的应用程序在最后一个阶段尝试将图像转换为帧时崩溃了 我说的是“数组”,但我并不是真的使用数组来制作图像,我是在动态地创建它们(我从视频源中获取正确的帧,并将覆盖图像应用到其中,然后我将此图像转换为新视频的帧) 从记忆的角度来看,这个功能似乎不是很好(也许在其他方面也是如此)。似乎我没有在这里发布应该发布的内容,但是发布了什么 当我不使用此功能时,我的记忆状况要好得多: 此外,我认为这是不够的,因为180MB的内存使用量仍然太高,在转换成视频后,我的内存使用量大约为100-110MB(而不是之前的55-60MB)。在Instruments/Allocations中,我可以从VideoToolbox中看到很多JVLIB实例(比如JVLIB_101510(JVLIB_101496,int)*)-我认为它们是转换和_CVPixelBufferStandardMemoryLayout实例所必需的-我认为这些实例是我创建的,显然我不会在这里发布任何东西Ios 将图像转换为帧时会消耗大量内存,ios,swift,memory,Ios,Swift,Memory,我正在尝试从一系列图像中创建视频,它正在工作,但只在模拟器中。看来主要的问题是内存使用。我已经对阵列进行了优化,但这显然是不够的,我的应用程序在最后一个阶段尝试将图像转换为帧时崩溃了 我说的是“数组”,但我并不是真的使用数组来制作图像,我是在动态地创建它们(我从视频源中获取正确的帧,并将覆盖图像应用到其中,然后我将此图像转换为新视频的帧) 从记忆的角度来看,这个功能似乎不是很好(也许在其他方面也是如此)。似乎我没有在这里发布应该发布的内容,但是发布了什么 当我不使用此功能时,我的记忆状况要好得多
func appendPixelBufferForImageAtURL(image: UIImage, pixelBufferAdaptor: AVAssetWriterInputPixelBufferAdaptor, presentationTime: CMTime) -> Bool {
var appendSucceeded = true
autoreleasepool {
var pixelBuffer: CVPixelBuffer? = nil
let status: CVReturn = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pixelBufferAdaptor.pixelBufferPool!, &pixelBuffer)
if let pixelBuffer = pixelBuffer where status == 0 {
let managedPixelBuffer = pixelBuffer
fillPixelBufferFromImage(image, pixelBuffer: managedPixelBuffer)
appendSucceeded = pixelBufferAdaptor.appendPixelBuffer(pixelBuffer, withPresentationTime: presentationTime)
} else {
NSLog("error: Failed to allocate pixel buffer from pool")
}
}
return appendSucceeded
}
我不明白这里怎么了
func fillPixelBufferFromImage(image: UIImage, pixelBuffer: CVPixelBufferRef) {
let imageData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage))
CVPixelBufferLockBaseAddress(pixelBuffer, 0)
let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer)
let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst.rawValue
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGBitmapContextCreate(
pixelData,
Int(self.externalInputSize.width),
Int(self.externalInputSize.height),
8,
CVPixelBufferGetBytesPerRow(pixelBuffer),
rgbColorSpace,
bitmapInfo
)
let imageDataProvider = CGDataProviderCreateWithCFData(imageData)
CGContextDrawImage(context, CGRectMake(0, 0, self.externalInputSize.width, self.externalInputSize.height), image.CGImage)
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0)
}
我并没有在这里发布上下文,但似乎我不必在Swift()中这样做
更新:谢谢大家
现在可以了。有什么帮助(如果有人有同样的问题):
在循环图像动画方面也有类似的问题(当UIImage对象被创建时,它会被缓存——如此多的实例消耗了大量内存)。ARC在这种情况下是不好的,因为它会随着时间的推移保存引用,并且不会以具有大量内存排列的周期释放引用。 尝试在
autoreleasepool
中包装代码,或查看手动内存管理:
autoreleasepool {
/* code */
}
在循环图像动画方面也有类似的问题(当UIImage对象被创建时,它会被缓存——如此多的实例消耗了大量内存)。ARC在这种情况下是不好的,因为它会随着时间的推移保存引用,并且不会以具有大量内存排列的周期释放引用。 尝试在
autoreleasepool
中包装代码,或查看手动内存管理:
autoreleasepool {
/* code */
}
从外观上看,您正在将非实时数据写入
AVAssetWriter
。在这种情况下,您需要小心,不要让编写器因提供帧的速度快于编写帧的速度而不知所措。最好的方法是让编写器从您那里提取数据,而不是向编写器推送数据。这是使用AVAssetWriterInput.requestMediaDataWhenRepayonQueue(\uu:usingBlock:)
最容易做到的。文档中有一个简单的示例说明如何使用此功能
在这种拉式风格中,您告诉编写器“只要您可以处理更多数据,就可以调用一个块。”编写器调用它,它应该不断添加数据,直到isReadForMoreMediaData
变为false。然后,该块返回,并将在写入程序准备进行更多操作时再次调用。当没有更多帧时,设置“我现在完成”布尔值
通过确保任何循环中都有autoreleasepool{}
,您应该小心地定期排空autorelease池,但看起来您通常已经在这样做了。如果你没有,并且你有一个循环,在没有自动释放池的情况下生成大图像,那么这肯定是你的问题
作为减少内存流失的一个小好处,您可能应该在属性中缓存任何静态对象,如rgbColorSpace
。您也可能不需要生成UIImage
来绘制像素缓冲区。您只需使用CGContextDrawImage
直接绘制CGImage
。(并可能从getTheTempImage
返回CGImage
)
不相关的旁注:避免使用
get
作为前缀方法。它有一个特定的内存管理含义,这与您的用法相反(它意味着结果将在指针指向指针的参数中传回)。ARC足够聪明,可以避免创建内存错误,但对于了解ARC命名规则的开发人员来说,它很容易混淆。与其getTheCombinedImage(:)
它应该是combinedImageForFrameNumber(:)
从外观上看,您正在将非实时数据写入AVAssetWriter
。在这种情况下,您需要小心,不要让编写器因提供帧的速度快于编写帧的速度而不知所措。最好的方法是让编写器从您那里提取数据,而不是向编写器推送数据。这是使用AVAssetWriterInput.requestMediaDataWhenRepayonQueue(\uu:usingBlock:)
最容易做到的。文档中有一个简单的示例说明如何使用此功能
在这种拉式风格中,您告诉编写器“只要您可以处理更多数据,就可以调用一个块。”编写器调用它,它应该不断添加数据,直到isReadForMoreMediaData
变为false。然后,该块返回,并将在写入程序准备进行更多操作时再次调用。当没有更多帧时,设置“我现在完成”布尔值
通过确保任何循环中都有autoreleasepool{}
,您应该小心地定期排空autorelease池,但看起来您通常已经在这样做了。如果你没有,并且你有一个循环,在没有自动释放池的情况下生成大图像,那么这肯定是你的问题
作为