AVLayerVideoGravityResize在新设备(iOS 10)上不匹配吗? [英] AVLayerVideoGravityResize does not match on new devices, iOS 10?

查看:78
本文介绍了AVLayerVideoGravityResize在新设备(iOS 10)上不匹配吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有全屏实时预览的相机

Camera with a full screen live preview,

    previewLayer!.videoGravity = AVLayerVideoGravityResize

制作图片...

    stillImageOutput?.captureStillImageAsynchronously(
        from: videoConnection, completionHandler:

全屏实时预览将或应该与静态图像精确匹配.

the full-screen live preview will or should precisely match the still image.

(为清楚起见:假设您不小心使用了AVLayerVideoGravityResizeAspectFill.在这种情况下,实时预览将与静止图像不匹配-在拉伸时会看到跳转".)

(For clarity: say you accidentally use AVLayerVideoGravityResizeAspectFill. In that case the live preview will NOT match the still image - you'll see a "jump" as it is stretched.)

如果您在iOS10上尝试以下操作(因此使用AVLayerVideoGravityResize-正确的选择)...

If you try the below (so using AVLayerVideoGravityResize - the correct choice) with iOS10...

它不能完全正常工作:您会在实时预览和静止图像之间看到一个小跳跃.一个或另一个的拉伸不正确.

it does not precisely work: you get A SMALL JUMP between the live preview, and, the still image. One or the other is slightly stretched incorrectly.

这实际上只是某些设备的错误吗?或在iOS中?

Could this actually just be a bug with some devices? or in iOS?

(在旧设备上,如果您在iOS9上尝试,它也可以正常运行-不会跳动.)

(It works perfectly - no jump - on old devices, and if you try it with 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() }
    */
    
    }

推荐答案

完整性检查-确定要使用AVLayerVideoGravityResize吗?这会将图像(不保留宽高比)拉伸到预览的帧.如果您打算保持宽高比,则可以选择AVLayerVideoGravityResizeAspect(如您观察到的那样,会有灰色条,但将保持宽高比)或AVLayerVideoGravityResizeAspectFill(可能是您想要的-预览的一部分将被剪切)关闭,但将保持宽高比).

Sanity check - are you sure AVLayerVideoGravityResize is the one you want to use? That's going to stretch the image (not preserving aspect ratio) to the frame of the preview. If you're intending to maintain aspect ratio you either want AVLayerVideoGravityResizeAspect (as you observed, there will be grey bars, but aspect ratio will be maintained) or AVLayerVideoGravityResizeAspectFill (probably what you want - part of the preview will be cut off, but aspect ratio will be maintained).

假设此处"视图(传递给makePhotoOn:的视图)的大小/位置与预览视图相同,则需要设置此处"视图的contentMode以匹配预览的行为.

Assuming your 'here' view (the one passed to makePhotoOn:) is the same size/position as your preview view, you'll want to set 'here' view's contentMode to match the behavior of your preview.

因此,如果您使用AVLayerVideoGravityResizeAspect进行预览,则:

So if you used AVLayerVideoGravityResizeAspect for the preview, then:

here.contentMode = .scaleAspectFit

如果您使用AVLayerVideoGravityResizeAspectFill进行预览,则:

If you used AVLayerVideoGravityResizeAspectFill for the preview, then:

here.contentMode = .scaleAspectFill.

视图的默认contentMode.scaleToFill(在此处注明: https://developer.apple.com/reference/uikit/uiview/1622619-contentmode ),因此您的此处" imageView可能会拉伸图像以匹配其大小,而不保持宽高比.

The default contentMode of a view is .scaleToFill (noted here: https://developer.apple.com/reference/uikit/uiview/1622619-contentmode) so your 'here' imageView is probably stretching the image to match its size, not maintaining aspect ratio.

如果这没有帮助,您可以考虑提供一个在github上出现问题的准系统项目,以便我们当中的修补匠能够快速构建和修补它.

If that doesn't help, you might consider providing a barebones project that exhibits the problem on github so that tinkerers among us on SO can quickly build and tinker with it.

这篇关于AVLayerVideoGravityResize在新设备(iOS 10)上不匹配吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