輸入設(shè)備AVCaptureDevice 繼承自NSObject:是關(guān)于相機(jī)硬件的接口,用于配置底層硬件的屬性(例如相機(jī)聚焦、白平衡、感光度ISO、曝光、幀率、閃光燈、縮放等),這些底層硬件包括前置攝像頭、后置攝像頭、麥克風(fēng)、閃光燈等。使用AVCaptureDevice向AVCaptureSession對象提供輸入數(shù)據(jù)(如音頻或視頻)。
1、驗(yàn)證授權(quán)
1.1、請求用戶授權(quán)指定的媒體類型
為保護(hù)用戶隱私,應(yīng)用在使用相機(jī)或者麥克風(fēng),總是需要用戶授權(quán)才能正常使用。當(dāng)應(yīng)用第一次為需要權(quán)限的媒體類型創(chuàng)建任何AVCaptureDeviceInput對象時(shí),系統(tǒng)會(huì)自動(dòng)顯示一個(gè)alert以請求用戶授權(quá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ù):
AVMediaType mediaType:媒體類型常量,可以是AVMediaTypeVideo,也可以是AVMediaTypeAudio;如果沒有提供媒體類型,將拋出異常NSInvalidArgumentException。 - 第二個(gè)參數(shù):
(void (^)(BOOL granted))handler:獲得用戶響應(yīng)后將調(diào)用的塊;塊中參數(shù)BOOL granted如果用戶授予使用硬件的權(quán)限,則返回YES;否則返回NO。注意:塊回調(diào)可能在任意線程,如果要處理UI,請回歸主線程。
該方法是異步調(diào)用,被調(diào)用時(shí)允許客戶端繼續(xù)運(yùn)行,不會(huì)堵塞當(dāng)前線程。在被授予訪問權(quán)限之前,任何AVMediaType類型的AVCaptureDevice都將關(guān)閉靜默音頻樣本或黑色視頻幀。
如果調(diào)用該方法之前,已經(jīng)顯示alert以請求用戶授權(quán),不管用戶同意授權(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ā)異常。
當(dāng)應(yīng)用在手機(jī)上,沒有請求用戶授權(quán)時(shí),執(zhí)行下述代碼,將會(huì)顯示一個(gè)alert以請求用戶授權(quán)
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
NSLog(@"granted --- %d currentThread : %@",granted,NSThread.currentThread);
}];
NSLog(@"currentThread : %@",NSThread.currentThread);

我們點(diǎn)擊同意,觀察打印結(jié)果:
14:06:49 currentThread : <NSThread: 0x17006ee80>{number = 1, name = main}
14:06:54 granted --- 1 currentThread : <NSThread: 0x174070600>{number = 3, name = (null)}
可以看到handler中返回YES,并且handler的響應(yīng)在任意線程中
注意:
(void (^)(BOOL granted))handler回調(diào)可能在任意線程,如果要處理UI,請確保在主線程。
1.2、獲取關(guān)于指定媒體類型的授權(quán)狀態(tài)
為保護(hù)用戶隱私,應(yīng)用在使用相機(jī)或者麥克風(fēng),總是需要用戶授權(quán)才能正常使用。當(dāng)應(yīng)用第一次為需要權(quán)限的媒體類型創(chuàng)建任何
AVCaptureDeviceInput對象時(shí),系統(tǒng)會(huì)自動(dòng)顯示一個(gè)alert以請求用戶授權(quán)。
為獲悉應(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)限。
我們不妨執(zhí)行下述代碼,分析打印結(jié)果:
switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
{
case AVAuthorizationStatusNotDetermined:
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
NSLog(@"granted --- %d currentThread : %@",granted,NSThread.currentThread);
}];
NSLog(@"用戶尚未授予或拒絕該權(quán)限:AVAuthorizationStatusNotDetermined");
break;
case AVAuthorizationStatusRestricted:
NSLog(@"不允許用戶訪問媒體捕獲設(shè)備:AVAuthorizationStatusRestricted");
break;
case AVAuthorizationStatusDenied:
NSLog(@"用戶已經(jīng)明確拒絕了應(yīng)用訪問捕獲設(shè)備:AVAuthorizationStatusDenied");
break;
case AVAuthorizationStatusAuthorized:
NSLog(@"用戶授予應(yīng)用訪問捕獲設(shè)備的權(quán)限:AVAuthorizationStatusAuthorized");
break;
default:
break;
}
NSLog(@"currentThread : %@",NSThread.currentThread);
/****************** 打印結(jié)果 *************************
14:24:54 用戶已經(jīng)明確拒絕了應(yīng)用訪問捕獲設(shè)備:AVAuthorizationStatusDenied
14:24:54 currentThread : <NSThread: 0x170264e00>{number = 1, name = main}
****************************************************/
注意:使用
AVMediaTypeVideo或AVMediaTypeAudio以外的任何媒體類型調(diào)用此方法都會(huì)引發(fā)異常NSInvalidArgumentException。
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[AVCaptureDevice authorizationStatusForMediaType:] The passed mediaType text is not supported'
*** First throw call stack:
(0x1836e2fe0 0x182144538 0x18b1008c0 0x1000a2b04 0x18982c838 0x18982c5a8 0x1898cc09c 0x1898cb870 0x1898cb424 0x1898cb388 0x189811cc0 0x186a02274 0x1869f6de8 0x1869f6ca8 0x18697234c 0x1869993ac 0x186999e78 0x1836909a8 0x18368e630 0x1835bedc4 0x18987efc8 0x189879c9c 0x1000a62f0 0x1825cd59c)
libc++abi.dylib: terminating with uncaught exception of type NSException

