2016-10-03 2 views
2

камера с полным экраном предварительного просмотра,AVLayerVideoGravityResize не соответствует новым устройствам, iOS 10?

previewLayer!.videoGravity = AVLayerVideoGravityResize 

сделать изображение ...

stillImageOutput?.captureStillImageAsynchronously(
     from: videoConnection, completionHandler: 

полноэкранным предварительный просмотр будет или должен точно соответствовать фотоснимка.

(для ясности: что вы случайно использовать AVLayerVideoGravityResizeAspectFill В этом случае предварительный просмотр не будет соответствовать неподвижное изображение - вы увидите «прыжок», как она растягивается.).

Однако ...

Если вы попытаетесь ниже (так, используя AVLayerVideoGravityResize - правильный выбор) с iOS10 ...

это точно не работает: вы получаете небольшой скачок между предварительным просмотром, и, неподвижным изображением. Один или другой слегка растянут неправильно.

Может ли это быть просто ошибкой с некоторыми устройствами? или в iOS?

(Это не работает отлично - не прыгать -. На старых устройствах, и если вы попробуете его с iOS9)

Кто-нибудь еще видел это? проверка

// CameraPlane ... the actual live camera plane per se 


import UIKit 
import AVFoundation 

class CameraPlane:UIViewController 
    { 
    var captureSession: AVCaptureSession? 
    var stillImageOutput: AVCaptureStillImageOutput? 
    var previewLayer: AVCaptureVideoPreviewLayer? 

    fileprivate func fixConnectionOrientation() 
     { 
     if let connection = self.previewLayer?.connection 
      { 
      let previewLayerConnection : AVCaptureConnection = connection 

      guard previewLayerConnection.isVideoOrientationSupported else 
       { 
       print("strangely no orientation support") 
       return 
       } 

      previewLayerConnection.videoOrientation = neededVideoOrientation() 
      previewLayer!.frame = view.bounds 
      } 
     } 

    func neededVideoOrientation()->(AVCaptureVideoOrientation) 
     { 
     let currentDevice:UIDevice = UIDevice.current 
     let orientation: UIDeviceOrientation = currentDevice.orientation 
     var r:AVCaptureVideoOrientation 
     switch (orientation) 
      { 
      case .portrait: r = .portrait 
       break 
      case .landscapeRight: r = .landscapeLeft 
       break 
      case .landscapeLeft: r = .landscapeRight 
       break 
      case .portraitUpsideDown: r = .portraitUpsideDown 
       break 
      default: r = .portrait 
       break 
      } 
     return r 
     } 

    override func viewDidLayoutSubviews() 
     { 
     super.viewDidLayoutSubviews() 
     fixConnectionOrientation() 
     } 

    func cameraBegin() 
     { 
     captureSession = AVCaptureSession() 

     captureSession!.sessionPreset = AVCaptureSessionPresetPhoto 
     // remember that of course, none of this will work on a simulator, only on a device 

     let backCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) 

     var error: NSError? 
     var input: AVCaptureDeviceInput! 
     do { 
      input = try AVCaptureDeviceInput(device: backCamera) 
      } catch let error1 as NSError 
       { 
       error = error1 
       input = nil 
       } 

     if (error != nil) 
      { 
      print("probably on simulator? no camera?") 
      return; 
      } 

     if (captureSession!.canAddInput(input) == false) 
      { 
      print("capture session problem?") 
      return; 
      } 

     captureSession!.addInput(input) 

     stillImageOutput = AVCaptureStillImageOutput() 
     stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG] 

     if (captureSession!.canAddOutput(stillImageOutput) == false) 
      { 
      print("capture session with stillImageOutput problem?") 
      return; 
      } 

     captureSession!.addOutput(stillImageOutput) 
     previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 

     // previewLayer!.videoGravity = AVLayerVideoGravityResizeAspect 
     // means, won't reach the top and bottom on devices, gray bars 

     // previewLayer!.videoGravity = AVLayerVideoGravityResizeAspectFill 
     // means, you get the "large squeeze" once you make photo 

     previewLayer!.videoGravity = AVLayerVideoGravityResize 
     // works perfectly on ios9, older devices etc. 
     // on 6s+, you get a small jump between the video live preview and the make photo 

     fixConnectionOrientation() 

     view.layer.addSublayer(previewLayer!) 
     captureSession!.startRunning() 
     previewLayer!.frame = view.bounds 
     } 

