在 Swift 中使用 AVAssetWriter 将 AVCaptureVideoDataOutput 保存到电影文件
Save AVCaptureVideoDataOutput to movie file using AVAssetWriter in Swift
我一直在网上寻找,但似乎找不到我需要的教程或帮助。
使用 AVFoundation
和 Dlib 库,我创建了一个应用程序,可以使用 phone 上的前置摄像头从实时视频中检测人脸。我正在使用 Shape Predictor 68 Face Landmark
s 执行此操作。为此,我很确定我必须使用 AVCaptureVideoDataOutput
而不是 AVMovieFileOutput,以便可以分析每一帧。
我现在希望能够将视频保存到文件中,根据我收集到的信息,我需要使用 AVAssetWriter
来执行此操作。我只是无法在任何地方找到有关如何开始使用它的太多信息。我是 Swift 和 iOS 编程的新手,通过查看 Apple 的文档并不能真正理解很多东西。
如果有人能帮助我,将不胜感激!
我找到了如何使用 AVAssetWriter 的方法。如果其他人需要帮助,我使用的代码如下:
func setUpWriter() {
do {
outputFileLocation = videoFileLocation()
videoWriter = try AVAssetWriter(outputURL: outputFileLocation!, fileType: AVFileType.mov)
// add video input
videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: [
AVVideoCodecKey : AVVideoCodecType.h264,
AVVideoWidthKey : 720,
AVVideoHeightKey : 1280,
AVVideoCompressionPropertiesKey : [
AVVideoAverageBitRateKey : 2300000,
],
])
videoWriterInput.expectsMediaDataInRealTime = true
if videoWriter.canAdd(videoWriterInput) {
videoWriter.add(videoWriterInput)
print("video input added")
} else {
print("no input added")
}
// add audio input
audioWriterInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
audioWriterInput.expectsMediaDataInRealTime = true
if videoWriter.canAdd(audioWriterInput!) {
videoWriter.add(audioWriterInput!)
print("audio input added")
}
videoWriter.startWriting()
} catch let error {
debugPrint(error.localizedDescription)
}
}
func canWrite() -> Bool {
return isRecording && videoWriter != nil && videoWriter?.status == .writing
}
//video file location method
func videoFileLocation() -> URL {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let videoOutputUrl = URL(fileURLWithPath: documentsPath.appendingPathComponent("videoFile")).appendingPathExtension("mov")
do {
if FileManager.default.fileExists(atPath: videoOutputUrl.path) {
try FileManager.default.removeItem(at: videoOutputUrl)
print("file removed")
}
} catch {
print(error)
}
return videoOutputUrl
}
// MARK: AVCaptureVideoDataOutputSampleBufferDelegate
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
let writable = canWrite()
if writable,
sessionAtSourceTime == nil {
// start writing
sessionAtSourceTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
videoWriter.startSession(atSourceTime: sessionAtSourceTime!)
//print("Writing")
}
if output == videoDataOutput {
connection.videoOrientation = .portrait
if connection.isVideoMirroringSupported {
connection.isVideoMirrored = true
}
}
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")
}
}
// MARK: Start recording
func start() {
guard !isRecording else { return }
isRecording = true
sessionAtSourceTime = nil
setUpWriter()
print(isRecording)
print(videoWriter)
if videoWriter.status == .writing {
print("status writing")
} else if videoWriter.status == .failed {
print("status failed")
} else if videoWriter.status == .cancelled {
print("status cancelled")
} else if videoWriter.status == .unknown {
print("status unknown")
} else {
print("status completed")
}
}
// MARK: Stop recording
func stop() {
guard isRecording else { return }
isRecording = false
videoWriterInput.markAsFinished()
print("marked as finished")
videoWriter.finishWriting { [weak self] in
self?.sessionAtSourceTime = nil
}
//print("finished writing \(self.outputFileLocation)")
captureSession.stopRunning()
performSegue(withIdentifier: "videoPreview", sender: nil)
}
我现在遇到另一个问题,当我同时使用 AVCaptureMetadataOutput、AVCaptureVideoDataOutput 和 AVCaptureAudioDataOutput 时,此解决方案不起作用。当我添加 AVCaptureAudioDataOutput 时应用程序崩溃。
我一直在网上寻找,但似乎找不到我需要的教程或帮助。
使用 AVFoundation
和 Dlib 库,我创建了一个应用程序,可以使用 phone 上的前置摄像头从实时视频中检测人脸。我正在使用 Shape Predictor 68 Face Landmark
s 执行此操作。为此,我很确定我必须使用 AVCaptureVideoDataOutput
而不是 AVMovieFileOutput,以便可以分析每一帧。
我现在希望能够将视频保存到文件中,根据我收集到的信息,我需要使用 AVAssetWriter
来执行此操作。我只是无法在任何地方找到有关如何开始使用它的太多信息。我是 Swift 和 iOS 编程的新手,通过查看 Apple 的文档并不能真正理解很多东西。
如果有人能帮助我,将不胜感激!
我找到了如何使用 AVAssetWriter 的方法。如果其他人需要帮助,我使用的代码如下:
func setUpWriter() {
do {
outputFileLocation = videoFileLocation()
videoWriter = try AVAssetWriter(outputURL: outputFileLocation!, fileType: AVFileType.mov)
// add video input
videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: [
AVVideoCodecKey : AVVideoCodecType.h264,
AVVideoWidthKey : 720,
AVVideoHeightKey : 1280,
AVVideoCompressionPropertiesKey : [
AVVideoAverageBitRateKey : 2300000,
],
])
videoWriterInput.expectsMediaDataInRealTime = true
if videoWriter.canAdd(videoWriterInput) {
videoWriter.add(videoWriterInput)
print("video input added")
} else {
print("no input added")
}
// add audio input
audioWriterInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
audioWriterInput.expectsMediaDataInRealTime = true
if videoWriter.canAdd(audioWriterInput!) {
videoWriter.add(audioWriterInput!)
print("audio input added")
}
videoWriter.startWriting()
} catch let error {
debugPrint(error.localizedDescription)
}
}
func canWrite() -> Bool {
return isRecording && videoWriter != nil && videoWriter?.status == .writing
}
//video file location method
func videoFileLocation() -> URL {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let videoOutputUrl = URL(fileURLWithPath: documentsPath.appendingPathComponent("videoFile")).appendingPathExtension("mov")
do {
if FileManager.default.fileExists(atPath: videoOutputUrl.path) {
try FileManager.default.removeItem(at: videoOutputUrl)
print("file removed")
}
} catch {
print(error)
}
return videoOutputUrl
}
// MARK: AVCaptureVideoDataOutputSampleBufferDelegate
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
let writable = canWrite()
if writable,
sessionAtSourceTime == nil {
// start writing
sessionAtSourceTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
videoWriter.startSession(atSourceTime: sessionAtSourceTime!)
//print("Writing")
}
if output == videoDataOutput {
connection.videoOrientation = .portrait
if connection.isVideoMirroringSupported {
connection.isVideoMirrored = true
}
}
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")
}
}
// MARK: Start recording
func start() {
guard !isRecording else { return }
isRecording = true
sessionAtSourceTime = nil
setUpWriter()
print(isRecording)
print(videoWriter)
if videoWriter.status == .writing {
print("status writing")
} else if videoWriter.status == .failed {
print("status failed")
} else if videoWriter.status == .cancelled {
print("status cancelled")
} else if videoWriter.status == .unknown {
print("status unknown")
} else {
print("status completed")
}
}
// MARK: Stop recording
func stop() {
guard isRecording else { return }
isRecording = false
videoWriterInput.markAsFinished()
print("marked as finished")
videoWriter.finishWriting { [weak self] in
self?.sessionAtSourceTime = nil
}
//print("finished writing \(self.outputFileLocation)")
captureSession.stopRunning()
performSegue(withIdentifier: "videoPreview", sender: nil)
}
我现在遇到另一个问题,当我同时使用 AVCaptureMetadataOutput、AVCaptureVideoDataOutput 和 AVCaptureAudioDataOutput 时,此解决方案不起作用。当我添加 AVCaptureAudioDataOutput 时应用程序崩溃。