Skip to content

Commit

Permalink
extract format selection into function and more
Browse files Browse the repository at this point in the history
  • Loading branch information
misos1 committed Sep 5, 2024
1 parent 30a4856 commit 5e1f249
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 36 deletions.
2 changes: 1 addition & 1 deletion packages/camera/camera_avfoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## 0.9.17+4

* Adds possibility to use any supported FPS and fixes crash when using unsupported FPS.
* Adds ability to use any supported FPS and fixes crash when using unsupported FPS.
* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.

## 0.9.17+3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,36 +225,7 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings

// The frame rate can be changed only on a locked for configuration device.
if ([mediaSettingsAVWrapper lockDevice:_captureDevice error:error]) {
// 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);
selectBestFormatForRequestedFrameRate(_captureDevice, _mediaSettings, videoDimensionsForFormat);

// Set frame rate with 1/10 precision allowing not integral values.
int fpsNominator = floor([_mediaSettings.framesPerSecond doubleValue] * 10.0);
Expand Down Expand Up @@ -282,7 +253,42 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings
return self;
}

- (double)frameRateForFormat:(AVCaptureDeviceFormat *)format closestTo:(double)targetFrameRate {
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)) {
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) {
Expand Down Expand Up @@ -581,19 +587,18 @@ - (AVCaptureDeviceFormat *)highestResolutionFormatForCaptureDevice:
CMFormatDescriptionGetMediaSubType(_captureDevice.activeFormat.formatDescription);
AVCaptureDeviceFormat *bestFormat = nil;
NSUInteger maxPixelCount = 0;
int bestSubTypeScore = 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;
FourCharCode subType = CMFormatDescriptionGetMediaSubType(format.formatDescription);
int subTypeScore = subType == preferredSubType ? 1 : 0;
if (pixelCount > maxPixelCount ||
(pixelCount == maxPixelCount && subTypeScore > bestSubTypeScore)) {
(pixelCount == maxPixelCount && subType == preferredSubType && bestSubType != preferredSubType)) {
bestFormat = format;
maxPixelCount = pixelCount;
bestSubTypeScore = subTypeScore;
bestSubType = subType;
}
}
return bestFormat;
Expand Down

0 comments on commit 5e1f249

Please sign in to comment.