无论UIViewContentMode选择如何,部分屏幕视频预览都会失真

时间:2016-10-11 20:55:45

标签: ios swift uiimageview uiimage avfoundation

我正在尝试制作一个简单的应用程序,它将在iphone屏幕的上半部分显示后置摄像头看到的原始预览,而在下半部分则使用相同的预览,但应用了各种过滤器。

我首先得到了原始预览部分,感谢几篇SO和博客文章。我正在显示的UIImageView占用了该部分的整个屏幕。

要获得半屏视图,我只需将图像视图的高度除以2,然后将其contentMode设置为显示所有内容,同时保持相同的宽高比:

imageView = UIImageView(frame: CGRectMake(0,0, self.view.frame.size.width, self.view.frame.size.height/2))

imageView.contentMode = UIViewContentMode.ScaleAspectFit

高度降低有效,但视图中的图像是垂直压缩的(例如直视的硬币看起来像水平的椭圆形)。我不认为预览的外观看起来像contentMode默认的ScaleToFill是巧合,但我尝试过没有改变模式。

完整的代码如下 - 项目有一个场景,一个视图控制器类;一切都是以编程方式完成的。

谢谢!

import UIKit
import AVFoundation

class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate
{
    var imageView : UIImageView!

    override func viewDidLoad()
    {
        super.viewDidLoad()

        imageView = UIImageView(frame: CGRectMake(0,0, self.view.frame.size.width, self.view.frame.size.height/2))
        imageView.contentMode = UIViewContentMode.ScaleAspectFit

        view.addSubview(imageView)

        let captureSession = AVCaptureSession()
        captureSession.sessionPreset = AVCaptureSessionPresetHigh

        let backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)

        do
        {
            let input = try AVCaptureDeviceInput(device: backCamera)
            captureSession.addInput(input)
        }
        catch
        {
            print("Camera not available")
            return
        }

        // Unused but required for AVCaptureVideoDataOutputSampleBufferDelegate:captureOutput() events to be fired
        let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        view.layer.addSublayer(previewLayer)

        let videoOutput = AVCaptureVideoDataOutput()

        videoOutput.setSampleBufferDelegate(self, queue: dispatch_queue_create("SampleBufferDelegate", DISPATCH_QUEUE_SERIAL))

        if captureSession.canAddOutput(videoOutput)
        {
            captureSession.addOutput(videoOutput)
        }

        videoOutput.connectionWithMediaType(AVMediaTypeVideo).videoOrientation = AVCaptureVideoOrientation.Portrait

        captureSession.startRunning()
    }

    func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!)
    {

        let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
        let cameraImage = CIImage(CVPixelBuffer: pixelBuffer!)

        dispatch_async(dispatch_get_main_queue())
        {
            self.imageView.image = UIImage(CIImage: cameraImage)
        }

    }

}

1 个答案:

答案 0 :(得分:1)

我想这行有问题,因为它在viewDidLoad()方法中。

不确定它与您的问题有关,但我觉得这对您来说非常重要。

imageView = UIImageView(frame: CGRectMake(0,0, self.view.frame.size.width, self.view.frame.size.height/2))

您无法在viewDidLoad()函数中获得正确的视图大小。

此外,从iOS 10开始,我发现在iOS布局引擎正确布局控件之前,控件的初始大小为(0, 0, 1000, 1000)

此外,您在viewDidLoad()中获得的大小可以是故事板中视图控制器的大小。因此,如果您在4英寸屏幕中布置控件,即使您在iPhone6或更大的屏幕上运行应用程序,它也会以viewDidLoad()方式返回4英寸屏幕的大小。

另外,请将imageView.layer.maskToBounds属性设置为true以防止图像出现任何边界。

还有一件事是,当视图边界发生变化时,您应该放置代码以适当地布置图像视图(如屏幕旋转)。