Knowing resolution of AVCaptureSession's session presets

18,641

Solution 1

According to Apple, there's no API for that. It stinks, I've had the same problem.

Solution 2

I am no AVFoundation pro, but I think the way to go is:

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

I'm not sure about the last step and I didn't try it myself. Just found that in the documentation and think it should work.

Searching for CMVideoDimensions in Xcode you'll find the RosyWriter example project. Have a look at that code (I don't have time to do that now).

Solution 3

You can programmatically get the resolution from activeFormat before capture begins, though not before adding inputs and outputs: 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
}

Solution 4

FYI, I attach here an official reply from Apple.


This is a follow-up to Bug ID# 13201137.

Engineering has determined that this issue behaves as intended based on the following information:

There are several problems with the included code:

1) The AVCaptureSession has no inputs. 2) The AVCaptureSession has no outputs.

Without at least one input (added to the session using [AVCaptureSession addInput:]) and a compatible output (added using [AVCaptureSession addOutput:]), there will be no active connections, therefore, the session won't actually run in the input device. It doesn't need to -- there are no outputs to which to deliver any camera data.

3) The JAViewController class assumes that the video port's -formatDescription property will be non nil as soon as [AVCaptureSession startRunning] returns.

There is no guarantee that the format description will be updated with the new camera format as soon as startRunning returns. -startRunning starts up the camera and returns when it is completely up and running, but doesn't wait for video frames to be actively flowing through the capture pipeline, which is when the format description would be updated.

You're just querying too fast. If you waited a few milliseconds more, it would be there. But the right way to do this is to listen for the AVCaptureInputPortFormatDescriptionDidChangeNotification.

4) Your JAViewController class creates a PVCameraInfo object in retrieveCameraInfo: and asks it a question, then lets it fall out of scope, where it is released and dealloc'ed.

Therefore, the session doesn't have long enough to run to satisfy your dimensions request. You stop the camera too quickly.

We consider this issue closed. If you have any questions or concern regarding this issue, please update your report directly (http://bugreport.apple.com).

Thank you for taking the time to notify us of this issue.

Best Regards,

Developer Bug Reporting Team Apple Worldwide Developer Relations

Solution 5

May be you can provide a list of all posible preset resolutions for every iPhone model and check which device model the app is running on? - using something like this...

[[UIDevice currentDevice] platformType]   // ex: UIDevice4GiPhone
[[UIDevice currentDevice] platformString] // ex: @"iPhone 4G"

However, you have to update the list for each newer device model. Hope this helps :)

Share:
18,641

Related videos on Youtube

Francisco Ryan Tolmasky I
Author by

Francisco Ryan Tolmasky I

Updated on June 04, 2022

Comments

  • Francisco Ryan Tolmasky I
    Francisco Ryan Tolmasky I almost 2 years

    I'm accessing the camera in iOS and using session presets as so:

    captureSession.sessionPreset = AVCaptureSessionPresetMedium;
    

    Pretty standard stuff. However, I'd like to know ahead of time the resolution of the video I'll be getting due to this preset (especially because depending on the device it'll be different). I know there are tables online you can look this up (such as here: http://cmgresearch.blogspot.com/2010/10/augmented-reality-on-iphone-with-ios40.html ). But I'd like to be able to get this programmatically so that I'm not just relying on magic numbers.

    So, something like this (theoretically):

    [captureSession resolutionForPreset:AVCaptureSessionPresetMedium];
    

    which might return a CGSize of { width: 360, height: 480}. I have not been able to find any such API, so far I've had to resort to waiting to get my first captured image and querying it then (which for other reasons in my program flow is not good).

  • Francisco Ryan Tolmasky I
    Francisco Ryan Tolmasky I over 12 years
    Unfortunately this is only set after the video starts shooting, so still no good (gave you a point though).
  • Christian Beer
    Christian Beer over 12 years
    Yeah, I didn't try. That's a pity there is no such API, though. Thanks for the point :)
  • JongAm Park
    JongAm Park over 11 years
    @Dex I did call "startRunning", but the CMVideoFormatDescriptionGetDimensions() keeps giving me { 0, 0} I called them while an app is being launched. Will that matter?
  • Dex
    Dex over 11 years
    @JongAmPark It's been a while since I've messed with this but I think you must wait for it to spool up completely and actually capture a frame via the captureOutput method. It's very annoying and caused me many headaches when writing my app.
  • JongAm Park
    JongAm Park about 11 years
    @Dex Thank you, Dex. I got an official answer from Apple. It's simply saying that I had to wait more until the video pipeline is ready and working. Also, the commenter told that even output should be connected. Currently, the bugreport site is down. When it's up, let me copy & paste their comment here.
  • spring
    spring about 11 years
    The code above worked for me - calling it after [capSession commitConfiguration], it works when switching between front and back cameras. What a silly info scavenger hunt!
  • Brad Moore
    Brad Moore over 10 years
    I was thinking about doing this, but the apple docs only list up until the iPhone 4.
  • mahboudz
    mahboudz over 9 years
    best to use AVCaptureInputPortFormatDescriptionDidChangeNotification as the place where you get the formatDescription and dimensions.
  • Peter Lapisu
    Peter Lapisu over 9 years
  • Crashalot
    Crashalot about 8 years
    There's no API, but there is a way to programmatically discover the video resolution before capture begins. Answer here: stackoverflow.com/a/35470937/144088
  • Rajat Mishra
    Rajat Mishra almost 4 years
    @Crashalot I was thinking then how snapchat does it? Because in snapchat, the camera is in full screen with no stretching/zommed issue. And when I saved a story to Gallery, then the image/video dimensions (for iPhone X) was 1122x2208. Thanks
  • Iskeraet
    Iskeraet about 3 years
    This can be shortened to just let formatDescription = <cameraGoesHere>.activeFormat.formatDescription let dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription) print(dimensions)