如何使用 Swift 实时对视频应用滤镜

How to apply filter to Video real-time using Swift

是否可以将过滤器应用于 AVLayer 并将其作为 addSublayer 添加到 view?我想使用 Swift 更改颜色并为来自摄像机的视频添加一些噪音,但我不知道如何操作。

我想,可以像这样添加 filterLayerpreviewLayer:

self.view.layer.addSublayer(previewLayer)
self.view.layer.addSublayer(filterLayer)

这也许可以用我的自定义过滤器创建视频,但我认为,使用 AVComposition

可以更有效地做到这一点

所以我需要知道的是:

  1. 实时将滤镜应用于摄像机视频输出的最简单方法是什么?
  2. 是否可以合并 AVCaptureVideoPreviewLayerCALayer?

感谢每一个建议..

还有另一种选择,使用 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,您可以设置 viewlayer 的合成过滤器 属性:

  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' 框。