如何使用 Swift 实时对视频应用滤镜
How to apply filter to Video real-time using Swift
是否可以将过滤器应用于 AVLayer 并将其作为 addSublayer 添加到 view?我想使用 Swift 更改颜色并为来自摄像机的视频添加一些噪音,但我不知道如何操作。
我想,可以像这样添加 filterLayer 和 previewLayer:
self.view.layer.addSublayer(previewLayer)
self.view.layer.addSublayer(filterLayer)
这也许可以用我的自定义过滤器创建视频,但我认为,使用 AVComposition
可以更有效地做到这一点
所以我需要知道的是:
- 实时将滤镜应用于摄像机视频输出的最简单方法是什么?
- 是否可以合并 AVCaptureVideoPreviewLayer 和 CALayer?
感谢每一个建议..
还有另一种选择,使用 AVCaptureSession 创建 CIImage 的实例,您可以对其应用 CIFilters(其中有负载,从模糊到色彩校正再到 VFX)。
这是一个使用 ComicBook 效果的示例。简而言之,创建一个 AVCaptureSession:
let captureSession = AVCaptureSession()
captureSession.sessionPreset = AVCaptureSessionPresetPhoto
创建一个AVCaptureDevice代表摄像头,这里我设置的是后置摄像头:
let backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
然后创建设备的具体实现并将其附加到会话。在 Swift 2 中,实例化 AVCaptureDeviceInput 会抛出一个错误,所以我们需要捕捉到:
do
{
let input = try AVCaptureDeviceInput(device: backCamera)
captureSession.addInput(input)
}
catch
{
print("can't access camera")
return
}
现在,这里有一点 'gotcha':虽然我们实际上并没有使用 AVCaptureVideoPreviewLayer,但它是让示例委托工作所必需的,因此我们创建了其中一个:
// although we don't use this, it's required to get captureOutput invoked
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
view.layer.addSublayer(previewLayer)
接下来,我们创建一个视频输出 AVCaptureVideoDataOutput,我们将使用它来访问视频源:
let videoOutput = AVCaptureVideoDataOutput()
确保自己实现了 AVCaptureVideoDataOutputSampleBufferDelegate,我们可以在视频输出上设置样本缓冲区委托:
videoOutput.setSampleBufferDelegate(self,
queue: dispatch_queue_create("sample buffer delegate", DISPATCH_QUEUE_SERIAL))
然后将视频输出附加到捕获会话:
captureSession.addOutput(videoOutput)
...最后,我们开始捕获会话:
captureSession.startRunning()
因为我们已经设置了委托,所以每次捕获帧时都会调用 captureOutput。 captureOutput 被传递了一个 CMSampleBuffer 类型的样本缓冲区,它只需要两行代码就可以将该数据转换为 CIImage 供 Core Image 处理:
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
let cameraImage = CIImage(CVPixelBuffer: pixelBuffer!)
...并且该图像数据被传递到我们的漫画书效果,而漫画书效果又用于填充图像视图:
let comicEffect = CIFilter(name: "CIComicEffect")
comicEffect!.setValue(cameraImage, forKey: kCIInputImageKey)
let filteredImage = UIImage(CIImage: comicEffect!.valueForKey(kCIOutputImageKey) as! CIImage!)
dispatch_async(dispatch_get_main_queue())
{
self.imageView.image = filteredImage
}
我有 source code for this project available in my GitHub repo here.
如果您使用的是 AVPlayerViewController
,您可以设置 view
的 layer
的合成过滤器 属性:
playerController.view.layer.compositingFilter = "multiplyBlendMode"
See here for the compositing filter options you can use。例如"multiplyBlendMode"、"screenBlendMode" 等
在 UIViewController
中执行此操作的示例:
class ViewController : UIViewController{
override func viewDidLoad() {
//load a movie called my_movie.mp4 that's in your xcode project
let path = Bundle.main.path(forResource: "my_movie", ofType:"mp4")
let player = AVPlayer(url: URL(fileURLWithPath: path!))
//make a movie player and set the filter
let playerController = AVPlayerViewController()
playerController.player = player
playerController.view.layer.compositingFilter = "multiplyBlendMode"
//add the player view controller to this view controller
self.addChild(playerController)
view.addSubview(playerController.view)
playerController.didMove(toParent: self)
//play the movie
player.play()
}
}
对于 let path = Bundle.main.path(forResource: "my_movie", ofType:"mp4")
,确保将 .mp4 文件添加到 Xcode 项目中的构建阶段 > 复制捆绑资源。或者在导入文件时选中 'add to target' 框。
是否可以将过滤器应用于 AVLayer 并将其作为 addSublayer 添加到 view?我想使用 Swift 更改颜色并为来自摄像机的视频添加一些噪音,但我不知道如何操作。
我想,可以像这样添加 filterLayer 和 previewLayer:
self.view.layer.addSublayer(previewLayer)
self.view.layer.addSublayer(filterLayer)
这也许可以用我的自定义过滤器创建视频,但我认为,使用 AVComposition
可以更有效地做到这一点所以我需要知道的是:
- 实时将滤镜应用于摄像机视频输出的最简单方法是什么?
- 是否可以合并 AVCaptureVideoPreviewLayer 和 CALayer?
感谢每一个建议..
还有另一种选择,使用 AVCaptureSession 创建 CIImage 的实例,您可以对其应用 CIFilters(其中有负载,从模糊到色彩校正再到 VFX)。
这是一个使用 ComicBook 效果的示例。简而言之,创建一个 AVCaptureSession:
let captureSession = AVCaptureSession()
captureSession.sessionPreset = AVCaptureSessionPresetPhoto
创建一个AVCaptureDevice代表摄像头,这里我设置的是后置摄像头:
let backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
然后创建设备的具体实现并将其附加到会话。在 Swift 2 中,实例化 AVCaptureDeviceInput 会抛出一个错误,所以我们需要捕捉到:
do
{
let input = try AVCaptureDeviceInput(device: backCamera)
captureSession.addInput(input)
}
catch
{
print("can't access camera")
return
}
现在,这里有一点 'gotcha':虽然我们实际上并没有使用 AVCaptureVideoPreviewLayer,但它是让示例委托工作所必需的,因此我们创建了其中一个:
// although we don't use this, it's required to get captureOutput invoked
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
view.layer.addSublayer(previewLayer)
接下来,我们创建一个视频输出 AVCaptureVideoDataOutput,我们将使用它来访问视频源:
let videoOutput = AVCaptureVideoDataOutput()
确保自己实现了 AVCaptureVideoDataOutputSampleBufferDelegate,我们可以在视频输出上设置样本缓冲区委托:
videoOutput.setSampleBufferDelegate(self,
queue: dispatch_queue_create("sample buffer delegate", DISPATCH_QUEUE_SERIAL))
然后将视频输出附加到捕获会话:
captureSession.addOutput(videoOutput)
...最后,我们开始捕获会话:
captureSession.startRunning()
因为我们已经设置了委托,所以每次捕获帧时都会调用 captureOutput。 captureOutput 被传递了一个 CMSampleBuffer 类型的样本缓冲区,它只需要两行代码就可以将该数据转换为 CIImage 供 Core Image 处理:
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
let cameraImage = CIImage(CVPixelBuffer: pixelBuffer!)
...并且该图像数据被传递到我们的漫画书效果,而漫画书效果又用于填充图像视图:
let comicEffect = CIFilter(name: "CIComicEffect")
comicEffect!.setValue(cameraImage, forKey: kCIInputImageKey)
let filteredImage = UIImage(CIImage: comicEffect!.valueForKey(kCIOutputImageKey) as! CIImage!)
dispatch_async(dispatch_get_main_queue())
{
self.imageView.image = filteredImage
}
我有 source code for this project available in my GitHub repo here.
如果您使用的是 AVPlayerViewController
,您可以设置 view
的 layer
的合成过滤器 属性:
playerController.view.layer.compositingFilter = "multiplyBlendMode"
See here for the compositing filter options you can use。例如"multiplyBlendMode"、"screenBlendMode" 等
在 UIViewController
中执行此操作的示例:
class ViewController : UIViewController{
override func viewDidLoad() {
//load a movie called my_movie.mp4 that's in your xcode project
let path = Bundle.main.path(forResource: "my_movie", ofType:"mp4")
let player = AVPlayer(url: URL(fileURLWithPath: path!))
//make a movie player and set the filter
let playerController = AVPlayerViewController()
playerController.player = player
playerController.view.layer.compositingFilter = "multiplyBlendMode"
//add the player view controller to this view controller
self.addChild(playerController)
view.addSubview(playerController.view)
playerController.didMove(toParent: self)
//play the movie
player.play()
}
}
对于 let path = Bundle.main.path(forResource: "my_movie", ofType:"mp4")
,确保将 .mp4 文件添加到 Xcode 项目中的构建阶段 > 复制捆绑资源。或者在导入文件时选中 'add to target' 框。