OC之AVCaptureDevice

輸入設(shè)備AVCaptureDevice 繼承自NSObject:是關(guān)于相機(jī)硬件的接口训枢,用于配置底層硬件的屬性(例如相機(jī)聚焦筛严、白平衡醉旦、感光度ISO、曝光、幀率车胡、閃光燈檬输、縮放等),這些底層硬件包括前置攝像頭匈棘、后置攝像頭丧慈、麥克風(fēng)、閃光燈等羹饰。使用AVCaptureDeviceAVCaptureSession對(duì)象提供輸入數(shù)據(jù)(如音頻或視頻)伊滋。

1、驗(yàn)證授權(quán)

1.1队秩、請(qǐng)求用戶授權(quán)指定的媒體類型

為保護(hù)用戶隱私笑旺,應(yīng)用在使用相機(jī)或者麥克風(fēng),總是需要用戶授權(quán)才能正常使用馍资。當(dāng)應(yīng)用第一次為需要權(quán)限的媒體類型創(chuàng)建任何AVCaptureDeviceInput對(duì)象時(shí)筒主,系統(tǒng)會(huì)自動(dòng)顯示一個(gè)alert以請(qǐng)求用戶授權(quán)。

調(diào)用下述類方法鸟蟹,可以讓應(yīng)用直接獲取用戶授權(quán)乌妙,而不是需要等到創(chuàng)建AVCaptureDeviceInput對(duì)象時(shí),系統(tǒng)自動(dòng)顯示一個(gè)alert以請(qǐng)求用戶授權(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然低,請(qǐng)回歸主線程。

該方法是異步調(diào)用务唐,被調(diào)用時(shí)允許客戶端繼續(xù)運(yùn)行雳攘,不會(huì)堵塞當(dāng)前線程。在被授予訪問權(quán)限之前绍哎,任何AVMediaType類型的AVCaptureDevice都將關(guān)閉靜默音頻樣本或黑色視頻幀来农。
如果調(diào)用該方法之前,已經(jīng)顯示alert以請(qǐng)求用戶授權(quán)崇堰,不管用戶同意授權(quán)或者拒絕授權(quán),該方法的回調(diào)都會(huì)立即返回用戶曾經(jīng)的授權(quán)結(jié)果,而不會(huì)再次去顯示一個(gè)alert以請(qǐng)求用戶授權(quán)海诲。

應(yīng)用程序必須在配置信息info.plist中提供使用NSCameraUsageDescriptionNSMicrophoneUsageDescription信息的解釋繁莹。iOS在最初請(qǐng)求用戶許可時(shí)顯示了這個(gè)解釋,然后在設(shè)置應(yīng)用程序中顯示特幔。在沒有使用說明的情況下啟動(dòng)AVCaptureSession會(huì)引發(fā)異常咨演。

當(dāng)應(yīng)用在手機(jī)上,沒有請(qǐng)求用戶授權(quán)時(shí)蚯斯,執(zhí)行下述代碼薄风,將會(huì)顯示一個(gè)alert以請(qǐng)求用戶授權(quán)

[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
    NSLog(@"granted --- %d currentThread : %@",granted,NSThread.currentThread);
}];
NSLog(@"currentThread : %@",NSThread.currentThread);
請(qǐng)求授權(quán).png

