Issue
I'm using AVFoundation to implement a Camera that is able to record videos while running special AI processing.
Having an AVCaptureMovieFileOutput
(for video recording) and a AVCaptureVideoDataOutput
(for processing AI) running at the same time is not supported (see Can use AVCaptureVideoDataOutput and AVCaptureMovieFileOutput at the same time?), so I have decided to use a single AVCaptureVideoDataOutput
which is able to record videos to a file while running the AI processing in the same captureOutput(...)
callback.
To my surprise, doing that drastically increases RAM usage from 58 MB to 187 MB (!!!), and CPU from 3-5% to 7-12% while idle. While actually recording, the RAM goes up even more (260 MB!).
I am wondering what I did wrong here, since I disabled all the AI processing and just compared the differences between AVCaptureMovieFileOutput
and AVCaptureVideoDataOutput
.
My code:
AVCaptureMovieFileOutput
Setup
if let movieOutput = self.movieOutput {
captureSession.removeOutput(movieOutput)
}
movieOutput = AVCaptureMovieFileOutput()
captureSession.addOutput(movieOutput!)
Delegate
(well there is none, AVCaptureMovieFileOutput
handles all that internally)
Benchmark
When idle, so not recording at all:
- RAM: 56 MB
- CPU: 3-5%
When recording using AVCaptureMovieFileOutput.startRecording
:
- RAM: 56 MB (how???)
- CPU: 20-30%
AVCaptureVideoDataOutput
Setup
// Video
if let videoOutput = self.videoOutput {
captureSession.removeOutput(videoOutput)
self.videoOutput = nil
}
videoOutput = AVCaptureVideoDataOutput()
videoOutput!.setSampleBufferDelegate(self, queue: videoQueue)
videoOutput!.alwaysDiscardsLateVideoFrames = true
captureSession.addOutput(videoOutput!)
// Audio
if let audioOutput = self.audioOutput {
captureSession.removeOutput(audioOutput)
self.audioOutput = nil
}
audioOutput = AVCaptureAudioDataOutput()
audioOutput!.setSampleBufferDelegate(self, queue: audioQueue)
captureSession.addOutput(audioOutput!)
Delegate
extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate,
AVCaptureAudioDataOutputSampleBufferDelegate {
public final func captureOutput(_ captureOutput: AVCaptureOutput,
didOutput sampleBuffer: CMSampleBuffer,
from _: AVCaptureConnection) {
// empty
}
public final func captureOutput(_ captureOutput: AVCaptureOutput,
didDrop buffer: CMSampleBuffer,
from _: AVCaptureConnection) {
// empty
}
}
yes, they are literally empty methods. My RAM and CPU usage is still that high without doing any work here.
Benchmark
When idle, so not recording at all:
- RAM: 151-187 MB
- CPU: 7-12%
When recording using a custom AVAssetWriter
:
- RAM: 260 MB
- CPU: 64%
Why is the AVCaptureMovieFileOutput
so much more efficient than an empty AVCaptureVideoDataOutput
? Also, why does it's RAM not go up at all when recording, compared to how my AVAssetWriter
implementation alone consumes 80 MB?
Here's my custom AVAssetWriter
implementation: RecordingSession.swift
, and here's where I call it.
Any help appreciated!