参考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);
}
网友评论