我們點(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,請(qǐng)確保在主線程横辆。

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對(duì)象時(shí),系統(tǒng)會(huì)自動(dòng)顯示一個(gè)alert以請(qǐng)求用戶授權(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}
****************************************************/

注意:使用AVMediaTypeVideoAVMediaTypeAudio以外的任何媒體類型調(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
不被支持的AVMediaType.png
1.3、媒體類型AVMediaType

媒體類型AVMediaType是使用typedef修飾的標(biāo)識(shí)符粘咖,提供各種媒體類型:

描述
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è)長(zhǎng)焦鏡頭,這兩個(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è)備(請(qǐng)參閱帶有發(fā)現(xiàn)會(huì)話的排序和篩選設(shè)備)蚜锨。在較老的iOS版本中档插,搜索整個(gè)數(shù)組以找到首選設(shè)備。

2.1.1亚再、 AVCaptureDeviceType

設(shè)備類型AVCaptureDeviceType是使用typedef修飾的標(biāo)識(shí)符郭膛,提供各種設(shè)備類型,與+ defaultDeviceWithDeviceType:mediaType:position:方法和AVCaptureDeviceDiscoverySession類一起使用氛悬。

設(shè)備類型AVCaptureDeviceType 描述
AVCaptureDeviceTypeBuiltInMicrophone 一個(gè)內(nèi)置的麥克風(fēng)
AVCaptureDeviceTypeBuiltInWideAngleCamera 內(nèi)置廣角相機(jī),這些裝置適用于一般用途则剃。
AVCaptureDeviceTypeBuiltInTelephotoCamera 內(nèi)置長(zhǎng)焦相機(jī),比廣角相機(jī)的焦距長(zhǎng)如捅。這種類型只是將窄角設(shè)備與配備兩種類型的攝像機(jī)的硬件上的寬角設(shè)備區(qū)分開來棍现。要確定攝像機(jī)設(shè)備的實(shí)際焦距,可以檢查AVCaptureDeviceformat數(shù)組中的AVCaptureDeviceFormat對(duì)象镜遣。
AVCaptureDeviceTypeBuiltInDualCamera 廣角相機(jī)和長(zhǎng)焦相機(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相對(duì)于系統(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堪伍。使用該方法可以輕松地為指定場(chǎng)景選擇系統(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è)備。

注意:使用該方法請(qǐng)求攝像機(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è)通知,通知對(duì)象是AVCaptureDevice實(shí)例恬涧,表示已可用的設(shè)備注益。
AVCaptureDeviceWasDisconnectedNotification 當(dāng)現(xiàn)有設(shè)備不可用時(shí)發(fā)送一個(gè)通知,通知對(duì)象是AVCaptureDevice實(shí)例溯捆,表示不可用的設(shè)備丑搔。
2.4、例子

我們以獲取mediaTypeAVMediaTypeVideo的后置鏡頭為例:

- (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;
            }
        }];
    }
}

