AVCaptureVideoPreviewLayer and preview from camera position

Tiziano picture Tiziano · Feb 12, 2015 · Viewed 9.6k times · Source

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

enter image description here

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

Answer

kellanburket picture kellanburket · Feb 12, 2015

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.