-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[camera_avfoundation] enable more than 30 fps #7394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
6c769f9
4920305
4f1483f
6c210c9
30a4856
5e1f249
5007358
65f8113
27868df
3983273
1d8f05a
cc632ec
f36d2dd
0125d77
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -226,6 +226,9 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings | |
| return nil; | ||
| } | ||
|
|
||
| selectBestFormatForRequestedFrameRate(_captureDevice, _mediaSettings, | ||
| _videoDimensionsForFormat); | ||
|
|
||
| // Set frame rate with 1/10 precision allowing not integral values. | ||
| int fpsNominator = floor([_mediaSettings.framesPerSecond doubleValue] * 10.0); | ||
| CMTime duration = CMTimeMake(10, fpsNominator); | ||
|
|
@@ -251,6 +254,55 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings | |
| return self; | ||
| } | ||
|
|
||
| static void selectBestFormatForRequestedFrameRate( | ||
|
||
| AVCaptureDevice *captureDevice, FCPPlatformMediaSettings *mediaSettings, | ||
| VideoDimensionsForFormat videoDimensionsForFormat) { | ||
| // Find the format which frame rate ranges are closest to the wanted frame rate. | ||
| CMVideoDimensions targetResolution = videoDimensionsForFormat(captureDevice.activeFormat); | ||
| double targetFrameRate = mediaSettings.framesPerSecond.doubleValue; | ||
| FourCharCode preferredSubType = | ||
| CMFormatDescriptionGetMediaSubType(captureDevice.activeFormat.formatDescription); | ||
| AVCaptureDeviceFormat *bestFormat = captureDevice.activeFormat; | ||
| double bestFrameRate = bestFrameRateForFormat(bestFormat, targetFrameRate); | ||
| double minDistance = fabs(bestFrameRate - targetFrameRate); | ||
| FourCharCode bestSubType = preferredSubType; | ||
| for (AVCaptureDeviceFormat *format in captureDevice.formats) { | ||
| CMVideoDimensions resolution = videoDimensionsForFormat(format); | ||
| if (resolution.width != targetResolution.width || | ||
| resolution.height != targetResolution.height) { | ||
| continue; | ||
| } | ||
| double frameRate = bestFrameRateForFormat(format, targetFrameRate); | ||
| double distance = fabs(frameRate - targetFrameRate); | ||
| FourCharCode subType = CMFormatDescriptionGetMediaSubType(format.formatDescription); | ||
| if (distance < minDistance || (distance == minDistance && subType == preferredSubType && | ||
| bestSubType != preferredSubType)) { | ||
stuartmorgan-g marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| bestFormat = format; | ||
| bestFrameRate = frameRate; | ||
| minDistance = distance; | ||
| bestSubType = subType; | ||
| } | ||
| } | ||
| if (![bestFormat isEqual:captureDevice.activeFormat]) { | ||
| captureDevice.activeFormat = bestFormat; | ||
| } | ||
| mediaSettings.framesPerSecond = @(bestFrameRate); | ||
| } | ||
|
|
||
| static double bestFrameRateForFormat(AVCaptureDeviceFormat *format, double targetFrameRate) { | ||
|
||
| double bestFrameRate = 0; | ||
| double minDistance = DBL_MAX; | ||
| for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) { | ||
| double frameRate = MIN(MAX(targetFrameRate, range.minFrameRate), range.maxFrameRate); | ||
| double distance = fabs(frameRate - targetFrameRate); | ||
| if (distance < minDistance) { | ||
| bestFrameRate = frameRate; | ||
| minDistance = distance; | ||
| } | ||
| } | ||
| return bestFrameRate; | ||
| } | ||
|
|
||
| - (AVCaptureConnection *)createConnection:(NSError **)error { | ||
| // Setup video capture input. | ||
| _captureVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:_captureDevice error:error]; | ||
|
|
@@ -474,56 +526,42 @@ - (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset | |
| // Set the best device format found and finish the device configuration. | ||
| _captureDevice.activeFormat = bestFormat; | ||
| [_captureDevice unlockForConfiguration]; | ||
|
|
||
| // Set the preview size based on values from the current capture device. | ||
| _previewSize = | ||
| CGSizeMake(_captureDevice.activeFormat.highResolutionStillImageDimensions.width, | ||
| _captureDevice.activeFormat.highResolutionStillImageDimensions.height); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| case FCPPlatformResolutionPresetUltraHigh: | ||
| if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset3840x2160]) { | ||
| _videoCaptureSession.sessionPreset = AVCaptureSessionPreset3840x2160; | ||
| _previewSize = CGSizeMake(3840, 2160); | ||
| break; | ||
| } | ||
| if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) { | ||
| _videoCaptureSession.sessionPreset = AVCaptureSessionPresetHigh; | ||
| _previewSize = | ||
| CGSizeMake(_captureDevice.activeFormat.highResolutionStillImageDimensions.width, | ||
| _captureDevice.activeFormat.highResolutionStillImageDimensions.height); | ||
| break; | ||
| } | ||
| case FCPPlatformResolutionPresetVeryHigh: | ||
| if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset1920x1080]) { | ||
| _videoCaptureSession.sessionPreset = AVCaptureSessionPreset1920x1080; | ||
| _previewSize = CGSizeMake(1920, 1080); | ||
| break; | ||
| } | ||
| case FCPPlatformResolutionPresetHigh: | ||
| if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) { | ||
| _videoCaptureSession.sessionPreset = AVCaptureSessionPreset1280x720; | ||
| _previewSize = CGSizeMake(1280, 720); | ||
| break; | ||
| } | ||
| case FCPPlatformResolutionPresetMedium: | ||
| if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) { | ||
| _videoCaptureSession.sessionPreset = AVCaptureSessionPreset640x480; | ||
| _previewSize = CGSizeMake(640, 480); | ||
| break; | ||
| } | ||
| case FCPPlatformResolutionPresetLow: | ||
| if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset352x288]) { | ||
| _videoCaptureSession.sessionPreset = AVCaptureSessionPreset352x288; | ||
| _previewSize = CGSizeMake(352, 288); | ||
| break; | ||
| } | ||
| default: | ||
| if ([_videoCaptureSession canSetSessionPreset:AVCaptureSessionPresetLow]) { | ||
| _videoCaptureSession.sessionPreset = AVCaptureSessionPresetLow; | ||
| _previewSize = CGSizeMake(352, 288); | ||
| } else { | ||
| if (error != nil) { | ||
| *error = | ||
|
|
@@ -537,23 +575,31 @@ - (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset | |
| return NO; | ||
| } | ||
| } | ||
| CMVideoDimensions size = self.videoDimensionsForFormat(_captureDevice.activeFormat); | ||
| _previewSize = CGSizeMake(size.width, size.height); | ||
| _audioCaptureSession.sessionPreset = _videoCaptureSession.sessionPreset; | ||
| return YES; | ||
| } | ||
|
|
||
| /// Finds the highest available resolution in terms of pixel count for the given device. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: "... if same pixel count, use the subtype as the tie breaker." |
||
| - (AVCaptureDeviceFormat *)highestResolutionFormatForCaptureDevice: | ||
| (AVCaptureDevice *)captureDevice { | ||
| FourCharCode preferredSubType = | ||
| CMFormatDescriptionGetMediaSubType(_captureDevice.activeFormat.formatDescription); | ||
| AVCaptureDeviceFormat *bestFormat = nil; | ||
| NSUInteger maxPixelCount = 0; | ||
| FourCharCode bestSubType = 0; | ||
| for (AVCaptureDeviceFormat *format in _captureDevice.formats) { | ||
| CMVideoDimensions res = self.videoDimensionsForFormat(format); | ||
| NSUInteger height = res.height; | ||
| NSUInteger width = res.width; | ||
| NSUInteger pixelCount = height * width; | ||
| if (pixelCount > maxPixelCount) { | ||
| maxPixelCount = pixelCount; | ||
| FourCharCode subType = CMFormatDescriptionGetMediaSubType(format.formatDescription); | ||
| if (pixelCount > maxPixelCount || (pixelCount == maxPixelCount && subType == preferredSubType && | ||
| bestSubType != preferredSubType)) { | ||
| bestFormat = format; | ||
| maxPixelCount = pixelCount; | ||
| bestSubType = subType; | ||
| } | ||
| } | ||
| return bestFormat; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These helpers should be defined above their call sites; I'm suprised this is even compiling.