我們可以看到顽冶,針對(duì)不同版本的 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è)置AVCaptureDeviceactiveFormat屬性非竿,會(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隶症、更改AVCaptureDeviceactiveFormat屬性政模。
  • 3、調(diào)用AVCaptureSessionstartRunning方法
  • 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缸濒,對(duì)于筆記本上的iSight攝像機(jī)足丢,或者對(duì)于筆記本顯示關(guān)閉時(shí)的內(nèi)部iSight攝像機(jī),issuspend會(huì)返回YES庇配。
linkedDevices NSArray<AVCaptureDevice *> 一組AVCaptureDevice對(duì)象斩跌,表示外接設(shè)備。例如捞慌,對(duì)于外部iSight攝像機(jī)耀鸦,數(shù)組包含一個(gè)AVCaptureDevice實(shí)例,表示外部iSight麥克風(fēng)啸澡。
transportType int32_t AVCaptureDevice的傳輸類型(USB袖订、PCI等)。
inputSources NSArray<AVCaptureDeviceInputSource *> AVCaptureDevice支持的輸入源的AVCaptureDeviceInputSource對(duì)象數(shù)組嗅虏。 有些設(shè)備可以從多個(gè)數(shù)據(jù)源之一(例如洛姑,同一音頻設(shè)備上的不同輸入插孔)捕獲數(shù)據(jù)。
activeInputSource AVCaptureDeviceInputSource 當(dāng)前活躍的輸入源皮服。要設(shè)置該屬性楞艾,需要先調(diào)用- lockForConfiguration:方法鎖定設(shè)備;否則將拋出異常NSGenericException龄广;如果傳遞的formatformats中不存在硫眯,調(diào)用-setActiveInputSource:拋出異常NSInvalidArgumentException
3.3择同、輸入源AVCaptureDeviceInputSource

AVCaptureDeviceInputSource是捕獲設(shè)備AVCaptureDevice上的輸入源两入。

AVCaptureDevice對(duì)象可以從inputSources數(shù)組中選擇一個(gè)作為輸入源,表示設(shè)備的不同的互斥輸入奠衔。例如谆刨,音頻捕獲設(shè)備可能具有ADAT光學(xué)和模擬輸入源;視頻捕獲設(shè)備可能有HDMI輸入源或組件輸入源塘娶。

屬性 類型 描述
inputSourceID NSString 輸入源ID;在指定AVCaptureDevice對(duì)象的輸入源中痊夭,ID是唯一的刁岸。
localizedName NSString 輸入源的本地化名稱;可以使用此屬性在用戶界面中顯示AVCaptureDevice輸入源的名稱她我。

4虹曙、檢查設(shè)備特征

屬性 類型 描述
connected BOOL 表示AVCaptureDevice實(shí)例當(dāng)前是否已連接,是否可用番舆。但是冬骚,當(dāng)這個(gè)屬性的值對(duì)于給定的AVCaptureDevice實(shí)例變成NO時(shí),它就不會(huì)再變成YES咒钟。如果相同的物理設(shè)備再次對(duì)系統(tǒng)可用糙臼,它將使用AVCaptureDevice的新實(shí)例表示。
position AVCaptureDevicePosition 表示設(shè)備AVCaptureDevice的物理位置禾怠。
modelID NSString 設(shè)備的型號(hào)ID返奉。該值是同一型號(hào)的所有設(shè)備的唯一標(biāo)識(shí)符,該值是跨設(shè)備連接和斷開連接以及跨不同系統(tǒng)的持久值吗氏。例如芽偏,內(nèi)置在兩個(gè)相同iPhone機(jī)型上的攝像頭的型號(hào)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ù)存在∥嫫耄可以存儲(chǔ)該值蛮放,以便將來收回或跟蹤特定設(shè)備的狀態(tài)。
lensAperture float 鏡片隔膜的尺寸奠宜,表示透鏡光圈的大小(f號(hào))包颁。是個(gè)只讀屬性,該值不變压真。
deviceType AVCaptureDeviceType 設(shè)備類型娩嚼,如內(nèi)置麥克風(fēng)或廣角攝像機(jī)。
manufacturer NSString 設(shè)備制造商滴肿。對(duì)于所有蘋果設(shè)備來說岳悟,這一屬性值都是“Apple Inc.”;來自第三方制造商的設(shè)備可能不被識(shí)別,此時(shí)該值值為空字符串贵少。
//返回一個(gè)布爾值呵俏,表示AVCaptureDevice是否為指定AVMediaType提供媒體。
- (BOOL)hasMediaType:(AVMediaType)mediaType;
//返回一個(gè)布爾值滔灶,表示AVCaptureDevice是否可以使用 指定sessionPreset的會(huì)話AVCaptureSession普碎。
- (BOOL)supportsAVCaptureSessionPreset:(AVCaptureSessionPreset)preset;

5、管理格式

5.1录平、捕獲格式AVCaptureDeviceFormat

