将 CIFilter 切换到视频

switch CIFilters to video

有人可以帮助我了解在不重启视频播放器的情况下切换 CIFilters 的正确方法吗?

我在视图中播放本地视频。如果我在集合视图中点击一个单元格,视频将更改 CIFilter。

我的代码

let filter = CIFilter(name: "CIPhotoEffectNoir")!
let asset = AVAsset(url: fooURL)
let item = AVPlayerItem(asset: asset)
item.videoComposition = AVVideoComposition(asset: asset,  applyingCIFiltersWithHandler: { request in
    let source = request.sourceImage.clampedToExtent()
    filter.setValue(source, forKey: kCIInputImageKey)

    let output = filter.outputImage

    request.finish(with: output!, context: nil)
})

player = AVPlayer(playerItem: item)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = videoViewDetail.bounds
videoViewDetail.layer.addSublayer(playerLayer)
player?.play()

代码效果很好,效果正确应用

但我有一个包含许多 CIFilter 的集合视图。 点击一个单元格时,我找不到切换与视频关联的过滤器的方法。 如果我使用新过滤器重新创建一个新播放器并将其添加为当前 "addsublayer" 播放器将重新启动视频。

@IBAction func tap(_ sender: UITapGestureRecognizer) {

    let location = sender.location(in: self.collectionView)
    let indexPath = self.collectionView.indexPathForItem(at: location)

    if let index = indexPath {
        // code to switch to another CIFilter like for example "CISepiaTone"
    }
}

在不重启视频的情况下将 CIFilters 更改为正在播放的视频的最佳方法是什么 是否可以使用新滤镜保存视频?

谢谢!

您在创建 AVVideoComposition 时提供的处理程序块会为播放器显示的每个视频帧连续调用。这意味着您只需切换该块内使用的过滤器。

实现这一点的最简单方法是从块外部引用过滤器而不是捕获它。然后你可以在 运行 时间更改参考。

例如,假设您的代码 运行 在某些视图控制器方法中,您可以执行以下操作:

class MyViewController: UIViewController {

    var filter: CIFilter = CIFilter(name: "CIPhotoEffectNoir")!

    func createPlayer() {
        let asset = AVAsset(url: fooURL)
        let item = AVPlayerItem(asset: asset)
        item.videoComposition = AVVideoComposition(asset: asset,  applyingCIFiltersWithHandler: { [weak self] request in
            guard let self = self else {
                request.finish(with error: SomeError)
                return
            }
            let source = request.sourceImage.clampedToExtent()
            self.filter.setValue(source, forKey: kCIInputImageKey)

            let output = self.filter.outputImage

            request.finish(with: output!, context: nil)
        })

        player = AVPlayer(playerItem: item)
        let playerLayer = AVPlayerLayer(player: player)
        playerLayer.frame = videoViewDetail.bounds
        videoViewDetail.layer.addSublayer(playerLayer)
        player?.play()
    }

    // ...

}

然后你可以很容易地改变过滤器,只需改变self.filter

(您可能希望同步对过滤器的访问,以避免并发问题。)