У меня довольно специфическая проблема, но, надеюсь, кто-нибудь сможет мне помочь. Я использую AVFoundation для создания видеокамеры с предварительным просмотром в реальном времени. Я использую AVCaptureVideoDataOutput для получения отдельных кадров и AVCaptureMetadataOutput для обнаружения лица. Я также использую предиктор ориентиров на лице Длиба, чтобы показать ориентиры на лице пользователя и измерить межглазное расстояние между глазами. Наконец, я использую AVAssetWriter, чтобы можно было записывать видео.
Контроллер вида имеет форму эллипса, поэтому пользователь знает, куда поместить свое лицо. Когда межглазное расстояние находится между определенным расстоянием, я хочу, чтобы эллипс стал синим, чтобы пользователь знал, что его лицо находится в правильном месте.
В тот момент, когда я достиг этого, отправив уведомление из моего класса SessionHandler в View Controller. Это работает, однако это приводит к тому, что количество кадров в секунду в видео сильно падает. Я получал 25 кадров в секунду (установленный мной вручную), и теперь он колеблется между 8-16.
Есть ли другой способ уведомить контроллер представления о том, что эллипс должен стать зеленым?
Вот мой код, где возникает проблема. Я знаю, что многое происходит.
// MARK: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioOutputSampleBufferDelegate
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
if !currentMetadata.isEmpty {
let boundsArray = currentMetadata
.compactMap { $0 as? AVMetadataFaceObject }
.map { (faceObject) -> NSValue in
let convertedObject = output.transformedMetadataObject(for: faceObject, connection: connection)
return NSValue(cgRect: convertedObject!.bounds)
}
if user.hasDlib {
wrapper?.doWork(on: sampleBuffer, inRects: boundsArray)
// Get the interocular distance so face is the correct place in the oval
let interocularDistance = wrapper?.getEyeDistance()
//print("Interocular Distance: \(interocularDistance)")
if user.hasInterocularDistance {
if interocularDistance! < 240 || interocularDistance! > 315 {
let name = Notification.Name(rawValue: setRemoveGreenEllipse)
NotificationCenter.default.post(name: name, object: nil)
//print("face not correct distance")
if videoRecorder.isRecording {
eyeDistanceCounter += 1
//print(eyeDistanceCounter)
if eyeDistanceCounter == 30 {
cancelledByUser = false
cancelledByEyeDistance = true
videoRecorder.cancel()
eyeDistanceCounter = 0
}
}
} else {
//print("face correct distance")
eyeDistanceCounter = 0
let name = Notification.Name(rawValue: setGreenEllipse)
NotificationCenter.default.post(name: name, object: nil)
}
}
}
} else {
// Check if face is detected during recording. If it isn't, then cancel recording
if videoRecorder.isRecording {
noFaceCount += 1
if noFaceCount == 50 {
cancelledByUser = false
videoRecorder.cancel()
noFaceCount = 0
}
}
}
if layer.status == .failed {
layer.flush()
}
layer.enqueue(sampleBuffer)
let writable = videoRecorder.canWrite()
if writable {
if videoRecorder.sessionAtSourceTime == nil {
// Start Writing
videoRecorder.sessionAtSourceTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
videoRecorder.videoWriter.startSession(atSourceTime: videoRecorder.sessionAtSourceTime!)
print("video session started")
}
if videoRecorder.videoWriterInput.isReadyForMoreMediaData {
// write video buffer
videoRecorder.videoWriterInput.append(sampleBuffer)
//print("video buffering")
}
}
}