Reputation: 611
I am building a feature where I record video and audio using AVFoundation. I will record for hours, but I want to upload chunks to our backend so that we can build a live HLS-playlist (after som processing of the segments).
First of all, is there a sample somewhere doing this? I haven't found any reference implementations so to say...
Here is my take on it:
AVCaptureSession
following the docs and examples on the web.AVCaptureVideoDataOutputSampleBufferDelegate
and AVCaptureAudioDataOutputSampleBufferDelegate
to get access to the sample buffersAVAssetWriter
s and switch between, one with mediaType
== AVMediaTypeVideo
and one with mediaType
== AVMediaTypeAudio
. CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer)
I switch between the writers after typically 5 seconds.Problems:
AVAssetWriter::append()
, it just fails
and returns false AVAssetWriter.status
.AVAssetWriterStatusFailed
and more information should be available in AVAssetWriter.error
AVAssetWriter.error
is set to
Optional(Error Domain=AVFoundationErrorDomain Code=-11800 \"The operation could not be completed\" UserInfo={NSUnderlyingError=0x14e73dc10 {Error Domain=NSOSStatusErrorDomain Code=-16364 \"(null)\"},NSLocalizedFailureReason=An unknown error occurred (-16364), NSLocalizedDescription=The operation could not be completed})
AVFoundationErrorDomain.code
11800
means AVErrorUnknown
Anyone that has had the same problems or knows how to find more info?
Finally, when I switch between writers, there is a period from when I call AVAssetWriter.startWriting()
(I do this when I create my idle writer, before it its time to switch to a new segment) to when I have called AVAssetWriter.startSession(atSourceTime: startTime)
. During this time I need to hold on to sampleBuffers (typically audio). I just make a copy
var copiedBuffer: CMSampleBuffer?
CMSampleBufferCreateCopy(nil, sampleBuffer, &copiedBuffer)
guard copiedBuffer != nil else {
throw VideoWriterError.failedToCopyBuffer
}
pendingSampleBuffers.append((isVideo, copiedBuffer))
After AVAssetWriter.StartSession()
, I write them to the new writer:
while !pendingSampleBuffers.isEmpty {
let (isVideo, sampleBufferOpt) = pendingSampleBuffers.removeFirst()
guard let sampleBuffer = sampleBufferOpt else {
throw VideoWriterError.failedToCopyBuffer
}
try capturedFrame(sampleBuffer: sampleBuffer, isVideo: isVideo)
}
Seems to work, but there is a lot of posts about copying is shallow. I wonder if that can be related to my problems? Sample buffers exist in some kind of pool?
Upvotes: 4
Views: 668
Reputation: 3878
If false is returned, clients can check the value of the AVAssetWriter status property to determine whether the writing operation completed, failed, or was cancelled. If the status is failed, The AVAssetWriter error property will contain an instance of NSErrorß that describes the failure.
From append(_:)
.
I hope this helps. Please do comment for improvements.
Upvotes: 2