AVCaptureVideoPreviewLayer无法填充屏幕

24

我阅读了数百篇关于如何使VideoPreviewLayer填充iPhone屏幕的线程,但是没有任何方法成功...也许你可以帮助我,因为我真的陷入了困境。

这是我的预览层初始化:

    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];

这是我的setupAvCapture方法:

  //-- 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];

我已经尝试使用了不同的AVCaptureSessionPresets和ResizeFit选项,但它始终是这个样子的:

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

如果我使用previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;则会变成这个样子。如果我记录图层的大小,则返回正确的全屏大小。

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


如果我手动设置previewLayer.frame = CGRectMake(0, 0, 1280, 720);它可以工作...有人能解释一下吗?似乎宽度/高度被翻转了(纵向),但实际上方向是横向的。所以我可以通过实现_screenWidth = [UIScreen mainScreen].bounds.size.width; _screenHeight = [UIScreen mainScreen].bounds.size.height;来修复它。如果_screenHeight > _screenWidth,则执行以下操作: _screenWidth = _screenHeight; _screenHeight = [UIScreen mainScreen].bounds.size.width; - user2135074
4个回答

83

尝试:

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

Swift更新

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

Swift 4.0 更新

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

1
这在第一次加载时可以工作。但在旋转后重新应用它似乎不能达到预期的效果。 - mattdeboard
也许你应该停止相机预览的旋转。在预览上面叠加一个透明视图,用于放置按钮并保持其旋转。我认为旋转相机预览有点有趣,但上述方法才是正确的答案。 :) - Nikolay

7

如果有人遇到此问题,只需获取屏幕的边界即可解决。

    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    previewLayer.frame = UIScreen.main.bounds
    previewLayer.videoGravity = .resizeAspectFill
    camPreview.layer.addSublayer(previewLayer)

1

Swift 5和Xcode13

这对我很有效

创建AVCapturePreviewLayer

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

将PreviewLayer添加到视图中

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

使得 PreviewLayer 占满视图的整个边界。
    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    previewLayer.frame = view.bounds 

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()

这是我的工作内容。我遇到的问题是,我将以下代码放在了主线程之外。这可能会导致问题。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接