2016-10-03 1 views
2

Kamera mit einem vollen Live-Vorschau-Bildschirm,AVLayerVideoGravityResize passt nicht auf neue Geräte, iOS 10?

previewLayer!.videoGravity = AVLayerVideoGravityResize 

ein Bild machen ...

stillImageOutput?.captureStillImageAsynchronously(
     from: videoConnection, completionHandler: 

das Vollbild wird Live-Vorschau oder genau sollte das Standbild entsprechen.

(Aus Gründen der Klarheit: sagen Sie versehentlich AVLayerVideoGravityResizeAspectFill verwenden In diesem Fall wird die Live-Vorschau wird nicht das Standbild entsprechen - Sie werden ein „Sprung“ sehen, wie es gedehnt wird..)

jedoch ...

Wenn Sie versuchen, unter dem (so AVLayerVideoGravityResize mit - der richtigen Wahl) mit iOS10 ...

es funktioniert nicht genau: Sie erhalten einen kleinen Sprung zwischen der Live-Vorschau, und das Standbild. Der eine oder andere ist leicht falsch gestreckt.

Könnte dies eigentlich nur ein Fehler bei einigen Geräten sein? oder in iOS?

(Es funktioniert perfekt - kein Sprung -. Auf alten Geräten, und wenn Sie es mit iOS9 versuchen)

Hat jemand gesehen?

// 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

Komm schon, muss jeder, der mit der Kamera arbeitet, das gesehen haben ?! – Fattie

Antwort

2

Plausibiltätsprüfung - sind Sie sicher, AVLayerVideoGravityResize ist diejenige, die Sie verwenden möchten? Dadurch wird das Bild (ohne das Seitenverhältnis zu erhalten) auf den Rahmen der Vorschau gestreckt. Wenn Sie beabsichtigen, Seitenverhältnis beizubehalten, möchten Sie entweder AVLayerVideoGravityResizeAspect (wie Sie beobachtet haben, wird es graue Balken geben, aber Seitenverhältnis wird beibehalten) oder AVLayerVideoGravityResizeAspectFill (wahrscheinlich was Sie wollen - Teil der Vorschau wird abgeschnitten, aber Aspekt Verhältnis wird beibehalten).

Angenommen, Ihre ‚hier‘ Ansicht (die eine zu makePhotoOn: bestanden) ist die gleiche Größe/Position als Vorschauansicht, werden Sie ‚hier‘ Ansicht contentMode die festlegen möchten das Verhalten Ihrer Vorschau anzupassen.

Also, wenn Sie AVLayerVideoGravityResizeAspect für die Vorschau verwendet wird, dann:

here.contentMode = .scaleAspectFit

Wenn Sie AVLayerVideoGravityResizeAspectFill für die Vorschau verwendet wird, dann:

here.contentMode = .scaleAspectFill.

Der Standard contentMode einer Ansicht ist .scaleToFill (hier notiert: https://developer.apple.com/reference/uikit/uiview/1622619-contentmode), also Ihr 'hier' Bildansicht dehnt wahrscheinlich das Bild aus, um seine Größe anzupassen, nicht Seitenverhältnis beizubehalten.

Wenn das nicht hilft, könnten Sie in Betracht ziehen, ein Barebone-Projekt bereitzustellen, das das Problem auf GitHub zeigt, so dass Tüftler unter uns auf SO schnell bauen und damit herumspielen können.

+0

heilige Scheiße ...... – Fattie

+0

Danke - Ich schickte eine Prämie, um zu sagen, danke und wird dies so schnell wie möglich untersuchen – Fattie

+0

Lassen Sie mich wissen, wie es geht! – charmingToad

Verwandte Themen