I am trying to create video from array of images, and it's working but only in simulator. It seems that the main problem is memory usage. I already optimised arrays but it's obviously not enough, and my app is crashing on the last stage, when it's trying to convert images to frames.
I said 'array' but I don't really use an array for images, I'm creating them on-the-fly (I'm getting the right frame from my video source and applying to it the overlay image, and after that I'm converting this image to frame for the new video).
func getTheCombinedImage(frameNumber: Int)->UIImage {
let videoURLAsset = videoAsset as! AVURLAsset
let generator:AVAssetImageGenerator = AVAssetImageGenerator(asset: videoURLAsset)
generator.requestedTimeToleranceBefore = kCMTimeZero
generator.requestedTimeToleranceAfter = kCMTimeZero
var actualTime : CMTime = CMTimeMake(0, 0)
let duration:CMTime = CMTimeMake(Int64(frameNumber), Int32(30))
let frameRef:CGImageRef = try! generator.copyCGImageAtTime(duration, actualTime: &actualTime)
let sourceImage:UIImage = UIImage(CGImage: frameRef)
let tempImage:UIImage = getTheTempImage(frameNumber)
UIGraphicsBeginImageContext(sourceImage.size)
sourceImage.drawInRect(CGRect(x: 0, y: 0, width: sourceImage.size.width, height: sourceImage.size.height), blendMode: CGBlendMode.Normal, alpha: 1.0)
tempImage.drawInRect(CGRect(x: 0, y: 0, width: tempImage.size.width, height: tempImage.size.height), blendMode: CGBlendMode.Normal, alpha: 1.0)
let combinedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return combinedImage
}
it seems that this function is not very good in terms of memory (and, maybe, in other terms too). It seems that I didn't release here what should be released but what?
When I don't use this function my memory situation is much better:
Also, I thinks that it is not enough because 180MB of memory usage is still too high, and after converting to video my memory usage level is like 100-110 MB (instead of 55-60 MB before that). In Instruments/Allocations I can see a lot of JVTLib instances from VideoToolbox (like JVTLib_101510(JVTLib_101496, int)*) — I think they are needed for conversion and _CVPixelBufferStandardMemoryLayout instances — I think these ones were created by me and obviously I'm not releasing something here too.
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
}
I don't understand what is wrong here.
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)
}
I'm not releasing context here but it seems that I don't have to do this in Swift (Do you need to release CGContextRef in Swift?)
update: thanks, guys
it works now. what helped (in case someone has the same problem):
don't put images into arrays (I fixed this before posting the question, but still)
don't panic and autoreleasepool everything.
try to optimize memory usage everywhere (the lower your memory usage on start the higher your memory cap).
put processed image into property.