Обозреватель вызывает задержку в методе AVFoundation captureOutput - PullRequest
0 голосов
/ 07 сентября 2018

У меня довольно специфическая проблема, но, надеюсь, кто-нибудь сможет мне помочь. Я использую 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")
        }
    }
}

1 Ответ

0 голосов
/ 07 января 2019

Вы, вероятно, могли бы вызывать уведомление один раз за 30 кадров, например, вместо каждого кадра.

Вы также можете вызвать функцию изменения цвета напрямую, если она находится в том же контроллере вида. Если нет, вы можете определить метод делегата и вызывать его напрямую, а не отправлять уведомления.

...