我正在使用 AVCaptureVideoPreviewLayer 来捕获条形码。一切正常,直到我尝试在运行 iPadOS 13 beta 4 的 iPad 上显示 AVCaptureVideoPreviewLayer 而我的应用程序/场景仅使用 iPad 屏幕的一部分(屏幕的其余部分包含另一个应用程序或我自己的应用程序的另一个场景)。在这种情况下,AVCaptureVideoPreviewLayer 只显示黑色。
我进行了大量搜索,并查看了相关文档,但找不到任何关于需要请求对相关捕获设备或捕获会话的独占访问权限的信息。
如果我在我的应用程序中显示了 AVCaptureVideoPreviewLayer,我可以通过添加/删除另一个多任务应用程序来查看正确的预览和它变黑或冻结,这样我自己的应用程序就会在使用整个 iPad 屏幕和只使用一半屏幕之间切换.
这要么是 iPadOS 错误,要么是我缺少一些独占访问请求或类似的请求。我发现唯一与远程相关的是lockForConfiguration
AVCaptureDevice 的方法,但由于我实际上并没有更改任何配置,所以它不是需要的(我尝试使用它并没有任何区别)。
您可以通过使用 Xcode 11 创建单视图 iOS 应用程序来复制此问题。添加一个扩展 UIViewController 的新 Cocoa Touch 类并使用以下代码填充其实现。向原始视图控制器添加一个按钮,并为创建和呈现新视图控制器的按钮添加一个操作。您还需要将NSCameraUsageDescription
密钥添加到 Info.plist。
#import "PreviewViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface PreviewViewController () <AVCaptureMetadataOutputObjectsDelegate>
@end
@implementation PreviewViewController {
AVCaptureDevice *_videoCaptureDevice;
AVCaptureSession *_captureSession;
AVCaptureVideoPreviewLayer *_previewLayer;
AVCaptureMetadataOutput *_metadataOutput;
}
- (void)deviceRotated {
UIDeviceOrientation orient = [UIDevice currentDevice].orientation;
switch (orient) {
case UIDeviceOrientationPortrait:
_previewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait;
break;
case UIDeviceOrientationPortraitUpsideDown:
if ([self supportedInterfaceOrientations] & UIInterfaceOrientationMaskPortraitUpsideDown) {
_previewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
} else {
_previewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait;
}
break;
case UIDeviceOrientationLandscapeLeft:
_previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
break;
case UIDeviceOrientationLandscapeRight:
_previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
break;
}
}
#pragma mark UIViewController methods
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.blackColor;
_captureSession = [[AVCaptureSession alloc] init];
_videoCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:_videoCaptureDevice error:&error];
if (!videoInput) {
NSLog(@"Np input: %@", error);
// TODO - no video input
return;
}
if ([_captureSession canAddInput:videoInput]) {
[_captureSession addInput:videoInput];
} else {
NSLog(@"Can't add input");
// TODO - now what?
return;
}
_metadataOutput = [[AVCaptureMetadataOutput alloc] init];
if ([_captureSession canAddOutput:_metadataOutput]) {
[_captureSession addOutput:_metadataOutput];
} else {
NSLog(@"Can't add output");
return;
}
_previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
_previewLayer.frame = self.view.layer.bounds;
_previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:_previewLayer];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
_previewLayer.frame = self.view.layer.bounds;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[_metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
if (!_captureSession.isRunning) {
// Attempted using lockForConfiguration on _videoCaptureDevice here but it made no difference
[_captureSession startRunning];
}
if (_previewLayer.connection.supportsVideoOrientation) {
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceRotated) name:UIDeviceOrientationDidChangeNotification object:nil];
[self deviceRotated]; // set initial
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[_metadataOutput setMetadataObjectsDelegate:nil queue:nil];
if (_captureSession.isRunning) {
[_captureSession stopRunning];
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
if (_previewLayer.connection.supportsVideoOrientation) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}
}
@end
我是否缺少一些获得独占访问权限所需的代码,或者这可能是 iPadOS 错误?