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

2024-04-21

具有全屏实时预览功能的相机,

    previewLayer!.videoGravity = AVLayerVideoGravityResize

制作图像...

    stillImageOutput?.captureStillImageAsynchronously(
        from: videoConnection, completionHandler:

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

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

然而...

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

它并不完全有效:你会得到一个小跳跃实时预览和静态图像之间。其中之一稍微被错误地拉​​伸。

这实际上可能只是某些设备的一个错误吗?或者在 iOS 中?

(它在旧设备上完美运行 - 不会跳转,如果您在 iOS 9 上尝试的话。)

还有其他人看过这个吗?

// 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(可能是你想要的 - 预览的一部分将被切断,但纵横比将保持)。

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

所以如果你用过AVLayerVideoGravityResizeAspect对于预览,然后:

here.contentMode = .scaleAspectFit

如果你用过AVLayerVideoGravityResizeAspectFill对于预览,然后:

here.contentMode = .scaleAspectFill.

默认contentMode一个视图是.scaleToFill(这里注明:https://developer.apple.com/reference/uikit/uiview/1622619-contentmode https://developer.apple.com/reference/uikit/uiview/1622619-contentmode)所以你的“这里”imageView可能会拉伸图像以匹配其大小,而不是保持纵横比。

如果这没有帮助,您可以考虑提供一个在 github 上展示问题的准系统项目,以便我们中的 SO 修补者可以快速构建和修补它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AVLayerVideoGravityResize 在新设备、iOS 10 上不匹配? 的相关文章

  • AVCaptureDevice isFlashModeSupported 已弃用 iOS 10

    我正在使用 AVCaptureDevice 的实例方法 isFlashModeSupported 如下所示 NSArray captureDeviceType AVCaptureDeviceTypeBuiltInWideAngleCamer
  • 将字符串转换为带时区的日期

    我有日期字符串2017 01 03T10 45 00 000 02 00我需要将其转移到类似的东西2017 01 03 10 45 00 0200 let formatter DateFormatter formatter dateForm
  • 非转义参数的闭包使用 - Swift 3 问题

    我知道 Swift 3 中的更改 其中 nonescaping 是闭包的默认行为 我已成功更改了有关更改的大部分代码 但我的代码的一部分无法摆脱闭包使用非转义参数可能会导致其转义编译错误 我尝试将 escaping 添加到 updateHa
  • 在 OpenGL 中移动相机时出现故障

    我正在为 iPhone 编写一个基于图块的游戏引擎 除了以下故障之外 它基本上可以正常工作 基本上 相机将始终将玩家保持在屏幕中央 并且它会移动以正确跟随玩家并在静止时正确绘制所有内容 然而 当玩家移动时 玩家行走的表面瓷砖会出现故障 如下
  • 尝试以紧凑模式访问 UITextView 时 iMessage 扩展程序崩溃

    下面是我在 iMessage 应用程序中的完整代码 class MessagesViewController MSMessagesAppViewController IBOutlet weak var messageView UITextV
  • Android:想要在相机预览上放置剪影叠加

    我想知道如何在相机预览上添加剪影 到目前为止 我已经完成了以下示例 它只是预览相机 http developer android com reference android view TextureView html http develo
  • Swift:多个本地通知,但只显示最新的

    我想在一天中的某些时间显示本地通知 并且我应该只能在通知中心看到 一个 最新通知 然而我的问题是 1 如果我将本地通知设置为不同的标识符 我会收到多个通知 这是预期的 但不是我想要的 2 如果我有一个标识符并将其设置为所有时间 我只会在我设
  • 来自 URL 的 YouTube 视频 ID - Swift3

    基本上我有一个 Youtube URL 作为字符串 我想从该 URL 中提取视频 ID 我在 Objective C 中找到了一些代码 如下所示 NSError error NULL NSRegularExpression regex NS
  • 如何在 Xcode 8.0 中安装 Alamofire 4.0

    我正在使用更新的 Xcode 8 0 如何使用 cocoa pod 安装 alamofire 4 0 我试过这个https github com Alamofire Alamofire https github com Alamofire
  • XCode 8.2.1 错误 - 没有这样的模块 YouTubePlayer

    我在用https github com gilesvangruisen Swift YouTube Player https github com gilesvangruisen Swift YouTube Player 首先 我尝试从任何
  • Actionscript 3主类是根,但不允许动画虚拟相机

    我最近开始使用 Actionscript 3 学习 Animate CC 我正在尝试使用 Animate 的 虚拟相机 功能 为我提供一个可以平移 旋转和缩放游戏的相机 当根没有子类时 很容易实现 Camera 例如 您可以在屏幕上放置一个
  • 如何在半屏上呈现 ViewController

    我有一个UIViewController其中只有一个UIView从底部覆盖了 viewController 的 1 3 像这样 我想在另一个 ViewController 上呈现这个 viewController 它应该从底部动画显示 并且
  • 如何打开相机然后切换到图像模式(反之亦然)

    就我而言 我想拍照或捕捉视频 实际上 如果我创建单独的意图 我可以做到这些 我的意思是我可以将相机打开为图像模式或视频模式 但无法在它们之间切换 这与我使用的意图过滤器有关吗 我应该怎么办 我如何在它们之间切换 我有同样的问题 在我想放置一
  • Swift 3 中的隐藏按钮

    我刚刚开始编码 我真的很想知道如何隐藏按钮 我想做的是当我按下按钮时 Start 我想让开始按钮和后退按钮消失 这是通过插座和操作完成的 我已经搜索了一下 但是当我想做的时候 它说do关键字应该指定一个语句块 我希望有人能帮助我 连接插座后
  • 文档 Main.storyboard 需要 Xcode 8.0 或更高版本

    我下载了 Xcode beta 并打开了现有的项目 看看它如何与 Xcode 8 beta 一起使用 我从 Xcode 8 打开了 Storyboard 文件 现在 当我从 Xcode 7 3 打开项目时 我无法打开故事板文件 它给出了以下
  • 将图片添加到图库 - Android

    我有一个活动 用相机拍照 然后将其添加到正确的文件夹 在本例中为 DCIM Camera 但是当你退出应用程序并加载 Android 图库时 它不在那里 我正在玩一些游戏 发现它只在重新启动手机后才出现 我不确定这背后的原因 也许它必须创建
  • 相机预览的有效模糊

    到目前为止我尝试过的 将每一帧转换为位图 然后用library https github com wasabeef Blurry并将其放入ImageView这是在相机预览前 显然太慢了 就像1 fps 然后我开始使用渲染脚本这会模糊每一帧
  • FocusState Textfield 在工具栏 ToolbarItem 中不起作用

    让我解释一下 我有一个带有 SearchBarView 的父视图 我正在传递这样的焦点状态绑定 SearchBarView searchText object searchQuery searching object searching f
  • Swift 错误:无法从 AST 上下文获取模块“My_App”

    我正在使用 Swift 3 Xcode 8 1 CocoaPods 1 1 1 运行后pod update 每次我尝试使用 Xcode 的 lldb 控制台时 它都会打印错误 例如 po self输出 共享 Swift 状态My App已出
  • 如何在 Safari 上打开本地 html 文件?

    我想打开本地 html 文件Safari集成到我的Swift 3应用 我知道如何使用网址来做到这一点 这是我用来执行此操作的代码 let encodedString url addingPercentEncoding withAllowed

随机推荐