2014 snapchat source code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
5.7 KiB

  1. //
  2. // SCManagedCaptureDeviceThresholdExposureHandler.m
  3. // Snapchat
  4. //
  5. // Created by Derek Peirce on 4/11/17.
  6. // Copyright © 2017 Snapchat, Inc. All rights reserved.
  7. //
  8. #import "SCManagedCaptureDeviceThresholdExposureHandler.h"
  9. #import "AVCaptureDevice+ConfigurationLock.h"
  10. #import "SCCameraTweaks.h"
  11. #import "SCExposureState.h"
  12. #import "SCManagedCaptureDeviceExposureHandler.h"
  13. #import <SCFoundation/SCTrace.h>
  14. #import <FBKVOController/FBKVOController.h>
  15. @import AVFoundation;
  16. @implementation SCManagedCaptureDeviceThresholdExposureHandler {
  17. AVCaptureDevice *_device;
  18. CGPoint _exposurePointOfInterest;
  19. CGFloat _threshold;
  20. // allows the exposure to change when the user taps to refocus
  21. SCExposureState *_exposureState;
  22. FBKVOController *_kvoController;
  23. }
  24. - (instancetype)initWithDevice:(AVCaptureDevice *)device
  25. pointOfInterest:(CGPoint)pointOfInterest
  26. threshold:(CGFloat)threshold
  27. {
  28. if (self = [super init]) {
  29. _device = device;
  30. _exposurePointOfInterest = pointOfInterest;
  31. _threshold = threshold;
  32. _kvoController = [FBKVOController controllerWithObserver:self];
  33. @weakify(self);
  34. [_kvoController observe:device
  35. keyPath:NSStringFromSelector(@selector(exposureMode))
  36. options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
  37. block:^(id observer, id object, NSDictionary *change) {
  38. @strongify(self);
  39. AVCaptureExposureMode old =
  40. (AVCaptureExposureMode)[(NSNumber *)change[NSKeyValueChangeOldKey] intValue];
  41. AVCaptureExposureMode new =
  42. (AVCaptureExposureMode)[(NSNumber *)change[NSKeyValueChangeNewKey] intValue];
  43. if (old == AVCaptureExposureModeAutoExpose && new == AVCaptureExposureModeLocked) {
  44. // auto expose is done, go back to custom
  45. self->_exposureState = [[SCExposureState alloc] initWithDevice:self->_device];
  46. [self->_exposureState applyISOAndExposureDurationToDevice:self->_device];
  47. }
  48. }];
  49. [_kvoController observe:device
  50. keyPath:NSStringFromSelector(@selector(exposureTargetOffset))
  51. options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
  52. block:^(id observer, id object, NSDictionary *change) {
  53. @strongify(self);
  54. if (self->_device.exposureMode == AVCaptureExposureModeCustom) {
  55. CGFloat offset = [(NSNumber *)change[NSKeyValueChangeOldKey] floatValue];
  56. if (fabs(offset) > self->_threshold) {
  57. [self->_device runTask:@"set exposure point"
  58. withLockedConfiguration:^() {
  59. // Set exposure point before changing focus mode
  60. // Be noticed that order does matter
  61. self->_device.exposurePointOfInterest = CGPointMake(0.5, 0.5);
  62. self->_device.exposureMode = AVCaptureExposureModeAutoExpose;
  63. }];
  64. }
  65. }
  66. }];
  67. }
  68. return self;
  69. }
  70. - (CGPoint)getExposurePointOfInterest
  71. {
  72. return _exposurePointOfInterest;
  73. }
  74. - (void)setExposurePointOfInterest:(CGPoint)pointOfInterest fromUser:(BOOL)fromUser
  75. {
  76. SCTraceStart();
  77. BOOL locked = _device.exposureMode == AVCaptureExposureModeLocked ||
  78. _device.exposureMode == AVCaptureExposureModeCustom ||
  79. _device.exposureMode == AVCaptureExposureModeAutoExpose;
  80. if (!locked || fromUser) {
  81. AVCaptureExposureMode exposureMode =
  82. (locked ? AVCaptureExposureModeAutoExpose : AVCaptureExposureModeContinuousAutoExposure);
  83. if ([_device isExposureModeSupported:exposureMode] && [_device isExposurePointOfInterestSupported]) {
  84. [_device runTask:@"set exposure point"
  85. withLockedConfiguration:^() {
  86. // Set exposure point before changing focus mode
  87. // Be noticed that order does matter
  88. _device.exposurePointOfInterest = pointOfInterest;
  89. _device.exposureMode = exposureMode;
  90. }];
  91. }
  92. _exposurePointOfInterest = pointOfInterest;
  93. }
  94. }
  95. - (void)setStableExposure:(BOOL)stableExposure
  96. {
  97. if (stableExposure) {
  98. _exposureState = [[SCExposureState alloc] initWithDevice:_device];
  99. [_exposureState applyISOAndExposureDurationToDevice:_device];
  100. } else {
  101. AVCaptureExposureMode exposureMode = AVCaptureExposureModeContinuousAutoExposure;
  102. if ([_device isExposureModeSupported:exposureMode]) {
  103. [_device runTask:@"set exposure point"
  104. withLockedConfiguration:^() {
  105. _device.exposureMode = AVCaptureExposureModeContinuousAutoExposure;
  106. }];
  107. }
  108. }
  109. }
  110. - (void)setVisible:(BOOL)visible
  111. {
  112. if (visible) {
  113. if (_device.exposureMode == AVCaptureExposureModeLocked ||
  114. _device.exposureMode == AVCaptureExposureModeCustom) {
  115. [_exposureState applyISOAndExposureDurationToDevice:_device];
  116. }
  117. } else {
  118. _exposureState = [[SCExposureState alloc] initWithDevice:_device];
  119. }
  120. }
  121. @end