BSFramework 组件包:
- 2D、3D无限轮播图组件
- 图片视频选择、图片视频预览、图片视频拍摄组件
- GitHub 地址
- iOS 自定义相机 拍照+视频录制(二) 视频篇
shortshoot.gif
框架:<AVFoundation/AVFoundation.h>
大致流程:
- session 初始化
- device 初始化
- input,output 初始化,并关联device
- session 添加 input 和 output
- 初始化预览层 AVCaptureVideoPreviewLayer
- session startRunning
- 点击拍照, didFinishProcessingPhotoSampleBuffer 代理回调后,处理数据,生成照片
PS : 其中还含有一些摄像头翻转,闪光灯等操作,但属于额外功能,不算流程,具体全部功能看源码
一、使用 AVCaptureSession 进行拍照
需要的属性大致有
@property (nonatomic ,strong) AVCaptureSession *session;
@property (nonatomic ,strong) AVCaptureDevice *device;
@property (nonatomic ,strong) AVCaptureDeviceInput *deviceInput;//图像输入源
@property (nonatomic ,strong) AVCaptureOutput *outPut; //图像输出源
@property (nonatomic ,strong) AVPlayer *player;
@property (nonatomic ,strong) AVPlayerLayer *playerLayer;
@property (nonatomic ,strong) AVCaptureConnection *connection;
首先处理权限问题
#pragma mark - 相机授权
-(void)authorization{
//请求相机权限
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (status == AVAuthorizationStatusNotDetermined) {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
__weak typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (granted) {
[weakSelf authorization];
}else{
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"" message:@"相机权限未开启,请前往 手机-设置 开启相机权限" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[weakSelf.navigationController popViewControllerAnimated:YES];
[weakSelf dismissViewControllerAnimated:YES completion:nil];
}];
[controller addAction:action];
[weakSelf presentViewController:controller animated:YES completion:nil];
return;
}
});
}];
}else if (status == AVAuthorizationStatusDenied) {
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"" message:@"相机权限未开启,请前往 手机-设置 开启相机权限" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self.navigationController popViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:nil];
}];
[controller addAction:action];
[self presentViewController:controller animated:YES completion:nil];
return;
}else if (status == AVAuthorizationStatusAuthorized){
[self configData];
[self initSubViews];
[self masonryLayout];
}
}
只有权限通过了,我才初始化 UI 界面,否则就 alert 提示。
然后初始化 session ,添加 device 、input、output
-(void)configData{
self.session = [[AVCaptureSession alloc]init];
if ([self.session canSetSessionPreset:AVCaptureSessionPresetHigh]){
self.session.sessionPreset = AVCaptureSessionPresetHigh;
}else if ([self.session canSetSessionPreset:AVCaptureSessionPresetiFrame960x540]) {
self.session.sessionPreset = AVCaptureSessionPresetiFrame960x540;
}
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//如果不放在子线程里,跳转到相机的时候,会卡
[self addPicIO];
[self addVideoIO];
dispatch_async(dispatch_get_main_queue(), ^{
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.session];
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.previewLayer.frame = CGRectMake(0, 30, SCREEN_WIDTH, SCREEN_HEIGHT - 30 - 150);
[self.view.layer insertSublayer:self.previewLayer atIndex:0];
[self.session startRunning];
});
});
}
#pragma mark 设置 拍照类型的输入输出源
-(void)addPicIO{
NSError *error = nil;
self.deviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:self.device error:&error];
if (!error) {
if ([self.session canAddInput:self.deviceInput]) {
[self.session addInput:self.deviceInput];
}
if ([self.session canAddOutput:self.outPut]) {
[self.session addOutput:self.outPut];
}
}
}
点击拍照处理
#pragma mark - action 交互事件
// 拍照
-(void)takePicture{
// 防止快速连点
if (self.bottomView.recordStatus == RECORD_STATUS_UNRECORD) {
return;
}
if (@available(iOS 10.0, *)) {
AVCapturePhotoOutput *outPut = (AVCapturePhotoOutput *)self.outPut;
AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettingsWithFormat:@{AVVideoCodecKey:AVVideoCodecJPEG}];
[outPut capturePhotoWithSettings:settings delegate:self];
}else{
// 兼容iOS 10以下机型,未测试,不清楚可不可以用
self.connection = [self.outPut connectionWithMediaType:AVMediaTypeVideo];
[self.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
AVCaptureStillImageOutput *outPut = (AVCaptureStillImageOutput *)self.outPut;
[outPut captureStillImageAsynchronouslyFromConnection:self.connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
[self.session stopRunning];
NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [UIImage imageWithData:jpegData];
self.photoImageView.image = image;
self.photoImageView.hidden = NO;
}];
}
if ([self.delegate respondsToSelector:@selector(photoCameraTakeBtnClicked)]) {
[self.delegate photoCameraTakeBtnClicked];
}
}
代理回调处理
-(void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhotoSampleBuffer:(CMSampleBufferRef)photoSampleBuffer previewPhotoSampleBuffer:(CMSampleBufferRef)previewPhotoSampleBuffer resolvedSettings:(AVCaptureResolvedPhotoSettings *)resolvedSettings bracketSettings:(AVCaptureBracketedStillImageSettings *)bracketSettings error:(NSError *)error API_AVAILABLE(ios(10.0)){
if (photoSampleBuffer) {
[self.session stopRunning];
NSData *data = [AVCapturePhotoOutput JPEGPhotoDataRepresentationForJPEGSampleBuffer:photoSampleBuffer previewPhotoSampleBuffer:previewPhotoSampleBuffer];
UIImage *image = [UIImage imageWithData:data];
self.photoImageView.image = image;
self.photoImageView.hidden = NO;
}
}
PS : 此代理是 iOS 10 以后的方法,低于 iOS 10 需要使用 ↓↓↓
// 兼容iOS 10以下机型,未测试,不清楚可不可以用
self.connection = [self.outPut connectionWithMediaType:AVMediaTypeVideo];
[self.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
AVCaptureStillImageOutput *outPut = (AVCaptureStillImageOutput *)self.outPut;
[outPut captureStillImageAsynchronouslyFromConnection:self.connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
[self.session stopRunning];
NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [UIImage imageWithData:jpegData];
self.photoImageView.image = image;
self.photoImageView.hidden = NO;
}];
友情链接
网友评论