-
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 1 commit
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
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -210,20 +210,50 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings | |
| [_motionManager startAccelerometerUpdates]; | ||
|
|
||
| if (_mediaSettings.framesPerSecond) { | ||
| [_mediaSettingsAVWrapper beginConfigurationForSession:_videoCaptureSession]; | ||
|
|
||
| // Possible values for presets are hard-coded in FLT interface having | ||
| // corresponding AVCaptureSessionPreset counterparts. | ||
| // If _resolutionPreset is not supported by camera there is | ||
| // fallback to lower resolution presets. | ||
| // If none can be selected there is error condition. | ||
| if (![self setCaptureSessionPreset:_mediaSettings.resolutionPreset withError:error]) { | ||
| [_videoCaptureSession commitConfiguration]; | ||
| return nil; | ||
| } | ||
|
|
||
| // The frame rate can be changed only on a locked for configuration device. | ||
| if ([mediaSettingsAVWrapper lockDevice:_captureDevice error:error]) { | ||
| [_mediaSettingsAVWrapper beginConfigurationForSession:_videoCaptureSession]; | ||
|
|
||
| // Possible values for presets are hard-coded in FLT interface having | ||
| // corresponding AVCaptureSessionPreset counterparts. | ||
| // If _resolutionPreset is not supported by camera there is | ||
| // fallback to lower resolution presets. | ||
| // If none can be selected there is error condition. | ||
| if (![self setCaptureSessionPreset:_mediaSettings.resolutionPreset withError:error]) { | ||
| [_videoCaptureSession commitConfiguration]; | ||
| [_captureDevice unlockForConfiguration]; | ||
| return nil; | ||
| // find the format which frame rate ranges are closest to the wanted frame rate | ||
|
||
| CMVideoDimensions targetRes = self.videoDimensionsForFormat(_captureDevice.activeFormat); | ||
|
||
| double targetFrameRate = _mediaSettings.framesPerSecond.doubleValue; | ||
| FourCharCode preferredSubType = | ||
| CMFormatDescriptionGetMediaSubType(_captureDevice.activeFormat.formatDescription); | ||
| AVCaptureDeviceFormat *bestFormat = _captureDevice.activeFormat; | ||
| double bestFrameRate = [self frameRateForFormat:bestFormat closestTo:targetFrameRate]; | ||
| double minDistance = fabs(bestFrameRate - targetFrameRate); | ||
| int bestSubTypeScore = 1; | ||
| for (AVCaptureDeviceFormat *format in _captureDevice.formats) { | ||
|
||
| CMVideoDimensions res = self.videoDimensionsForFormat(format); | ||
| if (res.width != targetRes.width || res.height != targetRes.height) { | ||
| continue; | ||
| } | ||
| double frameRate = [self frameRateForFormat:format closestTo:targetFrameRate]; | ||
| double distance = fabs(frameRate - targetFrameRate); | ||
| FourCharCode subType = CMFormatDescriptionGetMediaSubType(format.formatDescription); | ||
| int subTypeScore = subType == preferredSubType ? 1 : 0; | ||
| if (distance < minDistance || | ||
| (distance == minDistance && subTypeScore > bestSubTypeScore)) { | ||
|
||
| bestFormat = format; | ||
| bestFrameRate = frameRate; | ||
| minDistance = distance; | ||
| bestSubTypeScore = subTypeScore; | ||
| } | ||
| } | ||
| if (![bestFormat isEqual:_captureDevice.activeFormat]) { | ||
| _captureDevice.activeFormat = bestFormat; | ||
| } | ||
| _mediaSettings.framesPerSecond = @(bestFrameRate); | ||
|
|
||
| // Set frame rate with 1/10 precision allowing not integral values. | ||
| int fpsNominator = floor([_mediaSettings.framesPerSecond doubleValue] * 10.0); | ||
|
|
@@ -232,9 +262,10 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings | |
| [mediaSettingsAVWrapper setMinFrameDuration:duration onDevice:_captureDevice]; | ||
| [mediaSettingsAVWrapper setMaxFrameDuration:duration onDevice:_captureDevice]; | ||
|
|
||
| [_mediaSettingsAVWrapper commitConfigurationForSession:_videoCaptureSession]; | ||
| [_mediaSettingsAVWrapper unlockDevice:_captureDevice]; | ||
| [_mediaSettingsAVWrapper commitConfigurationForSession:_videoCaptureSession]; | ||
| } else { | ||
| [_mediaSettingsAVWrapper commitConfigurationForSession:_videoCaptureSession]; | ||
| return nil; | ||
| } | ||
| } else { | ||
|
|
@@ -250,6 +281,20 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings | |
| return self; | ||
| } | ||
|
|
||
| - (double)frameRateForFormat:(AVCaptureDeviceFormat *)format closestTo:(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]; | ||
|
|
@@ -543,16 +588,23 @@ - (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset | |
| /// 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; | ||
| int bestSubTypeScore = 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); | ||
| int subTypeScore = subType == preferredSubType ? 1 : 0; | ||
| if (pixelCount > maxPixelCount || | ||
| (pixelCount == maxPixelCount && subTypeScore > bestSubTypeScore)) { | ||
| bestFormat = format; | ||
| maxPixelCount = pixelCount; | ||
| bestSubTypeScore = subTypeScore; | ||
| } | ||
| } | ||
| 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.
Why is all this code moving out of the locked section; is that safe?
Uh oh!
There was an error while loading. Please reload this page.
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.
I did not see anything saying that the order of
beginConfigurationandlockForConfigurationis important or that setting the session preset must be under that lock. There is example where it is used in that order: https://developer.apple.com/documentation/avfoundation/avcapturedevice/1389221-activeformat?language=objcI moved
setCaptureSessionPresetoutside of lock because it can itself calllockForConfigurationandunlockForConfigurationand I did not see anything about whether that lock is recursive.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.
Seems
lockForConfigurationis actually recursive from my observation (I could not get mentioned exceptions until now) as locking twice and unlocking once does not cause exceptions but unlocking twice yes. So I can revert this change (?).Also it seems not all
commitConfigurationcalls go through_mediaSettingsAVWrapper.