AVCaptureDevice是相機(jī)硬件的接口,用于配置底層硬件的屬性,這些底層硬件包括前后置攝像頭、麥克風(fēng)、閃光燈等。
驗(yàn)證授權(quán)
1. 請求用戶授權(quán)指定的媒體類型
為保護(hù)用戶隱私,應(yīng)用在使用相機(jī)或者麥克風(fēng)時(shí),總是需要用戶授權(quán)才能正常使用。當(dāng)應(yīng)用第一次需要權(quán)限的媒體類型創(chuàng)建任何AVCaptureDeviceInput對象時(shí),系統(tǒng)會(huì)自動(dòng)顯示一個(gè)alert以請求用戶授權(quán)。在被授予任何訪問權(quán)限之前,任何AVMediaType類型的AVCaptureDevice都將關(guān)閉靜默音頻樣本或黑色視頻幀。
調(diào)用下面方法,可以讓應(yīng)用直接獲取用戶授權(quán),而不是需要等到創(chuàng)建AVCaptureDeviceInput對象時(shí),系統(tǒng)自動(dòng)顯示一個(gè)alert以請求用戶授權(quán)。
+ (void)requestAccessForMediaType:(AVMediaType)mediaType completionHandler:(void (^)(BOOL granted))handler
該方法有兩個(gè)參數(shù):
- 第一個(gè)參數(shù)mediaType: 媒體類型常量,可以是AVMediaTypeVideo和AVMediaTypeAudio,如果沒有提供媒體類型或提供其他的媒體類型,都將拋出異常
- 第二個(gè)參數(shù)(void (^)(BOOL granted))handler: 獲得用戶相應(yīng)后調(diào)用的塊,如果用戶授予使用硬件的權(quán)限,則granted返回YES,否則返回NO.注意塊回調(diào)可能在任意線程,如果需要處理UI,需要切回主線程。
如果調(diào)用該方法之前,已經(jīng)顯示alert以請求用戶授權(quán),不管用戶同意或者拒絕授權(quán),該方法的回調(diào)都會(huì)立即放回用戶曾經(jīng)的授權(quán)結(jié)果,而不會(huì)再次顯示一個(gè)alert請求用戶授權(quán)。
應(yīng)用程序必須在配置信息info.plist中提供使用NSCameraUsageDescription或NSMicrophoneUsageDescription信息的解釋。iOS在最初請求用戶許可時(shí)顯示了這個(gè)解釋,然后在設(shè)置應(yīng)用程序中顯示。在沒有使用說明的情況下啟動(dòng)AVCaptureSession會(huì)引發(fā)異常。
2. 獲取制定媒體類型的授權(quán)狀態(tài)
為了獲悉應(yīng)用程序是否獲取指定媒體類型的權(quán)限,應(yīng)用可以調(diào)用下面的類方法獲取授權(quán)狀態(tài):
+ (AVAuthorizationStatus)authorizationStatusForMediaType:(AVMediaType)mediaType;
該方法同步調(diào)用,會(huì)立即返回授權(quán)狀態(tài)。如果此方法返回AVAuthorizationStatusNotDetermined,則可以調(diào)用+requestAccessForMediaType:completionHandler:以提示用戶記錄權(quán)限
授權(quán)狀態(tài)AVAuthorizationStatus
- AVAuthorizationStatusNotDetermined: 用戶尚未授權(quán)
- AVAuthorizationStatusRestricted:不允許用戶訪問媒體捕獲設(shè)備,用戶不能改變客戶機(jī)的狀態(tài),可能由于活躍的限制,如家長控制,這個(gè)狀態(tài)通常是看不到的,用于發(fā)現(xiàn)設(shè)備的類方法不會(huì)返回用戶被限制訪問的設(shè)備。
- AVAuthorizationStatusDenied:用戶已經(jīng)明確拒絕了應(yīng)用訪問捕獲設(shè)備
- AVAuthorizationStatusAuthorized: 用戶授予應(yīng)用訪問捕獲設(shè)備的權(quán)限
媒體類型AVMediaType
- AVMediaTypeVideo: 指定視頻
- AVMediaTypeAudio: 指定音頻
- AVMediaTypeText: 指定文本
- AVMediaTypeClosedCaption: 指定閉路內(nèi)容
- AVMediaTypeSubtitle: 指定字幕
- AVMediaTypeTimecode: 指定一個(gè)時(shí)間代碼
- AVMediaTypeMetadata: 指定元數(shù)據(jù)
- AVMediaTypeMuxed: 指定混合媒體
- AVMediaTypeMetadataObject
- AVMediaTypeDepthData
通知
- AVCaptureDeviceWasConnectedNotification
當(dāng)新設(shè)備可用時(shí)發(fā)送一個(gè)通知,通知對象是AVCaptureDevice實(shí)例,表示已可用的設(shè)備。 - AVCaptureDeviceWasDisconnectedNotification
當(dāng)現(xiàn)有設(shè)備不可用時(shí)發(fā)送一個(gè)通知,通知對象是AVCaptureDevice實(shí)例,表示不可用的設(shè)備。
閃光燈
在光線不足的情況下,需要開啟屏幕的閃光燈來進(jìn)行補(bǔ)光,便于鏡頭可以捕捉更好的場景,拍攝出好的照片和視頻
- iOS 10之前閃光燈設(shè)置
AVCaptureDevice *device = nil;
NSArray *inputs = self.session.inputs;
for (AVCaptureDeviceInput *input in inputs) {
if ([device.deviceType isEqual:AVMediaTypeVideo]) {
device = input.device;
}
}
NSError *errorProperty = nil;
if ([device hasFlash]) {
if ([device isFlashAvailable]) {
if ([device isFlashModeSupported:AVCaptureFlashModeOn]) {
BOOL result = NO;
result = [device lockForConfiguration:&errorProperty];
if (result) {
[device setFlashMode:AVCaptureFlashModeOn];
}else {
NSLog(@"ERROR : CONFIGURATION CAPTURE DEVICE FLASH FAILURE, ERROR CODE:%ld", (long)errorProperty.code);
}
[device unlockForConfiguration];
}else{
NSLog(@"ERROR : FLASH IS UNAVAILABLE BECAUSE THE DEVCICE OVERHEATS");
}
}else {
NSLog(@"ERROR : SOFTWARE DEVICE HAVE NO FLASH");
}
}
- iOS 10之后閃光燈設(shè)置
NSArray *outputs = self.session.outputs;
for (AVCaptureOutput *output in outputs) {
if ([output isMemberOfClass:[AVCapturePhotoOutput class]]) {
AVCapturePhotoOutput *photoOutput = (AVCapturePhotoOutput *)output;
BOOL flashSupported = [[photoOutput supportedFlashModes] containsObject:@(AVCaptureFlashModeAuto)];
if (flashSupported) {
AVCapturePhotoSettings *photoSettings = photoOutput.photoSettingsForSceneMonitoring;
photoSettings.flashMode = AVCaptureFlashModeAuto;
}else {
NSLog(@"ERROR : PHOTOOUTPUT CAN NOT SUPPORT AVCAPTUREMODE TYPE");
}
}
}
- 閃光燈類型
AVCaptureFlashModeOff = 0,//閃光燈關(guān)閉
AVCaptureFlashModeOn = 1,//閃光燈開啟
AVCaptureFlashModeAuto = 2,//閃光燈自動(dòng)
手電筒
在光線不是很暗的情況下我們可以用手機(jī)的LED燈當(dāng)作手電筒使用。
AVCaptureDevice *device = nil;
NSArray *inputs = self.session.inputs;
for (AVCaptureDeviceInput *input in inputs) {
if ([device.deviceType isEqual:AVMediaTypeVideo]) {
device = input.device;
}
}
NSError *error = nil;
if ([device hasTorch]) {
if ([device isTorchAvailable]) {
if ([device isTorchModeSupported:AVCaptureTorchModeOn]) {
BOOL result = NO;
result = [device lockForConfiguration:&error];
if (result) {
[device setTorchMode:AVCaptureTorchModeOn];
}else {
NSLog(@"ERROR : CONFIGURATION DEVICE TORCH FAIL AND ERROR CODE %ld", (long)error.code);
}
error = nil;
// Torch light
result = [device setTorchModeOnWithLevel:0.5 error:&error];
if (!result) {
NSLog(@"ERROR : DEVICE SET TORCH FAILURE AND ERROR CODE %ld", error.code);
}
[device unlockForConfiguration];
}else {
NSLog(@"ERROR : DEVICE CAN NO SUPPORT TORCH");
}
}else {
NSLog(@"ERROR : SOFTHARE DEVICE TORCH IS UNAVAILABLE BECAUSE OVERHEATS");
}
}else {
NSLog(@"ERROR : SOFFHARE DEVICE HAS NO TORCH");
}
手電筒模式類型
AVCaptureTorchModeOff = 0,//關(guān)閉
AVCaptureTorchModeOn = 1,//打開
AVCaptureTorchModeAuto = 2,//自動(dòng)
聚焦
- (void)focusAtPoint:(CGPoint)point {
AVCaptureDevice *device = [self activeCamera];
if (device.isFocusPointOfInterestSupported && [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
NSError *error;
// 鎖定設(shè)備準(zhǔn)備配置,如果獲得了鎖
if ([device lockForConfiguration:&error]) {
// 將focusPointOfInterest屬性設(shè)置CGPoint
device.focusPointOfInterest = point;
device.focusMode = AVCaptureFocusModeAutoFocus;
// 釋放該鎖定
[device unlockForConfiguration];
} else {
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
[self.delegate deviceConfigurationFailedWithError:error];
}
}
}
}
- 聚焦類型
AVCaptureFocusModeLocked = 0,//鎖定當(dāng)前鏡頭位置
AVCaptureFocusModeAutoFocus = 1,//鏡頭自動(dòng)調(diào)焦
AVCaptureFocusModeContinuousAutoFocus = 2,//鏡頭連續(xù)自動(dòng)調(diào)焦
曝光
- (void)exposeAtPoint:(CGPoint)point {
AVCaptureDevice *device = [self activeCamera];
if (device.isExposurePointOfInterestSupported && [device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
NSError *error;
if ([device lockForConfiguration:&error]) {
device.exposurePointOfInterest = point;
device.exposureMode = AVCaptureExposureModeContinuousAutoExposure;
[device unlockForConfiguration];
} else {
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
[self.delegate deviceConfigurationFailedWithError:error];
}
}
}
}
- 曝光設(shè)置類型
AVCaptureExposureModeLocked = 0,//鎖定
AVCaptureExposureModeAutoExpose = 1,//自動(dòng)對焦
AVCaptureExposureModeContinuousAutoExposure = 2,//實(shí)現(xiàn)連續(xù)自動(dòng)對焦
白平衡
- 類型設(shè)置白平衡
AVCaptureDevice *device = nil;
NSArray *inputs = self.session.inputs;
for (AVCaptureDeviceInput *input in inputs) {
if ([device.deviceType isEqual:AVMediaTypeVideo]) {
device = input.device;
}
}
if ([device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
NSError *error;
if ([device lockForConfiguration:&error]) {
[device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];
}
[device unlockForConfiguration];
}
白平衡類型
AVCaptureWhiteBalanceModeLocked = 0,
AVCaptureWhiteBalanceModeAutoWhiteBalance = 1,
AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance = 2,
- RGB設(shè)置白平衡
AVCaptureDevice *device = nil;
NSArray *inputs = self.session.inputs;
for (AVCaptureDeviceInput *input in inputs) {
if ([device.deviceType isEqual:AVMediaTypeVideo]) {
device = input.device;
}
}
float maxWhiteBalance = device.maxWhiteBalanceGain;
float redGain = MIN(2.0, maxWhiteBalance);
float greenGain = MIN(2.0, maxWhiteBalance);
float blueGain = MIN(2.0, maxWhiteBalance);
AVCaptureWhiteBalanceGains whiteBalanceGains = {
redGain,
greenGain,
blueGain
};
[device setWhiteBalanceModeLockedWithDeviceWhiteBalanceGains:whiteBalanceGains completionHandler:nil];