Я работаю с видео, я создаю видео из массива 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))
}