首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >AVLayerVideoGravityResize在新设备上不匹配,iOS 10?

AVLayerVideoGravityResize在新设备上不匹配,iOS 10?
EN

Stack Overflow用户
提问于 2016-10-03 22:01:59
回答 1查看 755关注 0票数 2

带有全屏实时预览的摄像机,

代码语言:javascript
运行
复制
    previewLayer!.videoGravity = AVLayerVideoGravityResize

做个图像..。

代码语言:javascript
运行
复制
    stillImageOutput?.captureStillImageAsynchronously(
        from: videoConnection, completionHandler:

全屏直播预览将或应该与静止图像精确匹配.

(为了清楚起见:假设您不小心使用了AVLayerVideoGravityResizeAspectFill。在这种情况下,现场预览将不匹配静止图像-你会看到一个“跳转”,因为它是拉伸。)

然而..。

如果您尝试下面(所以使用AVLayerVideoGravityResize -正确的选择)与iOS10..。

它不准确地工作:你得到一个小的跳跃之间的实时预览,和静止的图像。其中一个或另一个稍微拉伸不正确。

这真的可能只是一些设备的缺陷吗?还是在iOS?

(它的工作原理非常完美--没有跳转到旧设备上,如果你在iOS9上试用它的话。)

还有其他人看过这个吗?

代码语言:javascript
运行
复制
// 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() }
    */
    
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-11-16 23:44:06

理智检查--你确定AVLayerVideoGravityResize是你想要使用的吗?这将使图像(不保留高宽比)延伸到预览的框架。如果你打算保持高宽比,你要么想要AVLayerVideoGravityResizeAspect (正如你观察到的那样,会有灰条,但高宽比会被保持)或AVLayerVideoGravityResizeAspectFill (可能是你想要的-预览的一部分将被切断,但纵横比将被保持)。

假设您的“这里”视图(传递给makePhotoOn:的视图)与预览视图的大小/位置相同,则需要设置“这里”视图的contentMode以匹配预览的行为。

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

here.contentMode = .scaleAspectFit

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

here.contentMode = .scaleAspectFill

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

如果这没有帮助,您可以考虑提供一个基本的项目,在github上展示问题,以便我们中间的修补程序能够快速地构建和修补它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39841095

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档