我正在使用Video,我从Uimage数组创建视频。它可以在少量图像时正常工作,但是在大量图像(例如:100多个图像)下,由于内存问题而崩溃。
我已经在创建视频时进行了测试,内存正在增大,但是在完成该过程之后,内存仍然是大小,而不是释放。
任何帮助将不胜感激
这是我的代码:
return [p[0] + p[1]
//创建像素缓冲区
func buildVideoFromImageArray(completed:@escaping (String)->Void) {
selectedPhotosArray = arrimageVideo
imageArrayToVideoURL = NSURL(fileURLWithPath: NSHomeDirectory() + "/Documents/video1.MP4")
removeFileAtURLIfExists(url: imageArrayToVideoURL)
guard let videoWriter = try? AVAssetWriter(outputURL: imageArrayToVideoURL as URL, fileType: AVFileType.mp4) else {
fatalError("AVAssetWriter error")
}
let outputSettings = [AVVideoCodecKey : AVVideoCodecH264, AVVideoWidthKey : NSNumber(value: Float(outputSize.width)), AVVideoHeightKey : NSNumber(value: Float(outputSize.height))] as [String : Any]
guard videoWriter.canApply(outputSettings: outputSettings, forMediaType: AVMediaType.video) else {
fatalError("Negative : Can't apply the Output settings...")
}
let videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: outputSettings)
let sourcePixelBufferAttributesDictionary = [kCVPixelBufferPixelFormatTypeKey as String : NSNumber(value: kCVPixelFormatType_32ARGB), kCVPixelBufferWidthKey as String: NSNumber(value: Float(outputSize.width)), kCVPixelBufferHeightKey as String: NSNumber(value: Float(outputSize.height))]
let pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: videoWriterInput, sourcePixelBufferAttributes: sourcePixelBufferAttributesDictionary)
if videoWriter.canAdd(videoWriterInput) {
videoWriter.add(videoWriterInput)
}
if videoWriter.startWriting() {
videoWriter.startSession(atSourceTime: kCMTimeZero)
assert(pixelBufferAdaptor.pixelBufferPool != nil)
let media_queue = DispatchQueue(label: "mediaInputQueue")
videoWriterInput.requestMediaDataWhenReady(on: media_queue, using: { () -> Void in
let fps: Int32 = 1000
var frameCount: Int64 = 0
var appendSucceeded = true
var lastTimeVl :Int64 = 0
var framePerSecond: Int64 = Int64(0)
for nextDicData in self.selectedPhotosArray{
if (videoWriterInput.isReadyForMoreMediaData) {
if let nextImage = nextDicData["img"] as? UIImage
{
var frameDuration = CMTimeMake(Int64(0), fps)
if let timeVl = nextDicData["time"] as? Float{
framePerSecond = Int64(timeVl * 1000)
print("TIME FRAME : \(timeVl)")
}else{
framePerSecond = Int64(0.1 * 1000)
}
frameDuration = CMTimeMake(framePerSecond ,fps)
let lastFrameTime = CMTimeMake(Int64(lastTimeVl), fps)
let presentationTime = lastFrameTime
if !self.appendPixelBufferForImage(image: nextImage, pixelBufferAdaptor: pixelBufferAdaptor, presentationTime: presentationTime){
print("AVAssetWriterInputPixelBufferAdapter failed to append pixel buffer")
break
}
if let index = self.selectedPhotosArray.firstIndex(where: { NSDictionary(dictionary: $0).isEqual(to: nextDicData)}){
self.selectedPhotosArray.remove(at: index)
}
}
}else{
//not ready
print("write is Not Ready: \(lastTimeVl)")
}
if !appendSucceeded {
break
}
frameCount += 1
lastTimeVl += framePerSecond
usleep(100000)
}
videoWriterInput.markAsFinished()
videoWriter.endSession(atSourceTime: CMTimeMake(lastTimeVl, fps))
videoWriter.finishWriting { () -> Void in
print("-----video1 url = \(self.imageArrayToVideoURL)")
self.urlString = "\(self.imageArrayToVideoURL)"
self.asset = AVAsset(url: self.imageArrayToVideoURL as URL)
DispatchQueue.main.async {
//code that caused error goes here
completed(self.urlString)
self.setupPlayerVideoWithUrl(strUrl: self.urlString)
}
}
})
}
}
func appendPixelBufferForImage(image: UIImage, pixelBufferAdaptor: AVAssetWriterInputPixelBufferAdaptor, presentationTime: CMTime) -> Bool {
var appendSucceeded = false
autoreleasepool {
if let pixelBufferPool = pixelBufferAdaptor.pixelBufferPool {
let pixelBufferPointer = UnsafeMutablePointer<CVPixelBuffer?>.allocate(capacity: 1)
let status: CVReturn = CVPixelBufferPoolCreatePixelBuffer(
kCFAllocatorDefault,
pixelBufferPool,
pixelBufferPointer
)
if let pixelBuffer = pixelBufferPointer.pointee, status == 0 {
fillPixelBufferFromImage(image, pixelBuffer: pixelBuffer)
appendSucceeded = pixelBufferAdaptor.append(
pixelBuffer,
withPresentationTime: presentationTime
)
pixelBufferPointer.deinitialize(count: 1)
} else {
NSLog("error: Failed to allocate pixel buffer from pool")
}
pixelBufferPointer.deallocate()
}
}
return appendSucceeded
}
答案 0 :(得分:-1)
我在我的应用程序中遇到了同样的问题,并且在花费了数小时之后。最后我得到了在使用 CVPixelBuffer 绘制图像期间释放内存的解决方案。
请参考下面的代码。
func pixelBufferFromImage(image: UIImage) -> CVPixelBuffer {
let ciimage = CIImage(image: image)
let tmpcontext = CIContext(options: nil)
let cgimage = tmpcontext.createCGImage(ciimage!, from: ciimage!.extent)
let cfnumPointer = UnsafeMutablePointer<UnsafeRawPointer>.allocate(capacity: 1)
let cfnum = CFNumberCreate(kCFAllocatorDefault, .intType, cfnumPointer)
let keys: [CFString] = [kCVPixelBufferCGImageCompatibilityKey, kCVPixelBufferCGBitmapContextCompatibilityKey, kCVPixelBufferBytesPerRowAlignmentKey]
let values: [CFTypeRef] = [kCFBooleanTrue, kCFBooleanTrue, cfnum!]
let keysPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 1)
let valuesPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 1)
keysPointer.initialize(to: keys)
valuesPointer.initialize(to: values)
let options:[String: Any] = [kCVPixelBufferCGImageCompatibilityKey as String: true, kCVPixelBufferCGBitmapContextCompatibilityKey as String: true]
let width = Int(image.size.width)
let height = Int(image.size.width)
var pxbuffer: CVPixelBuffer?
// if pxbuffer = nil, you will get status = -6661
var status = CVPixelBufferCreate(kCFAllocatorDefault, width, height,
kCVPixelFormatType_32BGRA, options as CFDictionary, &pxbuffer)
assert(status == kCVReturnSuccess && pxbuffer != nil, "newPixelBuffer failed")
status = CVPixelBufferLockBaseAddress(pxbuffer!, CVPixelBufferLockFlags(rawValue: 0));
let bufferAddress = CVPixelBufferGetBaseAddress(pxbuffer!);
let rgbColorSpace = CGColorSpaceCreateDeviceRGB();
let bytesperrow = CVPixelBufferGetBytesPerRow(pxbuffer!)
let context = CGContext(data: bufferAddress,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: bytesperrow,
space: rgbColorSpace,
bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue);
context?.concatenate(CGAffineTransform(rotationAngle: 0))
context?.draw(cgimage!, in: CGRect(x:0, y:0, width:CGFloat(width), height:CGFloat(height)));
status = CVPixelBufferUnlockBaseAddress(pxbuffer!, CVPixelBufferLockFlags(rawValue: 0));
return pxbuffer!;
}