參考demo AppleVideoCapturer
分辨率
- 通過 AVCaptureSession的sessionPreset來控制采集分辨率
- 通過AVCaptureDevice的activeFormat來控制。
- 其中通過activeFormat還可以實現高幀率模式的采集
sessionPreset
A constant value indicating the quality level or bit rate of the output.
決定了輸出的質量還有比特率。
You use this property to customize the quality level or bit rate of the output. For possible values of sessionPreset, see AVCaptureSessionPreset. The default value is
AVCaptureSessionPresetHigh
.
You can set this value while the session is running.
You can only set a preset ifcanSetSessionPreset:
returns YES f or that preset.
通過該屬性,可以設置輸出的視頻質量還有比特率。默認是AVCaptureSessionPresetHigh
。 可以在運行中設置,設置前需要檢查是否支持canSetSessionPreset:
返回YES
if ([self.session canSetSessionPreset:AVCaptureSessionPreset640x480]) {
[self.session setSessionPreset:AVCaptureSessionPreset640x480];
}
activeFormat
The currently active media data format of the capture device.
當前設備處于激活狀態的媒體數據格式。
- ios平臺,通過設置 AVCaptureSession sessionPreset 來配置圖片和視頻的采集。通過AVAudioSession 來配置音頻采集。
- 當使用sessionPreset的時候,AVCaptureSession會自動控制采集設備的activeFormat。 但是一些特殊的配置選項,例如(高幀率),不可以使用sessionPreset來配置。
- 設置一個不存在的formats,會拋出異常
- 修改屬性之前,需要保證線程安全,配置前調用
lockForConfiguration:
,結束調用unlockForConfiguration
- 當修改了activeFormat之后,AVCaptureSession的sessionPreset會自動被修改為AVCaptureSessionPresetInputPriority。 此時采集的配置以activeFormat為主。
macOS 設置采集分辨率
參考: mac-osx-avfoundation-video-capture
_session = [[AVCaptureSession alloc] init];
_sessionInput = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];
_sessionOutput = [[AVCaptureVideoDataOutput alloc] init];
NSDictionary *pixelBufferOptions = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:width], (id)kCVPixelBufferWidthKey,
[NSNumber numberWithDouble:height], (id)kCVPixelBufferHeightKey,
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey,
nil];
[_sessionOutput setVideoSettings:pixelBufferOptions];
幀率的控制
通過 AVCaptureDevice 的activeVideoMinFrameDuration
和 activeVideoMaxFrameDuration
來控制采集幀率
if ([self.videoDeviceInput.device lockForConfiguration:nil]) {
//最小幀間隔,反過來就是最大幀率, 20fps
self.videoDeviceInput.device.activeVideoMinFrameDuration = CMTimeMake(1, 20);
//最大幀間隔,反過來就是最小幀率,15fps
self.videoDeviceInput.device.activeVideoMaxFrameDuration = CMTimeMake(1, 15);
[self.videoDeviceInput.device unlockForConfiguration];
}
高幀率
如何獲取ios設備的最高幀率, 參考Apple code
func configureCameraForHighestFrameRate(device: AVCaptureDevice) {
var bestFormat: AVCaptureDevice.Format?
var bestFrameRateRange: AVFrameRateRange?
for format in device.formats {
for range in format.videoSupportedFrameRateRanges {
if range.maxFrameRate > bestFrameRateRange?.maxFrameRate ?? 0 {
bestFormat = format
bestFrameRateRange = range
}
}
}
if let bestFormat = bestFormat,
let bestFrameRateRange = bestFrameRateRange {
do {
try device.lockForConfiguration()
// Set the device's active format.
device.activeFormat = bestFormat
// Set the device's min/max frame duration.
let duration = bestFrameRateRange.minFrameDuration
device.activeVideoMinFrameDuration = duration
device.activeVideoMaxFrameDuration = duration
device.unlockForConfiguration()
} catch {
// Handle error.
}
}
}
- (AVCaptureDeviceFormat *)selectFormatForDevice:(AVCaptureDevice *)device {
NSArray<AVCaptureDeviceFormat *> *formats =
[RTC_OBJC_TYPE(RTCCameraVideoCapturer) supportedFormatsForDevice:device];
int targetWidth = [_settings currentVideoResolutionWidthFromStore];
int targetHeight = [_settings currentVideoResolutionHeightFromStore];
AVCaptureDeviceFormat *selectedFormat = nil;
int currentDiff = INT_MAX;
for (AVCaptureDeviceFormat *format in formats) {
CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
FourCharCode pixelFormat = CMFormatDescriptionGetMediaSubType(format.formatDescription);
int diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height);
if (diff < currentDiff) {
selectedFormat = format;
currentDiff = diff;
} else if (diff == currentDiff && pixelFormat == [_capturer preferredOutputPixelFormat]) {
selectedFormat = format;
}
}
return selectedFormat;
}
- (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format {
Float64 maxSupportedFramerate = 0;
for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) {
maxSupportedFramerate = fmax(maxSupportedFramerate, fpsRange.maxFrameRate);
}
return fmin(maxSupportedFramerate, kFramerateLimit);
}