AVCam 项目崩溃于 iPad

AVCam Project Crashes On iPad

Apple 的 AVCam 演示应用程序演示源代码可在此处找到:https://developer.apple.com/library/content/samplecode/AVCam/Introduction/Intro.html 在尝试拍照时崩溃(无论您构建的是 Objective-C 还是 Swift 版本) AVCamCameraViewController/CameraViewController(Swift) 中捕获照片的行:

[self.photoOutput capturePhotoWithSettings:photoSettings delegate:photoCaptureDelegate];

或(Swift)

self.photoOutput.capturePhoto(with: photoSettings, delegate: photoCaptureDelegate)

崩溃时的错误信息是:

2016-11-21 17:44:31.590070 AVCam[2178:2303627] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[AVCapturePhotoOutput capturePhotoWithSettings:delegate:] flashMode must be set to a value present in the supportedFlashModes array'

当我检查闪光灯模式数组时,我得到了这个:

(lldb) po [self.photoOutput supportedFlashModes] <__NSSingleObjectArrayI 0x170007c50>( 0 )

因此,为了添加闪光灯模式,文档说您必须在 AVCapturePhotoSettings 对象中指定要支持的模式。我用这行代码做到了:

photoSettings.flashMode = AVCaptureFlashModeAuto;

或(Swift)

photoSettings.flashMode = .auto

所以我的直觉是这是一个与 12.9" iPad Pro 和 特别相关的错误,我可能需要提交一份雷达,但我想我会问以防有人以前看过它。有什么想法吗?

更新

我也能够复制其他 iPad,所以它似乎不仅仅是 12.9" iPad Pro。

将这一行写入信息 plist

Privacy - Camera Usage Description

添加这个...

let position = self.videoDeviceInput.device.position
photoSettings.flashMode = position == .front || position == .unspecified ? .off : .auto

就在这之前...

self.photoOutput.capturePhoto(with: photoSettings, delegate: photoCaptureDelegate)

这应该可以解决问题。

所以根据 Soja 的回答,我决定询问 photoOutput 变量提供的 supportedFlashModes 数组,它是一个 AVCapturePhotoOutput.

self.inProgressPhotoCaptureDelegates[photoCaptureDelegate.requestedPhotoSettings.uniqueID] = photoCaptureDelegate

if let _ = self.photoOutput.supportedFlashModes.filter({ (mode) -> Bool in
    return mode.intValue == AVCaptureFlashMode.auto.rawValue
}).last {
    let position = self.videoDeviceInput.device.position
    photoSettings.flashMode = position == .front || position == .unspecified ? .off : .auto
} else {
    photoSettings.flashMode = .off
}

self.photoOutput.capturePhoto(with: photoSettings, delegate: photoCaptureDelegate)

可能有一些更全面的方法可以做到这一点,但这可以确保在尝试使用 .auto 模式之前支持它。这里的差异和问题似乎与设备类型有关,iPhone vs iPad,因为 iPad 的背面没有闪光灯 iPhone 做。换句话说,它在我的 phone.

上运行良好

// 对于在 MacOS 上尝试使用 Apple 提供的 AVCam 示例代码时可能遇到此问题的人,使用 Objective C 提供的代码版本,只需添加这(在 Objective C 中):

AVCaptureDevicePosition position = self.videoDeviceInput.device.position;
if (position == AVCaptureDevicePositionFront)
{
   photoSettings.flashMode = AVCaptureFlashModeOff;
}
else
{
   photoSettings.flashMode = AVCaptureFlashModeAuto;
}


//right before:

[self.photoOutput.capturePhoto(with: photoSettings, delegate: photoCaptureDelegate]

您必须检查设备是否支持"Flash"模式 与:

[self.photoOutput.supportedFlashModes containsObject:[NSNumber numberWithInt:AVCaptureFlashModeOn]])

然后使用:

@property (nonatomic) AVCapturePhotoOutput *photoOutput;


AVCapturePhotoSettings *photoSettings = [AVCapturePhotoSettings photoSettings];


  AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        if ([device hasTorch] && [device hasFlash]){
            [device lockForConfiguration:nil];
            if([self.photoOutput.supportedFlashModes containsObject:[NSNumber numberWithInt:AVCaptureFlashModeOn]]){
                [device setFlashMode:AVCaptureFlashModeOn];
                photoSettings.flashMode = AVCaptureFlashModeAuto;
            }
            else{
                photoSettings.flashMode = AVCaptureFlashModeOff;
            }
            [device unlockForConfiguration];
        }
        else{
            photoSettings.flashMode = AVCaptureFlashModeOff;
            [device unlockForConfiguration];
        }

然后

[self.photoOutput.capturePhoto(with: photoSettings, delegate: photoCaptureDelegate]

@RazvanR 解决方案适用于该 Apple AVCamera 代码,但就在它之前的代码

// NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];

不会,需要使用 AVCapturePhotoOutput

Swift版本是

Swift: photoData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoSampleBuffer, previewPhotoSampleBuffer: previewPhotoSampleBuffer)

...但不知道 Objective-C 版本是什么。

要检查相机是否有闪光灯,请使用该相机上的 AVCaptureDevice.hasFlash 属性。

使用 back/front 位置来猜测这个真的没有意义,因为已经有一些东西可以告诉你它是否有闪光。

在swift中必须检查照片输出是否支持闪光灯模式。

 let settings = AVCapturePhotoSettings()
 if photoOutput.supportedFlashModes.contains(.on) {
     settings.flashMode = self.flashMode
 } else {
     settings.flashMode = .off
 }

 self.photoOutput?.capturePhoto(with: settings, delegate: self)

不需要检查相机位置,我们只需要检查相机是否有闪光灯,并根据它设置闪光灯模式。

photoSettings.flashMode = AVCaptureDevice.default(for: AVMediaType.video)!.hasFlash ? .on : .off