Есть ли более быстрый способ создания CVPixelBuffer из UIImage в Swift?

Задача: записать видео в реальном времени с примененным к нему фильтром

Проблема Получение CVPixelBuffer из измененного UIImage слишком медленное

Вывод моей камеры фильтруется и направляется прямо в UIImageView, так что пользователь может видеть эффект в режиме реального времени, даже когда не записывает видео или делает фотографию. Я хотел бы каким-то образом записать этот изменяющийся UIImage в видео, чтобы он не был похож на тот, что я делаю сейчас. В настоящее время я делаю это, добавляя CVPixelBuffer к assetWriter, но поскольку я применяю фильтр к UIImage, я преобразую UIImage обратно в буфер. Я протестировал с и без буфера UIImage ->, поэтому я доказал, что это вызывает недопустимое замедление.

Ниже приведен код внутри captureOutput с комментариями, чтобы понять, что происходит, и метод получения буфера UIImage:

// this function is called to output the device's camera output in realtime
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection){

        if(captureOutput){

            // create ciImage from buffer
            let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
            let cameraImage = CIImage(cvPixelBuffer: pixelBuffer!)

            // set UIImage to ciImage
            image = UIImage(ciImage: cameraImage)


            if let ciImage = image?.ciImage {

                // apply filter to CIImage
                image = filterCIImage(with:ciImage)

                // make CGImage and apply orientation
                image = UIImage(cgImage: (image?.cgImage)!, scale: 1.0, orientation: UIImageOrientation.right)

                // get format description, dimensions and current sample time
                let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer)!
                self.currentVideoDimensions = CMVideoFormatDescriptionGetDimensions(formatDescription)
                self.currentSampleTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer)

                // check if user toggled video recording 
                // and asset writer is ready
                if(videoIsRecording && self.assetWriterPixelBufferInput?.assetWriterInput.isReadyForMoreMediaData == true){
                    // get pixel buffer from UIImage - SLOW!
                    let filteredBuffer = buffer(from: image!)

                    // append the buffer to the asset writer
                    let success = self.assetWriterPixelBufferInput?.append(filteredBuffer!, withPresentationTime: self.currentSampleTime!)

                    if success == false {
                        print("Pixel Buffer failed")
                    }

                }

            }


            DispatchQueue.main.async(){
                // update UIImageView with filtered camera output
                imageView!.image = image
            }

        }

    }


    // UIImage to buffer method:
    func buffer(from image: UIImage) -> CVPixelBuffer? {
        let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary
        var pixelBuffer : CVPixelBuffer?
        let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(image.size.width), Int(image.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer)
        guard (status == kCVReturnSuccess) else {
            return nil
        }

        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.noneSkipFirst.rawValue)

        context?.translateBy(x: 0, y: image.size.height)
        context?.scaleBy(x: 1.0, y: -1.0)

        UIGraphicsPushContext(context!)
        image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
        UIGraphicsPopContext()
        CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))

        return pixelBuffer
    }

0 ответов

Другие вопросы по тегам