iOS 13 ошибка: несогласованное состояние из AVCaptureStillImageOutput captureStillImageAsynchronouslyFromConnection - PullRequest
0 голосов
/ 06 января 2020

Я разрабатываю инструмент командной строки, который будет снимать фотографии с камеры (программно, без модальных видов или элементов управления) и сохранять их локально на устройстве. Поэтому я пытаюсь реализовать [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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...