diff --git a/Library/Sources/SCRecorder.h b/Library/Sources/SCRecorder.h index d980d106..536dd7fb 100644 --- a/Library/Sources/SCRecorder.h +++ b/Library/Sources/SCRecorder.h @@ -189,6 +189,16 @@ */ @property (assign, nonatomic) BOOL keepMirroringOnWrite; +/** + Whether adjusting exposure is supported on the current camera device + */ +@property (readonly, nonatomic) BOOL exposureSupported; + +/** + The current exposure point of interest + */ +@property (readonly, nonatomic) CGPoint exposurePointOfInterest; + /** Whether the focus is supported on the current camera device */ diff --git a/Library/Sources/SCRecorder.m b/Library/Sources/SCRecorder.m index 7d364043..f1a81e86 100644 --- a/Library/Sources/SCRecorder.m +++ b/Library/Sources/SCRecorder.m @@ -9,10 +9,6 @@ #import "SCRecorder.h" #import "SCRecordSession_Internal.h" #define dispatch_handler(x) if (x != nil) dispatch_async(dispatch_get_main_queue(), x) -#define SCRecorderFocusContext ((void*)0x1) -#define SCRecorderVideoEnabledContext ((void*)0x2) -#define SCRecorderAudioEnabledContext ((void*)0x3) -#define SCRecorderPhotoOptionsContext ((void*)0x3) #define kSCRecorderRecordSessionQueueKey "SCRecorderRecordSessionQueue" #define kMinTimeBetweenAppend 0.004 @@ -49,6 +45,12 @@ @interface SCRecorder() { @implementation SCRecorder +static char* SCRecorderFocusContext = "FocusContext"; +static char* SCRecorderExposureContext = "ExposureContext"; +static char* SCRecorderVideoEnabledContext = "VideoEnabledContext"; +static char* SCRecorderAudioEnabledContext = "AudioEnabledContext"; +static char* SCRecorderPhotoOptionsContext = "PhotoOptionsContext"; + - (id)init { self = [super init]; @@ -333,7 +335,11 @@ - (void)stopRunning { } - (void)_subjectAreaDidChange { - [self focusCenter]; + id delegate = self.delegate; + + if (![delegate respondsToSelector:@selector(recorderShouldAutomaticallyRefocus:)] || [delegate recorderShouldAutomaticallyRefocus:self]) { + [self focusCenter]; + } } - (UIImage *)_imageFromSampleBufferHolder:(SCSampleBufferHolder *)sampleBufferHolder { @@ -875,6 +881,18 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N } else { [self _focusDidComplete]; } + } else if (context == SCRecorderExposureContext) { + BOOL isAdjustingExposure = [[change objectForKey:NSKeyValueChangeNewKey] boolValue]; + + if (isAdjustingExposure) { + if ([delegate respondsToSelector:@selector(recorderDidStartAdjustingExposure:)]) { + [delegate recorderDidStartAdjustingExposure:self]; + } + } else { + if ([delegate respondsToSelector:@selector(recorderDidEndAdjustingExposure:)]) { + [delegate recorderDidEndAdjustingExposure:self]; + } + } } else if (context == SCRecorderAudioEnabledContext) { if ([NSThread isMainThread]) { [self reconfigureVideoInput:NO audioInput:YES]; @@ -898,10 +916,12 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N - (void)addVideoObservers:(AVCaptureDevice*)videoDevice { [videoDevice addObserver:self forKeyPath:@"adjustingFocus" options:NSKeyValueObservingOptionNew context:SCRecorderFocusContext]; + [videoDevice addObserver:self forKeyPath:@"adjustingExposure" options:NSKeyValueObservingOptionNew context:SCRecorderExposureContext]; } - (void)removeVideoObservers:(AVCaptureDevice*)videoDevice { [videoDevice removeObserver:self forKeyPath:@"adjustingFocus"]; + [videoDevice removeObserver:self forKeyPath:@"adjustingExposure"]; } - (void)configureDevice:(AVCaptureDevice*)newDevice mediaType:(NSString*)mediaType error:(NSError**)error { @@ -1070,6 +1090,7 @@ - (void)_applyPointOfInterest:(CGPoint)point continuousMode:(BOOL)continuousMode NSError *error; if ([device lockForConfiguration:&error]) { BOOL focusing = NO; + BOOL adjustingExposure = NO; if (device.isFocusPointOfInterestSupported) { device.focusPointOfInterest = point; @@ -1085,6 +1106,7 @@ - (void)_applyPointOfInterest:(CGPoint)point continuousMode:(BOOL)continuousMode if ([device isExposureModeSupported:exposureMode]) { device.exposureMode = exposureMode; + adjustingExposure = YES; } if ([device isWhiteBalanceModeSupported:whiteBalanceMode]) { @@ -1093,14 +1115,20 @@ - (void)_applyPointOfInterest:(CGPoint)point continuousMode:(BOOL)continuousMode [device unlockForConfiguration]; + id delegate = self.delegate; if (focusMode != AVCaptureFocusModeContinuousAutoFocus && focusing) { - id delegate = self.delegate; if ([delegate respondsToSelector:@selector(recorderWillStartFocus:)]) { [delegate recorderWillStartFocus:self]; } [self setAdjustingFocus:YES]; } + + if (exposureMode != AVCaptureExposureModeContinuousAutoExposure && adjustingExposure) { + if ([delegate respondsToSelector:@selector(recorderWillStartAdjustingExposure:)]) { + [delegate recorderWillStartAdjustingExposure:self]; + } + } } } @@ -1124,6 +1152,14 @@ - (void)refocus { [self autoFocusAtPoint:self.focusPointOfInterest]; } +- (CGPoint)exposurePointOfInterest { + return [self.currentVideoDeviceInput device].exposurePointOfInterest; +} + +- (BOOL)exposureSupported { + return [self.currentVideoDeviceInput device].isExposurePointOfInterestSupported; +} + - (CGPoint)focusPointOfInterest { return [self.currentVideoDeviceInput device].focusPointOfInterest; } diff --git a/Library/Sources/SCRecorderDelegate.h b/Library/Sources/SCRecorderDelegate.h index 63dd550f..03f537ea 100644 --- a/Library/Sources/SCRecorderDelegate.h +++ b/Library/Sources/SCRecorderDelegate.h @@ -38,6 +38,12 @@ typedef NS_ENUM(NSInteger, SCFlashMode) { */ - (void)recorder:(SCRecorder *__nonnull)recorder didChangeFlashMode:(SCFlashMode)flashMode error:(NSError *__nullable)error; +/** + Called when the recorder has lost the focus. Returning true will make the recorder + automatically refocus at the center. + */ +- (BOOL)recorderShouldAutomaticallyRefocus:(SCRecorder *__nonnull)recorder; + /** Called before the recorder will start focusing */ @@ -53,6 +59,21 @@ typedef NS_ENUM(NSInteger, SCFlashMode) { */ - (void)recorderDidEndFocus:(SCRecorder *__nonnull)recorder; +/** + Called before the recorder will start adjusting exposure + */ +- (void)recorderWillStartAdjustingExposure:(SCRecorder *__nonnull)recorder; + +/** + Called when the recorder has started adjusting exposure + */ +- (void)recorderDidStartAdjustingExposure:(SCRecorder *__nonnull)recorder; + +/** + Called when the recorder has finished adjusting exposure + */ +- (void)recorderDidEndAdjustingExposure:(SCRecorder *__nonnull)recorder; + /** Called when the recorder has initialized the audio in a session */ diff --git a/Library/Sources/SCRecorderToolsView.m b/Library/Sources/SCRecorderToolsView.m index 5fffb960..b227f2f6 100644 --- a/Library/Sources/SCRecorderToolsView.m +++ b/Library/Sources/SCRecorderToolsView.m @@ -96,7 +96,15 @@ - (void)layoutSubviews { } - (void)adjustFocusView { - CGPoint currentFocusPoint = [self.recorder convertPointOfInterestToViewCoordinates:self.recorder.focusPointOfInterest]; + CGPoint currentFocusPoint = CGPointMake(0.5, 0.5); + + if (self.recorder.focusSupported) { + currentFocusPoint = self.recorder.focusPointOfInterest; + } else if (self.recorder.exposureSupported) { + currentFocusPoint = self.recorder.exposurePointOfInterest; + } + + [self.recorder convertPointOfInterestToViewCoordinates:currentFocusPoint]; currentFocusPoint = [self convertPoint:currentFocusPoint fromView:self.recorder.previewView]; self.cameraFocusTargetView.center = currentFocusPoint; }