AVCaptureDeviceFormat 對(duì)象詳細(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對(duì)象上設(shè)置sessionPreset來配置圖像或視頻捕獲,并使用共享的AVAudioSession對(duì)象來配置音頻捕獲握童;在使用sessionPreset時(shí)姆怪,AVCaptureSession會(huì)自動(dòng)控制AVCaptureDevice的活動(dòng)格式activeFormat。然而澡绩,在AVCaptureSession的設(shè)置中稽揭,有些專門的捕獲選項(xiàng)(比如高幀率)是不可用的;對(duì)于這些選項(xiàng)肥卡,需要設(shè)置AVCaptureDevice的活動(dòng)格式activeFormat溪掀,這樣做將關(guān)聯(lián)的AVCaptureSessionsessionPreset更改為AVCaptureSessionPresetInputPriority

注意:試圖將activeFormat設(shè)置為formats數(shù)組中不存在的格式步鉴,會(huì)拋出NSInvalidArgumentException揪胃。

在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以獲得對(duì)設(shè)備配置屬性的訪問權(quán)氛琢,否則喊递,設(shè)置此屬性的值將引發(fā)異常;完成設(shè)備配置后阳似,調(diào)用-unlockForConfiguration釋放鎖并允許其他設(shè)備配置設(shè)置骚勘。還必須在調(diào)用AVCaptureSession-startRunning方法之前調(diào)用-lockForConfiguration:,或AVCaptureSessionsessionPreset將覆蓋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對(duì)象AVCaptureDeviceFormatsupporteddepthdataformat數(shù)組中沒有列出的捕獲格式,將會(huì)引發(fā)異常株依。

不能直接設(shè)置深度數(shù)據(jù)捕獲的幀速率:深度數(shù)據(jù)幀速率與設(shè)備的activeVideoMinFrameDurationactiveVideoMaxFrameDuration值是同步的驱证,可以等于設(shè)備當(dāng)前的幀速率,如果設(shè)備不能以足夠快的速度生成深度數(shù)據(jù)恋腕,則可以降低抹锄。深度數(shù)據(jù)捕獲可能會(huì)增加系統(tǒng)負(fù)載,從而降低視頻幀速率以實(shí)現(xiàn)熱可持續(xù)性荠藤。

在更改此屬性的值之前伙单,必須調(diào)用-lockForConfiguration:以獲得對(duì)設(shè)備配置屬性的訪問權(quán),否則哈肖,設(shè)置此屬性的值將引發(fā)異常吻育;完成設(shè)備配置后,調(diào)用-unlockForConfiguration釋放鎖并允許其他設(shè)備配置設(shè)置淤井。還必須在調(diào)用AVCaptureSession-startRunning方法之前調(diào)用-lockForConfiguration:布疼,或AVCaptureSessionsessionPreset將覆蓋AVCaptureDevice的活動(dòng)格式activeFormat

6币狠、焦點(diǎn)設(shè)置

鏡頭焦點(diǎn)與焦距的區(qū)別:
焦點(diǎn) 是透鏡(或曲面鏡)將光線會(huì)聚后所形成的點(diǎn),因光線會(huì)聚成一點(diǎn)可將物燒焦游两。
焦距 是焦點(diǎn)到面鏡的中心點(diǎn)之間的距離。鏡頭焦距的長(zhǎng)短決定著拍攝的成像大小漩绵,視場(chǎng)角大小贱案,景深大小和畫面的透視強(qiáng)弱。鏡頭的焦距是鏡頭的一個(gè)非常重要的指標(biāo)止吐。鏡頭焦距的長(zhǎng)短決定了被攝物在成像介質(zhì)(膠片或CCD等)上成像的大小宝踪,也就是相當(dāng)于物和象的比例尺。當(dāng)對(duì)同一距離遠(yuǎn)的同一個(gè)被攝目標(biāo)拍攝時(shí)祟印,鏡頭焦距長(zhǎng)的所成的象大肴沫,鏡頭焦距短的所成的象小。根據(jù)用途的不同蕴忆,照相機(jī)鏡頭的焦距相差非常大颤芬,有短到幾毫米,十幾毫米的,也有長(zhǎng)達(dá)幾米的站蝠。

6.1汰具、對(duì)焦模式
屬性 類型 描述
focusMode AVCaptureFocusMode 設(shè)備的對(duì)焦模式。在更改此屬性的值之前菱魔,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice留荔;否則,設(shè)置此屬性的值會(huì)引發(fā)異常澜倦。完成配置設(shè)備后聚蝶,請(qǐng)調(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è)置對(duì)焦模式時(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)系始終相對(duì)于橫向設(shè)備方向亚情,主頁(yè)按鈕位于右側(cè)妄痪。可以使用AVCaptureVideoPreviewLayer方法在此坐標(biāo)系和視圖坐標(biāo)之間進(jìn)行轉(zhuǎn)換楞件。

設(shè)置此屬性不會(huì)啟動(dòng)聚焦操作衫生。要將相機(jī)聚焦在中心點(diǎn),首先設(shè)置此屬性的值土浸,然后將focusMode屬性設(shè)置為AVCaptureFocusModeAutoFocusAVCaptureFocusModeContinuousAutoFocus罪针。

在更改此屬性的值之前,必須調(diào)用-lockForConfiguration: 以鎖定AVCaptureDevice黄伊;否則泪酱,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后,請(qǐng)調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置墓阀。

6.3毡惜、自動(dòng)對(duì)焦
屬性 類型 描述
smoothAutoFocusSupported BOOL 指示設(shè)備是否支持平滑自動(dòng)對(duì)焦。自動(dòng)對(duì)焦模式僅適用于兼容設(shè)備斯撮,如果此屬性的值為NO经伙,則將smoothAutoFocusEnabled的值設(shè)置為YES會(huì)引發(fā)異常。
smoothAutoFocusEnabled BOOL 用于確定是否啟用了平滑自動(dòng)對(duì)焦勿锅;在兼容設(shè)備上帕膜,可以啟用自動(dòng)對(duì)焦模式,使鏡頭移動(dòng)速度更慢溢十。在更改此屬性的值之前垮刹,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則茶宵,設(shè)置此屬性的值會(huì)引發(fā)異常危纫。完成配置設(shè)備后,請(qǐng)調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置乌庶。
6.4种蝶、自動(dòng)對(duì)焦范圍
  • 屬性AVCaptureAutoFocusRangeRestriction autoFocusRangeRestriction
    控制自動(dòng)對(duì)焦允許范圍;默認(rèn)情況下瞒大,能夠進(jìn)行硬件聚焦的設(shè)備會(huì)嘗試聚焦在任何距離的對(duì)象上螃征。如果希望主要關(guān)注近物體或遠(yuǎn)物體,請(qǐng)?jiān)O(shè)置范圍限制以提高速度并降低自動(dòng)聚焦的功耗透敌,并減少聚焦模糊的可能性盯滚。
    在更改此屬性的值之前,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice酗电;否則魄藕,設(shè)置此屬性的值會(huì)引發(fā)異常。完成配置設(shè)備后撵术,請(qǐng)調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置背率。

  • 屬性 BOOL autoFocusRangeRestrictionSupported:一個(gè)布爾值,指示設(shè)備是否支持焦距范圍限制嫩与。對(duì)焦范圍限制僅適用于兼容設(shè)備寝姿。 如果此屬性的值為NO,則設(shè)置autoFocusRangeRestriction會(huì)引發(fā)異常划滋。