/*Video Gravity. 
These string constants define how the video is displayed within a layer’s bounds rectangle. 
You use these constants when setting the videoGravity property of an AVPlayerLayer or AVCaptureVideoPreviewLayer instance. 

AVLayerVideoGravityResize 
Specifies that the video should be stretched to fill the layer’s bounds. 

AVLayerVideoGravityResizeAspect 
Specifies that the player should preserve the video’s aspect ratio and fit the video within the layer’s bounds. 

AVLayerVideoGravityResizeAspectFill 
Specifies that the player should preserve the video’s aspect ratio and fill the layer’s bounds. 
*/ 

    func makePhotoOn(_ here:UIImageView) 
     { 
     // recall that this indeed makes a still image, which is used as 
     // a new background image (indeed on the "stillImage" view) 
     // and you can then continue to move the door around on that scene. 

     if (stillImageOutput == nil) 
      { 
      print("simulator, using test image.") 
      here.image = UIImage(named:"ProductMouldings.jpg") 
      return 
      } 

     guard let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) 
     else 
      { 
      print("AVMediaTypeVideo didn't work?") 
      return 
      } 

     videoConnection.videoOrientation = (previewLayer!.connection?.videoOrientation)! 

     stillImageOutput?.captureStillImageAsynchronously(
      from: videoConnection, completionHandler: 
       { 
       (sampleBuffer, error) in 
       guard sampleBuffer != nil else 
        { 
        print("sample buffer woe?") 
        return 
        } 

       let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) 
       let dataProvider = CGDataProvider(data: imageData as! CFData) 
       let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) 

       let ort = self.neededImageOrientation() 
       let image = UIImage(cgImage:cgImageRef!, scale:1.0, orientation:ort) 

       here.image = image 
       }) 
     } 


    func neededImageOrientation()->(UIImageOrientation) 
     { 
     var n : UIImageOrientation 
     let currentDevice: UIDevice = UIDevice.current 
     let orientation: UIDeviceOrientation = currentDevice.orientation 
     switch orientation 
      { 
      case UIDeviceOrientation.portraitUpsideDown: 
       n = .left 
      case UIDeviceOrientation.landscapeRight: 
       n = .down 
      case UIDeviceOrientation.landscapeLeft: 
       n = .up 
      case UIDeviceOrientation.portrait: 
       n = .right 
      default: 
       n = .right 
      } 
     return n 
     } 

    /* 
    @IBAction func didPressTakeAnother(sender: AnyObject) 
     { captureSession!.startRunning() } 
    */ 

    } 
+0

Да ладно, все, кто работает с камерой, должны были это видеть ?! – Fattie

ответ

2

Sanity - вы уверены, что AVLayerVideoGravityResize является тот, который вы хотите использовать? Это позволит растянуть изображение (не сохраняя соотношение сторон) к кадру предварительного просмотра. Если вы намерены поддерживать соотношение сторон, вы либо хотите AVLayerVideoGravityResizeAspect (как вы заметили, будут серые полосы, но соотношение сторон будет сохранено) или AVLayerVideoGravityResizeAspectFill (возможно, что вы хотите - часть предварительного просмотра будет отключена, но аспект соотношение будет сохранено).

Предполагая, что ваш «здесь» вид (тот, который прошел до makePhotoOn:), имеет тот же размер/позицию, что и в вашем представлении предварительного просмотра, вы хотите установить «here» view contentMode в соответствии с поведением вашего предварительного просмотра.

Так что, если вы использовали AVLayerVideoGravityResizeAspect для предварительного просмотра, а затем:

here.contentMode = .scaleAspectFit

Если вы использовали AVLayerVideoGravityResizeAspectFill для предварительного просмотра, а затем:

here.contentMode = .scaleAspectFill.

По умолчанию contentMode из зрения .scaleToFill (отмеченный здесь: https://developer.apple.com/reference/uikit/uiview/1622619-contentmode) так что ваш «здесь» ImageView, вероятно, растягивая изображение, чтобы соответствовать его размеру, не сохраняя пропорцию.

Если это не поможет, вы можете подумать о предоставлении проекта barebone, который проявляет проблему на github, чтобы воины среди нас на SO могли быстро построить и поработать с ним.

+0

святой дерьмо ...... – Fattie

+0

Спасибо - я отправил щедрость, чтобы поблагодарить и расследовать это КАК МОЖНО СКОРЕЕ – Fattie

+0

Дайте мне знать, как это происходит! – charmingToad

Смежные вопросы