引言
工作中很多時(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)一目了然,可以幫助理解.

- (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。