如何在AVFoundation中只将某些CMSampleBuffer帧写入新的电影文件



我想对用户导入的视频执行姿势分析,自动生成AVFoundation视频输出,其中只有检测到姿势的帧才是结果的一部分。在为体育分析构建功能丰富的应用程序示例代码中,分析通过实现func cameraViewController(_ controller: CameraViewController, didReceiveBuffer buffer: CMSampleBuffer, orientation: CGImagePropertyOrientation)委托回调来进行,例如在GameViewController.swift的326行中。

我陷入困境的地方是使用这种分析只保留检测到姿势的特定帧。假设我已经分析了所有CMSampleBuffer帧,并对哪些帧具有我想要的姿势进行了分类。如何将那些特定的帧只用于新的视频输出?

";AVFoundation编程指南";苹果文档档案中的链接被破坏了,所以很难找到概念性的解释。首选Swift中的答案,尽管Objective-C仍然会有所帮助。

如果您想记录CMSampleBuffer,可以使用以下代码:

import Foundation
import AVFoundation
class MovieRecorder {

private var assetWriter: AVAssetWriter?

private var assetWriterVideoInput: AVAssetWriterInput?

private var assetWriterAudioInput: AVAssetWriterInput?

private var videoTransform: CGAffineTransform

private var videoSettings: [String: Any]
private var audioSettings: [String: Any]
private(set) var isRecording = false

init(audioSettings: [String: Any], videoSettings: [String: Any], videoTransform: CGAffineTransform) {
self.audioSettings = audioSettings
self.videoSettings = videoSettings
self.videoTransform = videoTransform
}

func startRecording() {
// Create an asset writer that records to a temporary file
let outputFileName = NSUUID().uuidString
let outputFileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(outputFileName).appendingPathExtension("MOV")
guard let assetWriter = try? AVAssetWriter(url: outputFileURL, fileType: .mov) else {
return
}

// Add an audio input
let assetWriterAudioInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioSettings)
assetWriterAudioInput.expectsMediaDataInRealTime = true
assetWriter.add(assetWriterAudioInput)

// Add a video input
let assetWriterVideoInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
assetWriterVideoInput.expectsMediaDataInRealTime = true
assetWriterVideoInput.transform = videoTransform
assetWriter.add(assetWriterVideoInput)

self.assetWriter = assetWriter
self.assetWriterAudioInput = assetWriterAudioInput
self.assetWriterVideoInput = assetWriterVideoInput

isRecording = true
}

func stopRecording(completion: @escaping (URL) -> Void) {
guard let assetWriter = assetWriter else {
return
}

self.isRecording = false
self.assetWriter = nil

assetWriter.finishWriting {
completion(assetWriter.outputURL)
}
}

func recordVideo(sampleBuffer: CMSampleBuffer) {
guard isRecording,
let assetWriter = assetWriter else {
return
}

if assetWriter.status == .unknown {
assetWriter.startWriting()
assetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(sampleBuffer))
} else if assetWriter.status == .writing {
if let input = assetWriterVideoInput,
input.isReadyForMoreMediaData {
input.append(sampleBuffer)
}
}
}

func recordAudio(sampleBuffer: CMSampleBuffer) {
guard isRecording,
let assetWriter = assetWriter,
assetWriter.status == .writing,
let input = assetWriterAudioInput,
input.isReadyForMoreMediaData else {
return
}

input.append(sampleBuffer)
}
}

最新更新