如何在iOS上录制视频而不使用预设?

4

在iOS上记录视频的简单方法是设置AVCaptureSession.sessionPreset

但对我来说这并不适用,因为我想要控制诸如binning、稳定性(电影、标准或无)和ISO之类的参数。

我找到了想要的格式并将其分配给activeFormat,但当我尝试开始录制时,出现错误:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 
'*** -[AVCaptureMovieFileOutput startRecordingToOutputFileURL:recordingDelegate:] No active/enabled connections'

这是我的初始化代码:

let device = AVCaptureDevice.defaultDevice(
    withDeviceType: .builtInWideAngleCamera,
    mediaType: AVMediaTypeVideo,
    position: .back)!
let session = AVCaptureSession()
session.addInput(try! AVCaptureDeviceInput(device: device))
output = AVCaptureMovieFileOutput()
session.addOutput(output)
device.setFormatWithHighestIso()
session.startRunning()

setFormatWithHighestIso() 的定义如下:

extension AVCaptureDevice {
  var goodVideoFormats: [AVCaptureDeviceFormat] {
    return (formats as! [AVCaptureDeviceFormat])
      .filter { CMFormatDescriptionGetMediaSubType($0.formatDescription) != 875704422 } // 420f
      .filter { $0.autoFocusSystem == .phaseDetection }
  }

  func setFormatWithHighestIso() {
    let format = goodVideoFormats
      .filter { $0.maxISO > 1759 }
      .filter { $0.height < 1937 }
      .first!

    try! lockForConfiguration()
    defer { unlockForConfiguration() }
    activeFormat = format
    NSLog("\(format)")
  }
}

最后的日志语句输出:
<AVCaptureDeviceFormat: 0x1702027d0 'vide'/'420f' 2592x1936, { 3- 30 fps}, HRSI:4032x3024, fov:58.986, max zoom:189.00 (upscales @1.56), AF System:2, ISO:22.0-1760.0, SS:0.000005-0.333333, supports wide color>

这确实是我想要的格式,所以setFormatWithHighestIso()按预期工作。请参阅苹果公司参考文献


我尝试过的其他方法:

  • 通过将 == 875704422 更改为 !=,使用 420v 而不是 420f。
  • 不是从照片模式开始启动相机,而是从视频模式开始启动,然后通过删除 AVCapturePhotoOutput 并添加 AVCaptureMovieFileOutput 来将其更改为视频模式。
  • 验证 AVCaptureConnection 已启用,确实如此。
  • 验证连接已激活,但事实并非如此:

    let conn = output.connection(withMediaType: AVMediaTypeVideo)! verify(conn.isActive)

我还尝试使用其他一些 AVCaptureDeviceFormats,它们有效:

extension AVCaptureDevice { 
  func setFormatWithCinematicVS() {
    let format = goodVideoFormats
      .filter { $0.isVideoStabilizationModeSupported(.cinematic) }
      .filter { $0.height == 720 }
      .first!

    try! lockForConfiguration()
    defer { unlockForConfiguration() }
    activeFormat = format
  }

  func setFormatWithStandardVS() {
    let format = goodVideoFormats
      .filter { $0.isVideoStabilizationModeSupported(.standard) }
      .filter { $0.height == 540 }
      .first!

    try! lockForConfiguration()
    defer { unlockForConfiguration() }
    activeFormat = format
  }
}

只有最高ISO格式不起作用,这种格式有什么特殊之处?

我需要手动创建AVCaptureConnection吗?但已经有一个连接了;它只是没有激活。

这是在运行iOS 10.3.3的iPhone 7 Plus上。如何通过设置activeFormat来录制特定格式的视频而不使用会话?

如果我使用sessionPreset而不是分配给activeFormat,则可以成功记录视频。


有其他问题谈论这个错误信息,但这不是它们的重复,因为我需要特别捕获视频而不使用预设。


我想尝试一下,但没有7+ - 其他型号上没有类似的错误吗?你能添加错误消息吗?也许加一个可运行的重现链接? - Rhythmic Fistman
我在问题中包含了错误。我会尝试创建可运行的复现,但与此同时,你有哪些设备?我会告诉你要尝试复现的格式。 - Kartick Vaddadi
我有一部6s手机,可以用吗? - Rhythmic Fistman
请在我的代码中将6s的maxISO从1759更改为1839,然后您应该能看到问题。 - Kartick Vaddadi
1个回答

0
解决方案是在将AVCaptureDevice添加到会话之前进行配置。而不是:
session.addInput(try! AVCaptureDeviceInput(device: device))
output = AVCaptureMovieFileOutput()
session.addOutput(output)
device.setFormatWithHighestIso()

你应该做:

device.setFormatWithHighestIso()  // Do this first!
session.addInput(try! AVCaptureDeviceInput(device: device))
output = AVCaptureMovieFileOutput()
session.addOutput(output)

当设备被添加到会话中时,将创建并以某种方式配置AVCaptureConnection。如果稍后更改设备的分辨率,则配置不再匹配,因此连接将被停用,视频将无法记录。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接