1080p 240FPS P3 D65

I am configuring an AVCaptureDevice's format correctly to capture 1080p 240FPS video with an AVCaptureMovieFileOutput (which seems to basically be an AVCaptureVideoDataOutput with recommendedVideoSettingsForAssetWriter(writingTo: .mov)). However, setting its activeColorSpace to .P3_D65 does not elicit change. The resulting video is in YUV colorspace, but the AVCaptureDevice's color space remains .sRGB. So, I'm not sure if the video is actually wide color or just being encoded as wide color, if that is possible.

Several errors in AV as it stands:

  • manually choosing a capture format does not set the session to input priority as suggested here and elsewhere - you must set the preset to inputPriority or you may have 1080p but at 30FPS, not 240FPS
  • a session does not automaticallyConfiguresCaptureDeviceForWideColor when possible if this attribute is true, the device's activeColorSpace does not change even when set by hand as aforementioned

To better understand what is happening here the relationships between the following should be elucidated in the AVFoundation documentation:

  • an AVCaptureDevice's activeColorSpace
  • a session's automaticallyConfiguresCaptureDeviceForWideColor attribute
  • an AVCaptureVideoDataOutput and its kCVPixelBufferPixelFormatTypeKey such as kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
  • an AVCaptureMovieFileOutput whose documentation whose documentation states "If the capture session’s automaticallyConfiguresCaptureDeviceForWideColor property is true, the session selects sRGB as the video colorspace in your movie [??? sRGB is not wide color]. You can override this behavior by adding an AVCapturePhotoOutput to your session and configuring its photo format or photo preset [session preset?] for a photo output."
  • is AVVideoAllowWideColorKey relevant to AVCaptureVideoDataOutput? when is it relevant?
  • when is Setting Color Properties for a Specific Resolution relevant?

From the above, there seems to be a strange unreliability of the automaticallyConfiguresCaptureDeviceForWideColor attribute, i.e., it's not setting the device's activeColorSpace to .P3_D65 as one would expect. Additionally, the AVCaptureMovieFileOutput's relationship with it seems very strange and possibly incorrect--sRGB is not wide color as the AVCaptureMovieFileOutput's documentation suggests.

Some example code (outputs from iPhone XS):

session.beginConfiguration()
session.sessionPreset = .inputPriority

device // builtInWideAngleCamera for video
format // 240FPS 1080p supports P3_D65

try device.lockForConfiguration()
device.activeFormat = format
device.activeColorSpace = .P3_D65
device.unlockForConfiguration()

guard let videoInput = try? AVCaptureDeviceInput(device: device) else { return }
     
session.addInput(videoInput)

session.addOutput(output) // AVCaptureMovieFileOutput or AVCaptureVideoDataOutput where AVAssetWriterInput configured with recommendedVideoSettingsForAssetWriter(writingTo: .mov)

session.commitConfiguration()
session.startRunning()
     
print(device.activeColorSpace == .P3_D65) // false
print(device.activeFormat)
// <AVCaptureDeviceFormat: 0x282660350 'vide'/'420f' 1920x1080, { 1-240 fps}, fov:69.654, binned, supports vis, max zoom:67.50 (upscales @1.00), AF System:1, ISO:24.0-960.0, SS:0.000045-1.000000, supports wide color>
print(device.activeFormat.formatDescription)
// <CMVideoFormatDescription 0x282b7d5f0 
// [0x1f43e9860]> {
// 	mediaType:'vide' 
// 	mediaSubType:'420f' 
// 	mediaSpecific: {
// 		codecType: '420f'		dimensions: 1920 x 1080 
// 	} 
// 	extensions: {(null)}
// }

// also tried adding this to the above per the AVCaptureMovieFileOutput documentation with the same result
let photoOutput = AVCapturePhotoOutput()
let settings = AVCapturePhotoSettings(format: [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange])
photoOutput.setPreparedPhotoSettingsArray([settings], completionHandler: nil)
session.addOutput(photoOutput)

