我正在使用 AVFoundation captureOutput didOutputSampleBuffer 来提取图像,然后用于过滤器。
self.bufferFrameQueue = DispatchQueue(label: "bufferFrame queue", qos: DispatchQoS.background, attributes: [], autoreleaseFrequency: .inherit)
self.videoDataOutput = AVCaptureVideoDataOutput()
if self.session.canAddOutput(self.videoDataOutput) {
self.session.addOutput(videoDataOutput)
self.videoDataOutput!.alwaysDiscardsLateVideoFrames = true
self.videoDataOutput!.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)]
self.videoDataOutput!.setSampleBufferDelegate(self, queue: self.bufferFrameQueue)
}
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
connection.videoOrientation = .portrait
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
DispatchQueue.main.async {
self.cameraBufferImage = ciImage
}
}
上面只是更新 self.cameraBufferImage ,只要有新的输出样本缓冲区。
然后,当按下过滤器按钮时,我使用 self.cameraBufferImage :
func filterButtonPressed() {
if var inputImage = self.cameraBufferImage {
if let currentFilter = CIFilter(name: "CISepiaTone") {
currentFilter.setValue(inputImage, forKey: "inputImage")
currentFilter.setValue(1, forKey: "inputIntensity")
if let output = currentFilter.outputImage {
if let cgimg = self.context.createCGImage(output, from: inputImage.extent) {
self.filterImageLayer = CALayer()
self.filterImageLayer!.frame = self.imagePreviewView.bounds
self.filterImageLayer!.contents = cgimg
self.filterImageLayer!.contentsGravity = kCAGravityResizeAspectFill
self.imagePreviewView.layer.addSublayer(self.filterImageLayer!)
}
}
}
}
}
当调用上述方法时,它会抓取当前的' self.cameraBufferImage 并使用它来应用过滤器。这在正常曝光持续时间(低于1/15秒左右......)
时工作正常当曝光持续时间很慢,即1/3秒时,需要一段时间(约1/3秒)来应用滤光片。此延迟仅在发布后第一次出现。如果再次完成,则根本没有延迟。
思想
据我所知,如果曝光时间为1/3秒,didOutputSampleBuffer每1/3秒更新一次。但是,为什么最初的延迟呢?难道它只是抓住那个确切时间可用的 self.cameraBufferImage ,而不是等待?
更新
只要输出捕获和,代理就会收到此消息 输出一个新的视频帧,按照规定解码或重新编码 它的videoSettings属性。代表可以使用提供的视频帧 与其他API一起进行进一步处理。
在输出指定的调度队列上调用此方法 sampleBufferCallbackQueue属性。它被定期调用,所以它 必须有效地防止捕获性能问题,包括 丢帧。
如果需要引用之外的CMSampleBuffer对象 这个方法的范围,你必须CFRetain它,然后CFRelease它 你完成了它。
为了保持最佳性能,请直接使用一些样本缓冲区 可能需要由设备重用的内存参考池 系统和其他捕获输入。这种情况经常发生 未压缩设备本机捕获,其中内存块被复制为 尽量少。如果多个样本缓冲区引用了这样的池 内存太长,输入将无法再复制新样本 进入内存,这些样本将被删除。
如果您的应用程序通过保留应用程序导致丢弃样本 提供CMSampleBuffer对象的时间太长,但需要访问 如果样本数据很长一段时间,请考虑复制数据 进入一个新的缓冲区然后释放样本缓冲区(如果是的话) 之前保留的)以便它可以重用它引用的内存。