Ошибка памяти при создании видео из массива UImages в Swift - PullRequest
1 голос
/ 06 апреля 2019

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