2016-08-20 57 views
7

我的iOS相機應用程序在Objective C中編寫時,從鎖定屏幕返回時/解鎖手機時會凍結其預覽圖層。AVCapture預覽在解鎖手機時凍結/卡住

viewWillAppear中調用了所有相機配置設置。到目前爲止,我已經取得了成功,除了唯一的問題,即從鎖定屏幕返回時,相機預覽圖層凍結或卡住。我的代碼的相機部分如下。

任何幫助,非常感謝。謝謝。 ps:請隨時指出我代碼中的任何錯誤,因爲我只是一個新手。

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    [self setGUIBasedOnMode]; 
    }); 
} 


-(void) setGUIBasedOnMode 
{ 
if (![self isStreamStarted]) { 
if (shutterActionMode == SnapCamSelectionModeLiveStream) 
{ 
    _flashButton.hidden = true; 
    _cameraButton.hidden = true; 
    _liveSteamSession = [[VCSimpleSession alloc] initWithVideoSize:[[UIScreen mainScreen]bounds].size frameRate:30 bitrate:1000000 useInterfaceOrientation:YES]; 
    [_liveSteamSession.previewView removeFromSuperview]; 
    AVCaptureVideoPreviewLayer *ptr; 
    [_liveSteamSession getCameraPreviewLayer:(&ptr)]; 
    _liveSteamSession.previewView.frame = self.view.bounds; 
    _liveSteamSession.delegate = self; 
} 
else{ 
    [_liveSteamSession.previewView removeFromSuperview]; 
    _liveSteamSession.delegate = nil; 
    _cameraButton.hidden = false; 
    if(flashFlag == 0){ 
     _flashButton.hidden = false; 
    } 
    else if(flashFlag == 1){ 
     _flashButton.hidden = true; 
    } 
    self.session = [[AVCaptureSession alloc] init]; 
    self.previewView.hidden = false; 
    self.previewView.session = self.session; 

    [self configureCameraSettings]; //All The Camera Configuration Settings. 

    dispatch_async(self.sessionQueue, ^{ 
     switch (self.setupResult) 
     { 
      case AVCamSetupResultSuccess: 
      { 
       [self addObservers]; 

       [self.session startRunning]; 

       self.sessionRunning = self.session.isRunning; 
       if(loadingCameraFlag == false){ 
        [self hidingView]; 
       } 
       break; 
      } 
      case AVCamSetupResultCameraNotAuthorized: 
      { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        NSString *message = NSLocalizedString(@"MyApp doesn't have permission to use the camera, please change privacy settings", @"Alert message when the user has denied access to the camera"); 
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"AVCam" message:message preferredStyle:UIAlertControllerStyleAlert]; 
        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"Alert OK button") style:UIAlertActionStyleCancel handler:nil]; 
        [alertController addAction:cancelAction]; 

        UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Settings", @"Alert button to open Settings") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 
         [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; 
        }]; 
        [alertController addAction:settingsAction]; 
        [self presentViewController:alertController animated:YES completion:nil]; 
       }); 
       break; 
      } 
      case AVCamSetupResultSessionConfigurationFailed: 
      { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        NSString *message = NSLocalizedString(@"Unable to capture media", @"Alert message when something goes wrong during capture session configuration"); 
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"MyApp" message:message preferredStyle:UIAlertControllerStyleAlert]; 
        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"Alert OK button") style:UIAlertActionStyleCancel handler:nil]; 
        [alertController addAction:cancelAction]; 
        [self presentViewController:alertController animated:YES completion:nil]; 
       }); 
       break; 
      } 
     } 
    }); 
} 
} 

