在ios实现视频录制功能一中,已经可以在设备上看到捕捉到的画面。此片实现的是实现照相功能中的曝光和自动对焦功能的实现。
一、思路和注意的地方
当我们在照相过程中,手指点击实现对应位置的聚焦和自动调节曝光到合适的值。这整个过程实际上都适合捕捉设备达交到(摄像头等),苹果为我们提供相关的接口和方法。在自己实现整个过程中要注意两点问题,坐标系统的转化和更改捕捉设备参数时的设备锁定。
1、坐标系统的转换
在5s垂直模式左上角的坐标为(0,0),右下角为(320,568),水平模式下右下角为(568,320)。捕捉设备上的坐标系统和此是不同的,但好在苹果在AvCaptureVideoPreviewLayer中为我们提供了对应的转换方法,使得我们可以直接在使用屏幕坐标系统对捕捉设备进行控制。
a、captureDevicePointOfInterestForPoint:获取屏幕坐标系的CGPoint数据,返回转换得到的设备坐标系CGPoint。
b、pointForCaptureDevicePointOfInterest:获取摄像头坐标系的CGPiont数据,返回转换得到的屏幕坐标系数据。
在后面的代码中可以看到a的使用。
2、捕捉设备的判断
a、如苹果的前置摄像头是没有聚焦功能的实现的,所以在可以切换摄像头的功能中要使用对焦和相关方法的时候,一定要注意是否支持对应功能。
b、我们在对捕捉设备进行控制的时候即改变焦点、曝光等,一定要将设备先锁定,在锁定成功后改变设备参数。当然在改变完成之后需要对应的将设被解锁。使用到以下的方法。
lockForConfiguration
unlockForConfiguration
以上是注意点,相关更多细节方面的东西在代码的注释中有详细的说明
- (void)focusAtPoint:(CGPoint)point {
if ([self.device isFocusPointOfInterestSupported] && [self.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {//用于判断设备是否支持设置区域焦距调节的功能和设备能否实现对自动变焦到合适的焦距(手机前置摄像头是没有焦距调节的)
NSError *error;
point = [self.layer captureDevicePointOfInterestForPoint:point]; //转化手指点击区域坐标,设备(摄像头等)的坐标系统和屏幕坐标系统是不一样的,得将屏幕坐标位置做响应改变
if ([self.device lockForConfiguration:&error]) { //锁定设备,类似于线程锁一样,是设备只能被一个访问。没有此步,任何对设备的改变都是无法进行的,此方法可以设置,设置成功后返回一个bool值
self.device.focusPointOfInterest = point; //指定变焦区域
self.device.focusMode = AVCaptureFocusModeAutoFocus;//设置变焦方式为自动变焦
[self.device unlockForConfiguration]; //当对设备设置完毕后,需要接触设备锁定
NSLog(@"tocus");
}else {
NSLog(@"%@",[error localizedDescription]);
}
}
}
//曝光方法
- (void)exposeArPoint:(CGPoint)point {
if (self.device.isExposurePointOfInterestSupported && [self.device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) { //先判断设备是否支持局部曝光和设备能否根据环境自动调节曝光值到合适的程度
point = [self.layer captureDevicePointOfInterestForPoint:point]; //转化坐标
NSError *error;
if ([self.device lockForConfiguration:&error]) { //锁定设备
self.device.exposurePointOfInterest = point; //设置此处的曝光值,锁定局部
self.device.exposureMode = AVCaptureExposureModeContinuousAutoExposure; //设置曝光方式为自动调节曝光到合适值
if ([self.device isExposureModeSupported:AVCaptureExposureModeLocked]) { //设备是否支持相关设置
//添加观察是考虑到曝光的设置问题,防止设备在还没有将曝光值设置完毕就操作了其他事件
[self.device addObserver:self forKeyPath:@"adjustingExposure" options:NSKeyValueObservingOptionNew context:nil];
[self.device unlockForConfiguration];
}
}
}}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"adjustingExposure"]) {
//当曝光已经不再设置和设备已经锁定了当前的曝光值,在进行相关操作
if (!self.device.isAdjustingExposure && [self.device isExposureModeSupported:AVCaptureExposureModeLocked]) {
[self.device removeObserver:self forKeyPath:@"adjustingExposure"];
dispatch_async(dispatch_get_main_queue(), ^{
NSError *error;
if ([self.device lockForConfiguration:&error]) {
self.device.exposureMode = AVCaptureExposureModeLocked; //锁定当前的曝光
[self.device unlockForConfiguration];
}
});
}
}else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
二、照片的生成和保存
现在可以调焦、曝光,接下来就是将预览层上的画面保存。在保存的时候我们就要使用到AVCaptureConnection捕捉输出类,它控制着链接。
//照片的生成和保存
- (void)makeAndsaveImage {
AVCaptureConnection *connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];//生成对应数据类型的连接器
if (connection.isVideoOrientationSupported) {
connection.videoOrientation = [self currentVideoOrientation]; //私有方法 用于判断方向
}
//核心
id handler = ^(CMSampleBufferRef sampleBUffer,NSError *error){
if (sampleBUffer != NULL) {
//先得到捕捉设备数据再生层图片
NSData *imagedata = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:sampleBUffer];
UIImage *image = [[UIImage alloc] initWithData:imagedata];
//将图片保存到系统相册中
[self saveImageToAssetsLibraty:image];
}else {
NSLog(@"%@",[error localizedDescription]);
}
};
//将操作放入异步中执行,此方法需要连接器和对应的代码块(block)
[self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:handler];
}
//用于判断方向
- (AVCaptureVideoOrientation )currentVideoOrientation {
AVCaptureVideoOrientation orientation;
switch ([UIDevice currentDevice].orientation) {
case UIDeviceOrientationPortrait:
orientation = AVCaptureVideoOrientationPortrait;
break;
case UIDeviceOrientationLandscapeLeft:
orientation = AVCaptureVideoOrientationLandscapeLeft;
break;
case UIDeviceOrientationLandscapeRight:
orientation = AVCaptureVideoOrientationLandscapeRight;
break;
case UIDeviceOrientationPortraitUpsideDown:
orientation = AVCaptureVideoOrientationPortraitUpsideDown;
break;
default:
break;
}
return orientation;
}
//照片保存到相册中
- (void)saveImageToAssetsLibraty:(UIImage *)image {
//保存到系统相册操作
ALAssetsLibrary *library = [[ALAssetsLibrary alloc]init];
[library writeImageToSavedPhotosAlbum:image.CGImage orientation:image.imageOrientation completionBlock:^(NSURL *assetURL, NSError *error) {
if (!error) {
NSLog(@"已经保存");
}
}];
}