How to configure AVCaptureSession for high res still images and low res (video) preview? - ios

I'd like to capture high resolution still images using AVCaptureSession. Therefore AVCaptureSession preset is set to Photo.
This is working well so far. On an iPhone 4 the final still image resolution is at its maximum of 2448x3264 pixels and the preview (video) resolution is 852x640 pixels.
Now, because the preview frames are analyzed to detect objects in the scene, I'd like to lower their resolution. How can this be done?
I've tried to set AVVideoSettings with a lower width/height to AVCaptureVideoDataOutput, but this leads to the following error message:
AVCaptureVideoDataOutput setVideoSettings:] - videoSettings dictionary contains one or more unsupported (ignored) keys: (AVVideoHeightKey, AVVideoWidthKey
So it seems this is not the right approach to configure the size of the preview frames received by AVCaptureVideoDataOutput / AVCaptureVideoDataOutputSampleBufferDelegate. Do you have any ideas how the resolution of the preview frames can be configured?
Any advise is welcome,
Thank you.

If you want to specify the settings manually, you need to set activeFormat on the AVCaptureDevice. This will be implicitly set the session preset to AVCaptureSessionPresetInputPriority.
The activeFormat takes a AVCaptureDeviceFormat but you can only take one from the list of AVCaptureDevice.formats. You'll need to go through the list and find one that fits your needs. Specifically, check that highResolutionStillImageDimensions is high enough for desired still capture and formatDescription (which needs to be inspected with CMFormatDescription* functions, e.g., CMVideoFormatDescriptionGetDimensions) matches your desired preview settings.

Just for the records: I ended up configuring AVCaptureSession in preset Low while aiming the camera. As soon as the shutter is triggered, the app switches to preset Photo, performs a focus run and takes the picture. This way it takes between 1 and 2.5 seconds to take a picture, which isn't that great, but it's at least a workaround.

To lower the size of the output of AVCaptureVideoDataOutput you can set the bitrate to be lower thus producing a small sample size.
commonly used keys for AVCaptureVideoDataOutput are:
AVVideoAverageBitRateKey
AVVideoProfileLevelKey
AVVideoExpectedSourceFrameRateKey
AVVideoMaxKeyFrameIntervalKey
For example:
private static let videoCompressionOptionsMedium = [AVVideoAverageBitRateKey : 1750000,
AVVideoProfileLevelKey : AVVideoProfileLevelH264BaselineAutoLevel,
AVVideoExpectedSourceFrameRateKey : Int(30),
AVVideoMaxKeyFrameIntervalKey : Int(30)]

Related

AVCaptureSessionPreset Photo and High Optimization

I have been trying all kinds of settings for the AVCaptureSessionPreset to match my desired output, but I don't seem to be able to get it right.
The Photo preset captures a photo where the resolution is too high, so it takes some time before the image is finished processing.
The High preset is perfect in the sense of performance. The image gets processed and returned almost instantaneously. But the aspect ratio is not right, it is 16:9 compared to the Photo preset which is 4:3.
I have also tried changing the AVCaptureDevice's activeFormat to a lower resolution. But the performance is just not as good as when using the High preset.
Someone with a similar problem from 2014:
AVCaptureSession preset creates a photo that is too big
The problem seems to be that you are attempting to perform some kind of time-consuming processing on the large photo data returned from the capture. Don't. It's large! Instead, when you configure the session, ask for a preview image at the desired size, and when the capture takes place, obtain the preview image and operate on that.

CMSampleBufferRef have always same video resolution?

I' trying to capture video by AVAssetWriter and AVCaptureOutput
You can find sample project here.
The video should be in portrait mode with any resolution. The main problem that it should be in portrait mode.
I'm trying to set different setting, but in the end, video is rotated and scaled to size (1920x1080) on iPhone SE.
Is it possible to control this resolution? Or at least orientation?
Video resolution is determined by the AVCaptureSession sessionPreset. You're setting that to medium, so you're getting the resolution that comes with that. If you want a different resolution, pass a different session preset, or use AVCaptureDevice to set a specific capture format. (For a good overview of capture session presets vs device formats, go back to this WWDC13 video.)
Per this Apple Developer Q&A, you need to set an orientation on the capture connection after you start the capture session in order to get "physically" rotated frame buffers (at a capture performance cost), or set the transform property on your asset writer (so that buffers are recorded in the sensor's native orientation, but clients display it in your intended orientation).

Can AVCaptureSession use custom resolution

I'm using AVCaptureSession to capture and record a video.
I need to record the video at a 4:3 ratio, and with a good resolution.
Is there a way to specify a custom resolution when capturing using AVCaptureSession?
I tried using the native presets but the problem is that I need to capture at a 4:3 ratio, and almost all of the presets are 16:9. and the ones that are 4:3 has very low resolution.
I can't fide any other way to change the preset to a custom one, what if I need to capture a 4:3 video with better resolution? Any ideas?
AVCaptureSession presets cover only a small subset of the capabilities of a device camera (the ones most apps want quick, easy access to). For more fine-grained control — such as to select a capture resolution not provided by a session preset — you need to use capture formats instead.
Look at the capture device's formats property, an array of AVCaptureDeviceFormat objects. Enumerate through that array until you find one whose dimensions are what you want. To get the dimensions, look at the format's underlying CMFormatDescription:
let fdesc = format.formatDescription
let dims = CMVideoFormatDescriptionGetDimensions(fdesc)
NSLog("%d x %d", dims.width, dims.height)
Once you've found the format you want, lock the device for configuration and set its activeFormat:
if try device.lockForConfiguration() {
device.activeFormat = myChosenFormat
// set up other things like activeVideoMinFrameDuration if you want
device.unlockForConfiguration()
}
You can find out more about configuring a capture session via AVCaptureDeviceFormat in Apple's programming guide and the WWDC2013 session that introduced device formats back in iOS 7.0. (Most of what you'll find about this topic is aimed at slow-motion video, taking high-res stills during video, and other things that you can't do with session presets, but those aren't the only things you can do with capture formats.)
Just record at the given aspect ratio and use an AVMutableComposition to crop the output video to the required aspect ratio: If you adjust the preview layer to mask to 4:3 this will appear seamless to the user.

AVFoundation max render size

I've searched quite a lot and it seems that couldn't find a definite answer to what is the maximum render size of a video on iOS using AVFoundation.
I need to stitch two or more videos side by side or above each and render them in one new video with a final size larger than 1920 x 1080. So for example if I have two full hd videos (1920 x 1080) side by side the final composition would be 3840 x 1080.
I've tried with AVAssetExportSession and it always shrinks the final video proportionally to max 1920 in width or 1080 in height. It's quite understandable because of all possible AVAssetExportSession settings like preset, file type etc.
I tried also using AVAssetReader and AVAssetWriter but the results are the same. I only have more control over the quality, bitrate etc.
So.. is there a way this can be achieved on iOS or we have to stick to max Full HD?
Thanks
Well... Actually the answer should be YES and also NO. At least of what I've found until now.
H.264 allows higher resolutions only using a higher level profile which is fine. However on iOS the max profile that can be used is AVVideoProfileLevelH264High41 which according the specs, permits a max resolution of 1,920×1,080#30.1 fps or 2,048×1,024#30.0 fps.
So encoding with H.264 won't do the job and the answer should be NO.
The other option is to use other compression/codec. I've tried AVVideoCodecJPEG and was able to render such a video. So the answer should be YES.
But.. the problem is that this video is not playable on iOS which again changes the answer to NO.
To summarise I'd say: it is possible if that video is meant to be used out of the device otherwise the video will simply not be useable.
Hope it will help other people as well and if someone else gives a better, even different answer I'll be glad.

How to crop a video in iOS

I was having a look at the RosyWriter Sample Code provided by Apple as a starting point and I'd like to find a way how to crop a video.
So i have the full resolution video from the iPhones Camera, but I just want to use a cropped part of it (and also rotate this subpart).
I figured that in captureOutput:didOutputSampleBuffer: fromConnection: i can modify each frame by modifying the CMSampleBufferRef that i get passed in.
So my questions now are:
Is this the right place to crop my video?
Where do I specify that the final video (that get's saved to disc) has a smaller resolution than the full video captured by AVCaptureSession? Setting the AVVideoWidthKey and AVVideoHeightKey has no effect.
How can I crop the video and still have good performance?
Any help is appreciated!
Thanks a lot!
EDIT:
Maybe I just need to know how I can make a video that was shot in portrait a landscape one by turning the images of the video by 90 degrees and then zoom in to fit the width again...?!?
In AVVideoSetttings.h there is the AVVideoScalingModeKey. This key combined with the defined values control how the video is scaled/cropped when encoding the images to the video container. For example if you specified a value of AVVideoScalingModeFit then cropping is used. Check out the header for how other values effect the video images.

Resources