Apples CI Face Detector を使用してリアルタイム ビデオで顔を検出したいのですが、AVAssetWriter を使用してビデオをファイルに記録したいと考えています。
動作していると思いましたが、オーディオは気まぐれです。ビデオと一緒に正しく記録される場合もあれば、記録を開始してもミュートになる場合もあれば、ビデオと同期していない場合もあれば、まったく機能しない場合もあります。
print ステートメントを使用すると、オーディオ サンプル バッファーがあることがわかります。そのコードをコメントアウトすると、記録が正常に機能するため、顔検出と関係があるに違いありません。
これが私のコードです:
// MARK: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioOutputSampleBufferDelegate
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
let writable = canWrite()
if writable {
print("Writable")
}
if writable,
sessionAtSourceTime == nil {
// Start Writing
sessionAtSourceTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
videoWriter.startSession(atSourceTime: sessionAtSourceTime!)
print("session started")
}
// processing on the images, not audio
if output == videoDataOutput {
connection.videoOrientation = .portrait
if connection.isVideoMirroringSupported {
connection.isVideoMirrored = true
}
// convert current frame to CIImage
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
let attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, pixelBuffer!, CMAttachmentMode(kCMAttachmentMode_ShouldPropagate)) as? [String: Any]
let ciImage = CIImage(cvImageBuffer: pixelBuffer!, options: attachments)
// Detects faces based on your ciimage
let features = faceDetector?.features(in: ciImage, options: [CIDetectorSmile : true,
CIDetectorEyeBlink : true,
]).compactMap({ $0 as? CIFaceFeature })
// Retreive frame of your buffer
let desc = CMSampleBufferGetFormatDescription(sampleBuffer)
let bufferFrame = CMVideoFormatDescriptionGetCleanAperture(desc!, false)
// Draw face masks
DispatchQueue.main.async { [weak self] in
UIView.animate(withDuration: 0.2) {
self?.drawFaceMasksFor(features: features!, bufferFrame: bufferFrame)
}
}
}
if writable,
output == videoDataOutput,
(videoWriterInput.isReadyForMoreMediaData) {
// write video buffer
videoWriterInput.append(sampleBuffer)
print("video buffering")
} else if writable,
output == audioDataOutput,
(audioWriterInput.isReadyForMoreMediaData) {
// write audio buffer
audioWriterInput?.append(sampleBuffer)
print("audio buffering")
}
}