iOS自定義相機(jī)

引言

工作中很多時(shí)候,系統(tǒng)的相機(jī)無法滿足需求,這個(gè)時(shí)候需要就要自定義相機(jī)。

1.先把UI搭建好

拍照界面主要是相機(jī)的預(yù)覽層以及拍完后照片的顯示。這里是在初始化操作之后做的,但因?yàn)楸容^簡單,我把它放在第一個(gè)步驟來寫。

self.previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.session];
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.previewLayer.frame = CGRectMake(0,kNavHeight,kScreenW, kScreenH-kBottomH-kNavHeight);
[self.view.layer insertSublayer:self.previewLayer atIndex:0];

AVCaptureVideoPreviewLayer是相機(jī)鏡頭捕捉到的預(yù)覽層。videoGravity也是一個(gè)枚舉,有點(diǎn)類似于UIImageView的contentMode。

2.自定義相機(jī)

自定義相機(jī)實(shí)現(xiàn)拍照、前后攝像頭的切換、閃光燈、聚焦、放大縮小、拍照后預(yù)覽、重拍等功能.

2.1 初始化操作

AVCaptureDevice             
AVCaptureSession            
AVCaptureDeviceInput        
AVCaptureStillImageOutput  
AVCaptureVideoPreviewLayer  
AVCaptureConnection        
UIDeviceOrientation      

AVCaptureDevice
用來獲取相機(jī)設(shè)備的一些屬性,實(shí)現(xiàn)攝像頭和麥克風(fēng)的初始化操作. 閃光燈、手電筒、聚焦、曝光、白平衡等一些基本設(shè)置.這里我沒有做對(duì)權(quán)限的控制,在實(shí)際的開發(fā)中是要做的.當(dāng)用戶點(diǎn)擊不允許使用相機(jī)的時(shí)候,如果不做處理的話,就會(huì)顯示黑屏甚至閃退.做權(quán)限處理,引導(dǎo)用戶去設(shè)置頁面打開攝像頭權(quán)限.

參考文章

AVCaptureSession
AVCaptureSession是AVFoundation的核心類.用于捕捉音頻和視頻,協(xié)調(diào)視頻和音頻的輸入和輸出流之間的數(shù)據(jù)交換.我覺得這張圖上的各個(gè)層級(jí)結(jié)構(gòu)一目了然,可以幫助理解.

image.png

- (void)initCameraSettings
{
    NSError *error;
    self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    self.session = [[AVCaptureSession alloc] init];
    if ([self.session canSetSessionPreset:AVCaptureSessionPresetiFrame960x540]) {
        self.session.sessionPreset = AVCaptureSessionPresetiFrame960x540;
    }
    self.deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
    self.imageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
    [self.imageOutput setOutputSettings:outputSettings];
    ...
}
2.1.1 設(shè)置SessionPreset

設(shè)置輸出的畫質(zhì)。要判斷是iPad還是iphone。sessionPreset是一個(gè)枚舉,您可以點(diǎn)擊進(jìn)去看一下,結(jié)合實(shí)際項(xiàng)目中的需要進(jìn)行選擇。另外,值得注意的是:如果您設(shè)置的畫質(zhì)高于手機(jī)本身支持的分辨率的話那么會(huì)造成崩潰。比如,我現(xiàn)在設(shè)置的是 AVCaptureSessionPresetiFrame960x540大概需要攝像頭支持50W的像素,而iphone4S的前置攝像頭只有30W的像素,顯然達(dá)不到標(biāo)準(zhǔn)。

2.1.2 設(shè)置Session的input

設(shè)置Session的輸入源??梢允荲ideo,也可以是Audio,或者兩者都添加。

2.1.2 設(shè)置Session的output

設(shè)置Session的輸出源??梢允菆D片源、音視頻源、文件源等.這里用相機(jī)拍照,當(dāng)然輸出的是AVCaptureStillImageOutput圖片源.AVCaptureStillImageOutput在iOS10中已經(jīng)被AVCapturePhotoOutput所代替.

2.2 實(shí)現(xiàn)拍照功能

