24

I read about one million threads about how to make a VideoPreviewLayer filling the complete screen of an iPhone but nothing works ... maybe you can help me because I'm really stuck.

This is my Preview layer init:

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
    // Choosing bigger preset for bigger screen.
    _sessionPreset = AVCaptureSessionPreset1280x720;
}
else
{
    _sessionPreset = AVCaptureSessionPresetHigh;
}

[self setupAVCapture];

AVCaptureSession *captureSession = _session;
AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];
UIView *aView = self.view;
previewLayer.frame = aView.bounds;
previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
[aView.layer addSublayer:previewLayer];

That's my setupAvCapture Method:

  //-- Setup Capture Session.
_session = [[AVCaptureSession alloc] init];
[_session beginConfiguration];

//-- Set preset session size.
[_session setSessionPreset:_sessionPreset];

//-- Creata a video device and input from that Device.  Add the input to the capture session.
AVCaptureDevice * videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if(videoDevice == nil)
    assert(0);

//-- Add the device to the session.
NSError *error;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if(error)
    assert(0);

[_session addInput:input];

//-- Create the output for the capture session.
AVCaptureVideoDataOutput * dataOutput = [[AVCaptureVideoDataOutput alloc] init];
[dataOutput setAlwaysDiscardsLateVideoFrames:YES]; // Probably want to set this to NO when recording

//-- Set to YUV420.
[dataOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange]
                                                         forKey:(id)kCVPixelBufferPixelFormatTypeKey]]; // Necessary for manual preview

// Set dispatch to be on the main thread so OpenGL can do things with the data
[dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];

[_session addOutput:dataOutput];
[_session commitConfiguration];

[_session startRunning];

I already tried to use different AVCaptureSessionPresets and ResizeFit options. But it always looks like this:

http://imageshack.us/photo/my-images/707/img0013g.png/

Or this if I use previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; If I log the size of the layer the correct full screen size is returned.

http://imageshack.us/photo/my-images/194/img0014k.png/

Gabriel.Massana
  • 8,165
  • 6
  • 62
  • 81
user2135074
  • 263
  • 1
  • 2
  • 7
  • If I set previewLayer.frame = CGRectMake(0, 0, 1280, 720); manually it's working ... can anyone explain that. It seems that width/height are flipped (portrait) but the orientation is landscape actually. So I can fix that implementing _screenWidth = [UIScreen mainScreen].bounds.size.width; _screenHeight = [UIScreen mainScreen].bounds.size.height; if(_screenHeight > _screenWidth){ _screenWidth = _screenHeight; _screenHeight = [UIScreen mainScreen].bounds.size.width; } – user2135074 Apr 26 '13 at 10:05

4 Answers4

83

try:

AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession: self.session];
[captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

Swift Update

let previewLayer = AVCaptureVideoPreviewLayer(session: session)
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill

Swift 4.0 Update

let previewLayer = AVCaptureVideoPreviewLayer(session: session)
previewLayer.videoGravity = .resizeAspectFill
Ethan Allen
  • 14,425
  • 24
  • 101
  • 194
Gabriel.Massana
  • 8,165
  • 6
  • 62
  • 81
  • 1
    This does work on first load. But on rotation re-applying this does not seem to do the needful. – mattdeboard Jul 13 '15 at 17:41
  • maybe you should stop the rotation of the camera preview. Make a transparent view layered over the preview for the buttons you are going to place and leave it rotating. I think rotating the camera preview is kinda funny and the above is the right answer. :) – Nikolay Sep 08 '15 at 08:21
7

In case someone have this issue you need just to take the bounds of screen

    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    previewLayer.frame = UIScreen.main.bounds
    previewLayer.videoGravity = .resizeAspectFill
    camPreview.layer.addSublayer(previewLayer)
Ahmed Safadi
  • 4,402
  • 37
  • 33
1
            videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)
            DispatchQueue.main.async {
                self.videoPreviewLayer?.frame = self.captureImageView.bounds
            }
            cropImageRect = captureImageView.frame
            videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
            videoPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
            captureImageView.layer.addSublayer(videoPreviewLayer!)
            session!.startRunning()

This is work for me. The problem I faced was, I put the following line out of main thread. Its create the problem I think.

self.videoPreviewLayer?.frame = self.captureImageView.bounds

Y Junction
  • 181
  • 1
  • 15
1

Swift 5 and Xcode13

This worked for me

Creates the AVCapturePreviewLayer

    class ViewController: UIViewController {
         let previewLayer = AVCapturePreviewLayer()
    }

Adds PreviewLayer into View

    override func viewDidLoad() {
           super.viewDidLoad()
    // Adds Element to the View Layer
           view.layer.addSublayer(previewLayer)

Makes PreviewLayer the full bounds of View

    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    previewLayer.frame = view.bounds 
LawlessLLC
  • 35
  • 6