1.3、媒體類型AVMediaType
媒體類型AVMediaType是使用typedef修飾的標(biāo)識符,提供各種媒體類型:
| 值 | 描述 |
|---|---|
AVMediaTypeVideo |
指定視頻 |
AVMediaTypeAudio |
指定音頻 |
AVMediaTypeText |
指定文本 |
AVMediaTypeClosedCaption |
指定閉路內(nèi)容 |
AVMediaTypeSubtitle |
指定字幕 |
AVMediaTypeTimecode |
指定一個(gè)時(shí)間代碼 |
AVMediaTypeMetadata |
指定元數(shù)據(jù) |
AVMediaTypeMuxed |
指定mux媒體 |
AVMediaTypeMetadataObject |
|
AVMediaTypeDepthData |
1.4、授權(quán)狀態(tài)AVAuthorizationStatus
授權(quán)狀態(tài)AVAuthorizationStatus是個(gè)枚舉類型,提供有關(guān)使用捕獲設(shè)備AVCaptureDevice權(quán)限信息的常量:
| 值 | 描述 |
|---|---|
AVAuthorizationStatusNotDetermined |
用戶尚未授予或拒絕該權(quán)限, |
AVAuthorizationStatusRestricted |
不允許用戶訪問媒體捕獲設(shè)備。這個(gè)狀態(tài)通常是看不到的:用于發(fā)現(xiàn)設(shè)備的AVCaptureDevice類方法不會(huì)返回用戶被限制訪問的設(shè)備。 |
AVAuthorizationStatusDenied |
用戶已經(jīng)明確拒絕了應(yīng)用訪問捕獲設(shè)備 |
AVAuthorizationStatusAuthorized |
用戶授予應(yīng)用訪問捕獲設(shè)備的權(quán)限 |
1.5、使用例子
+ (void)getAuthorizationStatus:(void(^)(void))authorizedBlock
{
switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]){
case AVAuthorizationStatusNotDetermined:{
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted){
if (granted){
dispatch_async(dispatch_get_main_queue(), ^{
if (authorizedBlock) {
authorizedBlock();
}
});
}
NSLog(@"granted --- %d currentThread : %@",granted,NSThread.currentThread);
}];
NSLog(@"用戶尚未授予或拒絕該權(quán)限:AVAuthorizationStatusNotDetermined");
}
break;
case AVAuthorizationStatusRestricted:
NSLog(@"不允許用戶訪問媒體捕獲設(shè)備:AVAuthorizationStatusRestricted");
break;
case AVAuthorizationStatusDenied:
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"沒有權(quán)限" message:@"該功能需要授權(quán)使用你的相機(jī)" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"拒絕" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {}];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"授權(quán)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSURL *url= [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if (@available(iOS 10.0, *)){
if( [[UIApplication sharedApplication]canOpenURL:url] ) {
[[UIApplication sharedApplication]openURL:url options:@{}completionHandler:^(BOOL success) {
}];
}
}else{
if( [[UIApplication sharedApplication]canOpenURL:url] ) {
[[UIApplication sharedApplication]openURL:url];
}
}
}];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
NSLog(@"用戶已經(jīng)明確拒絕了應(yīng)用訪問捕獲設(shè)備:AVAuthorizationStatusDenied");
}
break;
case AVAuthorizationStatusAuthorized:
{
dispatch_async(dispatch_get_main_queue(), ^{
if (authorizedBlock) {
authorizedBlock();
}
});
NSLog(@"用戶授予應(yīng)用訪問捕獲設(shè)備的權(quán)限:AVAuthorizationStatusAuthorized");
}
break;
default:
break;
}
}
在進(jìn)入相機(jī)拍攝界面之前,調(diào)用上述方法,只有授權(quán)使用相機(jī)時(shí)回調(diào)authorizedBlock 進(jìn)入相機(jī)界面:
[AVCaptureTools getAuthorizationStatus:^{
if (@available(iOS 10.2, *)) {
//使用 AVCapturePhotoOutput 拍照
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:[[AVCaptureViewController alloc]init]];
self.window.rootViewController = nav;
} else {
//使用 AVCaptureStillImageOutput 拍照
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:[[AVCaptureLowVersionViewController alloc]init]];
self.window.rootViewController = nav;
}
}];
2、發(fā)現(xiàn)設(shè)備
2.1、AVCaptureDeviceDiscoverySession
在 iPhone 7plus 及以后某些 iPhone 上,采用了后置雙攝像頭配置:一個(gè)廣角鏡頭和一個(gè)長焦鏡頭,這兩個(gè)鏡頭可以合并為一個(gè)單一采集設(shè)備一起工作。在iOS 10及以后的 版本中使用 AVCaptureDeviceDiscoverySession 查詢可用AVCaptureDevice。使用這個(gè)類可以找到所有匹配特定設(shè)備類型deviceTypes(如麥克風(fēng)或廣角相機(jī))、支持用于捕獲的媒體類型(如音頻、視頻或兩者)和相機(jī)位置(前或后)的可用AVCaptureDevice。
使用下述類方法創(chuàng)建一個(gè)AVCaptureDeviceDiscoverySession,用于查找具有指定標(biāo)準(zhǔn)的設(shè)備:
+ (instancetype)discoverySessionWithDeviceTypes:(NSArray<AVCaptureDeviceType> *)deviceTypes mediaType:(AVMediaType)mediaType position:(AVCaptureDevicePosition)position;
- 參數(shù)
NSArray<AVCaptureDeviceType> *deviceTypes:要搜索的設(shè)備類型列表,例如 麥克風(fēng)AVCaptureDeviceTypeBuiltInMicrophone和相機(jī)AVCaptureDeviceTypeBuiltInWideAngleCamera。這個(gè)數(shù)組必須至少包含一個(gè)有效的AVCaptureDeviceType值。
創(chuàng)建AVCaptureDeviceDiscoverySession后,讀取其設(shè)備數(shù)組devices以檢查匹配的設(shè)備并選擇一個(gè)可用的AVCaptureDevice。
@property(nonatomic, readonly) NSArray<AVCaptureDevice *> *devices;
這個(gè)數(shù)組只包含當(dāng)前可用的AVCaptureDevice(在讀取屬性時(shí)),并且滿足使用+ discoverySessionWithDeviceTypes:mediaType:position: initializer創(chuàng)建設(shè)備發(fā)現(xiàn)會(huì)話時(shí)指定的條件。
在 iOS 11.0 及更高版本中,這個(gè)數(shù)組的順序與用于創(chuàng)建發(fā)現(xiàn)會(huì)話的
deviceTypes參數(shù)的順序相匹配,因此可以快速選擇匹配首選類型的設(shè)備(請參閱帶有發(fā)現(xiàn)會(huì)話的排序和篩選設(shè)備)。在較老的iOS版本中,搜索整個(gè)數(shù)組以找到首選設(shè)備。
2.1.1、 AVCaptureDeviceType
設(shè)備類型AVCaptureDeviceType是使用typedef修飾的標(biāo)識符,提供各種設(shè)備類型,與+ defaultDeviceWithDeviceType:mediaType:position:方法和AVCaptureDeviceDiscoverySession類一起使用。
設(shè)備類型AVCaptureDeviceType
|
描述 |
|---|---|
AVCaptureDeviceTypeBuiltInMicrophone |
一個(gè)內(nèi)置的麥克風(fēng) |
AVCaptureDeviceTypeBuiltInWideAngleCamera |
內(nèi)置廣角相機(jī),這些裝置適用于一般用途。 |
AVCaptureDeviceTypeBuiltInTelephotoCamera |
內(nèi)置長焦相機(jī),比廣角相機(jī)的焦距長。這種類型只是將窄角設(shè)備與配備兩種類型的攝像機(jī)的硬件上的寬角設(shè)備區(qū)分開來。要確定攝像機(jī)設(shè)備的實(shí)際焦距,可以檢查AVCaptureDevice的format數(shù)組中的AVCaptureDeviceFormat對象。 |
AVCaptureDeviceTypeBuiltInDualCamera |
廣角相機(jī)和長焦相機(jī)的組合,創(chuàng)建了一個(gè)拍照,錄像的AVCaptureDevice。具有和深度捕捉,增強(qiáng)變焦和雙圖像捕捉功能。 |
AVCaptureDeviceTypeBuiltInTrueDepthCamera |
相機(jī)和其他傳感器的組合,創(chuàng)建了一個(gè)捕捉設(shè)備,能夠拍照、視頻和深度捕捉。 |
AVCaptureDeviceTypeBuiltInDuoCamera |
iOS 10.2 之后添加自動(dòng)變焦功能,該值功能被AVCaptureDeviceTypeBuiltInDualCamera替代 |
2.1.2、 AVCaptureDevicePosition
相機(jī)鏡頭位置AVCaptureDevicePosition是個(gè)枚舉類型:
| 值 | 描述 |
|---|---|
AVCaptureDevicePositionUnspecified |
AVCaptureDevice相對于系統(tǒng)硬件的位置未指定。 |
AVCaptureDevicePositionBack |
后置鏡頭 |
AVCaptureDevicePositionFront |
前置鏡頭 |
2.2、獲取指定設(shè)備
2.2.1、多個(gè)篩選條件獲取一個(gè)默認(rèn)設(shè)備
+ (AVCaptureDevice *)defaultDeviceWithDeviceType:(AVCaptureDeviceType)deviceType mediaType:(AVMediaType)mediaType position:(AVCaptureDevicePosition)position;
返回指定設(shè)備類型、媒體類型和位置的默認(rèn)設(shè)備;如果當(dāng)前沒有可用設(shè)備滿足指定條件,則為nil。使用該方法可以輕松地為指定場景選擇系統(tǒng)默認(rèn)AVCaptureDevice,例如,要在支持的硬件上獲得雙攝像頭,并返回到標(biāo)準(zhǔn)廣角攝像頭;
- (AVCaptureDevice *)defaultCamera {
AVCaptureDevice *device;
if (@available(iOS 10.0, *)) {
device = [AVCaptureDevice defaultDeviceWithDeviceType: AVCaptureDeviceTypeBuiltInDuoCamera
mediaType: AVMediaTypeVideo
position: AVCaptureDevicePositionBack];
} else {
// Fallback on earlier versions
}
if (device != nil) {
return device;
}
if (@available(iOS 10.0, *)) {
device = [AVCaptureDevice defaultDeviceWithDeviceType: AVCaptureDeviceTypeBuiltInWideAngleCamera
mediaType: AVMediaTypeVideo
position: AVCaptureDevicePositionBack];
} else {
// Fallback on earlier versions
}
if (device != nil) {
return device;
}
return nil;
}
2.2.2、給定ID的一個(gè)設(shè)備
+ (AVCaptureDevice *)deviceWithUniqueID:(NSString *)deviceUniqueID;
返回具有給定ID的設(shè)備。
2.2.3、給定媒體類型AVMediaType的一個(gè)設(shè)備
+ (AVCaptureDevice *)defaultDeviceWithMediaType:(AVMediaType)mediaType;
返回指定媒體類型AVMediaType的默認(rèn)設(shè)備。
注意:使用該方法請求攝像機(jī)
AVMediaTypeVideo時(shí),返回的總是AVCaptureDeviceTypeBuiltInWideAngleCamera設(shè)備類型。要使用其他設(shè)備類型,使用+ defaultDeviceWithDeviceType:mediaType:position:方法。
2.2.4、返回一組設(shè)備
//返回系統(tǒng)上可用捕獲設(shè)備的數(shù)組。已經(jīng)被蘋果使用AVCaptureDeviceDiscoverySession替代
+ (NSArray<AVCaptureDevice *> *)devices;
//返回給定媒體類型的設(shè)備數(shù)組。已經(jīng)被蘋果使用AVCaptureDeviceDiscoverySession替代
+ (NSArray<AVCaptureDevice *> *)devicesWithMediaType:(AVMediaType)mediaType;
2.3、通知
| 通知 | 描述 |
|---|---|
AVCaptureDeviceWasConnectedNotification |
當(dāng)新設(shè)備可用時(shí)發(fā)送一個(gè)通知,通知對象是AVCaptureDevice實(shí)例,表示已可用的設(shè)備。 |
AVCaptureDeviceWasDisconnectedNotification |
當(dāng)現(xiàn)有設(shè)備不可用時(shí)發(fā)送一個(gè)通知,通知對象是AVCaptureDevice實(shí)例,表示不可用的設(shè)備。 |
2.4、例子
我們以獲取mediaType為AVMediaTypeVideo的后置鏡頭為例:
- (void)getTheAVCaptureDevice
{
if (@available(iOS 10.2, *)) {
NSArray<AVCaptureDeviceType> *deviceTypes = @[AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeBuiltInDualCamera];//設(shè)備類型:廣角鏡頭、雙鏡頭
AVCaptureDeviceDiscoverySession *sessionDiscovery = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionBack];
NSArray<AVCaptureDevice *> *devices = sessionDiscovery.devices;//當(dāng)前可用的AVCaptureDevice集合
__block AVCaptureDevice *newVideoDevice = nil;
//遍歷所有可用的AVCaptureDevice,獲取 后置雙鏡頭
[devices enumerateObjectsUsingBlock:^(AVCaptureDevice * _Nonnull device, NSUInteger idx, BOOL * _Nonnull stop) {
if ( device.position == AVCaptureDevicePositionBack && [device.deviceType isEqualToString:AVCaptureDeviceTypeBuiltInDualCamera] ) {
newVideoDevice = device;
* stop = YES;
}
}];
if (!newVideoDevice){
//如果后置雙鏡頭獲取失敗,則獲取廣角鏡頭
[devices enumerateObjectsUsingBlock:^(AVCaptureDevice * _Nonnull device, NSUInteger idx, BOOL * _Nonnull stop) {
if ( device.position == AVCaptureDevicePositionBack) {
newVideoDevice = device;
* stop = YES;
}
}];
}
} else {
//獲取指定mediaType類型的AVCaptureDevice集合
NSArray<AVCaptureDevice *> *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
__block AVCaptureDevice *newVideoDevice = nil;
//遍歷所有可用的AVCaptureDevice,獲取后置鏡頭
[devices enumerateObjectsUsingBlock:^(AVCaptureDevice * _Nonnull device, NSUInteger idx, BOOL * _Nonnull stop) {
if ( device.position == AVCaptureDevicePositionBack) {
newVideoDevice = device;
* stop = YES;
}
}];
}
}
我們可以看到,針對不同版本的 iOS 系統(tǒng),蘋果提供了兩種方法獲取指定的AVCaptureDevice:在適配 iOS 10 以后的版本中,我們可以使用AVCaptureDeviceDiscoverySession 獲取后置雙鏡頭!但是在另一種方法中,我們無法使用雙鏡頭,只能獲取一個(gè)默認(rèn)的廣角鏡頭。
3、配置設(shè)備
3.1、鎖定設(shè)備
AVCaptureDevice在改變某些參數(shù)前必須先鎖定,直到改變結(jié)束才能解鎖:
//在修改AVCaptureDevice相關(guān)屬性之前,必須調(diào)用下述方法上鎖;當(dāng)這個(gè)方法成功地鎖定設(shè)備進(jìn)行配置時(shí),它返回YES;如果沒有獲得鎖,則為NO。
- (BOOL)lockForConfiguration:(NSError * _Nullable *)outError;
//在修改AVCaptureDevice相關(guān)屬性完成后,還需要調(diào)用下述方法解鎖,允許其他應(yīng)用程序進(jìn)行更改。
- (void)unlockForConfiguration;
如果要求設(shè)備屬性保持不變,可以持有一個(gè)鎖而不釋放它。然而,不必要地持有設(shè)備鎖可能會(huì)降低共享設(shè)備的其他應(yīng)用程序的捕獲質(zhì)量。
在iOS中,直接設(shè)置AVCaptureDevice的activeFormat屬性,會(huì)導(dǎo)致AVCaptureSession的預(yù)設(shè)值sessionPreset更改為AVCaptureSessionPresetInputPriority。更改AVCaptureSession時(shí),當(dāng)調(diào)用它的startRunning方法 或 更改它的結(jié)構(gòu)(如添加、刪除輸入和輸出)后調(diào)用-commitConfiguration方法時(shí),AVCaptureSession不再自動(dòng)配置捕獲格式。但是在 Mac OS 中,在進(jìn)行更改之后,AVCaptureSession仍然可以自動(dòng)配置捕獲格式activeFormat。
為了防止 Mac OS 中捕捉格式activeFormat的自動(dòng)更改,需要執(zhí)行以下步驟:
- 1、調(diào)用
AVCaptureDevice的- lockForConfiguration:方法鎖定設(shè)備。 - 2、更改
AVCaptureDevice的activeFormat屬性。 - 3、調(diào)用
AVCaptureSession的startRunning方法 - 4、調(diào)用
AVCaptureDevice的- unlockForConfiguration解鎖設(shè)備。
為了防止 在修改 Mac OS 中的AVCaptureSession的結(jié)構(gòu)后自動(dòng)更改activeFormat:
- 1、調(diào)用
AVCaptureDevice的- lockForConfiguration:方法鎖定設(shè)備。 - 2、調(diào)用
AVCaptureSession的- beginConfiguration方法,修改它的結(jié)構(gòu); - 3、調(diào)用
AVCaptureSession的- commitConfiguration方法,提交修改; - 4、調(diào)用
AVCaptureDevice的- unlockForConfiguration解鎖設(shè)備。
3.2、一些設(shè)備參數(shù)
| 屬性 | 類型 | 描述 |
|---|---|---|
inUseByAnotherApplication |
BOOL |
指示設(shè)備是否被其他應(yīng)用程序占用。 |
suspended |
BOOL |
指示設(shè)備是否掛起。一些設(shè)備由于參數(shù)設(shè)置不允許數(shù)據(jù)捕獲;例如,當(dāng)iSight的隱私虹膜關(guān)閉時(shí),isSuspended會(huì)返回YES,對于筆記本上的iSight攝像機(jī),或者對于筆記本顯示關(guān)閉時(shí)的內(nèi)部iSight攝像機(jī),issuspend會(huì)返回YES。 |
linkedDevices |
NSArray<AVCaptureDevice *> |
一組AVCaptureDevice對象,表示外接設(shè)備。例如,對于外部iSight攝像機(jī),數(shù)組包含一個(gè)AVCaptureDevice實(shí)例,表示外部iSight麥克風(fēng)。 |
transportType |
int32_t |
AVCaptureDevice的傳輸類型(USB、PCI等)。 |
inputSources |
NSArray<AVCaptureDeviceInputSource *> |
AVCaptureDevice支持的輸入源的AVCaptureDeviceInputSource對象數(shù)組。 有些設(shè)備可以從多個(gè)數(shù)據(jù)源之一(例如,同一音頻設(shè)備上的不同輸入插孔)捕獲數(shù)據(jù)。 |
activeInputSource |
AVCaptureDeviceInputSource |
當(dāng)前活躍的輸入源。要設(shè)置該屬性,需要先調(diào)用- lockForConfiguration:方法鎖定設(shè)備;否則將拋出異常NSGenericException;如果傳遞的format在formats中不存在,調(diào)用-setActiveInputSource:拋出異常NSInvalidArgumentException。 |
3.3、輸入源AVCaptureDeviceInputSource
AVCaptureDeviceInputSource是捕獲設(shè)備AVCaptureDevice上的輸入源。
AVCaptureDevice對象可以從inputSources數(shù)組中選擇一個(gè)作為輸入源,表示設(shè)備的不同的互斥輸入。例如,音頻捕獲設(shè)備可能具有ADAT光學(xué)和模擬輸入源;視頻捕獲設(shè)備可能有HDMI輸入源或組件輸入源。
| 屬性 | 類型 | 描述 |
|---|---|---|
inputSourceID |
NSString |
輸入源ID;在指定AVCaptureDevice對象的輸入源中,ID是唯一的。 |
localizedName |
NSString |
輸入源的本地化名稱;可以使用此屬性在用戶界面中顯示AVCaptureDevice輸入源的名稱。 |
4、檢查設(shè)備特征
| 屬性 | 類型 | 描述 |
|---|---|---|
connected |
BOOL |
表示AVCaptureDevice實(shí)例當(dāng)前是否已連接,是否可用。但是,當(dāng)這個(gè)屬性的值對于給定的AVCaptureDevice實(shí)例變成NO時(shí),它就不會(huì)再變成YES。如果相同的物理設(shè)備再次對系統(tǒng)可用,它將使用AVCaptureDevice的新實(shí)例表示。 |
position |
AVCaptureDevicePosition |
表示設(shè)備AVCaptureDevice的物理位置。 |
modelID |
NSString |
設(shè)備的型號ID。該值是同一型號的所有設(shè)備的唯一標(biāo)識符,該值是跨設(shè)備連接和斷開連接以及跨不同系統(tǒng)的持久值。例如,內(nèi)置在兩個(gè)相同iPhone機(jī)型上的攝像頭的型號ID將是相同的,盡管它們是不同的物理設(shè)備。 |
localizedName |
NSString |
一個(gè)本地可讀的AVCaptureDevice設(shè)備名稱;可以使用該值在用戶界面中顯示AVCaptureDevice設(shè)備設(shè)備的名稱。 |
uniqueID |
NSString |
AVCaptureDevice唯一ID,它可以跨設(shè)備連接和斷開連接、應(yīng)用程序重新啟動(dòng)和系統(tǒng)重新啟動(dòng)在一個(gè)系統(tǒng)上持續(xù)存在??梢源鎯υ撝?,以便將來收回或跟蹤特定設(shè)備的狀態(tài)。 |
lensAperture |
float |
鏡片隔膜的尺寸,表示透鏡光圈的大小(f號)。是個(gè)只讀屬性,該值不變。 |
deviceType |
AVCaptureDeviceType |
設(shè)備類型,如內(nèi)置麥克風(fēng)或廣角攝像機(jī)。 |
manufacturer |
NSString |
設(shè)備制造商。對于所有蘋果設(shè)備來說,這一屬性值都是“Apple Inc.”;來自第三方制造商的設(shè)備可能不被識別,此時(shí)該值值為空字符串。 |
//返回一個(gè)布爾值,表示AVCaptureDevice是否為指定AVMediaType提供媒體。
- (BOOL)hasMediaType:(AVMediaType)mediaType;
//返回一個(gè)布爾值,表示AVCaptureDevice是否可以使用 指定sessionPreset的會(huì)話AVCaptureSession。
- (BOOL)supportsAVCaptureSessionPreset:(AVCaptureSessionPreset)preset;
5、管理格式
5.1、捕獲格式AVCaptureDeviceFormat
AVCaptureDeviceFormat 對象詳細(xì)描述了特定捕獲模式的視頻、圖像或音頻參數(shù)等,提供一組可用于配置AVCaptureDevice的媒體格式與設(shè)置,如視頻分辨率和幀速率。
5.2、設(shè)備支持的捕獲格式
@property(nonatomic, readonly) NSArray<AVCaptureDeviceFormat *> *formats;
該屬性提供了AVCaptureDevice支持的捕獲格式,如果需要訪問AVCaptureSession預(yù)設(shè)中未包含的設(shè)置,可以將activeFormat屬性設(shè)置為該數(shù)組中的任何格式。
5.3、當(dāng)前捕獲格式
@property(nonatomic, retain) AVCaptureDeviceFormat *activeFormat;
該屬性提供了AVCaptureDevice的當(dāng)前活動(dòng)媒體數(shù)據(jù)格式;可以使用此屬性獲取或設(shè)置當(dāng)前活動(dòng)的設(shè)備格式。
在iOS中,通常在AVCaptureSession對象上設(shè)置sessionPreset來配置圖像或視頻捕獲,并使用共享的AVAudioSession對象來配置音頻捕獲;在使用sessionPreset時(shí),AVCaptureSession會(huì)自動(dòng)控制AVCaptureDevice的活動(dòng)格式activeFormat。然而,在AVCaptureSession的設(shè)置中,有些專門的捕獲選項(xiàng)(比如高幀率)是不可用的;對于這些選項(xiàng),需要設(shè)置AVCaptureDevice的活動(dòng)格式activeFormat,這樣做將關(guān)聯(lián)的AVCaptureSession的sessionPreset更改為AVCaptureSessionPresetInputPriority。
注意:試圖將activeFormat設(shè)置為formats數(shù)組中不存在的格式,會(huì)拋出NSInvalidArgumentException。
在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以獲得對設(shè)備配置屬性的訪問權(quán),否則,設(shè)置此屬性的值將引發(fā)異常;完成設(shè)備配置后,調(diào)用-unlockForConfiguration釋放鎖并允許其他設(shè)備配置設(shè)置。還必須在調(diào)用AVCaptureSession的-startRunning方法之前調(diào)用-lockForConfiguration:,或AVCaptureSession的sessionPreset將覆蓋AVCaptureDevice的活動(dòng)格式activeFormat。
5.4、當(dāng)前深度捕獲格式
@property(nonatomic, retain) AVCaptureDeviceFormat *activeDepthDataFormat;
該屬性提供了AVCaptureDevice的當(dāng)前活動(dòng)深度數(shù)據(jù)格式。
當(dāng)使用AVCaptureDepthDataOutput類捕獲深度信息時(shí),或者使用AVCapturePhotoOutput類在照片旁邊啟用捕獲深度映射時(shí),捕獲輸出自動(dòng)使用與其活動(dòng)照片/視頻捕獲格式相關(guān)聯(lián)的深度數(shù)據(jù)格式。如果需要更改深度捕獲格式,需要設(shè)置此屬性的值。
深度數(shù)據(jù)捕獲要求視頻/照片數(shù)據(jù)的兼容捕獲格式,如果將此屬性設(shè)置為當(dāng)前activeFormat對象AVCaptureDeviceFormat的supporteddepthdataformat數(shù)組中沒有列出的捕獲格式,將會(huì)引發(fā)異常。
不能直接設(shè)置深度數(shù)據(jù)捕獲的幀速率:深度數(shù)據(jù)幀速率與設(shè)備的activeVideoMinFrameDuration和activeVideoMaxFrameDuration值是同步的,可以等于設(shè)備當(dāng)前的幀速率,如果設(shè)備不能以足夠快的速度生成深度數(shù)據(jù),則可以降低。深度數(shù)據(jù)捕獲可能會(huì)增加系統(tǒng)負(fù)載,從而降低視頻幀速率以實(shí)現(xiàn)熱可持續(xù)性。
在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以獲得對設(shè)備配置屬性的訪問權(quán),否則,設(shè)置此屬性的值將引發(fā)異常;完成設(shè)備配置后,調(diào)用-unlockForConfiguration釋放鎖并允許其他設(shè)備配置設(shè)置。還必須在調(diào)用AVCaptureSession的-startRunning方法之前調(diào)用-lockForConfiguration:,或AVCaptureSession的sessionPreset將覆蓋AVCaptureDevice的活動(dòng)格式activeFormat。
6、焦點(diǎn)設(shè)置
鏡頭焦點(diǎn)與焦距的區(qū)別:
焦點(diǎn) 是透鏡(或曲面鏡)將光線會(huì)聚后所形成的點(diǎn),因光線會(huì)聚成一點(diǎn)可將物燒焦。
焦距 是焦點(diǎn)到面鏡的中心點(diǎn)之間的距離。鏡頭焦距的長短決定著拍攝的成像大小,視場角大小,景深大小和畫面的透視強(qiáng)弱。鏡頭的焦距是鏡頭的一個(gè)非常重要的指標(biāo)。鏡頭焦距的長短決定了被攝物在成像介質(zhì)(膠片或CCD等)上成像的大小,也就是相當(dāng)于物和象的比例尺。當(dāng)對同一距離遠(yuǎn)的同一個(gè)被攝目標(biāo)拍攝時(shí),鏡頭焦距長的所成的象大,鏡頭焦距短的所成的象小。根據(jù)用途的不同,照相機(jī)鏡頭的焦距相差非常大,有短到幾毫米,十幾毫米的,也有長達(dá)幾米的。
6.1、對焦模式
| 屬性 | 類型 | 描述 |
|---|---|---|
focusMode |
AVCaptureFocusMode |
設(shè)備的對焦模式。在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。 |
focusPointOfInterestSupported |
BOOL |
指示設(shè)備是否支持焦點(diǎn)。 |
adjustingFocus |
BOOL |
指示設(shè)備當(dāng)前是否正在調(diào)整其焦點(diǎn)設(shè)置。 |
AVCaptureFocusMode 用于指定捕獲設(shè)備的焦點(diǎn)模式的枚舉。
| 枚舉值 | 描述 |
|---|---|
AVCaptureFocusModeLocked |
焦點(diǎn)被鎖定。 |
AVCaptureFocusModeAutoFocus |
設(shè)備會(huì)自動(dòng)調(diào)整焦距一次,然后將焦點(diǎn)模式更改為AVCaptureFocusModeLocked。 |
AVCaptureFocusModeContinuousAutoFocus |
AVCaptureDevice持續(xù)監(jiān)視焦點(diǎn)并在必要時(shí)自動(dòng)聚焦。 |
當(dāng)設(shè)備支持焦點(diǎn),設(shè)置對焦模式時(shí),我們需要調(diào)用- (BOOL)isFocusModeSupported:(AVCaptureFocusMode)focusMode方法判斷設(shè)備是否支持給定的焦點(diǎn)模式。如果支持focusMode則為YES,否則為NO。
6.2、焦點(diǎn)位置設(shè)置
@property(nonatomic) CGPoint focusPointOfInterest;
聚焦的中心點(diǎn); {0,0}是圖片區(qū)域的左上角,{1,1}是右下角。無論實(shí)際的設(shè)備方向如何,此坐標(biāo)系始終相對于橫向設(shè)備方向,主頁按鈕位于右側(cè)??梢允褂?code>AVCaptureVideoPreviewLayer方法在此坐標(biāo)系和視圖坐標(biāo)之間進(jìn)行轉(zhuǎn)換。
設(shè)置此屬性不會(huì)啟動(dòng)聚焦操作。要將相機(jī)聚焦在中心點(diǎn),首先設(shè)置此屬性的值,然后將focusMode屬性設(shè)置為AVCaptureFocusModeAutoFocus或AVCaptureFocusModeContinuousAutoFocus。
在更改此屬性的值之前,必須調(diào)用-lockForConfiguration: 以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。
6.3、自動(dòng)對焦
| 屬性 | 類型 | 描述 |
|---|---|---|
smoothAutoFocusSupported |
BOOL |
指示設(shè)備是否支持平滑自動(dòng)對焦。自動(dòng)對焦模式僅適用于兼容設(shè)備,如果此屬性的值為NO,則將smoothAutoFocusEnabled的值設(shè)置為YES會(huì)引發(fā)異常。 |
smoothAutoFocusEnabled |
BOOL |
用于確定是否啟用了平滑自動(dòng)對焦;在兼容設(shè)備上,可以啟用自動(dòng)對焦模式,使鏡頭移動(dòng)速度更慢。在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。 |
6.4、自動(dòng)對焦范圍
屬性
AVCaptureAutoFocusRangeRestriction autoFocusRangeRestriction:
控制自動(dòng)對焦允許范圍;默認(rèn)情況下,能夠進(jìn)行硬件聚焦的設(shè)備會(huì)嘗試聚焦在任何距離的對象上。如果希望主要關(guān)注近物體或遠(yuǎn)物體,請?jiān)O(shè)置范圍限制以提高速度并降低自動(dòng)聚焦的功耗,并減少聚焦模糊的可能性。
在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。屬性
BOOL autoFocusRangeRestrictionSupported:一個(gè)布爾值,指示設(shè)備是否支持焦距范圍限制。對焦范圍限制僅適用于兼容設(shè)備。 如果此屬性的值為NO,則設(shè)置autoFocusRangeRestriction會(huì)引發(fā)異常。
AVCaptureAutoFocusRangeRestriction
用于指定捕獲設(shè)備的自動(dòng)聚焦范圍的枚舉:如果您希望主要關(guān)注近物體或遠(yuǎn)物體,可以使用autoFocusRangeRestriction屬性為聚焦系統(tǒng)提供提示。 這種方法使自動(dòng)對焦更快,更節(jié)能,并且更不容易出錯(cuò)。 限制優(yōu)先于指定范圍內(nèi)的距離聚焦,但如果設(shè)備在該范圍內(nèi)沒有找到焦點(diǎn),則不會(huì)阻止聚焦在別處。
| 枚舉值 | 描述 |
|---|---|
AVCaptureAutoFocusRangeRestrictionNone |
設(shè)備會(huì)嘗試關(guān)注任何范圍內(nèi)的對象。此值是默認(rèn)值,是不支持焦點(diǎn)范圍限制的設(shè)備上允許的唯一值。 |
AVCaptureAutoFocusRangeRestrictionNear |
該設(shè)備主要嘗試聚焦在相機(jī)附近的拍攝對象上。對于使用AVCaptureMetadataOutput識別機(jī)器可讀代碼的應(yīng)用程序,建議使用此值。 |
AVCaptureAutoFocusRangeRestrictionFar |
該設(shè)備主要嘗試對焦于遠(yuǎn)離相機(jī)的拍攝對象。 |
7、鏡頭焦距設(shè)置
7.1、獲取鏡頭焦距
@property(nonatomic, readonly) float lensPosition;
表示鏡頭的焦距;取值范圍是 0.0~1.0 :0.0是鏡頭可以聚焦的最短距離,1.0是最遠(yuǎn)的距離;默認(rèn)值是1.0。
該值只能通過-setFocusModeLockedWithLensPosition:completionHandler:來設(shè)置。
const float AVCaptureLensPositionCurrent表示當(dāng)前鏡頭位置的特殊常數(shù)。將此值傳遞給-setFocusModeLockedWithLensPosition:completionHandler:在不更改鏡頭當(dāng)前位置的情況下鎖定焦點(diǎn)(即禁用自動(dòng)對焦)。
7.2、焦距是否支持修改
@property(nonatomic, readonly, getter=isLockingFocusWithCustomLensPositionSupported) BOOL lockingFocusWithCustomLensPositionSupported;
指示設(shè)備是否支持將焦點(diǎn)鎖定到特定的鏡頭位置的布爾值;如果此屬性的值為NO,則使用除AVCaptureLensPositionCurrent之外的鏡頭位置值調(diào)用-setFocusModeLockedWithLensPosition:completionHandler:方法會(huì)引發(fā)異常。
7.3、設(shè)置鏡頭焦距
- (void)setFocusModeLockedWithLensPosition:(float)lensPosition completionHandler:(void (^)(CMTime syncTime))handler;
修改鏡頭焦距為指定值;該方法是設(shè)置鏡頭焦距的唯一路徑。如果lensPosition被設(shè)為不支持的值,這個(gè)方法會(huì)拋出NSInvalidArgumentException異常。如果調(diào)用該方法前沒有使用lockForConfiguration鎖定AVCaptureDevice,則會(huì)引發(fā)NSGenericException異常。
- 第一個(gè)參數(shù)
lensPosition:鏡頭的焦距; - 第二個(gè)參數(shù)
(void (^)(CMTime syncTime))handler: 當(dāng)lensPosition設(shè)置為指定值且屬性focusMode為AVCaptureFocusModeLocked時(shí)調(diào)用的塊。 該塊接收與已應(yīng)用所有設(shè)置的第一個(gè)緩沖區(qū)匹配的時(shí)間戳;時(shí)間戳與設(shè)備時(shí)鐘同步,因此必須先轉(zhuǎn)換為主時(shí)鐘,然后再與AVCaptureVideoDataOutput實(shí)例傳送的緩沖區(qū)的時(shí)間戳進(jìn)行比較。如果不需要知道操作的完成情況,可以將參數(shù)傳遞nil。
8、閃光燈設(shè)置
| 屬性 | 類型 | 描述 |
|---|---|---|
hasFlash |
BOOL |
指示AVCaptureDevice是否有閃光燈。 |
flashMode |
AVCaptureFlashMode |
當(dāng)前的閃光燈模式。在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。 |
flashAvailable |
BOOL |
指示閃光燈當(dāng)前是否可用;例如,如果設(shè)備過熱并需要冷卻,閃光燈可能會(huì)變得不可用。 |
AVCaptureFlashMode 是指定AVCaptureDevice的閃光燈模式的枚舉:
| 枚舉值 | 描述 |
|---|---|
AVCaptureFlashModeOff |
捕獲設(shè)備閃光燈始終處于關(guān)閉狀態(tài)。 |
AVCaptureFlashModeOn |
捕獲設(shè)備閃存始終打開。 |
AVCaptureFlashModeAuto |
捕獲設(shè)備持續(xù)監(jiān)控光照水平,并在必要時(shí)使用閃光燈。 |
我們可以調(diào)用 - (BOOL)isFlashModeSupported:(AVCaptureFlashMode)flashMode;方法判斷是否支持指定的閃光模式。
- (void)flashModelButtonClick:(UIButton *)sender
{
dispatch_async( self.sessionQueue, ^{
AVCaptureDevice *device = self.videoDeviceInput.device;
//是否有閃光燈,閃光燈當(dāng)前是否可用:如果設(shè)備過熱并需要冷卻,閃光燈可能會(huì)變得不可用
if (device.hasFlash == NO || device.flashAvailable == NO) {
return ;
}
NSError *error = nil;
if ([device lockForConfiguration:&error] ) {
switch (device.flashMode){
case AVCaptureFlashModeAuto:{
if ([device isFlashModeSupported:AVCaptureFlashModeOn]){
[device setFlashMode:AVCaptureFlashModeOn];
dispatch_async(dispatch_get_main_queue(), ^{
[sender setImage:resourceImage(@"cameraFlash_On") forState:UIControlStateNormal];
});
}
}
break;
case AVCaptureFlashModeOff:{
if ([device isFlashModeSupported:AVCaptureFlashModeAuto]){
[device setFlashMode:AVCaptureFlashModeAuto];
dispatch_async(dispatch_get_main_queue(), ^{
[sender setImage:resourceImage(@"cameraFlash_Auto") forState:UIControlStateNormal];
});
}
}
break;
case AVCaptureFlashModeOn: {
if ([device isFlashModeSupported:AVCaptureFlashModeOff]){
[device setFlashMode:AVCaptureFlashModeOff];
dispatch_async(dispatch_get_main_queue(), ^{
[sender setImage:resourceImage(@"cameraFlash_Off") forState:UIControlStateNormal];
});
}
}
break;
default:
break;
}
[device unlockForConfiguration];
}
else {
NSLog( @"Could not lock device for configuration: %@", error );
}
} );
}
9、手電筒設(shè)置
手電筒是一種光源,例如LED閃光燈,可在設(shè)備上使用,用于照亮捕獲的內(nèi)容或提供一般照明。
| 屬性 | 類型 | 描述 |
|---|---|---|
hasTorch |
BOOL |
反映當(dāng)前設(shè)備是否具有內(nèi)置的手電筒。即使設(shè)備有手電筒,也可能無法使用。 因此,在使用之前檢查torchAvailable屬性的值。 |
torchAvailable |
BOOL |
指示手電筒當(dāng)前是否可供使用。例如,如果設(shè)備過熱并需要冷卻,則手電筒可能無法使用。 |
torchActive |
BOOL |
指示設(shè)備的手電筒當(dāng)前是否打開。必須在設(shè)備上有一個(gè)手電筒,并且當(dāng)前可用,然后才能激活它。 |
torchLevel |
float |
獲取當(dāng)前手電筒亮度級別;其值在 0.0 到 1.0 的范圍內(nèi):0.0 表示手電筒已關(guān)閉,1.0 表示理論最大值,如果設(shè)備當(dāng)前過熱,則實(shí)際最大值可能更低。 |
torchMode |
AVCaptureTorchMode |
目前的手電筒模式;設(shè)置此屬性的值還會(huì)將手電筒級別設(shè)置為其最大當(dāng)前值。在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。 |
9.1、手電筒模式
AVCaptureTorchMode 指定AVCaptureDevice的手電筒模式的枚舉:
| 枚舉值 | 描述 |
|---|---|
AVCaptureTorchModeOff |
設(shè)備手電筒始終關(guān)閉。 |
AVCaptureTorchModeOn |
設(shè)備手電筒始終打開。 |
AVCaptureTorchModeAuto |
設(shè)備持續(xù)監(jiān)控光照水平,并在必要時(shí)使用手電筒。 |
- (BOOL)isTorchModeSupported:(AVCaptureTorchMode)torchMode;
我們必須在修改torchMode之前調(diào)用上述方法判斷設(shè)備是否支持指定的手電筒模式。
9.2、設(shè)置手電筒照明級別
- (BOOL)setTorchModeOnWithLevel:(float)torchLevel error:(NSError * _Nullable *)outError;
我們設(shè)置手電筒照明級別,需要調(diào)用上述方法。要將割炬模式級別torchLevel設(shè)置為當(dāng)前可用的最大值,需要使用常量AVCaptureMaxAvailableTorchLevel。
設(shè)置手電筒照明級別之前需要將手電筒模式torchMode設(shè)置為AVCaptureTorchModeOn并將級別設(shè)置為指定值。 如果設(shè)備不支持AVCaptureTorchModeOn手電筒模式,或者如果為torchLevel指定的值超出了可接受的范圍,則此方法會(huì)引發(fā)異常。 如果割炬值在可接受范圍內(nèi)但大于當(dāng)前支持的最大值 - 可能是因?yàn)樵O(shè)備過熱 - 此方法只返回NO。
在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。
10、縮放設(shè)置
10.1、用于控制圖像的縮放值
@property(nonatomic) CGFloat videoZoomFactor;
該屬性是一個(gè)用于控制AVCaptureDevice的圖像的裁剪和放大的值;它是一個(gè)乘數(shù):例如,值 2.0 會(huì)使圖像主體的大小加倍(并使視野減半)。允許的值范圍從 1.0(完整視野)到活動(dòng)格式AVCaptureDeviceFormat的屬性videoMaxZoomFactor值。
AVCaptureDevice通過圍繞傳感器捕獲的圖像的中心進(jìn)行裁剪來實(shí)現(xiàn)縮放效果。在低縮放系數(shù)下,裁剪的圖像等于或大于輸出大小。在較高的縮放系數(shù)下,設(shè)備必須將裁剪后的圖像縮放到輸出尺寸,從而導(dǎo)致圖像質(zhì)量下降。活動(dòng)格式AVCaptureDeviceFormat的videoZoomFactorUpscaleThreshold屬性指示將進(jìn)行放大的因素。
在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。
設(shè)置此屬性的值會(huì)立即跳轉(zhuǎn)到新的縮放系數(shù);要流暢過渡,需要使用-rampToVideoZoomFactor:withRate:方法。
最小縮放值
@property(nonatomic, readonly) CGFloat minAvailableVideoZoomFactor;
當(dāng)前AVCaptureDevice配置中允許的最小縮放系數(shù)。在單攝像頭設(shè)備上,此值始終為 1.0 ;在雙攝像頭設(shè)備上,如果設(shè)備將深度數(shù)據(jù)傳送到一個(gè)或多個(gè)捕獲輸出,則允許的視頻縮放系數(shù)范圍可能會(huì)發(fā)生變化。
設(shè)置屬性videoZoomFactor或調(diào)用-rampToVideoZoomFactor:withRate:方法使值小于 1.0 會(huì)引發(fā)異常。 將視頻縮放系數(shù)設(shè)置為介于 1.0 和最小可用縮放系數(shù)之間的值會(huì)將縮放設(shè)置限制為最小值。
最大縮放值
@property(nonatomic, readonly) CGFloat maxAvailableVideoZoomFactor;
當(dāng)前AVCaptureDevice配置中允許的最大縮放系數(shù)。在單攝像頭設(shè)備上,此值始終等于AVCaptureDeviceFormat的屬性videoMaxZoomFactor ;在雙攝像頭設(shè)備上,如果設(shè)備將深度數(shù)據(jù)傳送到一個(gè)或多個(gè)捕獲輸出,則允許的視頻縮放系數(shù)范圍可能會(huì)發(fā)生變化。
設(shè)置屬性videoZoomFactor或調(diào)用-rampToVideoZoomFactor:withRate:方法使其值大于AVCaptureDeviceFormat的屬性videoMaxZoomFactor,會(huì)引發(fā)異常。將視頻縮放系數(shù)設(shè)置為最大可用縮放系數(shù)與設(shè)備格式最大值之間的值會(huì)將縮放設(shè)置限制為最大可用值。
10.2、流暢過渡到新的縮放值
我們可以使用下述方法實(shí)現(xiàn)從當(dāng)前縮放因子到另一個(gè)縮放因子的流暢過渡:
- (void)rampToVideoZoomFactor:(CGFloat)factor withRate:(float)rate;
在該方法中有兩個(gè)參數(shù):
-
CGFloat factor: 新的放大系數(shù); -
float rate:轉(zhuǎn)換到新放大系數(shù)的速率,以每秒 2 的冪表示。
縮放值factor允許范圍從1.0(完整視野)到活動(dòng)捕獲格式AVCaptureDeviceFormat指定的屬性videoMaxZoomFactor值。
在變化期間,縮放系數(shù)factor以指數(shù)速率變化,但這會(huì)產(chǎn)生視覺線性過渡。rate參數(shù)控制此轉(zhuǎn)換的速度,與方向無關(guān); 例如,值 1.0 會(huì)導(dǎo)致縮放因子在放大時(shí)每秒加倍(即,如果指定的因子大于當(dāng)前的videoZoomFactor),或者如果縮小則每秒減半。
在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。
10.3、結(jié)束縮放
流暢的進(jìn)行縮放需要一定的過渡時(shí)間,我們可能需要停止該緩慢的過渡,需要調(diào)用下述方法:
- (void)cancelVideoZoomRamp;
該方法能流暢地結(jié)束正在進(jìn)行的縮放而不是突然停止;調(diào)用此方法相當(dāng)于調(diào)用 -rampToVideoZoomFactor:withRate: 的速率rate為零。 如果正在進(jìn)行縮放轉(zhuǎn)換,則轉(zhuǎn)換將減慢為停止。
在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。
10.4、其它指示參數(shù)
| 屬性 | 類型 | 描述 |
|---|---|---|
rampingVideoZoom |
BOOL |
指示是否正在進(jìn)行縮放轉(zhuǎn)換的布爾值。使用KVO觀察對此屬性值的更改,以便在縮放過渡開始或結(jié)束時(shí)得到通知。 |
dualCameraSwitchOverVideoZoomFactor |
CGFloat |
雙攝像頭設(shè)備可以在攝像頭之間自動(dòng)切換的視頻縮放系數(shù);在該系數(shù)下,來自廣角攝像機(jī)的縮放視野與遠(yuǎn)攝相機(jī)的全視野相匹配。 當(dāng)videoZoomFactor設(shè)置達(dá)到或超過此值時(shí),設(shè)備可以根據(jù)場景條件自動(dòng)選擇哪個(gè)攝像機(jī)提供輸出圖像(或自動(dòng)組合兩者的圖像以創(chuàng)建最終輸出)。對于低于此值的縮放系數(shù),設(shè)備始終使用來自廣角攝像機(jī)的圖像。在單攝像頭設(shè)備上,此值始終為1.0。 |
10.5、縮放示例
//最小縮放值
- (CGFloat)minZoomFactor
{
CGFloat minZoomFactor = 1.0;
if (@available(iOS 11.0, *)) {
minZoomFactor = self.device.minAvailableVideoZoomFactor;
}
return minZoomFactor;
}
//最大縮放值
- (CGFloat)maxZoomFactor
{
CGFloat maxZoomFactor = self.device.activeFormat.videoMaxZoomFactor;
if (@available(iOS 11.0, *)) {
maxZoomFactor = self.device.maxAvailableVideoZoomFactor;
}
if (maxZoomFactor > 6.0) {
maxZoomFactor = 6.0;
}
return maxZoomFactor;
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]){
self.slider.minimumValue = self.minZoomFactor;
self.slider.maximumValue = self.maxZoomFactor;
self.currentZoomFactor = self.device.videoZoomFactor;
}
return YES;
}
//縮放手勢
- (void)zoomChangePinchGestureRecognizerClick:(UIPinchGestureRecognizer *)pinchGestureRecognizer
{
if (pinchGestureRecognizer.state == UIGestureRecognizerStateBegan ||
pinchGestureRecognizer.state == UIGestureRecognizerStateChanged)
{
CGFloat currentZoomFactor = self.currentZoomFactor * pinchGestureRecognizer.scale;
self.slider.hidden = NO;
if (currentZoomFactor < self.maxZoomFactor &&
currentZoomFactor > self.minZoomFactor){
NSError *error = nil;
if ([self.device lockForConfiguration:&error] ) {
self.device.videoZoomFactor = currentZoomFactor;
self.slider.value = self.device.videoZoomFactor;
[self.device unlockForConfiguration];
}
else {
NSLog( @"Could not lock device for configuration: %@", error );
}
}
}
else
{
self.slider.hidden = YES;
}
}
- (void)sliderValueChangeClick:(UISlider *)sender
{
self.slider.hidden = NO;
if (sender.value < self.maxZoomFactor &&
sender.value > self.minZoomFactor){
NSError *error = nil;
if ([self.device lockForConfiguration:&error] ) {
self.device.videoZoomFactor = sender.value;
[self.device unlockForConfiguration];
}
else {
NSLog( @"Could not lock device for configuration: %@", error );
}
}
}
由于篇幅限制,關(guān)于 AVCaptureDevice 的更多知識在 OC之AVCaptureDevice續(xù)