了解AVCaptureSession的会话预设的分辨率

18

我正在iOS中访问相机,并使用以下会话预设:

captureSession.sessionPreset = AVCaptureSessionPresetMedium;

这是很标准的内容。但是,我想预先知道由于此预设而获得的视频分辨率(尤其是因为根据设备不同,它会有所不同)。我知道有在线表格可以查找此信息(例如在此处: http://cmgresearch.blogspot.com/2010/10/augmented-reality-on-iphone-with-ios40.html)。但是我想以编程的方式获取这些信息,以便不仅仅依靠魔术数字。

所以,理论上应该像这样:

[captureSession resolutionForPreset:AVCaptureSessionPresetMedium];

可能会返回{width:360,height:480}的CGSize。到目前为止,我尚未能找到任何此类API,因此我不得不等待获取我的第一张捕获的图像,然后进行查询(由于程序流程的其他原因,这并不好)。


你好,你找到解决方案了吗?我也在寻找同样的东西。 - Asta ni enohpi
8个回答

25

我不是AVFoundation专家,但我认为正确的做法是:

captureSession.sessionPreset = AVCaptureSessionPresetMedium;
AVCaptureInput *input = [captureSession.inputs objectAtIndex:0]; // maybe search the input in array
AVCaptureInputPort *port = [input.ports objectAtIndex:0];
CMFormatDescriptionRef formatDescription = port.formatDescription;
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);

对于最后一步我不确定,也没有自己试过。只是在文档中找到了这个,认为应该可以工作。

在 Xcode 中搜索 CMVideoDimensions ,您将找到 RosyWriter 示例项目。查看那段代码(我现在没有时间去做)。


1
很不幸,这只有在视频开始拍摄后才能设置,所以还是不好(虽然我给了你一个点)。 - Francisco Ryan Tolmasky I
@Dex 谢谢你,Dex。我从苹果官方得到了答复。他们简单地说我需要等待更长时间,直到视频管道准备好并且正常工作。此外,评论者还说即使输出也应该连接。目前,错误报告网站已经关闭。当它重新开放时,我会在这里复制粘贴他们的评论。 - JongAm Park
2
上面的代码对我有效 - 在[capSession commitConfiguration]之后调用它,当在前置和后置摄像头之间切换时它也能工作。真是一个愚蠢的信息搜索任务! - spring
最好使用AVCaptureInputPortFormatDescriptionDidChangeNotification作为获取formatDescription和dimensions的位置。 - mahboudz
1
iOS8 在这里查看 https://dev59.com/toPba4cB1Zd3GeqPs366#25902160 - Peter Lapisu
显示剩余8条评论

9
您可以在拍摄开始之前通过 activeFormat 从程序上获取分辨率,但是在添加输入和输出之前不行。参考链接: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVCaptureDevice_Class/index.html#//apple_ref/occ/instp/AVCaptureDevice/activeFormat
private func getCaptureResolution() -> CGSize {
    // Define default resolution
    var resolution = CGSize(width: 0, height: 0)

    // Get cur video device
    let curVideoDevice = useBackCamera ? backCameraDevice : frontCameraDevice

    // Set if video portrait orientation
    let portraitOrientation = orientation == .Portrait || orientation == .PortraitUpsideDown

    // Get video dimensions
    if let formatDescription = curVideoDevice?.activeFormat.formatDescription {
        let dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription)
        resolution = CGSize(width: CGFloat(dimensions.width), height: CGFloat(dimensions.height))
        if (portraitOrientation) {
            resolution = CGSize(width: resolution.height, height: resolution.width)
        }
    }

    // Return resolution
    return resolution
}

这可以简化为:let formatDescription = <相机位置>.activeFormat.formatDescription let dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription) print(dimensions) - Iskeraet

7

补充信息,我在此附上了苹果公司的官方回复。


这是对Bug ID# 13201137的跟进。

工程师根据以下信息确定该问题的行为符合预期:

包含的代码存在几个问题:

1)AVCaptureSession没有输入。

2)AVCaptureSession没有输出。

如果没有至少一个输入(使用[AVCaptureSession addInput:]添加到会话中)和一个兼容的输出(使用[AVCaptureSession addOutput:]添加),则不会有活动连接,因此,会话实际上不会在输入设备中运行。它不需要-因为没有输出可以传送任何相机数据。

3)JAViewController类假定视频端口的-formatDescription属性一旦[AVCaptureSession startRunning]返回即非空。

不能保证格式描述将随着startRunning返回立即更新为新的摄像机格式。-startRunning启动相机并在完全运行时返回,但不等待视频帧通过捕获管道积极流动,这就是格式描述将被更新的时候。

您只是查询得太快了。如果您再等待几毫秒,它就会出现。但正确的方法是监听AVCaptureInputPortFormatDescriptionDidChangeNotification。

