Я разрабатываю инструмент командной строки, который будет снимать фотографии с камеры (программно, без модальных видов или элементов управления) и сохранять их локально на устройстве. Поэтому я пытаюсь реализовать [AVCaptureStillImageOutput]
. (Да, я знаю, что это устарело с iOS 10, но моя цель - нацелиться и на предыдущую версию системы, начиная с iOS 9.)
Таким образом, проблема, с которой я сталкиваюсь, является фатальной исключение в функции [captureStillImageAsynchronouslyFromConnection]
, в котором говорится Inconsistent state
:
*** -[AVCaptureStillImageOutput captureStillImageAsynchronouslyFromConnection:completionHandler:] Inconsistent state
Я видел другие потоки SO и, думаю, реализовал все возможные решения для обойти эту ошибку, но ничего не получилось, поэтому я публикую этот вопрос с моим кодом.
Я тестировал этот код на iOS 9, и он работает нормально, но ошибка возникает на iOS 13. Может ли устаревание вызвать ошибку? В любом случае, программа прекрасно скомпилируется и работает до указанной функции c. Все вроде нормально, фронтальная камера найдена, сессия запущена, videoConnection активна и включена .. Тем не менее captureStillImageAsynchronouslyFromConnection
возвращает исключение.
Пожалуйста, найдите мой код ниже. Любая помощь приветствуется!
Заголовок:
#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
@interface CameraManager : NSObject
@property (retain) AVCaptureStillImageOutput *stillImageOutput;
@property (retain) AVCaptureConnection *videoConnection;
@property (retain) AVCaptureSession *session;
+ (instancetype)sharedInstance;
- (void) takePhoto;
@end
Реализация класса:
#import "CameraManager.h"
@interface CameraManager()
@end
@implementation CameraManager
+ (instancetype)sharedInstance {
static CameraManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[CameraManager alloc] init];
});
return sharedInstance;
}
-(AVCaptureDevice *) frontFacingCameraIfAvailable{
NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
AVCaptureDevice *captureDevice = nil;
for (AVCaptureDevice *device in videoDevices){
if (device.position == AVCaptureDevicePositionFront){
captureDevice = device;
break;
}
}
if (!captureDevice){
captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
}
return captureDevice;
}
-(void) setupCaptureSession {
self.session = [[AVCaptureSession alloc] init];
self.session.sessionPreset = AVCaptureSessionPresetMedium;
AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
NSError *error = nil;
AVCaptureDevice *device = [self frontFacingCameraIfAvailable];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {
NSLog(@"ERROR: trying to open camera: %@", error);
}
[self.session addInput:input];
self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil];
[self.stillImageOutput setOutputSettings:outputSettings];
[self.session addOutput:self.stillImageOutput];
[self.session startRunning];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionWasInterrupted:) name:AVCaptureSessionWasInterruptedNotification object:self.session];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionInterruptionEnded:) name:AVCaptureSessionInterruptionEndedNotification object:self.session];
}
- (void) sessionWasInterrupted:(NSNotification*)notification
{
AVCaptureSessionInterruptionReason reason = [notification.userInfo[AVCaptureSessionInterruptionReasonKey] integerValue];
NSLog(@"Capture session was interrupted with reason %ld", (long)reason);
}
- (void) sessionInterruptionEnded:(NSNotification*)notification
{
NSLog(@"sessionInterruptionEnded");
}
-(void) takePhoto {
[self setupCaptureSession];
self.videoConnection = nil;
for (AVCaptureConnection *connection in self.stillImageOutput.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {
self.videoConnection = connection;
break;
}
}
if (self.videoConnection) { break; }
}
NSLog(@"about to request a capture from: %@", self.stillImageOutput);
[self.videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
if (!self.videoConnection || !self.videoConnection.enabled || !self.videoConnection.active) {
NSLog(@"videoConnection not enabled or not active");
return;
} else {
NSLog(@"videoConnection enabled: %hhd, active: %hhd", (char)self.videoConnection.enabled, (char)self.videoConnection.active);
}
// NSLog(@"videoConnection: %@", self.videoConnection);
NSError *error;
if (error) {
NSLog(@"Error %@", error);
}
@try {
// here captureStillImageAsynchronouslyFromConnection crash with:
// *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '*** -[AVCaptureStillImageOutput
captureStillImageAsynchronouslyFromConnection:completionHandler:] Inconsistent state'
[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:self.videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
NSLog(@"Here should have imageData %@", imageData);
}];
}
@catch (NSException *exception) {
NSLog(@"EXCEPTION %@", exception.reason);
}
@finally {
NSLog(@"Continue..");
}
}
@end