【问题标题】:switch CIFilters to video将 CIFilters 切换到视频
【发布时间】:2020-02-16 15:39:34
【问题描述】:

有人可以帮我理解在不重启视频播放器的情况下切换 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 更改为正在播放的视频的最佳方法是什么 是否可以使用新过滤器保存视频?

谢谢!

【问题讨论】:

    标签: ios video swift5 cifilter avvideocomposition


    【解决方案1】:

    您在创建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即可轻松更改过滤器。

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

    【讨论】:

    • 效果很好!!谢谢!为了保存结果,我尝试使用 AVMutableComposition 作为 AVPlayerItem 的资产 .... 是正确的方法吗?
    • 要导出,最好使用AVAssetExportSession。它还可以与AVVideoComposition 一起使用,并将视频写入您指定的文件 URL。
    • 我尝试将资产 (letasset = AVAsset(url: fooURL)) 传递给 AVAssetExportSession。新视频正确保存但没有过滤器。任何想法?我使用 let exporter = AVAssetExportSession(asset: asset!, presetName: AVAssetExportPresetHighestQuality)。谢谢弗兰克!!!
    • 您还必须设置导出会话的videoComposition,就像对播放器项目所做的那样。
    猜你喜欢
    • 2019-05-28
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    • 2015-02-16
    • 2020-08-27
    • 2014-05-05
    • 2021-12-20
    相关资源
    最近更新 更多