如何在不等待处理的情况下将CIFilter应用于Swift中的视频

时间:2019-09-18 10:50:48

标签: ios swift video-processing core-image cifilter

我目前正在我的一个应用程序中开发一项功能,用户可以在其中添加照片和视频。他们具有录制视频或拍照的能力,但之后我想通过应用滤镜或更改亮度,对比度,曝光度,...来完全控制输出。

这对照片来说相对容易。为了简化工作流程,我使用了一个名为BBMetalImage的第三方库。这很好用,我可以对照片和视频应用滤镜,但是处理视频需要很长时间,我不希望用户这样做。应用过滤器时,一个15秒的剪辑可能会迅速花费20-30秒的时间进行处理。

我目前是这样的:

var lookupFilterName: String! = "lookup_1"
let outputURL = URL(fileURLWithPath: "\(NSTemporaryDirectory())\(NSUUID().uuidString).mp4")
try? FileManager.default.removeItem(at: outputURL)
videoWriter = BBMetalVideoWriter(url: outputURL, frameSize: BBMetalIntSize(width: 480, height: 600))
videoSource = BBMetalVideoSource(url: currentVideoURL!)
videoSource.audioConsumer = videoWriter
if(filter != 0) {
    lookupFilterName = "lookup_\(filter)"
}
let lookupFilter = BBMetalLookupFilter(lookupTable: UIImage(named: lookupFilterName)!.bb_metalTexture!)
videoSource.add(consumer: lookupFilter).add(consumer: videoWriter)
videoSource.audioConsumer = videoWriter
videoWriter.start()
videoSource.start { [weak self] (_) in
    guard let self = self else { return }
    self.videoWriter.finish {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            if(self.currentVideoURL != nil) {
                self.queuePlayer?.pause()
                self.queuePlayer?.removeAllItems()
                if let playerLayer = self.playerLayer {
                    playerLayer.removeFromSuperlayer()
                }
                self.currentFinalVideoURL = outputURL
                let playerItem = AVPlayerItem(url: outputURL)
                self.queuePlayer = AVQueuePlayer(items: [playerItem])
                self.playerLayer = AVPlayerLayer(player: self.queuePlayer)
                self.playerLooper = AVPlayerLooper(player: self.queuePlayer!, templateItem: playerItem)
                self.videoPreview.layer.addSublayer(self.playerLayer!)
                self.playerLayer?.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width * 1.25)
                self.playerLayer?.backgroundColor = UIColor.black.cgColor
                self.queuePlayer?.play()
                self.videoWriter = nil
                self.videoSource = nil
            } else {
                self.videoWriter = nil
                self.videoSource = nil
            }
        }
    }
}

请不要误会我的意思。它完成了这项工作:它返回应用了滤镜的视频。基本上发生了什么,它获取原始视频的源URL,对其应用过滤器,将其写入另一个临时路径,然后向用户显示该视频。

我认为,这必须要快得多。我开始研究其他应用程序,尤其是Instagram,在这些应用程序中,当您应用过滤器时,它会立即更改(甚至不需要一秒钟),并继续播放视频而无需从第一帧重新开始。这就是我真正想要的。

我已经仔细研究了一下,发现应该使用CIFilter,因为Core Image提供了一种非常快速,可靠的方式来处理照片(和视频?)。

所以我的问题是:

  1. 使用CIFilter时是否可以应用定制的查找过滤器或LUT,还是仅限于Core Image框架中提供的内置过滤器(例如GaussianBlur等)?
  2. 我应该如何“实时”更改视频,而又不会对最终用户造成延迟?我在某处读到,这是使用缓冲区完成的,此后,视频的每一帧都会以所需的效果进行操作并实时播放。关于如何实现此目标的任何参考或示例?我不知道从这个具体问题开始。当用户停止编辑(滤镜,亮度,对比度等)时,我还希望能够导出该视频。

干杯!欢迎提供所有信息。

1 个答案:

答案 0 :(得分:1)

AVFoundation 框架可以轻松地逐帧处理视频。它每次都会在当前时间从视频生成像素缓冲帧,并让您根据需要在帧上添加任何效果(滤镜,亮度,对比度,随心所欲)。实时处理帧可以在GPU上完成。 OpenGL 金属可用于此目的。它还将帮助您使用自己的定制过滤器。您可以按照此link开始。