AVCaptureVideoPreviewLayer无法填满整个iPhone 4S屏幕

65
AVCaptureVideoPreviewLayer *avLayer = 
                [AVCaptureVideoPreviewLayer layerWithSession:session];
avLayer.frame = self.view.frame;
[self.view.layer addSublayer:avLayer];

我使用AVCaptureVideoPreviewLayer在视图上显示视频。 但是视频的视图没有填满整个iPhone4屏幕(右侧和左侧有两个灰色的条)。

我希望视频能填满整个屏幕。 我该怎么做?非常感谢!

输入图像描述

7个回答

190
也许这可以解决它?
CGRect bounds=view.layer.bounds;
avLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
avLayer.bounds=bounds;
avLayer.position=CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));

这个解决方案在2015年使用Swift 2.0修复了我的问题。 - Mark Barrasso
1
2016年修复了Swift 3.0!我真正需要的只是将“videoGravity”设置为调整宽高比填充。 - Drmorgan
1
Swift 3.0 在2017年 :) - Alex
2018年在Objective-C中可用 :) - Ethan Halprin

14

可能会导致困惑的一个潜在原因是 AVCaptureVideoPreviewLayer 是一个 CoreAnimation 层,并且在所有上面的答案中都是被静态地定位(例如,没有约束)相对于一个视图。如果您使用约束来布局视图,则这些约束不会自动调整预览层的大小。

这意味着您不能在 viewDidLoad 中设置预览层,因为布局还没有完成,预览层将按照它在 Interface Builder 中的大小进行调整。

相反,请覆盖 ViewController 上的 viewDidLayoutSubviews 并在那里定位预览层。

- (void)viewDidLayoutSubviews
{
    CGRect bounds=view.layer.bounds;
    avLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;  
    avLayer.bounds=bounds;
    avLayer.position=CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
}

11

@fitzwald的回答可以给你想要的结果,但有更简单的方法。发生的情况是会话预设默认为Video-High(不匹配屏幕的纵横比)。使用Photo预设可以实现全屏预览(如在Camera.app中)。只需设置

session.sessionPreset = AVCaptureSessionPresetPhoto;

在开始会话之前,请参考苹果文档以了解更多信息。


4
我认为这是错误的。有两个问题:首先,使用 presetPhoto 会破坏内置行为(例如,如果设置了此预设,AVCaptureVideoPreviewLayer 将拒绝流式传输实时视频)。其次,我发现它仍无法自动调整大小以填充 CALayer。 - Adam
此外,您提供的链接没有帮助 - 苹果尚未记录此变量(“sessionPreset”)或任何值。iOS 4已经上线将近一年了,所以也许我们很快就会得到一些文档资料。(祈祷中) - Adam
1
@Adam,针对你的第一个问题,我已经成功地使用presetPhoto来填充屏幕并显示视频。我不知道你遇到了什么问题。我正在寻找一种分享我的_setupPreviewLayer代码的方法。至于你的第二个评论,虽然它没有得到很好的记录,但这是苹果推荐设置预览层的方式。如果你可以访问WWDC 2010示例代码,那里有一些非常有用的例子。AVCamDemo和PinchyPreview对我帮助很大。 - eschurter
1
我同意@eschurter的观点 - 请注意,仅使用“AspectFill”会让您对相机看到的画面产生虚假印象。只需尝试切换到内置摄像头(不移动),您就会发现您没有相同的画面。 这确实是由于纵横比。您可以在此处阅读摘要:http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/03_MediaCapture.html (640x480预设也会有所帮助,不一定是照片) - Oded Ben Dov
这个解决方案更好地考虑了实际相机帧,正如@OdedBenDov所提到的。当仅使用纵横比填充时,我会拍照并留下额外的空间,而这些空间在预览中并没有显示出来。 - SuperGuyAbe
显示剩余2条评论

9

为了谷歌的缘故,这是被接受的答案,但使用的是稍微有些不同的Swift:

var bounds:CGRect = self.view.layer.bounds
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
previewLayer?.bounds = bounds
previewLayer?.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))

4

被接受的答案

Swift 3:

  let bounds = view.layer.bounds
  self.cameraLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
  self.cameraLayer.bounds = bounds
  self.cameraLayer.position = CGPoint(x:bounds.midX, y:bounds.midY)
  self.cameraView?.layer.addSublayer(self.cameraLayer)

Swift 4:

  let bounds = view.layer.bounds
  self.cameraLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
  self.cameraLayer.bounds = bounds
  self.cameraLayer.position = CGPoint(x:bounds.midX, y:bounds.midY)
  self.cameraView?.layer.addSublayer(self.cameraLayer)

2

Swift 5

我通过以下代码解决了这个问题:

    let bounds = view.layer.bounds
    let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    view.layer.addSublayer(previewLayer)
    previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
    previewLayer.bounds = bounds
    previewLayer.position = CGPoint(x:bounds.midX, y:bounds.midY)

1
我使用以下代码来实现这个功能。
previewLayer.frame = CGRectMake(0, 0, self.view.frame.size.width,self.view.frame.size.height);
previewLayer.orientation = [[UIDevice currentDevice] orientation];
previewLayer.contentsGravity = kCAGravityResizeAspectFill;

除了设置方向之外,这实际上是对我有效的解决方案。 - Dan F

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