之前使用過AVFoundation實(shí)現(xiàn)二維碼掃描的功能辐马,當(dāng)初第一次接觸這個(gè)框架彤路,只是搜索資料今野,實(shí)現(xiàn)功能就草草了事了耘沼,最近要實(shí)現(xiàn)視頻的錄制功能矗蕊,又用到了這個(gè)框架顽腾,而且發(fā)現(xiàn)珊佣,步驟跟實(shí)現(xiàn)二維碼的時(shí)候十分相似堂油,所以來總結(jié)一下棒卷。
使用AVFoundation拍照和錄制視頻的一般步驟如下:
- 創(chuàng)建AVCaptureSession對(duì)象顾孽。
- 使用AVCaptureDevice的靜態(tài)方法獲得需要使用的設(shè)備,例如拍照和錄像就需要獲得攝像頭設(shè)備比规,錄音就要獲得麥克風(fēng)設(shè)備若厚。
- 利用輸入設(shè)備AVCaptureDevice初始化AVCaptureDeviceInput對(duì)象。
- 初始化輸出數(shù)據(jù)管理對(duì)象蜒什,如果要拍照就初始化AVCaptureStillImageOutput對(duì)象测秸;如果拍攝視頻就初始化AVCaptureMovieFileOutput對(duì)象。
- 將數(shù)據(jù)輸入對(duì)象AVCaptureDeviceInput、數(shù)據(jù)輸出對(duì)象AVCaptureOutput添加到媒體會(huì)話管理對(duì)象AVCaptureSession中霎冯。
- 創(chuàng)建視頻預(yù)覽圖層AVCaptureVideoPreviewLayer并指定媒體會(huì)話铃拇,添加圖層到顯示容器中,調(diào)用AVCaptureSession的startRuning方法開始捕獲沈撞。
- 將捕獲的音頻或視頻數(shù)據(jù)輸出到指定文件慷荔。
錄制視頻
@property (weak, nonatomic) IBOutlet UIView *viewContainer;
@property (weak, nonatomic) IBOutlet UIButton *videoButton;
@property (strong, nonatomic) AVCaptureSession *captureSession;
@property (strong, nonatomic) AVCaptureDevice *audioDevice;
@property (strong, nonatomic) AVCaptureDevice *captureDevice;
@property (strong, nonatomic) AVCaptureDeviceInput *audioDeviceInput;
@property (strong, nonatomic) AVCaptureDeviceInput *captureDeviceInput;
@property (strong, nonatomic) AVCaptureMovieFileOutput *captureMovieOutput; //視頻輸出流
@property (strong, nonatomic) AVCaptureVideoPreviewLayer *capturePreviewLayer; // 相機(jī)預(yù)覽化圖層
// 初始化會(huì)話
if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
// 設(shè)置分辨率
self.captureSession.sessionPreset = AVCaptureSessionPreset640x480;
}
// 獲取輸入數(shù)據(jù) 視頻和音頻
NSError *error;
self.captureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.captureDevice error:&error];
if (error) {
NSLog(@"Error Description:%@", error.localizedDescription);
}
self.audioDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.audioDevice error:&error];
if (error) {
NSLog(@"Error Description:%@", error.localizedDescription);
}
// 初始化輸出對(duì)象
self.captureMovieOutput = [[AVCaptureMovieFileOutput alloc] init];
// 將設(shè)備輸入添加到會(huì)話
if ([self.captureSession canAddInput:self.captureDeviceInput] && [self.captureSession canAddInput:self.audioDeviceInput]) {
[self.captureSession addInput:self.audioDeviceInput];
[self.captureSession addInput:self.captureDeviceInput];
AVCaptureConnection *captureConnection = [self.captureMovieOutput connectionWithMediaType:AVMediaTypeVideo];
if ([captureConnection isVideoStabilizationSupported]) {
captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
}
}
// 將設(shè)備輸出添加到會(huì)話中
if ([self.captureSession canAddOutput:self.captureMovieOutput]) {
[self.captureSession addOutput:self.captureMovieOutput];
}
// 創(chuàng)建預(yù)覽化圖層
self.capturePreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
CALayer *layer = self.viewContainer.layer;
self.capturePreviewLayer.frame = layer.bounds;
// 填充模式
self.capturePreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[layer insertSublayer:self.capturePreviewLayer below:self.videoButton.layer];
#pragma mark - Getter And Setter
- (AVCaptureSession *)captureSession{
if (_captureSession == nil) {
_captureSession = [[AVCaptureSession alloc] init];
}
return _captureSession;
}
- (AVCaptureDevice *)audioDevice{
if (_audioDevice == nil) {
_audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
}
return _audioDevice;
}
- (AVCaptureDevice *)captureDevice{
if (_captureDevice == nil) {
NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *camera in cameras) {
if ([camera position] == AVCaptureDevicePositionBack) {
return camera;
}
}
}
return _captureDevice;
}
二維碼掃描
// 初始化捕捉設(shè)備(AVCaptureDevice),類型為AVMediaTypeVideo
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// captureDevice創(chuàng)建輸出流
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (!input) {
NSLog(@"%@",[error localizedDescription]);
return;
}
// 創(chuàng)建媒體數(shù)據(jù)輸出流
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
// 實(shí)例化捕捉會(huì)話
_caputureSession = [[AVCaptureSession alloc] init];
// 輸入流,輸出流添加到會(huì)話
[_caputureSession addInput:input];
[_caputureSession addOutput:output];
// 設(shè)置代理
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 設(shè)置輸出媒體數(shù)據(jù)類型為QRCode
[output setMetadataObjectTypes:[NSArray arrayWithObjects:AVMetadataObjectTypeQRCode,AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Mod43Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeInterleaved2of5Code, nil]];
// 實(shí)例化預(yù)覽圖層
_videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_caputureSession];
// 設(shè)置圖層填充方式
[_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
// _videoPreviewLayer.frame = _viewPreview.layer.bounds;
_videoPreviewLayer.frame = [UIScreen mainScreen].bounds;
// 添加到預(yù)覽圖層
[_viewPreview.layer addSublayer:_videoPreviewLayer];
// 掃描范圍
// CGSize size = _viewPreview.bounds.size;
CGSize size = [UIScreen mainScreen].bounds.size;
CGRect cropRect = CGRectMake(_videoPreviewLayer.bounds.size.width/2 - (105/375.0)*SCREEN_WIDTH, (200/667.5)*SCREEN_HEIGHT, (210/375.0)*SCREEN_WIDTH, (210/667.5)*SCREEN_HEIGHT);
[output setRectOfInterest:CGRectMake(cropRect.origin.y/size.height, cropRect.origin.x/size.width, cropRect.size.height/size.height, cropRect.size.width/size.width)];
// 掃描框
_boxView = [[UIView alloc] initWithFrame:_videoPreviewLayer.frame];
_boxView.backgroundColor = [UIColor clearColor];
UIImageView *scanView = [[UIImageView alloc] initWithFrame:_boxView.frame];
scanView.image = [UIImage imageNamed:@"device_QR_scanning"];
[_boxView addSubview:scanView];
[_viewPreview addSubview:_boxView];
// 開始掃描
[_caputureSession startRunning];