AVCaptureAutoFocusRangeRestriction
用于指定捕獲設(shè)備的自動(dòng)聚焦范圍的枚舉:如果您希望主要關(guān)注近物體或遠(yuǎn)物體饵筑,可以使用autoFocusRangeRestriction屬性為聚焦系統(tǒng)提供提示。 這種方法使自動(dòng)對(duì)焦更快处坪,更節(jié)能根资,并且更不容易出錯(cuò)架专。 限制優(yōu)先于指定范圍內(nèi)的距離聚焦,但如果設(shè)備在該范圍內(nèi)沒有找到焦點(diǎn)嫂冻,則不會(huì)阻止聚焦在別處胶征。

枚舉值 描述
AVCaptureAutoFocusRangeRestrictionNone 設(shè)備會(huì)嘗試關(guān)注任何范圍內(nèi)的對(duì)象。此值是默認(rèn)值桨仿,是不支持焦點(diǎn)范圍限制的設(shè)備上允許的唯一值睛低。
AVCaptureAutoFocusRangeRestrictionNear 該設(shè)備主要嘗試聚焦在相機(jī)附近的拍攝對(duì)象上。對(duì)于使用AVCaptureMetadataOutput識(shí)別機(jī)器可讀代碼的應(yīng)用程序服傍,建議使用此值钱雷。
AVCaptureAutoFocusRangeRestrictionFar 該設(shè)備主要嘗試對(duì)焦于遠(yuǎn)離相機(jī)的拍攝對(duì)象。

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)對(duì)焦)。

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è)置為指定值且屬性focusModeAVCaptureFocusModeLocked時(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è)備后,請(qǐng)調(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)前手電筒亮度級(jí)別置济;其值在 0.0 到 1.0 的范圍內(nèi):0.0 表示手電筒已關(guān)閉解恰,1.0 表示理論最大值锋八,如果設(shè)備當(dāng)前過熱,則實(shí)際最大值可能更低护盈。
torchMode AVCaptureTorchMode 目前的手電筒模式挟纱;設(shè)置此屬性的值還會(huì)將手電筒級(jí)別設(shè)置為其最大當(dāng)前值。在更改此屬性的值之前腐宋,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice紊服;否則,設(shè)置此屬性的值會(huì)引發(fā)異常脏款。完成配置設(shè)備后围苫,請(qǐng)調(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è)置手電筒照明級(jí)別
- (BOOL)setTorchModeOnWithLevel:(float)torchLevel error:(NSError * _Nullable *)outError;

