以后要往这方面发展啦,好好梳理一下知识 (。◕ˇ∀ˇ◕)
1.设备授权
- (void)judgeDeviceAuth{
switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) {
case AVAuthorizationStatusAuthorized:
NSLog(@"已授权");
[self initAVCapture];
break;
//未进行授权选择<例如: 没有选择退出APP, 再次打开提示>
case AVAuthorizationStatusNotDetermined:
{
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
NSLog(@"已授权");
[self initAVCapture];
}else{
NSLog(@"用户拒绝授权摄像头的使用权,返回上一页.请打开\n设置-->隐私/通用等权限设置");
}
}];
}
break;
default:{
NSLog(@"用户拒绝授权摄像头的使用权,返回上一页.请打开\n设置-->隐私/通用等权限设置");
}
break;
}
}
2.初始化AVCapture
- (void)initAVCapture{
_captureSession = [[AVCaptureSession alloc] init];
//设置录像的分辨率
if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
[_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480];
}
[_captureSession beginConfiguration];
//设置摄像头为后置摄像头
_videoDevice = [self deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];
//视频的输入输出
[self videoIO];
//音频的输入
[self audioIO];
//创建预览层
[self previewLayer];
[_captureSession commitConfiguration];
[_captureSession startRunning];
}
3.音视频的输入和输出
- (void)videoIO{
/*---------------input-------------------------*/
NSError *videoError;
_videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_videoDevice error:&videoError];
if (videoError) {
NSLog(@"---- 取得摄像头设备时出错 ------ %@",videoError);
return;
}
// 将视频输入对象添加到会话中
if ([_captureSession canAddInput:_videoInput]) {
[_captureSession addInput:_videoInput];
}
/*---------------output------------------------*/
_movieOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([_captureSession canAddOutput:_movieOutput]) {
[_captureSession addOutput:_movieOutput];
AVCaptureConnection *captureConnection = [_movieOutput connectionWithMediaType:AVMediaTypeVideo];
// 视频稳定设置
if ([captureConnection isVideoStabilizationSupported]) {
captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
}
captureConnection.videoScaleAndCropFactor = captureConnection.videoMaxScaleAndCropFactor;
}
}
- (void)audioIO{
/*-------------input---------*/
NSError *audioError;
// 添加一个音频输入设备
_audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
// 音频输入对象
_audioInput = [[AVCaptureDeviceInput alloc] initWithDevice:_audioDevice error:&audioError];
if (audioError) {
NSLog(@"取得录音设备时出错 ------ %@",audioError);
return;
}
// 将音频输入对象添加到会话中
if ([_captureSession canAddInput:_audioInput]) {
[_captureSession addInput:_audioInput];
}
}
4.创建预览层
- (void)previewLayer{
[self.view layoutIfNeeded];
// 通过会话 (AVCaptureSession) 创建预览层
_captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
_captureVideoPreviewLayer.frame = self.view.layer.bounds;
//有时候需要拍摄完整屏幕大小的时候可以修改这个
// _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
// 如果预览图层和视频方向不一致,可以修改这个
_captureVideoPreviewLayer.connection.videoOrientation = [_movieOutput connectionWithMediaType:AVMediaTypeVideo].videoOrientation;
_captureVideoPreviewLayer.position = CGPointMake(self.view.frame.size.width*0.5,self.view.frame.size.height*0.5);
// 显示在视图表面的图层
CALayer *layer = self.view.layer;
layer.masksToBounds = true;
[self.view layoutIfNeeded];
[layer addSublayer:_captureVideoPreviewLayer];
}
5.获取摄像头
- (AVCaptureDevice *)deviceWithMediaType:(NSString *)mediaType preferringPosition:(AVCaptureDevicePosition)position
{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType];
AVCaptureDevice *captureDevice = devices.firstObject;
for ( AVCaptureDevice *device in devices ) {
if ( device.position == position ) {
captureDevice = device;
break;
}
}
return captureDevice;
}
6.摄像头切换
- (void)changeCamera {
UIButton * changeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
changeBtn.backgroundColor = [UIColor yellowColor];
changeBtn.frame = CGRectMake(0, 20, 100, 100);
[changeBtn addTarget:self action:@selector(changeCanmera:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:changeBtn];
}
- (void)changeCanmera:(id)sender {
switch (_videoDevice.position) {
case AVCaptureDevicePositionBack:
_videoDevice = [self deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionFront];
break;
case AVCaptureDevicePositionFront:
_videoDevice = [self deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];
break;
default:
return;
break;
}
[self changeDevicePropertySafety:^(AVCaptureDevice *captureDevice) {
NSError *error;
AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_videoDevice error:&error];
if (newVideoInput != nil) {
//必选先 remove 才能询问 canAdd
[_captureSession removeInput:_videoInput];
if ([_captureSession canAddInput:newVideoInput]) {
[_captureSession addInput:newVideoInput];
_videoInput = newVideoInput;
}else{
[_captureSession addInput:_videoInput];
}
} else if (error) {
NSLog(@"切换前/后摄像头失败, error = %@", error);
}
}];
}
7.更改设备属性前一定要锁上
-(void)changeDevicePropertySafety:(void (^)(AVCaptureDevice *captureDevice))propertyChange{
//也可以直接用_videoDevice,但是下面这种更好
AVCaptureDevice *captureDevice= [_videoInput device];
NSError *error;
//注意改变设备属性前一定要首先调用lockForConfiguration:调用完之后使用unlockForConfiguration方法解锁,意义是---进行修改期间,先锁定,防止多处同时修改
BOOL lockAcquired = [captureDevice lockForConfiguration:&error];
if (!lockAcquired) {
NSLog(@"锁定设备过程error,错误信息:%@",error.localizedDescription);
}else{
//调整设备前后要调用beginConfiguration/commitConfiguration
[_captureSession beginConfiguration];
propertyChange(captureDevice);
[captureDevice unlockForConfiguration];
[_captureSession commitConfiguration];
}
}