1、如何使用AVFoundation框架自定义相机请先参照iOS项目实战之自定义相机
2.1、上述帖子中有讲到,如果需要对焦,可以通过AVCaptureDevice的setFocusPointOfInterest:方法来实现,传入一个CGPoint值,但这里的CGPoint不是View上面的点,而是范围的0~1的相对百分点;
2.2、这个CGPoint如何得来呢,我们在点击屏幕时可以监听相关View的点击事件,添加一个UITapGestureRecognizer手势,在点时后,可以通过UITapGestureRecognizer的locationInView:方法得到CGPoint,这是一个绝对值,即点击了相关View上的某个点,有了这个点,再通过AVCaptureVideoPreviewLayer的一个转换方法:captureDevicePointOfInterestForPoint:可以将绝对点转换成相对点。
2.3、得到CGPoint后,就可以调用AVCaptureDevice(即摄像头)的setFocusPointOfInterest:方法来实现了,但需要注意的是,这个方法不能直接调用,要分三步曲来完成:锁定AVCaptureDevice,修改参数值,解锁AVCaptureDevice。一般形式如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /// 对焦事件 - (void)focusAtPoint:(CGPoint)point { ????AVCaptureDevice *device = self.deviceInput.device; ????NSError *error; ????if ([device isFocusModeSupported:AVCaptureFocusModeAutoFocus] && [device isFocusPointOfInterestSupported]) ????{ ????????if ([device lockForConfiguration:&error]) { ????????????[device setFocusPointOfInterest:point];???? // 对焦点 ????????????[device setExposurePointOfInterest:point];? // 曝光点 ????????????[device setFocusMode:AVCaptureFocusModeAutoFocus];? // 自动对焦模式 ????????????[device unlockForConfiguration]; ????????} else { ????????????NSLog(@"Error: %@", error); ????????} ????} } |
3、自动对焦实现了,如何调节焦距呢?
3.1、这里所谓的调节焦距不是对焦的意思,而是在拍摄远景时所需要的放大(拉近)影像
3.2、有两种方式来实现,第一种方式,通过放大AVCaptureVideoPreviewLayer及AVCaptureStillImageOutput的videoScaleAndCropFactor属性来实现,简单一点讲就是把预览图层放大,这样在屏幕上就只能看到一部分影像了,然后在捕捉生成图片时做相同倍数的放大,裁剪超出部分的像素实现,这种方式好比原本拍摄的照片是4000*3000的分辨率,现在通过放大只取中间2000*1500的部分输出同样大小的照片,最终的效果就是放大了图像。
3.3、另一种方式,通过调节AVCaptureDevice的videoZoomFactor属性来实现焦距的调整,这种方式事实上是在图像取景的时候就进行了相关调整,取摄像头的部分影像进入sesstion,这样更合理,并且前面那种方式有个问题:因为是通过放大图层来模拟拉近焦距,所以实际上图层是不清晰的,对焦也没什么效果。然而第二种方式中videoZoomFactor属性需要iOS7以上才支持。
3.4、设置videoZoomFactor属性与对焦一样同样需要三部曲来实现,锁定Device、设置属性、解锁Device
1 2 3 4 5 6 7 | /// 调整摄像头焦距 - (void)setDevice:(AVCaptureDevice *)device videoZoomFactor:(CGFloat)scale { ????[device lockForConfiguration:nil]; ????device.videoZoomFactor = scale; ????[device unlockForConfiguration]; } |
4、关键代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | // //? SACameraCtrl.m //? Test // //? Created by 余西安 on 15/4/13. //? Copyright (c) 2015年 Sian. All rights reserved. // ? #import "SACameraCtrl.h" #import "SAPreview.h" #import "SAPhotoViewCtrl.h" #import <AVFoundation/AVFoundation.h> #import <CoreMotion/CoreMotion.h> #define SourcePath [[NSBundle mainBundle] pathForResource:@"SAImagePickerController.bundle" ofType:nil] ? @interface SACameraCtrl () <UIAccelerometerDelegate> { ????CGFloat _deviceScale; } // 输入流预览图层 @property (nonatomic, strong)?? AVCaptureVideoPreviewLayer? *previewLayer; ? @property (weak, nonatomic) IBOutlet SAPreview *preview; ? // AVCaptureSession对象来执行输入设备和输出设备之间的数据传递 @property (nonatomic, strong)?? AVCaptureSession??????????? *session; ? // 设备输入流 @property (nonatomic, strong)?? AVCaptureDeviceInput??????? *deviceInput; ? // 照片输出流 @property (nonatomic, strong)?? AVCaptureStillImageOutput?? *imageOutput; ? // 摄像头焦倍 @property (nonatomic, assign)?? CGFloat???????? deviceScale; ? // 图片输出视图 @property (nonatomic, strong)?? UIImageView???? *cameraShowView; ? // 摄像头数组 @property (nonatomic, strong, readonly) NSArray???? *devices;?????? // AVCaptureDevices ? // 闪光灯切换按钮 @property (weak, nonatomic) IBOutlet??? UIButton??? *flashButton; ? @end ? @implementation SACameraCtrl ? - (void)viewDidLoad { ????[super viewDidLoad]; ????// 创建交互流 ????self.session = [[AVCaptureSession alloc] init]; ????self.session.sessionPreset = AVCaptureSessionPresetPhoto; ????? ????// 媒体输入 ????AVCaptureDevice *device = [self.devices firstObject]; ????[self setDevice:device FlashMode:AVCaptureFlashModeAuto]; ????self.deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:NULL]; ????if([self.session canAddInput:self.deviceInput])[self.session addInput:self.deviceInput]; ? ????// 媒体输出 ????self.imageOutput = [[AVCaptureStillImageOutput alloc] init]; ????self.imageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG}; ????AVCaptureConnection * connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo]; ????connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight; ????if([self.session canAddOutput:self.imageOutput])[self.session addOutput:self.imageOutput]; ????? ????// 媒体预览 ????self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session]; ????self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspect; ????[self.preview.layer addSublayer:self.previewLayer]; ????[self setPreviewGesture]; } ? ? #pragma mark - 前后摄像头 - (NSArray *)devices { ????return [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; } ? - (void)viewWillAppear:(BOOL)animated { ????[super viewWillAppear:animated]; ????self.deviceScale = 1.0; ????self.previewLayer.frame = self.preview.layer.bounds; ????self.navigationController.navigationBar.hidden = YES; ????[self setDevice:self.deviceInput.device videoZoomFactor:self.deviceScale]; ????[self.session startRunning]; } ? - (void)viewDidAppear:(BOOL)animated { ????[super viewDidAppear:animated]; ????[[UIApplication sharedApplication] setStatusBarHidden:YES]; } ? - (void)viewWillDisappear:(BOOL)animated { ????[super viewWillDisappear:animated]; ????[[UIApplication sharedApplication] setStatusBarHidden:NO]; } ? - (void)viewDidDisappear:(BOOL)animated { ????[super viewDidDisappear:animated]; ????[self.session stopRunning]; } ? /// 媒体预览图层手势事件 - (void)setPreviewGesture { ????// 注册一个手势事件来实现对焦功能 ????UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapPreview:)]; ????UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchPreview:)]; ????[self.preview addGestureRecognizer:tap]; ????if ([UIDevice currentDevice].systemVersion.floatValue >= 7.0) [self.preview addGestureRecognizer:pinch]; } ? /// 预览图层点击事件 - (void)tapPreview:(UITapGestureRecognizer *)gesture { ????CGPoint point = [gesture locationInView:gesture.view]; ????CGPoint p = [self.previewLayer captureDevicePointOfInterestForPoint:point]; ????[self focusAtPoint:p]; ????// 对焦动画 ????self.preview.aperture.center = point; ????[self.preview showAperture]; } ? /// 焦距调整事件 - (void)pinchPreview:(UIPinchGestureRecognizer *)gesture { ????CGFloat scale = self.deviceScale + (gesture.scale - 1); ????if (scale > 5) scale = 5;?? // 最大5倍焦距 ????if (scale < 1) scale = 1;?? // 最小1倍焦距 ????[self setDevice:self.deviceInput.device videoZoomFactor:scale]; ????// 缩放结束时记录当前倍焦 ????if (gesture.state == UIGestureRecognizerStateEnded) self.deviceScale = scale; } ? /// 对焦事件 - (void)focusAtPoint:(CGPoint)point { ????AVCaptureDevice *device = self.deviceInput.device; ????NSError *error; ????if ([device isFocusModeSupported:AVCaptureFocusModeAutoFocus] && [device isFocusPointOfInterestSupported]) ????{ ????????if ([device lockForConfiguration:&error]) { ????????????[device setFocusPointOfInterest:point];???? // 对焦点 ????????????[device setExposurePointOfInterest:point];? // 曝光点 ????????????[device setFocusMode:AVCaptureFocusModeAutoFocus];? // 自动对焦模式 ????????????[device unlockForConfiguration]; ????????} else { ????????????NSLog(@"Error: %@", error); ????????} ????} } ? /// 摄像头切换事件 - (IBAction)switchCamera:(UIButton *)sender { ????if (self.devices.count < 2) return; ????? ????NSInteger oldIndex = [self.devices indexOfObject:self.deviceInput.device]; ????NSInteger newIndex = (oldIndex + 1) % self.devices.count; ????AVCaptureDevice *newDevice = [self.devices objectAtIndex:newIndex]; ????AVCaptureDeviceInput *newInput = [AVCaptureDeviceInput deviceInputWithDevice:newDevice error:NULL]; ????if (newInput) { ????????[self.session beginConfiguration]; ????????[self.session removeInput:self.deviceInput]; ????????[self.session addInput:newInput]; ????????[self.session commitConfiguration]; ????????self.deviceInput = newInput; ????????self.flashButton.hidden = !newDevice.isFlashAvailable; ????} } ? /// 取消事件 - (IBAction)cancel:(UIButton *)sender { ????[self dismissViewControllerAnimated:YES completion:nil]; } ? /// 拍照事件 - (IBAction)shutter:(UIButton *)sender { ????sender.userInteractionEnabled = NO; ????AVCaptureConnection * connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo]; ????connection.videoOrientation = AVCaptureVideoOrientationPortrait; ????connection.videoScaleAndCropFactor = 1.0;?? // 获取流比例 ????if (!connection) { ????????NSLog(@"take photo failed!"); ????????return; ????} ????? ????[self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { ????????if (imageDataSampleBuffer == NULL) { ????????????return; ????????} ????????NSData * imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; ????????UIImage * image = [UIImage imageWithData:imageData]; ????????SAPhotoViewCtrl *photoView = [[SAPhotoViewCtrl alloc] initWithImage:image]; ????????[self.navigationController pushViewController:photoView animated:NO]; ????????sender.userInteractionEnabled = YES; ????}]; } ? /// 调整摄像头焦距 - (void)setDevice:(AVCaptureDevice *)device videoZoomFactor:(CGFloat)scale { ????[device lockForConfiguration:nil]; ????device.videoZoomFactor = scale; ????[device unlockForConfiguration]; } ? /// 闪光灯开关按钮 - (IBAction)overTurn:(UIButton *)sender { ????sender.tag = (sender.tag + 1) % 3; ????NSString *imageName = [NSString stringWithFormat:@"camera_flashlight_%d.png", (int)sender.tag]; ????[sender setBackgroundImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal]; ????[self setDevice:self.deviceInput.device FlashMode:(2 - sender.tag)]; } ? /// 切换闪光灯模式 - (void)setDevice:(AVCaptureDevice *)device FlashMode:(AVCaptureFlashMode)flashModel { ????if (device.isFlashAvailable == NO) return; ????if ([device lockForConfiguration:nil]) { ????????device.flashMode = flashModel; ????} ????[device unlockForConfiguration]; } ? @end |
5、Demo下载 SAAVFoundation