It could be as simple as the device always records in .P3_D65 in this format, but the activeColorSpace property is wrong.


Thanks for reading! I hope to talk to an engineer at WWDC21 about AVFoundation and "how to do iOS". Aside from the specific above issues, some general developer issues with the camera on iOS:

  • AVFoundation is very encapsulated/black box and lacks examples
  • lack of camera documentation per device since the iPhone 8 and prior (you literally have to check with a DiscoverySession and then print formats)

These issues can also be extended to CoreMotion, AVKit, even SwiftUI (a big thank you to the folks at hackingwithswift! I digress but it took us like a month to figure out how to do a navigation stack), etc. Not having reliable documentation and examples and not knowing the hardware constraints of an iPhone, particularly sensors, makes development difficult.

I second cosmicvarion’s sentiments re: trying to develop for the iOS camera - it is more like reverse engineering. The documentation seems like auto-generated by doxygen or swagger. Having raw sensor access and even doing the debayering oneself would lead to more controlled results faster.

I totally concur, Cinegeek. It is like reverse engineering.

Update to the above:

I did find a helpful Medium blog, "Adventures in Wide Color: An iOS Exploration", by Peter Edmonston (unable to link, not a permitted domain). The author describes how you have to "trick" AVCapture into providing wide color for getting a wide color video preview. Here is his code. It also pointed me to this archived documentation.

However, I am still unable to record wide color video by setting AVCaptureDevice format to 1080p 240FPS P3 D65 and outputting to AVCaptureMovieFileOutput or AVCaptureVideoDataOutput due to the aforementioned .inputPriority preset issue.

Hello,

For deeper details about enabling wide color video capture I strongly recommend that you watch this WWDC video (timestamped link straight to the relevant portion): https://developer.apple.com/videos/play/wwdc2016/501/?time=2972

It sounds like you have a very specific format in mind for capture, and so the best approach here may be to "force" display P3 to your video data output.

To do so, follow these steps (which I have verified output P3 sample buffers):

Before starting your capture session:

  1. Don't use a preset for your capture session.
  2. Set automaticallyConfiguresCaptureDeviceForWideColor to false, otherwise it might end up stepping on the manual format.
  3. Get the capture device you are planning to use (i.e. back wide angle camera), and add it as an input to the capture session.
  4. Search the capture devices supported formats for an appropriate format:

            for format in backWideAngle.device.formats {

                

                // Check for P3_D65 support.

                guard format.supportedColorSpaces.contains(where: {

                    $0 == AVCaptureColorSpace.P3_D65

                }) else { continue }

                

                // Check for 240 fps

                guard format.videoSupportedFrameRateRanges.contains(where: { range in

                    range.maxFrameRate == 240

                }) else { continue }

                

                // Check for the resolution you want.

                guard format.formatDescription.dimensions.width == 1920 else { continue }

                guard format.formatDescription.dimensions.height == 1080 else { continue }

                

                bestFormat = format

                break // We found a suitable format, no need to keep looking.

            }

            

            guard let bestFormat = bestFormat else { fatalError("No format matching conditions on this device.")

            }
  1. Set the activeFormat, activeColorSpace, and activeVideoMinFrameDuration of the capture device:

            try! backWideAngle.device.lockForConfiguration()

            backWideAngle.device.activeFormat = bestFormat

            backWideAngle.device.activeColorSpace = .P3_D65

            backWideAngle.device.activeVideoMinFrameDuration = CMTime(value: 1, timescale: 240)

            backWideAngle.device.unlockForConfiguration()
  1. Add your AVCaptureVideoDataOutput to the session, set the sampleBufferDelegate
  2. startRunning your session.

At this point, you should be receiving wide color sample buffers, if you print(sampleBuffer.formatDescription), it should be clear that these samples are in a P3_D65 format.

If you continue to have troubles either capturing or utilizing wide color buffers, please Request Technical Support! 😃

1080p 240FPS P3 D65
 
 
Q