如何解决Swift:播放本地视频并实时应用 CIFilter
我正在尝试播放本地视频并无延迟地实时应用 CIFilter
。我怎样才能做到这一点?我已经知道如何将 CIFilter
应用到 AVPlayer
中的视频,但它的性能没有我想要的那么快。
这是我当前的代码:
@objc func exposure(slider: UiSlider,event: UIEvent) {
if let touchEvent = event.alltouches?.first {
switch touchEvent.phase {
case .moved:
player.currentItem?.videoComposition = AVVideoComposition(asset: player.currentItem!.asset,applyingCIFiltersWithHandler: { request in
let exposureFilter = CIFilter.exposureAdjust()
exposureFilter.inputimage = request.sourceImage.clampedToExtent()
exposureFilter.ev = slider.value
let output = self.exposureFilter.outputimage!.cropped(to: request.sourceImage.extent)
// Provide the filter output to the composition
request.finish(with: output,context: nil)
})
default:
break
}
}
}
解决方法
问题在于,您每次滑块值发生变化时,都会重新创建视频合成并将其重新分配给播放器项目。这是非常昂贵和不必要的。您可以改为执行以下操作:
- 在组合块的外部处创建过滤器并保留对它的引用,例如在属性中。
- 此外,只创建一次合成并让它应用引用过滤器(而不是为每一帧创建一个新的过滤器)。
- 当滑块值发生变化时,只需设置过滤器对应的参数值即可。下次合成渲染帧时,它将自动使用新的参数值,因为它使用对刚刚更改的过滤器的引用。
像这样:
let exposureFilter = CIFilter.exposureAdjust()
init() {
// set initial composition
self.updateComposition()
}
func updateComposition() {
player.currentItem?.videoComposition = AVVideoComposition(asset: player.currentItem!.asset,applyingCIFiltersWithHandler: { request in
self.exposureFilter.inputImage = request.sourceImage.clampedToExtent()
let output = self.exposureFilter.outputImage!.cropped(to: request.sourceImage.extent)
request.finish(with: output,context: nil)
})
}
@objc func exposureChanged(slider: UISlider) {
self.exposureFilter.ev = slider.value
// we need to re-set the composition if the player is paused to cause an update (see remark below)
if player.rate == 0.0 {
self.updateComposition()
}
}
(顺便说一句,当滑块值更改时,您只需执行 slider.addTarget(self,action:#selector(exposureChanged(slider:)),for: .valueChanged)
即可获得通知。无需评估事件。)
最后一点:当您想要重新分配合成时,实际上有一个用例,即当播放器当前暂停但您仍然希望显示当前帧的预览并更改过滤器值时。请参阅this technical note from Apple了解如何操作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。