gpt4 book ai didi

ios - 在 Swift 中从 UImage 数组创建视频时出现内存崩溃问题

转载 作者:行者123 更新时间:2023-12-03 22:30:43 24 4
gpt4 key购买 nike

我正在处理视频,我从 Uimage 数组创建视频。它适用于少量图像,但大量(例如:100 多张图像)由于内存问题而崩溃。

我已经测试过在创建视频时,内存变大但在过程完成后内存仍然是大小,而不是释放。

任何帮助将不胜感激

这是我的代码:

    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
}
    func fillPixelBufferFromImage(_ image: UIImage, pixelBuffer: CVPixelBuffer) {
CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))

let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer)
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGContext(
data: pixelData,
width: Int(image.size.width),
height: Int(image.size.height),
bitsPerComponent: 8,
bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer),
space: rgbColorSpace,
bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue
)

context!.clear(CGRect(x: 0, y: 0, width: CGFloat(self.outputSize.width), height: CGFloat(self.outputSize.height)))
context?.draw(image.cgImage!, in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))

CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
}

最佳答案

我在我的应用程序中遇到了同样的问题,并且在花费了数小时之后。最后我得到了在使用 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!;

}

关于ios - 在 Swift 中从 UImage 数组创建视频时出现内存崩溃问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55545597/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com