HXCustomCameraController.m 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. //
  2. // HXCustomCameraController.m
  3. // HXPhotoPickerExample
  4. //
  5. // Created by Silence on 2017/10/31.
  6. // Copyright © 2017年 Silence. All rights reserved.
  7. //
  8. #import "HXCustomCameraController.h"
  9. #import <CoreMotion/CoreMotion.h>
  10. #import "HXPhotoTools.h"
  11. #import "HXCustomPreviewView.h"
  12. const CGFloat HXZoomRate = 1.0f;
  13. @interface HXCustomCameraController ()<AVCaptureFileOutputRecordingDelegate>
  14. @property (strong, nonatomic) dispatch_queue_t videoQueue;
  15. @property (strong, nonatomic) AVCaptureSession *captureSession;
  16. @property (weak, nonatomic) AVCaptureDeviceInput *activeVideoInput;
  17. @property (strong, nonatomic) AVCaptureStillImageOutput *imageOutput;
  18. @property (strong, nonatomic) AVCaptureMovieFileOutput *movieOutput;
  19. @property (strong, nonatomic) NSURL *outputURL;
  20. @property (strong, nonatomic) CMMotionManager *motionManager;
  21. @property (nonatomic, assign) UIDeviceOrientation deviceOrientation;
  22. @property (nonatomic, assign) UIDeviceOrientation imageOrientation;
  23. @end
  24. @implementation HXCustomCameraController
  25. - (instancetype)init {
  26. self = [super init];
  27. if (self) {
  28. self.motionManager = [[CMMotionManager alloc] init];
  29. self.motionManager.deviceMotionUpdateInterval = 1/15.0;
  30. }
  31. return self;
  32. }
  33. - (void)startMontionUpdate {
  34. if (self.motionManager.deviceMotionAvailable) {
  35. HXWeakSelf
  36. [self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
  37. [weakSelf performSelectorOnMainThread:@selector(handleDeviceMotion:) withObject:motion waitUntilDone:YES];
  38. }];
  39. }
  40. }
  41. - (void)stopMontionUpdate {
  42. [self.motionManager stopDeviceMotionUpdates];
  43. }
  44. - (void)dealloc {
  45. }
  46. /// 重力感应回调
  47. - (void)handleDeviceMotion:(CMDeviceMotion *)deviceMotion {
  48. double x = deviceMotion.gravity.x;
  49. double y = deviceMotion.gravity.y;
  50. if (fabs(y) >= fabs(x)) {
  51. if (y >= 0) {
  52. _imageOrientation = UIDeviceOrientationPortraitUpsideDown;
  53. _deviceOrientation = UIDeviceOrientationPortraitUpsideDown;
  54. if ([self.delegate respondsToSelector:@selector(handleDeviceMotion:)]) {
  55. [self.delegate handleDeviceMotion:UIDeviceOrientationPortraitUpsideDown];
  56. }
  57. } else {
  58. _imageOrientation = UIDeviceOrientationPortrait;
  59. _deviceOrientation = UIDeviceOrientationPortrait;
  60. if ([self.delegate respondsToSelector:@selector(handleDeviceMotion:)]) {
  61. [self.delegate handleDeviceMotion:UIDeviceOrientationPortrait];
  62. }
  63. }
  64. } else {
  65. if (x >= 0) { // Home键左侧水平拍摄
  66. _imageOrientation = UIDeviceOrientationLandscapeRight;
  67. _deviceOrientation = UIDeviceOrientationLandscapeRight;
  68. if ([self.delegate respondsToSelector:@selector(handleDeviceMotion:)]) {
  69. [self.delegate handleDeviceMotion:UIDeviceOrientationLandscapeRight];
  70. }
  71. } else {
  72. _imageOrientation = UIDeviceOrientationLandscapeLeft;
  73. _deviceOrientation = UIDeviceOrientationLandscapeLeft; // Home键右侧水平拍摄
  74. if ([self.delegate respondsToSelector:@selector(handleDeviceMotion:)]) {
  75. [self.delegate handleDeviceMotion:UIDeviceOrientationLandscapeLeft];
  76. }
  77. }
  78. }
  79. }
  80. - (void)initSeesion {
  81. self.captureSession = [[AVCaptureSession alloc] init];
  82. }
  83. - (void)setupPreviewLayer:(AVCaptureVideoPreviewLayer *)previewLayer startSessionCompletion:(void (^)(BOOL success))completion {
  84. if ([self.captureSession canSetSessionPreset:self.sessionPreset]) {
  85. self.captureSession.sessionPreset = self.sessionPreset;
  86. }else {
  87. if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
  88. self.captureSession.sessionPreset = AVCaptureSessionPreset1280x720;
  89. }else if ([self.captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) {
  90. self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;
  91. }else {
  92. self.captureSession.sessionPreset = AVCaptureSessionPreset640x480;
  93. }
  94. }
  95. AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  96. if (self.defaultFrontCamera) {
  97. videoDevice = [self cameraWithPosition:AVCaptureDevicePositionFront];
  98. }
  99. AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:nil];
  100. if (videoInput) {
  101. if ([self.captureSession canAddInput:videoInput]) {
  102. [self.captureSession addInput:videoInput];
  103. self.activeVideoInput = videoInput;
  104. }
  105. }else {
  106. if (completion) {
  107. completion(NO);
  108. }
  109. return;
  110. }
  111. previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
  112. if (completion) {
  113. completion(YES);
  114. }
  115. }
  116. - (AVCaptureMovieFileOutput *)movieOutput {
  117. if (!_movieOutput) {
  118. _movieOutput = [[AVCaptureMovieFileOutput alloc] init];
  119. CMTime maxDuration = CMTimeMakeWithSeconds(MAX(1, self.videoMaximumDuration), 30);
  120. _movieOutput.maxRecordedDuration = maxDuration;
  121. }
  122. return _movieOutput;
  123. }
  124. - (AVCaptureStillImageOutput *)imageOutput {
  125. if (!_imageOutput) {
  126. _imageOutput = [[AVCaptureStillImageOutput alloc] init];
  127. _imageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG};
  128. _imageOutput.highResolutionStillImageOutputEnabled = YES;
  129. }
  130. return _imageOutput;
  131. }
  132. - (void)initImageOutput {
  133. if ([self.captureSession canAddOutput:self.imageOutput]) {
  134. [self.captureSession addOutput:self.imageOutput];
  135. }
  136. }
  137. - (void)initMovieOutput {
  138. if ([self.captureSession canAddOutput:self.movieOutput]) {
  139. [self.captureSession addOutput:self.movieOutput];
  140. AVCaptureConnection *videoConnection = [self.movieOutput connectionWithMediaType:AVMediaTypeVideo];
  141. if ([videoConnection isVideoStabilizationSupported]) {
  142. videoConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
  143. }
  144. }
  145. }
  146. - (void)removeMovieOutput {
  147. [self.captureSession removeOutput:self.movieOutput];
  148. }
  149. - (BOOL)addAudioInput {
  150. NSError *error;
  151. AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
  152. AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
  153. if (audioDevice) {
  154. if ([self.captureSession canAddInput:audioInput]) {
  155. [self.captureSession addInput:audioInput];
  156. }
  157. }else {
  158. return NO;
  159. }
  160. if (error) {
  161. return NO;
  162. }else {
  163. return YES;
  164. }
  165. }
  166. - (void)startSession {
  167. AVCaptureSession *session = self.captureSession;
  168. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  169. if (![session isRunning]) {
  170. [session startRunning];
  171. }
  172. });
  173. // if (![self.captureSession isRunning]) {
  174. // dispatch_async(self.videoQueue, ^{
  175. // [self.captureSession startRunning];
  176. // });
  177. // }
  178. }
  179. - (void)stopSession {
  180. AVCaptureSession *session = self.captureSession;
  181. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  182. if (session.running) {
  183. [session stopRunning];
  184. }
  185. });
  186. // if ([self.captureSession isRunning]) {
  187. // dispatch_async(self.videoQueue, ^{
  188. // [self.captureSession stopRunning];
  189. // });
  190. // }
  191. }
  192. - (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position {
  193. NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
  194. for (AVCaptureDevice *device in devices) {
  195. if (device.position == position) {
  196. return device;
  197. }
  198. }
  199. return nil;
  200. }
  201. - (AVCaptureDevice *)activeCamera {
  202. return self.activeVideoInput.device;
  203. }
  204. - (AVCaptureDevice *)inactiveCamer {
  205. AVCaptureDevice *device = nil;
  206. if (self.cameraCount > 1) {
  207. if ([self activeCamera].position == AVCaptureDevicePositionBack) {
  208. device = [self cameraWithPosition:AVCaptureDevicePositionFront];
  209. }else {
  210. device = [self cameraWithPosition:AVCaptureDevicePositionBack];
  211. }
  212. }
  213. return device;
  214. }
  215. - (BOOL)canSwitchCameras {
  216. return self.cameraCount > 1;
  217. }
  218. - (NSUInteger)cameraCount {
  219. return [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
  220. }
  221. - (BOOL)switchCameras {
  222. if (![self canSwitchCameras]) {
  223. return NO;
  224. }
  225. NSError *error;
  226. AVCaptureDevice *videoDevice = [self inactiveCamer];
  227. AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
  228. if (videoInput) {
  229. [self.captureSession beginConfiguration];
  230. [self.captureSession removeInput:self.activeVideoInput];
  231. if ([self.captureSession canAddInput:videoInput]) {
  232. [self.captureSession addInput:videoInput];
  233. self.activeVideoInput = videoInput;
  234. }else {
  235. [self.captureSession addInput:self.activeVideoInput];
  236. }
  237. [self.captureSession commitConfiguration];
  238. }else {
  239. if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
  240. [self.delegate deviceConfigurationFailedWithError:error];
  241. }
  242. return NO;
  243. }
  244. return YES;
  245. }
  246. - (BOOL)cameraSupportsTapToFocus {
  247. return [[self activeCamera] isFocusPointOfInterestSupported];
  248. }
  249. - (void)focusAtPoint:(CGPoint)point {
  250. AVCaptureDevice *device = [self activeCamera];
  251. if (device.isFocusPointOfInterestSupported && [device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
  252. NSError *error;
  253. if ([device lockForConfiguration:&error]) {
  254. if (device.smoothAutoFocusSupported) {
  255. device.smoothAutoFocusEnabled = YES;
  256. }
  257. device.focusPointOfInterest = point;
  258. device.focusMode = AVCaptureFocusModeContinuousAutoFocus;
  259. [device unlockForConfiguration];
  260. }else {
  261. if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
  262. [self.delegate deviceConfigurationFailedWithError:error];
  263. }
  264. }
  265. }
  266. }
  267. - (BOOL)cameraSupportsTapToExpose {
  268. return [[self activeCamera] isExposurePointOfInterestSupported];
  269. }
  270. static const NSString *HXCustomCameraAdjustingExposureContext;
  271. - (void)exposeAtPoint:(CGPoint)point {
  272. AVCaptureDevice *device = [self activeCamera];
  273. AVCaptureExposureMode exposureMode = AVCaptureExposureModeContinuousAutoExposure;
  274. if (device.isExposurePointOfInterestSupported && [device isExposureModeSupported:exposureMode]) {
  275. NSError *error;
  276. if ([device lockForConfiguration:&error]) {
  277. device.exposurePointOfInterest = point;
  278. device.exposureMode = exposureMode;
  279. // if ([device isExposureModeSupported:AVCaptureExposureModeLocked]) {
  280. // [device addObserver:self forKeyPath:@"adjustingExposure" options:NSKeyValueObservingOptionNew context:&HXCustomCameraAdjustingExposureContext];
  281. // }
  282. [device unlockForConfiguration];
  283. }else {
  284. if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
  285. [self.delegate deviceConfigurationFailedWithError:error];
  286. }
  287. }
  288. }
  289. }
  290. - (void)resetFocusAndExposureModes {
  291. AVCaptureDevice *device = [self activeCamera];
  292. AVCaptureExposureMode exposureMode =
  293. AVCaptureExposureModeContinuousAutoExposure;
  294. AVCaptureFocusMode focusMode = AVCaptureFocusModeContinuousAutoFocus;
  295. BOOL canResetFocus = [device isFocusPointOfInterestSupported] &&
  296. [device isFocusModeSupported:focusMode];
  297. BOOL canResetExposure = [device isExposurePointOfInterestSupported] &&
  298. [device isExposureModeSupported:exposureMode];
  299. CGPoint centerPoint = CGPointMake(0.5f, 0.5f);
  300. NSError *error;
  301. if ([device lockForConfiguration:&error]) {
  302. if (device.smoothAutoFocusSupported) {
  303. device.smoothAutoFocusEnabled = YES;
  304. }
  305. if (canResetFocus) {
  306. device.focusMode = focusMode;
  307. device.focusPointOfInterest = centerPoint;
  308. }
  309. if (canResetExposure) {
  310. device.exposureMode = exposureMode;
  311. device.exposurePointOfInterest = centerPoint;
  312. }
  313. [device unlockForConfiguration];
  314. } else {
  315. if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
  316. [self.delegate deviceConfigurationFailedWithError:error];
  317. }
  318. }
  319. }
  320. // 闪光灯
  321. - (BOOL)cameraHasFlash {
  322. return [[self activeCamera] hasFlash];
  323. }
  324. - (AVCaptureFlashMode)flashMode {
  325. return [[self activeCamera] flashMode];
  326. }
  327. - (void)setFlashMode:(AVCaptureFlashMode)flashMode {
  328. AVCaptureDevice *device = [self activeCamera];
  329. if (device.flashMode != flashMode &&
  330. [device isFlashModeSupported:flashMode]) {
  331. NSError *error;
  332. if ([device lockForConfiguration:&error]) {
  333. device.flashMode = flashMode;
  334. [device unlockForConfiguration];
  335. } else {
  336. if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
  337. [self.delegate deviceConfigurationFailedWithError:error];
  338. }
  339. }
  340. }
  341. }
  342. // 手电筒
  343. - (BOOL)cameraHasTorch {
  344. return [[self activeCamera] hasTorch];
  345. }
  346. - (AVCaptureTorchMode)torchMode {
  347. return [[self activeCamera] torchMode];
  348. }
  349. - (void)setTorchMode:(AVCaptureTorchMode)torchMode {
  350. AVCaptureDevice *device = [self activeCamera];
  351. if (device.torchMode != torchMode &&
  352. [device isTorchModeSupported:torchMode]) {
  353. NSError *error;
  354. if ([device lockForConfiguration:&error]) {
  355. device.torchMode = torchMode;
  356. [device unlockForConfiguration];
  357. } else {
  358. if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
  359. [self.delegate deviceConfigurationFailedWithError:error];
  360. }
  361. }
  362. }
  363. }
  364. - (void)captureStillImage {
  365. AVCaptureConnection *connection =
  366. [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
  367. if (connection.isVideoOrientationSupported) {
  368. connection.videoOrientation = [self currentVideoOrientation];
  369. }
  370. AVCaptureDevicePosition position = [[self activeCamera] position];
  371. if (position == AVCaptureDevicePositionUnspecified ||
  372. position == AVCaptureDevicePositionFront) {
  373. connection.videoMirrored = YES;
  374. }else {
  375. connection.videoMirrored = NO;
  376. }
  377. HXWeakSelf
  378. id handler = ^(CMSampleBufferRef sampleBuffer, NSError *error) {
  379. if (sampleBuffer != NULL) {
  380. NSData *imageData =
  381. [AVCaptureStillImageOutput
  382. jpegStillImageNSDataRepresentation:sampleBuffer];
  383. UIImage *image = [[UIImage alloc] initWithData:imageData];
  384. if ([weakSelf.delegate respondsToSelector:@selector(takePicturesComplete:)]) {
  385. [weakSelf.delegate takePicturesComplete:image];
  386. }
  387. } else {
  388. if ([weakSelf.delegate respondsToSelector:@selector(takePicturesFailed)]) {
  389. [weakSelf.delegate takePicturesFailed];
  390. }
  391. }
  392. };
  393. [self.imageOutput captureStillImageAsynchronouslyFromConnection:connection
  394. completionHandler:handler];
  395. }
  396. - (AVCaptureVideoOrientation)currentVideoOrientation {
  397. AVCaptureVideoOrientation orientation;
  398. switch (self.imageOrientation) {
  399. case UIDeviceOrientationPortrait:
  400. orientation = AVCaptureVideoOrientationPortrait;
  401. break;
  402. case UIDeviceOrientationLandscapeRight:
  403. orientation = AVCaptureVideoOrientationLandscapeLeft;
  404. break;
  405. case UIDeviceOrientationPortraitUpsideDown:
  406. orientation = AVCaptureVideoOrientationPortraitUpsideDown;
  407. break;
  408. default:
  409. orientation = AVCaptureVideoOrientationLandscapeRight;
  410. break;
  411. }
  412. return orientation;
  413. }
  414. - (BOOL)isRecording {
  415. return self.movieOutput.isRecording;
  416. }
  417. - (void)startRecording {
  418. if (![self isRecording]) {
  419. AVCaptureConnection *videoConnection =
  420. [self.movieOutput connectionWithMediaType:AVMediaTypeVideo];
  421. // 设置编码格式
  422. if (HX_IOS11_Later && self.videoCodecKey) {
  423. NSMutableDictionary* outputSettings = [NSMutableDictionary dictionary];
  424. outputSettings[AVVideoCodecKey] = self.videoCodecKey;
  425. [self.movieOutput setOutputSettings:outputSettings forConnection:videoConnection];
  426. }
  427. if ([videoConnection isVideoOrientationSupported]) {
  428. videoConnection.videoOrientation = (AVCaptureVideoOrientation)_deviceOrientation;
  429. }
  430. AVCaptureDevice *device = [self activeCamera];
  431. if (device.isSmoothAutoFocusSupported) {
  432. NSError *error;
  433. if ([device lockForConfiguration:&error]) {
  434. device.smoothAutoFocusEnabled = NO;
  435. [device unlockForConfiguration];
  436. }
  437. }
  438. self.outputURL = [self uniqueURL];
  439. [self.movieOutput startRecordingToOutputFileURL:self.outputURL
  440. recordingDelegate:self];
  441. }
  442. }
  443. - (CMTime)recordedDuration {
  444. return self.movieOutput.recordedDuration;
  445. }
  446. - (NSURL *)uniqueURL {
  447. return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), [NSString stringWithFormat:@"hx%@.mov",[self videoOutFutFileName]]]];
  448. }
  449. - (NSString *)videoOutFutFileName {
  450. return [NSString hx_fileName];
  451. }
  452. - (void)stopRecording {
  453. if ([self isRecording]) {
  454. [self.movieOutput stopRecording];
  455. }
  456. }
  457. #pragma mark - AVCaptureFileOutputRecordingDelegate
  458. // 开始录制
  459. - (void)captureOutput:(AVCaptureFileOutput *)output didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray<AVCaptureConnection *> *)connections {
  460. if ([self.delegate respondsToSelector:@selector(videoStartRecording)]) {
  461. [self.delegate videoStartRecording];
  462. }
  463. }
  464. // 录制完成
  465. - (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
  466. fromConnections:(NSArray *)connections
  467. error:(NSError *)error {
  468. if ([error.userInfo[AVErrorRecordingSuccessfullyFinishedKey] boolValue]) {
  469. if ([self.delegate respondsToSelector:@selector(videoFinishRecording:)]) {
  470. [self.delegate videoFinishRecording:[self.outputURL copy]];
  471. }
  472. self.outputURL = nil;
  473. return;
  474. }
  475. if (error) {
  476. if ([self.delegate respondsToSelector:@selector(mediaCaptureFailedWithError:)]) {
  477. [self.delegate mediaCaptureFailedWithError:error];
  478. }
  479. } else {
  480. if ([self.delegate respondsToSelector:@selector(videoFinishRecording:)]) {
  481. [self.delegate videoFinishRecording:[self.outputURL copy]];
  482. }
  483. }
  484. self.outputURL = nil;
  485. }
  486. - (void)updateZoomingDelegate {
  487. // CGFloat curZoomFactor = self.activeCamera.videoZoomFactor;
  488. // CGFloat maxZoomFactor = [self maxZoomFactor];
  489. // CGFloat value = log(curZoomFactor) / log(maxZoomFactor);
  490. // if ([self.delegate respondsToSelector:@selector(rampedZoomToValue:)]) {
  491. // [self.delegate rampedZoomToValue:value];
  492. // }
  493. }
  494. - (BOOL)cameraSupportsZoom {
  495. return self.activeCamera.activeFormat.videoMaxZoomFactor > 1.0f;
  496. }
  497. - (CGFloat)maxZoomFactor {
  498. return MIN(self.activeCamera.activeFormat.videoMaxZoomFactor, 5.0f);
  499. }
  500. - (CGFloat)currentZoomFacto {
  501. return self.activeCamera.videoZoomFactor;
  502. }
  503. - (void)setZoomValue:(CGFloat)zoomValue {
  504. if (zoomValue > self.maxZoomFactor) {
  505. zoomValue = self.maxZoomFactor;
  506. }
  507. if (!self.activeCamera.isRampingVideoZoom) {
  508. NSError *error;
  509. if ([self.activeCamera lockForConfiguration:&error]) {
  510. // Provide linear feel to zoom slider
  511. // CGFloat zoomFactor = pow([self maxZoomFactor], zoomValue);
  512. self.activeCamera.videoZoomFactor = zoomValue;
  513. [self.activeCamera unlockForConfiguration];
  514. } else {
  515. if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
  516. [self.delegate deviceConfigurationFailedWithError:error];
  517. }
  518. }
  519. }
  520. }
  521. - (void)rampZoomToValue:(CGFloat)zoomValue {
  522. // CGFloat zoomFactor = pow([self maxZoomFactor], zoomValue);
  523. NSError *error;
  524. if ([self.activeCamera lockForConfiguration:&error]) {
  525. [self.activeCamera rampToVideoZoomFactor:zoomValue
  526. withRate:HXZoomRate];
  527. [self.activeCamera unlockForConfiguration];
  528. } else {
  529. if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
  530. [self.delegate deviceConfigurationFailedWithError:error];
  531. }
  532. }
  533. }
  534. - (void)cancelZoom {
  535. NSError *error;
  536. if ([self.activeCamera lockForConfiguration:&error]) {
  537. [self.activeCamera cancelVideoZoomRamp];
  538. [self.activeCamera unlockForConfiguration];
  539. } else {
  540. if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
  541. [self.delegate deviceConfigurationFailedWithError:error];
  542. }
  543. }
  544. }
  545. @end