我們?cè)O(shè)置手電筒照明級(jí)別衰伯,需要調(diào)用上述方法。要將割炬模式級(jí)別torchLevel設(shè)置為當(dāng)前可用的最大值积蔚,需要使用常量AVCaptureMaxAvailableTorchLevel意鲸。

設(shè)置手電筒照明級(jí)別之前需要將手電筒模式torchMode設(shè)置為AVCaptureTorchModeOn并將級(jí)別設(shè)置為指定值。 如果設(shè)備不支持AVCaptureTorchModeOn手電筒模式尽爆,或者如果為torchLevel指定的值超出了可接受的范圍怎顾,則此方法會(huì)引發(fā)異常。 如果割炬值在可接受范圍內(nèi)但大于當(dāng)前支持的最大值 - 可能是因?yàn)樵O(shè)備過熱 - 此方法只返回NO漱贱。

在更改此屬性的值之前槐雾,必須調(diào)用-lockForConfiguration:以鎖定AVCaptureDevice;否則幅狮,設(shè)置此屬性的值會(huì)引發(fā)異常募强。完成配置設(shè)備后,請(qǐng)調(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è)備后鲫趁,請(qǐng)調(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è)備后脉执,請(qǐng)調(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è)備后贴浙,請(qǐng)調(diào)用-unlockForConfiguration以釋放鎖定并允許其他設(shè)備配置設(shè)置。

10.4署恍、其它指示參數(shù)
屬性 類型 描述
rampingVideoZoom BOOL 指示是否正在進(jìn)行縮放轉(zhuǎn)換的布爾值崎溃。使用KVO觀察對(duì)此屬性值的更改,以便在縮放過渡開始或結(jié)束時(shí)得到通知盯质。
dualCameraSwitchOverVideoZoomFactor CGFloat 雙攝像頭設(shè)備可以在攝像頭之間自動(dòng)切換的視頻縮放系數(shù)袁串;在該系數(shù)下,來自廣角攝像機(jī)的縮放視野與遠(yuǎn)攝相機(jī)的全視野相匹配呼巷。 當(dāng)videoZoomFactor設(shè)置達(dá)到或超過此值時(shí)囱修,設(shè)備可以根據(jù)場(chǎng)景條件自動(dòng)選擇哪個(gè)攝像機(jī)提供輸出圖像(或自動(dòng)組合兩者的圖像以創(chuàng)建最終輸出)。對(duì)于低于此值的縮放系數(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;
}

//縮放手勢(shì)
- (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 的更多知識(shí)在 OC之AVCaptureDevice續(xù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末喘漏,一起剝皮案震驚了整個(gè)濱河市簇宽,隨后出現(xiàn)的幾起案子谣光,更是在濱河造成了極大的恐慌唧垦,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跌宛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)臂拓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來习寸,“玉大人胶惰,你說我怎么就攤上這事∠枷” “怎么了孵滞?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)鸯匹。 經(jīng)常有香客問我坊饶,道長(zhǎng),這世上最難降的妖魔是什么殴蓬? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任匿级,我火速辦了婚禮,結(jié)果婚禮上染厅,老公的妹妹穿的比我還像新娘痘绎。我一直安慰自己,他們只是感情好肖粮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布孤页。 她就那樣靜靜地躺著,像睡著了一般涩馆。 火紅的嫁衣襯著肌膚如雪行施。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天凌净,我揣著相機(jī)與錄音悲龟,去河邊找鬼。 笑死冰寻,一個(gè)胖子當(dāng)著我的面吹牛须教,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼轻腺,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼乐疆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贬养,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤挤土,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后误算,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仰美,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年儿礼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了咖杂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚊夫,死狀恐怖诉字,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情知纷,我是刑警寧澤壤圃,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站琅轧,受9級(jí)特大地震影響伍绳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鹰晨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一墨叛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧模蜡,春花似錦漠趁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至卤妒,卻和暖如春甥绿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背则披。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工共缕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人士复。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓图谷,卻偏偏與公主長(zhǎng)得像翩活,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子便贵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345