4)您的JAViewController类在retrieveCameraInfo:中创建PVCameraInfo对象并询问一个问题,然后让它掉出范围,在那里它被释放和dealloc'ed。

因此,会话不够长以满足您的尺寸要求。您停止相机的时间太快了。

我们认为这个问题已经解决。如果您对此问题有任何疑问或关注,请直接更新您的报告(http://bugreport.apple.com)。

感谢您抽出时间通知我们这个问题。

最好的问候,

开发人员Bug报告团队 Apple全球开发者关系


最好使用AVCaptureInputPortFormatDescriptionDidChangeNotification作为获取formatDescription和dimensions的位置。 - mahboudz

6
根据苹果公司的说法,没有相关API。这很糟糕,我也遇到了同样的问题。

1
没有API,但有一种方法可以在开始捕获之前以编程方式发现视频分辨率。答案在这里:https://dev59.com/gWsz5IYBdhLWcg3wlY-9#35470937 - Crashalot
@Crashalot 我在想Snapchat是如何做到的?因为在Snapchat中,相机全屏显示,没有拉伸/缩放问题。当我将一个故事保存到图库时,图像/视频尺寸(对于iPhone X)为1122x2208。谢谢。 - Rajat Mishra

3

如果预设为.photo,则返回的尺寸适用于静态照片大小,而非预览视频大小。

如果预设不是.photo,则返回的尺寸适用于视频大小,而非拍摄照片大小。

if self.session.sessionPreset != .photo {
    // return video size, not captured photo size
    let format = videoDevice.activeFormat
    let formatDescription = format.formatDescription
    let dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription) 
} else {
    // other way to get video size
}

@Christian Beer的回答是针对指定预设的好方法。 我的方法适用于主动预设。


3
也许你可以提供每个iPhone型号所有可能的预设分辨率列表,并检查该应用程序运行的设备型号?-使用类似以下内容的方式...
[[UIDevice currentDevice] platformType]   // ex: UIDevice4GiPhone
[[UIDevice currentDevice] platformString] // ex: @"iPhone 4G"

然而,您需要为每个较新的设备型号更新列表。希望这可以帮到您 :)

我在考虑这个问题,但是苹果文档只列出了iPhone 4及以下的版本。 - Brad Moore

0

想要实现你想要的功能(获取已知的视频或图像格式),最好的方法是设置捕获设备的格式。

首先找到你想要使用的捕获设备:

       if #available(iOS 10.0, *) {
        captureDevice = defaultCamera()
    } else {
        let devices = AVCaptureDevice.devices()
        // Loop through all the capture devices on this phone
        for device in devices {
            // Make sure this particular device supports video
            if ((device as AnyObject).hasMediaType(AVMediaType.video)) {
                // Finally check the position and confirm we've got the back camera
                if((device as AnyObject).position == AVCaptureDevice.Position.back) {
                    captureDevice = device as AVCaptureDevice
                }
            }
        }
    }
    self.autoLevelWindowCenter = ALCWindow.frame
    if captureDevice != nil && currentUser != nil {
        beginSession()
    }
}




    func defaultCamera() -> AVCaptureDevice? {
    if #available(iOS 10.0, *) { // only use the wide angle camera never dual camera
        if let device = AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera,
                                                             for: AVMediaType.video,
                                                             position: .back) {
            return device
        } else {
            return nil
        }
    } else {
        return nil
    }
}

然后找到该设备可以使用的格式:
        let options = captureDevice!.formats
    var supportable = options.first as! AVCaptureDevice.Format
    for format in options {
        let testFormat = format 
        let description = testFormat.description
        if (description.contains("60 fps") && description.contains("1280x 720")){
            supportable = testFormat
        }
    }

你可以进行更复杂的格式解析,但也许你并不在意。

然后只需将设备设置为该格式:

do {
    try captureDevice?.lockForConfiguration()
    captureDevice!.activeFormat = supportable
    // setup other capture device stuff like autofocus, frame rate, ISO, shutter speed, etc.
    try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice!))
    // add the device to an active CaptureSession
}

你可能想查看AVFoundation文档和关于AVCaptureSession的教程,因为输出有很多事情可以做。例如,您可以使用AVAssetExportSession将结果转换为.mp4,以便您可以在YouTube上发布等。希望这可以帮助到您。

-2

苹果在 iPhone 相机上使用了 4:3 的宽高比。

您可以使用此比率,通过固定 AVCaptureVideoPreviewLayer 的宽度或高度约束,并将纵横比约束设置为 4:3 来获取捕获视频的帧大小。

4:3 Ratio

在左侧的图像中,宽度被固定为300像素,高度通过设置4:3比例来获取,结果为400像素。
在右侧的图像中,高度被固定为300像素,宽度通过设置3:4比例来获取,结果为225像素。

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