iOS获取设备摄像头——视频采集。
使用AVFoundation框架获取设备摄像头:
iOS10+
使用 AVCaptureDeviceDiscoverySession类。
AVCaptureDeviceDiscoverySession:用于查找、监视可用捕获设备的查询。
此类,匹配指定类型的设备(如麦克风和广角相机)。支持媒体类型采集(如音频、视频、或音视频同时),和位置(如前置摄像头、后置摄像头)。
当创建一个采集设备发现会话(对该类进行实例化,获取一个对象),你可以检查它的设备数组(即其devices属性,符合会话标准的一系列当前可用设备集合)
/*此属性仅包含【当前可用】、并且满足使用【DiscoverySessionWithDeviceTypes:
mediaType:position:initializer创建设备发现会话】时的【指定条件】的采集设备。*/
/*
iOS 11.0+,此数组的顺序与您用于创建发现会话的deviceTypes参数的顺序匹配、一致,
因此您可以快速选择与您的首选类型匹配的设备。 较旧的iOS版本中,搜索整个数组以查找首选设备。
*/
@property(nonatomic, readonly) NSArray<AVCaptureDevice *> *devices;
例如:
/*摄像头翻转*/
-(NSError*)reverseCamera{
//获取所有摄像头
AVCaptureDeviceDiscoverySession * _Nonnull cameras = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position: AVCaptureDevicePositionUnspecified];//AVCaptureDevicePositionFront & AVCaptureDevicePositionBack
//获取当前摄像头方向
AVCaptureDevicePosition currentPosition = self.captureDeviceInput.device.position;
AVCaptureDevicePosition toPosition = AVCaptureDevicePositionUnspecified;
if (currentPosition == AVCaptureDevicePositionBack || currentPosition == AVCaptureDevicePositionUnspecified) {
toPosition = AVCaptureDevicePositionFront;
}else{
toPosition = AVCaptureDevicePositionBack;
}
NSArray* captureDeviceArray = [cameras.devices filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"position == %d",toPosition]];
if (captureDeviceArray.count == 0) {
return [self throw_errorWithDomain:@"VideoCapture: reverseCamera failed! get new camera failed!"];
}
NSError* error = nil;
//添加翻转页面
CATransition *animation = [CATransition animation];
animation.duration = 1.0;
animation.delegate = self;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.type = @"oglFlip";
AVCaptureDevice *camera = captureDeviceArray.firstObject;
_newInput = [AVCaptureDeviceInput deviceInputWithDevice:camera error:&error];
animation.subtype = kCATransitionFromRight;
[self.videoPreviewLayer addAnimation:animation forKey:nil];
/*在翻转动画时机修改输入设备*/
//重新获取连接并设置方向
self.captureConnection = [self.captureVideoDataOutput connectionWithMediaType:AVMediaTypeVideo];
//设置摄像头镜像 不设置的话前置摄像头采集出来的图像是反转的
if (toPosition == AVCaptureDevicePositionFront && self.captureConnection.supportsVideoMirroring) {
self.captureConnection.videoMirrored = YES;
}
self.captureConnection.videoOrientation = self.capturerParam.videoOrientation;
return nil;
}
-(void)animationDidStart:(CAAnimation *)anim{//修改输入设备
[self.captureSession beginConfiguration];
[self.captureSession removeInput:self.captureDeviceInput];
if ([self.captureSession canAddInput:self->_newInput]) {
[self.captureSession addInput:self->_newInput];
self.captureDeviceInput = self->_newInput;
}
[self.captureSession commitConfiguration];
}
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{}
AVCaptureDevice类:
为采集会话提供输入(如音频或视频),并为特定于硬件的采集功能提供控制。 AVCaptureDevice对象,表示物理捕获(或称‘采集’)设备和与该物理采集设备相关联的属性。使用它配置底层硬件的属性。采集设备还向AVCaptureSession对象提供输入数据(例如音频或视频)。 您可以使用AVCaptureDevice类的方法来枚举可用的设备,查询其功能,并获知设备何时来来去去。 在尝试设置捕获设备的属性(其聚焦模式,曝光模式等)之前,必须首先使用lockForConfiguration()方法获取设备上的锁。 您还应该查询设备的功能,以确保要设置的新模式对该设备有效。 然后,您可以设置属性并使用unlockForConfiguration()方法释放锁定。 如果希望所有可设置的设备属性保持不变,则可以锁定该锁。 但是,不必要地保持设备锁定可能会降低共享该设备的其他应用程序中的捕获质量,因此不建议这样做。 捕获设置的最常见配置可通过AVCaptureSession对象及其可用预设获得。 但是,在iOS设备上,某些特殊选项(例如高帧频)要求直接在AVCaptureDevice实例上设置捕获格式。 以下代码示例说明了如何选择iOS设备的最高帧速率:
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.*/ }
}
}
在iOS中,直接配置捕获设备的activeFormat属性会将捕获会话的预设更改为inputPriority。 进行此更改后:会话拓扑更改后,捕获会话不再在调用startRunning()或commitConfiguration()方法时自动配置捕获格式。
iOS10以下
使用AVCaptureDevice类获取设备摄像头。
// --- 获取所有摄像头 ---
NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
// --- 获取当前摄像头方向 ---
AVCaptureDevicePosition currentPosition = self.captureDeviceInput.device.position;
AVCaptureDevicePosition toPosition = AVCaptureDevicePositionUnspecified;
if (currentPosition == AVCaptureDevicePositionBack || currentPosition == AVCaptureDevicePositionUnspecified) {
toPosition = AVCaptureDevicePositionFront;
} else {
toPosition = AVCaptureDevicePositionBack;
}
NSArray *captureDeviceArr = [cameras filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"position == %d", toPosition]];
if (captureDeviceArr.count == 0) {
return [self errorWithDomain:@"VideoCapture:Can't Reverse Camera! get new camera faild!"];
}