Background:
I am using AVCaptureVideoDataOutput
in alignment with AVCaptureSession
and other various AV
tools to create a video session such that I can create a camera session. I have a live feed of what the camera sees it is on the screen.
I use AVCaptureVideoDataOutput
and not AVCaptureMovieFileOutput
because the images I obtain through the live feed are processed using CIFilter
's. Now, I want to record what is being shown to the user when I press a button. My thoughts on doing this were using the below function as I thought this function captures every frame. I infer this from Apple's Page which states:
Delegates receive this message whenever the output captures and outputs a new video frame, decoding or re-encoding it as specified by its videoSettings property. Delegates can use the provided video frame in conjunction with other APIs for further processing.
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)
I expected each frame to be here such that I could use an AVAssetWriter
and add the buffer to the videoWriterInput
. This can be seen here where the answer indicates that the method func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)
adds the sampleBuffer
to the videoWriterInput
each time.
My Efforts:
I have attempted to simulate the above SO post where the answer utilizes AVAssetWriter
to write AVCaptureVideoDataOutput
to a file. However, my code, which is indicated below, is not calling the AVCaptureVideoDataOutputSampleBufferDelegate
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)
delegate method.
NOTE: This is not all the code - I am adding only relevant portions - if there is something missing that you need, please let me know
VideoCapture.swift
class VideoCapture: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {
private let captureSession = AVCaptureSession()
private let videoDataOutput = AVCaptureVideoDataOutput()
private let dataOutputQueue = DispatchQueue(label: "com.Camera.dataOutputQueue")
private var videoConnection: AVCaptureConnection!
//NEVER GETS CALLED
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
print("Buf: \(sampleBuffer)")
}
func captureOutput(_ output: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
print("Drop Buff: \(sampleBuffer)")
}
init() {
//Some Setup
captureSession.sessionPreset = AVCaptureSession.Preset.high
//...
do {
// video output
videoDataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)]
videoDataOutput.alwaysDiscardsLateVideoFrames = true
videoDataOutput.setSampleBufferDelegate(self, queue: dataOutputQueue)
guard captureSession.canAddOutput(videoDataOutput) else { fatalError() }
captureSession.addOutput(videoDataOutput)
videoConnection = videoDataOutput.connection(with: .video)
}
//...
}
}
AnotherFile.swift
class VC: UIViewController {
private var videoCapture: VideoCapture!
init() {
self.videoCapture = VideoCapture()
}
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let videoCapture = videoCapture else {return}
videoCapture.startCapture()
}
}
What I Expected:
I expect the method
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)
to be called and at least print out the buffer from the above example. This is not happening, so I am unable to further my development and insert my buffer into a videoWriteInput
for recording.
What Actually Happens:
It is never called. I made sure to setup the delegates using videoDataOutput.setSampleBufferDelegate(self, queue: dataOutputQueue)
and clearly indicate that the delegate methods are made. I was sure to use the auto-complete feature so that the method was created from XCode so I didn't mess up the method name such as this SO post.
Question:
How can I appropriately get the method to be called -- assuming my intuition is correct that this method is called for each frame and is a buffer I can insert into my videoWriterInput
-- so that I can record a video from the AVCaptureSession
I can see on screen?
Noteworthy:
This project DOES NOT work in terms of calling
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)
while this DOES work.
EDIT:
I have found out that for some reason, AVCaptureDataOutputSynchronizer
causes it to not call the Delegate function. Any Ideas?