我正在使用AVCaptureVideoPreviewLayer捕获条形码。一切正常,直到我尝试在运行iPadOS 13 beta 4的iPad上显示AVCaptureVideoPreviewLayer时,而我的应用程序/场景仅使用iPad屏幕的一部分(屏幕的其余部分包含另一个应用程序或我自己的应用程序的另一个场景)。在这种情况下,AVCaptureVideoPreviewLayer仅显示黑色。
我已经进行了很多搜索,并且仔细阅读了相关文档,但找不到需要请求对相关捕获设备或捕获会话进行独占访问的任何内容。
如果我的应用程序中显示了AVCaptureVideoPreviewLayer,则可以通过添加/删除另一个多任务应用程序来查看正确的预览,使其变黑或死机,以使我自己的应用程序可以使用整个iPad屏幕,而仅使用一半屏幕上的。
这是iPadOS错误,或者我缺少某些要求独占访问或类似要求的请求。我发现唯一与远程相关的是AVCaptureDevice的lockForConfiguration
方法,但是由于我实际上并未更改任何配置,因此它不是必需的(并且我尝试使用它,没有任何区别)。
您可以通过使用Xcode 11创建一个单视图iOS应用程序来复制此问题。添加一个新的Cocoa Touch类,该类扩展了UIViewController并使用以下代码填充其实现。将按钮添加到原始视图控制器,然后为按钮添加一个动作,以创建并显示新的视图控制器。您还需要将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的错误?