-(void)configureCameraSettings 
{ 
self.sessionQueue = dispatch_queue_create("session queue",  DISPATCH_QUEUE_SERIAL); 
self.setupResult = AVCamSetupResultSuccess; 
switch ([AVCaptureDevice  authorizationStatusForMediaType:AVMediaTypeVideo]) 
{ 
    case AVAuthorizationStatusAuthorized: 
    { 
     break; 
    } 
    case AVAuthorizationStatusNotDetermined: 
    { 
     dispatch_suspend(self.sessionQueue); 
     [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { 
      if (! granted) { 
       self.setupResult = AVCamSetupResultCameraNotAuthorized; 
      } 
      dispatch_resume(self.sessionQueue); 
     }]; 
     break; 
    } 
    default: 
    { 
     self.setupResult = AVCamSetupResultCameraNotAuthorized; 
     break; 
    } 
} 

dispatch_async(self.sessionQueue, ^{ 
if (self.setupResult != AVCamSetupResultSuccess) { 
    return; 
} 
self.backgroundRecordingID = UIBackgroundTaskInvalid; 
NSError *error = nil; 

AVCaptureDevice *videoDevice = [IPhoneCameraViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack]; 
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error]; 

[self.session beginConfiguration]; 

if ([self.session canAddInput:videoDeviceInput]) { 
    [self.session addInput:videoDeviceInput]; 
    self.videoDeviceInput = videoDeviceInput; 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation; 
     AVCaptureVideoOrientation initialVideoOrientation = AVCaptureVideoOrientationPortrait; 
     if (statusBarOrientation != UIInterfaceOrientationUnknown) { 
      initialVideoOrientation = (AVCaptureVideoOrientation)statusBarOrientation; 
     } 
     AVCaptureVideoPreviewLayer *previewLayer = (AVCaptureVideoPreviewLayer *)self.previewView.layer; 
     if (shutterActionMode == SnapCamSelectionModeVideo) 
     { 
      [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; 
      if([self.session canSetSessionPreset:AVCaptureSessionPresetMedium]){ 
       [self.session setSessionPreset:AVCaptureSessionPresetMedium]; 
      } 
     } 
     previewLayer.connection.videoOrientation = initialVideoOrientation; 
    }); 
} 
else { 
    self.setupResult = AVCamSetupResultSessionConfigurationFailed; 
} 

AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; 
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error]; 

if (! audioDeviceInput) { 
} 

if ([self.session canAddInput:audioDeviceInput]) { 
    [self.session addInput:audioDeviceInput]; 
} 
else { 
} 

AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; 

Float64 TotalSeconds = 10*60; 
int32_t preferredTimeScale = 30; 
CMTime maxDuration = CMTimeMakeWithSeconds(TotalSeconds, preferredTimeScale);   movieFileOutput.maxRecordedDuration = maxDuration; 
movieFileOutput.minFreeDiskSpaceLimit = 1024 * 1024 * 100; 

if ([self.session canAddOutput:movieFileOutput]) { 
    [self.session addOutput:movieFileOutput]; 
    AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo]; 
    if (connection.isVideoStabilizationSupported) { 
     connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto; 
    } 
    self.movieFileOutput = movieFileOutput; 
} 
else { 
    self.setupResult = AVCamSetupResultSessionConfigurationFailed; 
} 

AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; 
if ([self.session canAddOutput:stillImageOutput]) { 
    stillImageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG}; 
    [self.session addOutput:stillImageOutput]; 
    self.stillImageOutput = stillImageOutput; 
} 
else { 
    self.setupResult = AVCamSetupResultSessionConfigurationFailed; 
} 
[self.session commitConfiguration]; 
}); 
} 
+0

http://stackoverflow.com/a/30707170/4601170 –

回答

0

ViewDidLoadViewWillAppearViewDidAppear方法應用生命週期的執行之間有很大的區別。 UIViews的

創建或執行一些任務重是原因凍結相當昂貴的,並且你應該避免儘可能多地這樣做,在viewWillAppear中方法

看看:

  1. ViewDidLoad:每當我向應該與視圖一起出現的視圖添加控件時,我就把它放在ViewDidLoad方法中。基本上這個方法在視圖加載到內存時被調用。例如,如果我的視圖是一個帶有3個標籤的表單,我會在這裏添加標籤;如果沒有這些形式,視圖將永遠不會存在
  2. ViewWillAppear:ViewWillAppear通常只是爲了更新表單上的數據。因此,對於上面的示例,我將使用它實際將我的域中的數據加載到表單中。創建UIViews相當昂貴,你應該儘可能地避免在ViewWillAppear方法上做這件事,因爲當它被調用時,這意味着iPhone已經準備好向用戶展示UIView,並且你在這裏做的任何事情都很重會以非常明顯的方式影響性能(如動畫被延遲等)。
  3. ViewDidAppear:ViewDidAppear以啓動新線程來執行需要很長時間的事情,例如執行web服務調用以獲取上述表單的額外數據。好處是,因爲視圖已經存在並顯示給用戶,您可以在獲取數據時向用戶顯示一個很好的「等待」消息。
1

嘗試觀察UIApplicationDidEnterBackgroundNotification/UIApplicationWillEnterForegroundNotification,UIApplicationWillResignActiveNotification/UIApplicationDidBecomeActiveNotification通知停止/啓動捕獲會話相應