- (void)clickPhoto
{
    self.connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
    [self.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
    [self.imageOutput captureStillImageAsynchronouslyFromConnection:self.connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [UIImage imageWithData:jpegData];
        self.showImageView.image = image;
    }];
}

這里的AVCaptureConnection是session和AVCaptureStillImageOutput連接的樞紐。通過回調(diào)拿到圖片的數(shù)據(jù),顯示出來。這樣就完成了基本的拍照功能。但如果把拍好的照片傳給后臺(tái),會(huì)發(fā)現(xiàn)照片旋轉(zhuǎn)了90度,明明在手機(jī)上是豎屏的,后臺(tái)下載后卻是橫屏的。這是由于iphone的方向傳感器造成的,遇到這種問題,只需要調(diào)整一下UIImage的imageOrientation屬性即可。這個(gè)網(wǎng)上有現(xiàn)成的demo。如果您有興趣,這篇文章我覺得寫的非常細(xì)致。如何處理iOS中照片的方向,您可以參考。在這個(gè)基礎(chǔ)上,再實(shí)現(xiàn)前置攝像頭拍照。旋轉(zhuǎn)攝像頭的時(shí)候,可以再加一個(gè)翻轉(zhuǎn)動(dòng)畫,當(dāng)然這根據(jù)需求而定。

- (void)rotateCamera
{
    NSArray *inputs = self.session.inputs;
    for (AVCaptureDeviceInput *input in inputs ) {
        AVCaptureDevice *device = input.device;
        if ([device hasMediaType:AVMediaTypeVideo] ) {
            AVCaptureDevicePosition position = device.position;
            AVCaptureDevice *newCamera = nil;
            AVCaptureDeviceInput *newInput = nil;
            if(position == AVCaptureDevicePositionFront)
                newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
            else
                newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
            newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
            [self.session beginConfiguration];
            [self.session removeInput:input];
            [self.session addInput:newInput];
            [self.session commitConfiguration];
            break;
        }
    }
}

2.3 輔助功能

2.3.1 對(duì)焦、閃光燈

在預(yù)覽層上加一層遮照View來響應(yīng)手勢的觸發(fā)。聚焦功能如下。

    if ([self.device lockForConfiguration:&error]) {
        if ([self.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            [self.device setFocusPointOfInterest:focusPoint];
            [self.device setFocusMode:AVCaptureFocusModeAutoFocus];
        }
        [self.device unlockForConfiguration];
    }

為了更好的用戶體驗(yàn),模仿系統(tǒng)相機(jī)的功能,在此基礎(chǔ)上,增加一個(gè)動(dòng)畫效果。可以看到,系統(tǒng)相機(jī)有一個(gè)正方形的框,當(dāng)點(diǎn)擊的時(shí)候有一個(gè)縮放的效果。這里增加一個(gè)focusView,通過transform動(dòng)畫實(shí)現(xiàn)這個(gè)效果。

閃光燈的效果也比較簡單,閃光燈有三種狀態(tài)。這里只處理了閃光燈的開和關(guān)兩種狀態(tài)。

    AVCaptureFlashModeOff  = 0,
    AVCaptureFlashModeOn   = 1,
    AVCaptureFlashModeAuto = 2,
    [self.session beginConfiguration];
    [self.device lockForConfiguration:nil];
    [self.device setFlashMode:mode];
    [self.device unlockForConfiguration];
    [self.session commitConfiguration];
    [self.session startRunning];

3.總結(jié)

以上,基本的相機(jī)功能就實(shí)現(xiàn)了。在這個(gè)基礎(chǔ)上還可以增加很多功能。比如,把圖片寫進(jìn)相冊,從相冊選取圖片,以及圖片的裁剪和小視頻的錄制等等就不在此篇贅敘。最近在做總結(jié),關(guān)于之前寫過的音視頻采集、二維碼掃描、圖片合成視頻等利用AVFoundation框架的功能會(huì)一一整理出來。另外,下面這篇博客是用swift實(shí)現(xiàn)的,功能很全面。我的代碼還在整理中,之后也會(huì)同步到github。

Swift版本相機(jī)參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容