将CIFilter应用于视频文件并保存

Joj*_*dmo 13 ios avasset cifilter swift

是否有任何快速,轻量级的方式应用于CIFilter视频?在提到它之前,我已经看过GPUImage - 它看起来像是非常强大的魔法代码,但它对我正在尝试做的事情来说真的太过分了.

基本上,我想

  1. 拿一个视频文件,比如存储在 /tmp/myVideoFile.mp4
  2. CIFilter视频文件应用于此视频文件
  3. 比如说,将视频文件保存到不同的(或相同的)位置 /tmp/anotherVideoFile.mp4

我已经能够将CIFilter应用到一个非常容易和快速使用的视频中 AVPlayerItemVideoOutput

let player = AVPlayer(playerItem: AVPlayerItem(asset: video))
let output = AVPlayerItemVideoOutput(pixelBufferAttributes: nil)
player.currentItem?.addOutput(self.output)
player.play()

let displayLink = CADisplayLink(target: self, selector: #selector(self.displayLinkDidRefresh(_:)))
displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)

func displayLinkDidRefresh(link: CADisplayLink){
    let itemTime = output.itemTimeForHostTime(CACurrentMediaTime())
    if output.hasNewPixelBufferForItemTime(itemTime){
        if let pixelBuffer = output.copyPixelBufferForItemTime(itemTime, itemTimeForDisplay: nil){
            let image = CIImage(CVPixelBuffer: pixelBuffer)
            // apply filters to image
            // display image
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这个伟大的工程,但我一直有很多只是麻烦哪怕一丁点找出如何将过滤器应用到已保存的视频文件.有一个选项,基本上只是做我上面做的,使用AVPlayer,播放视频,并在播放时从每一帧获取像素缓冲区,但这不适用于后台视频处理.我不认为用户会喜欢等待他们的视频用于过滤器的应用.

在过度简化的代码中,我正在寻找这样的东西:

var newVideo = AVMutableAsset() // We'll just pretend like this is a thing

var originalVideo = AVAsset(url: NSURL(urlString: "/example/location.mp4"))
originalVideo.getAllFrames(){(pixelBuffer: CVPixelBuffer) -> Void in
    let image = CIImage(CVPixelBuffer: pixelBuffer)
        .imageByApplyingFilter("Filter", withInputParameters: [:])

    newVideo.addFrame(image)
}

newVideo.exportTo(url: NSURL(urlString: "/this/isAnother/example.mp4"))
Run Code Online (Sandbox Code Playgroud)

有没有办法快速(再次,不涉及GPUImage,理想情况下在iOS 7中工作)的方式将过滤器应用于视频文件然后保存?例如,这将拍摄已保存的视频,将其加载到AVAsset应用中CIFilter,然后将新视频保存到其他位置.

ric*_*ter 24

在iOS 9/OS X 10.11/tvOS中,有一种将CIFilters应用于视频的便捷方法.它适用于AVVideoComposition,因此您可以将它用于播放和文件到文件导入/导出.请参阅AVVideoComposition.init(asset:applyingCIFiltersWithHandler:)方法文档.

Apple的核心图像编程指南中也有一个例子:

let filter = CIFilter(name: "CIGaussianBlur")!
let composition = AVVideoComposition(asset: asset, applyingCIFiltersWithHandler: { request in

    // Clamp to avoid blurring transparent pixels at the image edges
    let source = request.sourceImage.clampingToExtent()
    filter.setValue(source, forKey: kCIInputImageKey)

    // Vary filter parameters based on video timing
    let seconds = CMTimeGetSeconds(request.compositionTime)
    filter.setValue(seconds * 10.0, forKey: kCIInputRadiusKey)

    // Crop the blurred output to the bounds of the original image
    let output = filter.outputImage!.cropping(to: request.sourceImage.extent)

    // Provide the filter output to the composition
    request.finish(with: output, context: nil)
})
Run Code Online (Sandbox Code Playgroud)

那部分设定了构图.完成后,您可以通过将其分配给AVPlayer或将其写入文件来播放它AVAssetExportSession.既然你是在后者之后,这是一个例子:

let export = AVAssetExportSession(asset: asset, presetName: AVAssetExportPreset1920x1200)
export.outputFileType = AVFileTypeQuickTimeMovie
export.outputURL = outURL
export.videoComposition = composition

export.exportAsynchronouslyWithCompletionHandler(/*...*/)
Run Code Online (Sandbox Code Playgroud)

在核心图像的WWDC15会议上有更多关于这一点,大约20分钟开始.


如果你想要一个适用于早期操作系统的解决方案,那就有点复杂了.

旁白:想想你真正需要支持多久.截至2016年8月15日,87%的设备在iOS 9.0或更高版本上,97%在iOS 8.0或更高版本上.付出很多努力来支持您的潜在客户群的一小部分 - 当您完成项目并准备部署时,它将变得更小 - 可能不值得花费.

有几种方法可以解决这个问题.无论哪种方式,您将获得CVPixelBuffer表示源帧,从中创建CIImages,应用过滤器以及渲染新CVPixelBuffers的方法.

  1. 使用AVAssetReaderAVAssetWriter读写像素缓冲区.有关如何执行此操作的示例(读取和写入部分;您仍需要在Apple的AVFoundation编程指南的导出章节中进行过滤).

  2. 使用AVVideoComposition带有自定义合成类.您的自定义合成器具有AVAsynchronousVideoCompositionRequest可以访问像素缓冲区的对象,以及提供处理像素缓冲区的方法.Apple有一个名为AVCustomEdit的示例代码项目,它显示了如何执行此操作(再次,只是获取和返回示例缓冲区部分;您希望使用Core Image处理而不是使用其GL渲染器).

在这两个中,AVVideoComposition路径更灵活,因为您可以使用合成进行回放和导出.

  • 还有其他人从中得到模糊的结果吗? (2认同)
  • 结构精美的总结。 (2认同)