如何以每秒240帧的速度录制和保存?
How to record and save at 240 frames per second?
我需要以 phone 的最大帧速率 (240 fps) 从 iPhone Xs 录制和保存视频。保存的文件始终以 30 fps 结束。我浏览了十几个 guides/docs/Stack 溢出帖子,但尚未找到正确的解决方案。我已经通过在 VLC 中打开录制的文件以及提取和计算帧数进行了测试。
我做错了什么?
环境:Xcode 10.1,构建目标 iOS 12.1,在 iPhone Xs 运行 iOS 12.1.2
上测试
我在这里访问设备并将其配置为它支持的最佳帧率:
override func viewDidLoad() {
super.viewDidLoad()
let deviceDiscoverSession = AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)
guard let backCameraDevice = deviceDiscoverSession else {
print("Failed to open back, wide-angle camera")
return
}
self.currentDevice = backCameraDevice
do {
let input = try AVCaptureDeviceInput(device: backCameraDevice)
// configureDevice() // putting this here makes no difference
self.session.addInput(input)
configureDevice()
} catch {
print(error)
return
}
}
func configureDevice() {
var bestFormat: AVCaptureDevice.Format? = nil
var bestFrameRateRange: AVFrameRateRange? = nil
var bestPixelArea: Int32 = 0
for format in currentDevice!.formats {
let dims: CMVideoDimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription)
let pixelArea: Int32 = dims.width * dims.height
let ranges = format.videoSupportedFrameRateRanges
for range in ranges {
if bestFrameRateRange==nil || range.maxFrameRate > bestFrameRateRange!.maxFrameRate || ((range.maxFrameRate == bestFrameRateRange!.maxFrameRate) && (pixelArea > bestPixelArea)) {
bestFormat = format as AVCaptureDevice.Format
bestFrameRateRange = range
bestPixelArea = pixelArea
}
}
}
do {
try currentDevice!.lockForConfiguration()
if let best_format = bestFormat {
currentDevice!.activeFormat = best_format
currentDevice!.activeVideoMinFrameDuration = bestFrameRateRange!.minFrameDuration
currentDevice!.activeVideoMaxFrameDuration = bestFrameRateRange!.maxFrameDuration
}
} catch {
print(error)
}
let movieFileOutput = AVCaptureMovieFileOutput()
if self.session.canAddOutput(movieFileOutput) {
self.session.beginConfiguration()
self.session.addOutput(movieFileOutput)
self.session.sessionPreset = .high
if let connection = movieFileOutput.connection(with: .video) {
if movieFileOutput.availableVideoCodecTypes.contains(.h264) {
movieFileOutput.setOutputSettings([AVVideoCodecKey:
AVVideoCodecType.h264], for: connection)
}
}
self.session.commitConfiguration()
self.movieFileOutput = movieFileOutput
}
currentDevice!.unlockForConfiguration()
}
当用户停止录制时,我调用了一个函数,部分包含以下代码将文件保存到临时目录(后来移动到应用程序的文档目录)
sessionQueue.async {
if !self.isRecording {
self.isRecording = true
let movieFileOutputConnection = self.movieFileOutput!.connection(with: .video)
movieFileOutputConnection?.videoOrientation = .landscapeRight
let availableVideoCodecTypes = self.movieFileOutput!.availableVideoCodecTypes
if availableVideoCodecTypes.contains(.h264) {
self.movieFileOutput!.setOutputSettings([AVVideoCodecKey: AVVideoCodecType.h264], for: movieFileOutputConnection!)
}
let outputFileName = NSUUID().uuidString
let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mp4")!)
self.movieFileOutput?.startRecording(to: URL(fileURLWithPath: outputFilePath), recordingDelegate: self)
} else {
self.movieFileOutput?.stopRecording()
self.isRecording = false
}
}
典型的答案似乎是。在添加到会话之前或之后调用配置似乎没有什么不同。
我已经尝试在 self.movieFileOutput?.startRecording()
调用之前以及上面显示的位置配置 movieFileOutput
。两者给出相同的结果。
我通过更深入地阅读
了解了这一点
在 configureDevice()
中我设置了 self.session.sessionPreset = .high
而实际上我需要设置 self.session.sessionPreset = .inputPriority
这是 Swift 4 相当于上面答案中建议的 AVCaptureSessionPresetInputPriority 值.
我需要以 phone 的最大帧速率 (240 fps) 从 iPhone Xs 录制和保存视频。保存的文件始终以 30 fps 结束。我浏览了十几个 guides/docs/Stack 溢出帖子,但尚未找到正确的解决方案。我已经通过在 VLC 中打开录制的文件以及提取和计算帧数进行了测试。
我做错了什么?
环境:Xcode 10.1,构建目标 iOS 12.1,在 iPhone Xs 运行 iOS 12.1.2
上测试我在这里访问设备并将其配置为它支持的最佳帧率:
override func viewDidLoad() {
super.viewDidLoad()
let deviceDiscoverSession = AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)
guard let backCameraDevice = deviceDiscoverSession else {
print("Failed to open back, wide-angle camera")
return
}
self.currentDevice = backCameraDevice
do {
let input = try AVCaptureDeviceInput(device: backCameraDevice)
// configureDevice() // putting this here makes no difference
self.session.addInput(input)
configureDevice()
} catch {
print(error)
return
}
}
func configureDevice() {
var bestFormat: AVCaptureDevice.Format? = nil
var bestFrameRateRange: AVFrameRateRange? = nil
var bestPixelArea: Int32 = 0
for format in currentDevice!.formats {
let dims: CMVideoDimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription)
let pixelArea: Int32 = dims.width * dims.height
let ranges = format.videoSupportedFrameRateRanges
for range in ranges {
if bestFrameRateRange==nil || range.maxFrameRate > bestFrameRateRange!.maxFrameRate || ((range.maxFrameRate == bestFrameRateRange!.maxFrameRate) && (pixelArea > bestPixelArea)) {
bestFormat = format as AVCaptureDevice.Format
bestFrameRateRange = range
bestPixelArea = pixelArea
}
}
}
do {
try currentDevice!.lockForConfiguration()
if let best_format = bestFormat {
currentDevice!.activeFormat = best_format
currentDevice!.activeVideoMinFrameDuration = bestFrameRateRange!.minFrameDuration
currentDevice!.activeVideoMaxFrameDuration = bestFrameRateRange!.maxFrameDuration
}
} catch {
print(error)
}
let movieFileOutput = AVCaptureMovieFileOutput()
if self.session.canAddOutput(movieFileOutput) {
self.session.beginConfiguration()
self.session.addOutput(movieFileOutput)
self.session.sessionPreset = .high
if let connection = movieFileOutput.connection(with: .video) {
if movieFileOutput.availableVideoCodecTypes.contains(.h264) {
movieFileOutput.setOutputSettings([AVVideoCodecKey:
AVVideoCodecType.h264], for: connection)
}
}
self.session.commitConfiguration()
self.movieFileOutput = movieFileOutput
}
currentDevice!.unlockForConfiguration()
}
当用户停止录制时,我调用了一个函数,部分包含以下代码将文件保存到临时目录(后来移动到应用程序的文档目录)
sessionQueue.async {
if !self.isRecording {
self.isRecording = true
let movieFileOutputConnection = self.movieFileOutput!.connection(with: .video)
movieFileOutputConnection?.videoOrientation = .landscapeRight
let availableVideoCodecTypes = self.movieFileOutput!.availableVideoCodecTypes
if availableVideoCodecTypes.contains(.h264) {
self.movieFileOutput!.setOutputSettings([AVVideoCodecKey: AVVideoCodecType.h264], for: movieFileOutputConnection!)
}
let outputFileName = NSUUID().uuidString
let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mp4")!)
self.movieFileOutput?.startRecording(to: URL(fileURLWithPath: outputFilePath), recordingDelegate: self)
} else {
self.movieFileOutput?.stopRecording()
self.isRecording = false
}
}
典型的答案似乎是
我已经尝试在 self.movieFileOutput?.startRecording()
调用之前以及上面显示的位置配置 movieFileOutput
。两者给出相同的结果。
我通过更深入地阅读
在 configureDevice()
中我设置了 self.session.sessionPreset = .high
而实际上我需要设置 self.session.sessionPreset = .inputPriority
这是 Swift 4 相当于上面答案中建议的 AVCaptureSessionPresetInputPriority 值.