AVCaptureVideoPreviewLayer and preview from camera

2020-06-25 06:58发布

问题:

I'm developing an app that permits user to takes photo. I've started using AVCam apple provides but i'm actually have a problem Simply i cannot position the camera layer where i want but it's positioned automatically on center of the View

On the left side you can see what i actually have, on the right side what i'd like to have. The View that contains the preview that comes from the camera is a UIView subclass and this is the code

class AVPreviewView : UIView {
    override class func layerClass() -> AnyClass {
        return AVCaptureVideoPreviewLayer.self
    }
    func session () -> AVCaptureSession {
        return (self.layer as AVCaptureVideoPreviewLayer).session
    }

    func setSession(session : AVCaptureSession) -> Void {
        (self.layer as AVCaptureVideoPreviewLayer).session = session;
        (self.layer as AVCaptureVideoPreviewLayer).videoGravity = AVLayerVideoGravityResizeAspect;

    }
}

Any help is appreciated

回答1:

First get your screen size so you can calculate the aspect ratio

    let screenWidth = UIScreen.mainScreen().bounds.size.width
    let screenHeight = UIScreen.mainScreen().bounds.size.height
    var aspectRatio: CGFloat = 1.0

    var viewFinderHeight: CGFloat = 0.0
    var viewFinderWidth: CGFloat = 0.0
    var viewFinderMarginLeft: CGFloat = 0.0
    var viewFinderMarginTop: CGFlaot = 0.0

Now calculate the size of the preview layer.

    func setSession(session : AVCaptureSession) -> Void {

        if screenWidth > screenHeight {
            aspectRatio = screenHeight / screenWidth * aspectRatio
            viewFinderWidth = self.bounds.width
            viewFinderHeight = self.bounds.height * aspectRatio
            viewFinderMarginTop *= aspectRatio
        } else {
            aspectRatio = screenWidth / screenHeight
            viewFinderWidth = self.bounds.width * aspectRatio
            viewFinderHeight = self.bounds.height
            viewFinderMarginLeft *= aspectRatio
        }

        (self.layer as AVCaptureVideoPreviewLayer).session = session;

Set the layer's videoGravity to AVLayerVideoGravityResizeAspectFill so that the layer stretches to fill given your custom view.

        (self.layer as AVCaptureVideoPreviewLayer).videoGravity = AVLayerVideoGravityResizeAspectFill;

Finally, set the frame of your preview layer to the values calculated above with any offset that you like.

        (self.layer as AVCaptureVideoPreviewLayer).frame = CGRectMake(viewFinderMarginLeft, viewFinderMarginTop, viewFinderWidth, viewFinderHeight)

    }

This may take some tweaking since I haven't tested it live, but you should be able to create a more flexible VideoPreviewArea delimited by the bounds of your APPreviewView.



回答2:

What you're seeing isn't the layer being positioned as much as it is the aspect of the view/layer doesn't match the aspect ratio of the camera, so it's using the videoGravity property and aspect filling it (which always implies centered)

When you create the layer, size it so that the aspect ratio is correct, then position it at will. Or, in this case, resize the view to the correct aspect ratio, then the view can be positioned at will.



回答3:

I had a similar problem I fix it doing this:

 previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
                previewLayer.anchorPoint = videoLayer.bounds.origin
                previewLayer.frame = CGRect(x: videoLayer.bounds.origin.x, y: videoLayer.bounds.origin.y, width: videoLayer.frame.size.width, height: videoLayer.frame.size.height)
//                videoLayer.addSubview(previewLayer)
                //                previewLayer.
                videoLayer.layer.addSublayer(previewLayer)
                captureSession.startRunning()

Hope this can help :)



回答4:

I ran into this problem and the code provided did not fix the situation even though the code was working. I have been building my app using the interface builder.

In the the attributes inspector there under extend edges there are settings which all the view to be extended under tops bars and under bottom bars. My settings had these checked which was throwing off calculations for the positioning of the view.

Extend edges settings: