Jonny Banana
6 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 2721 additions and 0 deletions
-
233Resource/SCCaptureResource.h
-
66Resource/SCCaptureResource.m
-
377Tweaks/SCCameraTweaks.h
-
396Tweaks/SCCameraTweaks.m
-
47UI/AVCameraViewEnums.h
-
32UI/Lenses/LensButtonZ/SCFeatureLensButtonZ.h
-
33UI/Lenses/LensSideButton/SCFeatureLensSideButton.h
-
24UI/SCLongPressGestureRecognizer.h
-
88UI/SCLongPressGestureRecognizer.m
-
31VolumeButton/SCCameraVolumeButtonHandler.h
-
190VolumeButton/SCCameraVolumeButtonHandler.m
-
109Worker/SCCaptureWorker.h
-
1095Worker/SCCaptureWorker.m
@ -0,0 +1,233 @@ |
|||||
|
// |
||||
|
// SCCaptureResource.h |
||||
|
// Snapchat |
||||
|
// |
||||
|
// Created by Lin Jia on 10/19/17. |
||||
|
// |
||||
|
// |
||||
|
|
||||
|
#import "SCManagedCapturerLensAPI.h" |
||||
|
#import "SCManagedCapturerListenerAnnouncer.h" |
||||
|
#import "SCSnapCreationTriggers.h" |
||||
|
|
||||
|
#import <SCCameraFoundation/SCManagedVideoDataSource.h> |
||||
|
|
||||
|
#import <FBKVOController/FBKVOController.h> |
||||
|
|
||||
|
#import <Foundation/Foundation.h> |
||||
|
|
||||
|
/* |
||||
|
In general, the function of SCCapturer is to use some resources (such as SCManagedCapturerListenerAnnouncer), to do |
||||
|
something (such as announce an event). |
||||
|
|
||||
|
SCCaptureResource abstract away the "resources" part of SCCapturer. It has no APIs itself, it is used to be the |
||||
|
resource which gets passed arround for capturer V2 state machine. |
||||
|
*/ |
||||
|
@class SCManagedDeviceCapacityAnalyzer; |
||||
|
|
||||
|
@class SCManagedCapturePreviewLayerController; |
||||
|
|
||||
|
@class ARSession; |
||||
|
|
||||
|
@class SCManagedVideoScanner; |
||||
|
|
||||
|
@class LSAGLView; |
||||
|
|
||||
|
@protocol SCManagedCapturerLSAComponentTrackerAPI; |
||||
|
|
||||
|
@class SCManagedStillImageCapturer; |
||||
|
|
||||
|
@class SCManagedVideoCapturer; |
||||
|
|
||||
|
@class SCQueuePerformer; |
||||
|
|
||||
|
@class SCManagedVideoFrameSampler; |
||||
|
|
||||
|
@class SCManagedDroppedFramesReporter; |
||||
|
|
||||
|
@class SCManagedVideoStreamReporter; |
||||
|
|
||||
|
@protocol SCManagedCapturerGLViewManagerAPI; |
||||
|
|
||||
|
@class SCCapturerToken; |
||||
|
|
||||
|
@class SCSingleFrameStreamCapturer; |
||||
|
|
||||
|
@class SCManagedFrontFlashController; |
||||
|
|
||||
|
@class SCManagedVideoCapturerHandler; |
||||
|
|
||||
|
@class SCManagedStillImageCapturerHandler; |
||||
|
|
||||
|
@class SCManagedDeviceCapacityAnalyzerHandler; |
||||
|
|
||||
|
@class SCManagedCaptureDeviceDefaultZoomHandler; |
||||
|
|
||||
|
@class SCManagedCaptureDeviceHandler; |
||||
|
|
||||
|
@class SCBlackCameraNoOutputDetector; |
||||
|
|
||||
|
@class SCCaptureSessionFixer; |
||||
|
|
||||
|
@protocol SCCaptureFaceDetector; |
||||
|
|
||||
|
@protocol SCManagedCapturerLensAPI; |
||||
|
|
||||
|
@protocol SCManagedCapturerARImageCaptureProvider; |
||||
|
|
||||
|
@class SCManagedCapturerARSessionHandler; |
||||
|
|
||||
|
@class SCManagedCaptureDeviceSubjectAreaHandler; |
||||
|
|
||||
|
@class SCManagedCaptureSession; |
||||
|
|
||||
|
@class SCBlackCameraDetector; |
||||
|
|
||||
|
@protocol SCLensProcessingCore; |
||||
|
|
||||
|
@protocol SCManagedCapturerLensAPI; |
||||
|
|
||||
|
@protocol SCManagedCapturePreviewLayerControllerDelegate; |
||||
|
|
||||
|
typedef enum : NSUInteger { |
||||
|
SCManagedCapturerStatusUnknown = 0, |
||||
|
SCManagedCapturerStatusReady, |
||||
|
SCManagedCapturerStatusRunning, |
||||
|
} SCManagedCapturerStatus; |
||||
|
|
||||
|
@protocol SCDeviceMotionProvider |
||||
|
|
||||
|
@property (nonatomic, readonly) BOOL isUnderDeviceMotion; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
@protocol SCFileInputDecider |
||||
|
|
||||
|
@property (nonatomic, readonly) BOOL shouldProcessFileInput; |
||||
|
@property (nonatomic, readonly) NSURL *fileURL; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
@interface SCCaptureResource : NSObject |
||||
|
|
||||
|
@property (nonatomic, readwrite, assign) SCManagedCapturerStatus status; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedCapturerState *state; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedCaptureDevice *device; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCManagedCapturerLensAPI> lensProcessingCore; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCManagedCapturerLensAPIProvider> lensAPIProvider; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) ARSession *arSession NS_AVAILABLE_IOS(11_0); |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedStillImageCapturer *arImageCapturer NS_AVAILABLE_IOS(11_0); |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedCaptureSession *managedSession; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCManagedVideoDataSource> videoDataSource; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedDeviceCapacityAnalyzer *deviceCapacityAnalyzer; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedVideoScanner *videoScanner; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedCapturerListenerAnnouncer *announcer; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) AVCaptureVideoPreviewLayer *videoPreviewLayer; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCManagedCapturerGLViewManagerAPI> videoPreviewGLViewManager; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedStillImageCapturer *stillImageCapturer; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedVideoCapturer *videoCapturer; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCQueuePerformer *queuePerformer; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedVideoFrameSampler *videoFrameSampler; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedDroppedFramesReporter *droppedFramesReporter; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedVideoStreamReporter *videoStreamReporter; // INTERNAL USE ONLY |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedFrontFlashController *frontFlashController; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedVideoCapturerHandler *videoCapturerHandler; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedStillImageCapturerHandler *stillImageCapturerHandler; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedDeviceCapacityAnalyzerHandler *deviceCapacityAnalyzerHandler; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedCaptureDeviceDefaultZoomHandler *deviceZoomHandler; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedCaptureDeviceHandler *captureDeviceHandler; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCCaptureFaceDetector> captureFaceDetector; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) FBKVOController *kvoController; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCManagedCapturerLSAComponentTrackerAPI> lsaTrackingComponentHandler; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedCapturerARSessionHandler *arSessionHandler; |
||||
|
|
||||
|
@property (nonatomic, assign) SEL completeARSessionShutdown; |
||||
|
|
||||
|
@property (nonatomic, assign) SEL handleAVSessionStatusChange; |
||||
|
|
||||
|
@property (nonatomic, assign) BOOL videoRecording; |
||||
|
|
||||
|
@property (nonatomic, assign) NSInteger numRetriesFixAVCaptureSessionWithCurrentSession; |
||||
|
|
||||
|
@property (nonatomic, assign) BOOL appInBackground; |
||||
|
|
||||
|
@property (nonatomic, assign) NSUInteger streamingSequence; |
||||
|
|
||||
|
@property (nonatomic, assign) BOOL stillImageCapturing; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) NSTimer *livenessTimer; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) NSMutableSet<SCCapturerToken *> *tokenSet; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCSingleFrameStreamCapturer *frameCap; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCManagedSampleBufferDisplayController> sampleBufferDisplayController; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCSnapCreationTriggers *snapCreationTriggers; |
||||
|
|
||||
|
// Different from most properties above, following are main thread properties. |
||||
|
@property (nonatomic, assign) BOOL allowsZoom; |
||||
|
|
||||
|
@property (nonatomic, assign) NSUInteger numRetriesFixInconsistencyWithCurrentSession; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) NSMutableDictionary *debugInfoDict; |
||||
|
|
||||
|
@property (nonatomic, assign) BOOL notificationRegistered; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCManagedCaptureDeviceSubjectAreaHandler *deviceSubjectAreaHandler; |
||||
|
|
||||
|
@property (nonatomic, assign) SEL sessionRuntimeError; |
||||
|
|
||||
|
@property (nonatomic, assign) SEL livenessConsistency; |
||||
|
|
||||
|
// TODO: these properties will be refactored into SCCaptureSessionFixer class |
||||
|
// The refactor will be in a separate PR |
||||
|
// Timestamp when _fixAVSessionIfNecessary is called |
||||
|
@property (nonatomic, assign) NSTimeInterval lastFixSessionTimestamp; |
||||
|
// Timestamp when session runtime error is handled |
||||
|
@property (nonatomic, assign) NSTimeInterval lastSessionRuntimeErrorTime; |
||||
|
// Wether we schedule fix of creating session already |
||||
|
@property (nonatomic, assign) BOOL isRecreateSessionFixScheduled; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCCaptureSessionFixer *captureSessionFixer; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) SCBlackCameraDetector *blackCameraDetector; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCDeviceMotionProvider> deviceMotionProvider; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCManagedCapturerARImageCaptureProvider> arImageCaptureProvider; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) id<SCFileInputDecider> fileInputDecider; |
||||
|
|
||||
|
@property (nonatomic, readwrite, strong) |
||||
|
id<SCManagedCapturePreviewLayerControllerDelegate> previewLayerControllerDelegate; |
||||
|
@end |
@ -0,0 +1,66 @@ |
|||||
|
// |
||||
|
// SCCaptureResource.m |
||||
|
// Snapchat |
||||
|
// |
||||
|
// Created by Lin Jia on 10/19/17. |
||||
|
// |
||||
|
// |
||||
|
|
||||
|
#import "SCCaptureResource.h" |
||||
|
|
||||
|
#import "SCBlackCameraDetector.h" |
||||
|
#import "SCManagedCapturerState.h" |
||||
|
#import "SCManagedFrontFlashController.h" |
||||
|
#import "SCManagedVideoCapturer.h" |
||||
|
|
||||
|
#import <SCFoundation/SCAssertWrapper.h> |
||||
|
#import <SCFoundation/SCQueuePerformer.h> |
||||
|
#import <SCFoundation/SCTraceODPCompatible.h> |
||||
|
|
||||
|
#import <FBKVOController/FBKVOController.h> |
||||
|
|
||||
|
@interface SCCaptureResource () { |
||||
|
FBKVOController *_previewHiddenKVO; |
||||
|
} |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
@implementation SCCaptureResource |
||||
|
|
||||
|
- (SCManagedFrontFlashController *)frontFlashController |
||||
|
{ |
||||
|
SCTraceODPCompatibleStart(2); |
||||
|
SCAssert([self.queuePerformer isCurrentPerformer], @""); |
||||
|
if (!_frontFlashController) { |
||||
|
_frontFlashController = [[SCManagedFrontFlashController alloc] init]; |
||||
|
} |
||||
|
return _frontFlashController; |
||||
|
} |
||||
|
|
||||
|
- (void)setVideoPreviewLayer:(AVCaptureVideoPreviewLayer *)layer |
||||
|
{ |
||||
|
SC_GUARD_ELSE_RETURN(layer != _videoPreviewLayer); |
||||
|
|
||||
|
if (_videoPreviewLayer) { |
||||
|
[_previewHiddenKVO unobserve:_videoPreviewLayer]; |
||||
|
} |
||||
|
_videoPreviewLayer = layer; |
||||
|
|
||||
|
SC_GUARD_ELSE_RETURN(_videoPreviewLayer); |
||||
|
|
||||
|
if (!_previewHiddenKVO) { |
||||
|
_previewHiddenKVO = [[FBKVOController alloc] initWithObserver:self]; |
||||
|
} |
||||
|
|
||||
|
[_previewHiddenKVO observe:_videoPreviewLayer |
||||
|
keyPath:@keypath(_videoPreviewLayer.hidden) |
||||
|
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld |
||||
|
block:^(id observer, id object, NSDictionary *change) { |
||||
|
BOOL oldValue = [change[NSKeyValueChangeOldKey] boolValue]; |
||||
|
BOOL newValue = [change[NSKeyValueChangeNewKey] boolValue]; |
||||
|
if (oldValue != newValue) { |
||||
|
[_blackCameraDetector capturePreviewDidBecomeVisible:!newValue]; |
||||
|
} |
||||
|
}]; |
||||
|
} |
||||
|
@end |
@ -0,0 +1,377 @@ |
|||||
|
// |
||||
|
// SCCameraTweaks.h |
||||
|
// Snapchat |
||||
|
// |
||||
|
// Created by Liu Liu on 9/16/15. |
||||
|
// Copyright © 2015 Snapchat, Inc. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
#import <SCBase/SCMacros.h> |
||||
|
#import <SCCameraFoundation/SCManagedCaptureDevicePosition.h> |
||||
|
#import <SCTweakAdditions/SCTweakDefines.h> |
||||
|
|
||||
|
#import <Tweaks/FBTweakInline.h> |
||||
|
|
||||
|
#import <CoreGraphics/CoreGraphics.h> |
||||
|
#import <Foundation/Foundation.h> |
||||
|
|
||||
|
// Core Camera |
||||
|
|
||||
|
typedef NS_ENUM(NSUInteger, SCManagedCaptureDeviceZoomHandlerType) { |
||||
|
SCManagedCaptureDeviceDefaultZoom, |
||||
|
SCManagedCaptureDeviceSavitzkyGolayFilter, |
||||
|
SCManagedCaptureDeviceLinearInterpolation, |
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSUInteger, SCCameraTweaksStrategyType) { |
||||
|
SCCameraTweaksStrategyFollowABTest = 0, |
||||
|
SCCameraTweaksStrategyOverrideToYes, |
||||
|
SCCameraTweaksStrategyOverrideToNo |
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSUInteger, SCCameraHandsFreeModeType) { |
||||
|
SCCameraHandsFreeModeTypeABTest = 0, |
||||
|
SCCameraHandsFreeModeTypeDisabled, |
||||
|
SCCameraHandsFreeModeTypeMainOnly, |
||||
|
SCCameraHandsFreeModeTypeChatMoveCaptureButton, |
||||
|
SCCameraHandsFreeModeTypeMainAndChat, |
||||
|
SCCameraHandsFreeModeTypeLeftOfCapture, |
||||
|
}; |
||||
|
|
||||
|
/// Face detection and focus strategy in Tweak. There are less options in internal Tweaks than the A/B testing |
||||
|
/// strategies. |
||||
|
typedef NS_ENUM(NSUInteger, SCCameraFaceFocusModeStrategyType) { |
||||
|
SCCameraFaceFocusModeStrategyTypeABTest = 0, |
||||
|
SCCameraFaceFocusModeStrategyTypeDisabled, // Disabled for both cameras. |
||||
|
SCCameraFaceFocusModeStrategyTypeOffByDefault, // Enabled for both cameras, but is off by default. |
||||
|
SCCameraFaceFocusModeStrategyTypeOnByDefault, // Enabled for both cameras, but is off by default. |
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSUInteger, SCCameraFaceFocusDetectionMethodType) { |
||||
|
SCCameraFaceFocusDetectionMethodTypeABTest = 0, |
||||
|
SCCameraFaceFocusDetectionMethodTypeCIDetector, // Use SCCaptureCoreImageFaceDetector |
||||
|
SCCameraFaceFocusDetectionMethodTypeAVMetadata, // Use SCCaptureMetadataOutputDetector |
||||
|
}; |
||||
|
|
||||
|
SC_EXTERN_C_BEGIN |
||||
|
|
||||
|
extern SCManagedCaptureDeviceZoomHandlerType SCCameraTweaksDeviceZoomHandlerStrategy(void); |
||||
|
|
||||
|
extern BOOL SCCameraTweaksBlackCameraRecoveryEnabled(void); |
||||
|
|
||||
|
extern BOOL SCCameraTweaksMicPermissionEnabled(void); |
||||
|
|
||||
|
extern BOOL SCCameraTweaksEnableCaptureKeepRecordedVideo(void); |
||||
|
|
||||
|
extern BOOL SCCameraTweaksEnableHandsFreeXToCancel(void); |
||||
|
extern SCCameraHandsFreeModeType SCCameraTweaksHandsFreeMode(void); |
||||
|
|
||||
|
BOOL SCCameraTweaksEnableShortPreviewTransitionAnimationDuration(void); |
||||
|
|
||||
|
extern BOOL SCCameraTweaksEnablePreviewPresenterFastPreview(void); |
||||
|
|
||||
|
extern BOOL SCCameraTweaksEnableCaptureSharePerformer(void); |
||||
|
|
||||
|
extern BOOL SCCameraTweaksEnableFaceDetectionFocus(SCManagedCaptureDevicePosition captureDevicePosition); |
||||
|
|
||||
|
extern BOOL SCCameraTweaksTurnOnFaceDetectionFocusByDefault(SCManagedCaptureDevicePosition captureDevicePosition); |
||||
|
|
||||
|
extern SCCameraFaceFocusDetectionMethodType SCCameraFaceFocusDetectionMethod(void); |
||||
|
|
||||
|
extern CGFloat SCCameraFaceFocusMinFaceSize(void); |
||||
|
|
||||
|
extern BOOL SCCameraTweaksSessionLightWeightFixEnabled(void); |
||||
|
|
||||
|
SC_EXTERN_C_END |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnableVideoStabilization(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera", @"Enable video stabilization", NO); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnableForceTouchToToggleCamera(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Recording", @"Force Touch to Toggle", NO); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnableStayOnCameraAfterPostingStory(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Story", @"Stay on camera after posting", NO); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnableKeepLastFrameOnCamera(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera", @"Keep last frame on camera", YES); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksSmoothAutoFocusWhileRecording(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera", @"Smooth autofocus while recording", YES); |
||||
|
} |
||||
|
|
||||
|
static inline NSInteger SCCameraExposureAdjustmentMode(void) |
||||
|
{ |
||||
|
return [FBTweakValue( |
||||
|
@"Camera", @"Core Camera", @"Adjust Exposure", (id) @0, |
||||
|
(@{ @0 : @"NO", |
||||
|
@1 : @"Dynamic enhancement", |
||||
|
@2 : @"Night vision", |
||||
|
@3 : @"Inverted night vision" })) integerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksRotateToggleCameraButton(void) |
||||
|
{ |
||||
|
return SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Rotate Toggle-Camera Button", NO); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksRotateToggleCameraButtonTime(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera", @"Toggle-Camera Button Rotation Time", 0.3); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksDefaultPortrait(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera", @"Default to Portrait Orientation", YES); |
||||
|
} |
||||
|
|
||||
|
// For test purpose |
||||
|
static inline BOOL SCCameraTweaksTranscodingAlwaysFails(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera", @"Transcoding always fails", NO); |
||||
|
} |
||||
|
|
||||
|
// This tweak disables the video masking behavior of the snap overlays; |
||||
|
// Intended to be used by curators who are on-site snapping special events. |
||||
|
// Ping news-dev@snapchat.com for any questions/comments |
||||
|
static inline BOOL SCCameraTweaksDisableOverlayVideoMask(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Creative Tools", @"Disable Overlay Video Masking", NO); |
||||
|
} |
||||
|
|
||||
|
static inline NSInteger SCCameraTweaksDelayTurnOnFilters(void) |
||||
|
{ |
||||
|
return [FBTweakValue(@"Camera", @"Core Camera", @"Delay turn on filter", (id) @0, |
||||
|
(@{ @0 : @"Respect A/B testing", |
||||
|
@1 : @"Override to YES", |
||||
|
@2 : @"Override to NO" })) integerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnableExposurePointObservation(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Face Focus", @"Observe Exposure Point", NO); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnableFocusPointObservation(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Face Focus", @"Observe Focus Point", NO); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksSmoothZoomThresholdTime() |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Threshold time", 0.3); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksSmoothZoomThresholdFactor() |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Threshold factor diff", 0.25); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksSmoothZoomIntermediateFramesPerSecond() |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Intermediate fps", 60); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksSmoothZoomDelayTolerantTime() |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Delay tolerant time", 0.15); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksSmoothZoomMinStepLength() |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Zoom Strategy - Linear Interpolation", @"Min step length", 0.05); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksExposureDeadline() |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Adjust Exposure", @"Exposure Deadline", 0.2); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksKillFrontCamera(void) |
||||
|
{ |
||||
|
return SCTweakValueWithHalt(@"Camera", @"Debugging", @"Kill Front Camera", NO); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksKillBackCamera(void) |
||||
|
{ |
||||
|
return SCTweakValueWithHalt(@"Camera", @"Debugging", @"Kill Back Camera", NO); |
||||
|
} |
||||
|
|
||||
|
#if TARGET_IPHONE_SIMULATOR |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksUseRealMockImage(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Debugging", @"Use real mock image on simulator", YES); |
||||
|
} |
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksShortPreviewTransitionAnimationDuration() |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Preview Transition", @"Short Animation Duration", 0.35); |
||||
|
} |
||||
|
|
||||
|
static inline SCCameraTweaksStrategyType SCCameraTweaksPreviewTransitionAnimationDurationStrategy() |
||||
|
{ |
||||
|
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Preview Transition", @"Enable Short Animation Duration", |
||||
|
(id) @(SCCameraTweaksStrategyFollowABTest), (@{ |
||||
|
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES", |
||||
|
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO" |
||||
|
})); |
||||
|
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksEnablePortraitModeButton(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Enable Button", NO); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksDepthBlurForegroundThreshold(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Foreground Blur Threshold", 0.3); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksDepthBlurBackgroundThreshold(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Background Blur Threshold", 0.1); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksBlurSigma(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Blur Sigma", 4.0); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnableFilterInputFocusRect(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Filter Input Focus Rect", NO); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnablePortraitModeTapToFocus(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Tap to Focus", NO); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnablePortraitModeAutofocus(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Autofocus", NO); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksDepthToGrayscaleOverride(void) |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Portrait Mode", @"Depth to Grayscale Override", NO); |
||||
|
} |
||||
|
|
||||
|
static inline SCCameraTweaksStrategyType SCCameraTweaksEnableHandsFreeXToCancelStrategy(void) |
||||
|
{ |
||||
|
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Hands-Free Recording", @"X to Cancel", |
||||
|
(id) @(SCCameraTweaksStrategyFollowABTest), (@{ |
||||
|
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES", |
||||
|
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO" |
||||
|
})); |
||||
|
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline SCCameraHandsFreeModeType SCCameraTweaksHandsFreeModeType() |
||||
|
{ |
||||
|
NSNumber *strategy = SCTweakValueWithHalt( |
||||
|
@"Camera", @"Hands-Free Recording", @"Enabled", (id) @(SCCameraHandsFreeModeTypeABTest), (@{ |
||||
|
@(SCCameraHandsFreeModeTypeABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraHandsFreeModeTypeDisabled) : @"Disable", |
||||
|
@(SCCameraHandsFreeModeTypeMainOnly) : @"Main Camera only", |
||||
|
@(SCCameraHandsFreeModeTypeChatMoveCaptureButton) : @"Main Camera + move Chat capture button", |
||||
|
@(SCCameraHandsFreeModeTypeMainAndChat) : @"Main + Chat Cameras", |
||||
|
@(SCCameraHandsFreeModeTypeLeftOfCapture) : @"Left of Main + Chat Cameras" |
||||
|
})); |
||||
|
return (SCCameraHandsFreeModeType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline SCCameraTweaksStrategyType SCCameraTweaksPreviewPresenterFastPreviewStrategy(void) |
||||
|
{ |
||||
|
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Preview Presenter", @"Fast Preview", |
||||
|
(id) @(SCCameraTweaksStrategyFollowABTest), (@{ |
||||
|
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES", |
||||
|
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO" |
||||
|
})); |
||||
|
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline NSInteger SCCameraTweaksEnableCaptureKeepRecordedVideoStrategy(void) |
||||
|
{ |
||||
|
NSNumber *strategy = |
||||
|
SCTweakValueWithHalt(@"Camera", @"Core Camera - Capture Keep Recorded Video", |
||||
|
@"Enable Capture Keep Recorded Video", (id) @(SCCameraTweaksStrategyFollowABTest), (@{ |
||||
|
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES", |
||||
|
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO" |
||||
|
})); |
||||
|
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline NSInteger SCCameraTweaksEnableCaptureSharePerformerStrategy(void) |
||||
|
{ |
||||
|
NSNumber *strategy = |
||||
|
SCTweakValueWithHalt(@"Camera", @"Core Camera - Capture Share Performer", @"Enable Capture Share Performer", |
||||
|
(id) @(SCCameraTweaksStrategyFollowABTest), (@{ |
||||
|
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES", |
||||
|
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO" |
||||
|
})); |
||||
|
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline SCCameraFaceFocusModeStrategyType SCCameraTweaksFaceFocusStrategy() |
||||
|
{ |
||||
|
NSNumber *strategy = |
||||
|
SCTweakValueWithHalt(@"Camera", @"Core Camera - Face Focus", @"Enable Face Focus", |
||||
|
(id) @(SCCameraFaceFocusModeStrategyTypeABTest), (@{ |
||||
|
@(SCCameraFaceFocusModeStrategyTypeABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraFaceFocusModeStrategyTypeDisabled) : @"Disabled", |
||||
|
@(SCCameraFaceFocusModeStrategyTypeOffByDefault) : @"Enabled, off by default", |
||||
|
@(SCCameraFaceFocusModeStrategyTypeOnByDefault) : @"Enabled, on by default", |
||||
|
})); |
||||
|
return (SCCameraFaceFocusModeStrategyType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline SCCameraFaceFocusDetectionMethodType SCCameraTweaksFaceFocusDetectionMethodType() |
||||
|
{ |
||||
|
NSNumber *strategy = |
||||
|
SCTweakValueWithHalt(@"Camera", @"Core Camera - Face Focus", @"Detection Method", |
||||
|
(id) @(SCCameraFaceFocusDetectionMethodTypeABTest), (@{ |
||||
|
@(SCCameraFaceFocusDetectionMethodTypeABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraFaceFocusDetectionMethodTypeCIDetector) : @"CIDetector", |
||||
|
@(SCCameraFaceFocusDetectionMethodTypeAVMetadata) : @"AVMetadata", |
||||
|
})); |
||||
|
return (SCCameraFaceFocusDetectionMethodType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
static inline int SCCameraTweaksFaceFocusDetectionFrequency() |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Face Focus", @"Detection Frequency", 3, 1, 30); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksFaceFocusMinFaceSizeRespectABTesting() |
||||
|
{ |
||||
|
return SCTweakValueWithHalt(@"Camera", @"Core Camera - Face Focus", @"Min Face Size Respect AB", YES); |
||||
|
} |
||||
|
|
||||
|
static inline CGFloat SCCameraTweaksFaceFocusMinFaceSizeValue() |
||||
|
{ |
||||
|
return FBTweakValue(@"Camera", @"Core Camera - Face Focus", @"Min Face Size", 0.25, 0.01, 0.5); |
||||
|
} |
||||
|
|
||||
|
static inline BOOL SCCameraTweaksEnableDualCamera(void) |
||||
|
{ |
||||
|
return SCTweakValueWithHalt(@"Camera", @"Core Camera - Dual Camera", @"Enable Dual Camera", NO); |
||||
|
} |
@ -0,0 +1,396 @@ |
|||||
|
// |
||||
|
// SCCameraTweaks.m |
||||
|
// Snapchat |
||||
|
// |
||||
|
// Created by Liu Liu on 10/4/16. |
||||
|
// Copyright © 2016 Snapchat, Inc. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
#import "SCCameraTweaks.h" |
||||
|
|
||||
|
#import "SCManagedCapturePreviewLayerController.h" |
||||
|
|
||||
|
#import <SCFoundation/SCDeviceName.h> |
||||
|
#import <SCFoundation/SCZeroDependencyExperiments.h> |
||||
|
#import <SCTweakAdditions/SCTweakDefines.h> |
||||
|
|
||||
|
SCManagedCaptureDeviceZoomHandlerType SCCameraTweaksDeviceZoomHandlerStrategy(void) |
||||
|
{ |
||||
|
|
||||
|
NSNumber *strategyNumber = SCTweakValueWithHalt( |
||||
|
@"Camera", @"Core Camera", @"Zoom Strategy", |
||||
|
@(SCIsMasterBuild() ? SCManagedCaptureDeviceLinearInterpolation : SCManagedCaptureDeviceDefaultZoom), (@{ |
||||
|
@(SCManagedCaptureDeviceDefaultZoom) : @"Default", |
||||
|
@(SCManagedCaptureDeviceSavitzkyGolayFilter) : @"Savitzky-Golay Filter", |
||||
|
@(SCManagedCaptureDeviceLinearInterpolation) : @"Linear Interpolation" |
||||
|
})); |
||||
|
return (SCManagedCaptureDeviceZoomHandlerType)[strategyNumber integerValue]; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksEnableFaceDetectionFocus(SCManagedCaptureDevicePosition captureDevicePosition) |
||||
|
{ |
||||
|
SC_GUARD_ELSE_RETURN_VALUE([SCDeviceName isIphone], NO); |
||||
|
SC_GUARD_ELSE_RETURN_VALUE(captureDevicePosition != SCManagedCaptureDevicePositionBackDualCamera, NO); |
||||
|
|
||||
|
BOOL isFrontCamera = (captureDevicePosition == SCManagedCaptureDevicePositionFront); |
||||
|
BOOL isEnabled = NO; |
||||
|
SCCameraFaceFocusModeStrategyType option = SCCameraTweaksFaceFocusStrategy(); |
||||
|
switch (option) { |
||||
|
case SCCameraFaceFocusModeStrategyTypeABTest: |
||||
|
if (isFrontCamera) { |
||||
|
isEnabled = SCExperimentWithFaceDetectionFocusFrontCameraEnabled(); |
||||
|
} else { |
||||
|
isEnabled = SCExperimentWithFaceDetectionFocusBackCameraEnabled(); |
||||
|
} |
||||
|
break; |
||||
|
case SCCameraFaceFocusModeStrategyTypeDisabled: |
||||
|
isEnabled = NO; |
||||
|
break; |
||||
|
case SCCameraFaceFocusModeStrategyTypeOffByDefault: |
||||
|
case SCCameraFaceFocusModeStrategyTypeOnByDefault: |
||||
|
isEnabled = YES; |
||||
|
break; |
||||
|
} |
||||
|
return isEnabled; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksTurnOnFaceDetectionFocusByDefault(SCManagedCaptureDevicePosition captureDevicePosition) |
||||
|
{ |
||||
|
SC_GUARD_ELSE_RETURN_VALUE([SCDeviceName isIphone], NO); |
||||
|
SC_GUARD_ELSE_RETURN_VALUE(captureDevicePosition != SCManagedCaptureDevicePositionBackDualCamera, NO); |
||||
|
|
||||
|
BOOL isFrontCamera = (captureDevicePosition == SCManagedCaptureDevicePositionFront); |
||||
|
BOOL isOnByDefault = NO; |
||||
|
SCCameraFaceFocusModeStrategyType option = SCCameraTweaksFaceFocusStrategy(); |
||||
|
switch (option) { |
||||
|
case SCCameraFaceFocusModeStrategyTypeABTest: |
||||
|
if (isFrontCamera) { |
||||
|
isOnByDefault = SCExperimentWithFaceDetectionFocusFrontCameraOnByDefault(); |
||||
|
} else { |
||||
|
isOnByDefault = SCExperimentWithFaceDetectionFocusBackCameraOnByDefault(); |
||||
|
} |
||||
|
break; |
||||
|
case SCCameraFaceFocusModeStrategyTypeDisabled: |
||||
|
case SCCameraFaceFocusModeStrategyTypeOffByDefault: |
||||
|
isOnByDefault = NO; |
||||
|
break; |
||||
|
case SCCameraFaceFocusModeStrategyTypeOnByDefault: |
||||
|
isOnByDefault = YES; |
||||
|
break; |
||||
|
} |
||||
|
return isOnByDefault; |
||||
|
} |
||||
|
|
||||
|
SCCameraFaceFocusDetectionMethodType SCCameraFaceFocusDetectionMethod() |
||||
|
{ |
||||
|
static SCCameraFaceFocusDetectionMethodType detectionMethodType; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
SCCameraFaceFocusDetectionMethodType option = SCCameraTweaksFaceFocusDetectionMethodType(); |
||||
|
switch (option) { |
||||
|
case SCCameraFaceFocusDetectionMethodTypeABTest: { |
||||
|
// Check the validity of AB value. |
||||
|
NSUInteger experimentValue = SCExperimentWithFaceDetectionFocusDetectionMethod(); |
||||
|
if (experimentValue >= SCCameraFaceFocusDetectionMethodTypeCIDetector && |
||||
|
experimentValue <= SCCameraFaceFocusDetectionMethodTypeAVMetadata) { |
||||
|
detectionMethodType = experimentValue; |
||||
|
} else { |
||||
|
// Use CIDetector by default. |
||||
|
detectionMethodType = SCCameraFaceFocusDetectionMethodTypeCIDetector; |
||||
|
} |
||||
|
} break; |
||||
|
case SCCameraFaceFocusDetectionMethodTypeAVMetadata: |
||||
|
detectionMethodType = SCCameraFaceFocusDetectionMethodTypeAVMetadata; |
||||
|
break; |
||||
|
case SCCameraFaceFocusDetectionMethodTypeCIDetector: |
||||
|
detectionMethodType = SCCameraFaceFocusDetectionMethodTypeCIDetector; |
||||
|
break; |
||||
|
} |
||||
|
}); |
||||
|
return detectionMethodType; |
||||
|
} |
||||
|
|
||||
|
CGFloat SCCameraFaceFocusMinFaceSize(void) |
||||
|
{ |
||||
|
static CGFloat minFaceSize; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
if (SCCameraTweaksFaceFocusMinFaceSizeRespectABTesting()) { |
||||
|
minFaceSize = (CGFloat)SCExperimentWithFaceDetectionMinFaceSize(); |
||||
|
} else { |
||||
|
minFaceSize = SCCameraTweaksFaceFocusMinFaceSizeValue(); |
||||
|
} |
||||
|
if (minFaceSize < 0.01 || minFaceSize > 0.5) { |
||||
|
minFaceSize = 0.25; // Default value is 0.25 |
||||
|
} |
||||
|
}); |
||||
|
return minFaceSize; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksEnableCaptureKeepRecordedVideo(void) |
||||
|
{ |
||||
|
static BOOL enableCaptureKeepRecordedVideo; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
switch (SCCameraTweaksEnableCaptureKeepRecordedVideoStrategy()) { |
||||
|
case SCCameraTweaksStrategyOverrideToYes: { |
||||
|
enableCaptureKeepRecordedVideo = YES; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyOverrideToNo: { |
||||
|
enableCaptureKeepRecordedVideo = NO; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyFollowABTest: { |
||||
|
enableCaptureKeepRecordedVideo = SCExperimentWithCaptureKeepRecordedVideo(); |
||||
|
break; |
||||
|
} |
||||
|
default: { |
||||
|
enableCaptureKeepRecordedVideo = NO; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
return enableCaptureKeepRecordedVideo; |
||||
|
} |
||||
|
|
||||
|
static inline SCCameraTweaksStrategyType SCCameraTweaksBlackCameraRecoveryStrategy(void) |
||||
|
{ |
||||
|
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Black Camera Recovery", |
||||
|
(id) @(SCCameraTweaksStrategyFollowABTest), (@{ |
||||
|
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES", |
||||
|
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO" |
||||
|
})); |
||||
|
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksBlackCameraRecoveryEnabled(void) |
||||
|
{ |
||||
|
static BOOL enabled; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
switch (SCCameraTweaksBlackCameraRecoveryStrategy()) { |
||||
|
case SCCameraTweaksStrategyOverrideToYes: |
||||
|
enabled = YES; |
||||
|
break; |
||||
|
case SCCameraTweaksStrategyOverrideToNo: |
||||
|
enabled = NO; |
||||
|
break; |
||||
|
case SCCameraTweaksStrategyFollowABTest: |
||||
|
enabled = SCExperimentWithBlackCameraRecovery(); |
||||
|
break; |
||||
|
default: |
||||
|
enabled = NO; |
||||
|
break; |
||||
|
} |
||||
|
}); |
||||
|
return enabled; |
||||
|
} |
||||
|
|
||||
|
static inline SCCameraTweaksStrategyType SCCameraTweaksMicrophoneNotificationStrategy(void) |
||||
|
{ |
||||
|
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Mic Notification", |
||||
|
(id) @(SCCameraTweaksStrategyFollowABTest), (@{ |
||||
|
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES", |
||||
|
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO" |
||||
|
})); |
||||
|
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksMicPermissionEnabled(void) |
||||
|
{ |
||||
|
static BOOL enabled; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
switch (SCCameraTweaksMicrophoneNotificationStrategy()) { |
||||
|
case SCCameraTweaksStrategyOverrideToYes: |
||||
|
enabled = YES; |
||||
|
break; |
||||
|
case SCCameraTweaksStrategyOverrideToNo: |
||||
|
enabled = NO; |
||||
|
break; |
||||
|
case SCCameraTweaksStrategyFollowABTest: |
||||
|
enabled = SCExperimentWithMicrophonePermissionNotificationEnabled(); |
||||
|
break; |
||||
|
default: |
||||
|
enabled = NO; |
||||
|
break; |
||||
|
} |
||||
|
}); |
||||
|
return enabled; |
||||
|
} |
||||
|
|
||||
|
SCCameraHandsFreeModeType SCCameraTweaksHandsFreeMode(void) |
||||
|
{ |
||||
|
static SCCameraHandsFreeModeType handsFreeModeType; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
SCCameraHandsFreeModeType option = SCCameraTweaksHandsFreeModeType(); |
||||
|
switch (option) { |
||||
|
case SCCameraHandsFreeModeTypeDisabled: |
||||
|
handsFreeModeType = SCCameraHandsFreeModeTypeDisabled; |
||||
|
break; |
||||
|
case SCCameraHandsFreeModeTypeMainOnly: |
||||
|
handsFreeModeType = SCCameraHandsFreeModeTypeMainOnly; |
||||
|
break; |
||||
|
case SCCameraHandsFreeModeTypeChatMoveCaptureButton: |
||||
|
handsFreeModeType = SCCameraHandsFreeModeTypeChatMoveCaptureButton; |
||||
|
break; |
||||
|
case SCCameraHandsFreeModeTypeMainAndChat: |
||||
|
handsFreeModeType = SCCameraHandsFreeModeTypeMainAndChat; |
||||
|
break; |
||||
|
case SCCameraHandsFreeModeTypeLeftOfCapture: |
||||
|
handsFreeModeType = SCCameraHandsFreeModeTypeLeftOfCapture; |
||||
|
break; |
||||
|
case SCCameraHandsFreeModeTypeABTest: |
||||
|
default: |
||||
|
handsFreeModeType = SCExperimentWithHandsFreeMode(); |
||||
|
break; |
||||
|
} |
||||
|
}); |
||||
|
return handsFreeModeType; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksEnableHandsFreeXToCancel(void) |
||||
|
{ |
||||
|
static BOOL enableHandsFreeXToCancel; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
switch (SCCameraTweaksEnableHandsFreeXToCancelStrategy()) { |
||||
|
case SCCameraTweaksStrategyOverrideToYes: { |
||||
|
enableHandsFreeXToCancel = YES; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyOverrideToNo: { |
||||
|
enableHandsFreeXToCancel = NO; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyFollowABTest: { |
||||
|
enableHandsFreeXToCancel = SCExperimentWithHandsFreeXToCancel(); |
||||
|
break; |
||||
|
} |
||||
|
default: { |
||||
|
enableHandsFreeXToCancel = NO; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
return enableHandsFreeXToCancel; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksEnableShortPreviewTransitionAnimationDuration(void) |
||||
|
{ |
||||
|
static BOOL enableShortPreviewTransitionAnimationDuration; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
switch (SCCameraTweaksPreviewTransitionAnimationDurationStrategy()) { |
||||
|
case SCCameraTweaksStrategyOverrideToYes: { |
||||
|
enableShortPreviewTransitionAnimationDuration = YES; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyOverrideToNo: { |
||||
|
enableShortPreviewTransitionAnimationDuration = NO; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyFollowABTest: { |
||||
|
enableShortPreviewTransitionAnimationDuration = SCExperimentWithShortPreviewTransitionAnimationDuration(); |
||||
|
break; |
||||
|
} |
||||
|
default: { |
||||
|
enableShortPreviewTransitionAnimationDuration = YES; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
return enableShortPreviewTransitionAnimationDuration; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksEnablePreviewPresenterFastPreview(void) |
||||
|
{ |
||||
|
static BOOL enablePreviewPresenterFastPreview; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
switch (SCCameraTweaksPreviewPresenterFastPreviewStrategy()) { |
||||
|
case SCCameraTweaksStrategyOverrideToYes: { |
||||
|
enablePreviewPresenterFastPreview = YES; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyOverrideToNo: { |
||||
|
enablePreviewPresenterFastPreview = NO; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyFollowABTest: { |
||||
|
enablePreviewPresenterFastPreview = SCExperimentWithPreviewPresenterFastPreview(); |
||||
|
break; |
||||
|
} |
||||
|
default: { |
||||
|
enablePreviewPresenterFastPreview = NO; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
return enablePreviewPresenterFastPreview; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksEnableCaptureSharePerformer(void) |
||||
|
{ |
||||
|
static BOOL enableCaptureSharePerformer; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
switch (SCCameraTweaksEnableCaptureSharePerformerStrategy()) { |
||||
|
case SCCameraTweaksStrategyOverrideToYes: { |
||||
|
enableCaptureSharePerformer = YES; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyOverrideToNo: { |
||||
|
enableCaptureSharePerformer = NO; |
||||
|
break; |
||||
|
} |
||||
|
case SCCameraTweaksStrategyFollowABTest: { |
||||
|
enableCaptureSharePerformer = SCExperimentWithCaptureSharePerformer(); |
||||
|
break; |
||||
|
} |
||||
|
default: { |
||||
|
enableCaptureSharePerformer = NO; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
return enableCaptureSharePerformer; |
||||
|
} |
||||
|
|
||||
|
static inline SCCameraTweaksStrategyType SCCameraTweaksSessionLightWeightFixStrategy(void) |
||||
|
{ |
||||
|
NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Light-weight Session Fix", |
||||
|
(id) @(SCCameraTweaksStrategyFollowABTest), (@{ |
||||
|
@(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing", |
||||
|
@(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES", |
||||
|
@(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO" |
||||
|
})); |
||||
|
return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue]; |
||||
|
} |
||||
|
|
||||
|
BOOL SCCameraTweaksSessionLightWeightFixEnabled(void) |
||||
|
{ |
||||
|
static BOOL enabled; |
||||
|
static dispatch_once_t onceToken; |
||||
|
dispatch_once(&onceToken, ^{ |
||||
|
switch (SCCameraTweaksSessionLightWeightFixStrategy()) { |
||||
|
case SCCameraTweaksStrategyOverrideToYes: |
||||
|
enabled = YES; |
||||
|
break; |
||||
|
case SCCameraTweaksStrategyOverrideToNo: |
||||
|
enabled = NO; |
||||
|
break; |
||||
|
case SCCameraTweaksStrategyFollowABTest: |
||||
|
enabled = SCExperimentWithSessionLightWeightFix(); |
||||
|
break; |
||||
|
default: |
||||
|
enabled = NO; |
||||
|
break; |
||||
|
} |
||||
|
}); |
||||
|
return enabled; |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
// |
||||
|
// AVCameraViewEnums.h |
||||
|
// SCCamera |
||||
|
// |
||||
|
// Copyright © 2016 Snapchat, Inc. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
#import <Foundation/Foundation.h> |
||||
|
|
||||
|
/** |
||||
|
The context specifies the way in which the camera is presented to the user. |
||||
|
The controller can be configured a variety of ways depending on the context. |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, AVCameraViewControllerContext) { |
||||
|
AVCameraViewControllerContextMainVC = 1, |
||||
|
AVCameraViewControllerContextReply, |
||||
|
AVCameraViewControllerContextDefault = AVCameraViewControllerContextReply, |
||||
|
AVCameraViewControllerContextSnapAds, |
||||
|
AVCameraViewControllerContextAddToStory, |
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSInteger, AVCameraViewType) { |
||||
|
AVCameraViewNoReply = 0, |
||||
|
AVCameraViewReplyLeft, |
||||
|
AVCameraViewReplyRight, |
||||
|
AVCameraViewChat, |
||||
|
AVCameraViewReplyHydra, |
||||
|
AVCameraViewSnapAds, |
||||
|
AVCameraViewGalleryMadeWithLenses, |
||||
|
AVCameraViewSnapConnectSnapKit, |
||||
|
AVCameraViewSnappable |
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSUInteger, AVCameraViewControllerRecordingState) { |
||||
|
AVCameraViewControllerRecordingStateDefault, // No capture activity |
||||
|
AVCameraViewControllerRecordingStatePrepareRecording, // Preparing for recording with delay |
||||
|
AVCameraViewControllerRecordingStateInitiatedRecording, // Actively recording |
||||
|
AVCameraViewControllerRecordingStateTakingPicture, // Taking a still image |
||||
|
AVCameraViewControllerRecordingStatePictureTaken, // Picture is taken |
||||
|
AVCameraViewControllerRecordingStatePreview, // Preparing to present preview |
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSUInteger, SCCameraRecordingMethod) { |
||||
|
SCCameraRecordingMethodCameraButton, |
||||
|
SCCameraRecordingMethodVolumeButton, |
||||
|
SCCameraRecordingMethodLensInitiated |
||||
|
}; |
@ -0,0 +1,32 @@ |
|||||
|
// |
||||
|
// SCFeatureLensButtonZ.h |
||||
|
// SCCamera |
||||
|
// |
||||
|
// Created by Anton Udovychenko on 4/24/18. |
||||
|
// |
||||
|
|
||||
|
#import "AVCameraViewEnums.h" |
||||
|
#import "SCFeature.h" |
||||
|
|
||||
|
#import <Foundation/Foundation.h> |
||||
|
|
||||
|
@protocol SCFeatureLensButtonZ; |
||||
|
@class SCGrowingButton, SCLens; |
||||
|
|
||||
|
NS_ASSUME_NONNULL_BEGIN |
||||
|
|
||||
|
@protocol SCFeatureLensButtonZDelegate <NSObject> |
||||
|
- (void)featureLensZButton:(id<SCFeatureLensButtonZ>)featureLensZButton |
||||
|
didPressLensButton:(SCGrowingButton *)lensButton; |
||||
|
- (nullable NSArray<SCLens *> *)allLenses; |
||||
|
@end |
||||
|
|
||||
|
@protocol SCFeatureLensButtonZ <SCFeature> |
||||
|
|
||||
|
@property (nonatomic, weak) id<SCFeatureLensButtonZDelegate> delegate; |
||||
|
|
||||
|
- (void)setLensButtonActive:(BOOL)active; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
NS_ASSUME_NONNULL_END |
@ -0,0 +1,33 @@ |
|||||
|
// |
||||
|
// SCFeatureLensSideButton.h |
||||
|
// SCCamera |
||||
|
// |
||||
|
// Created by Anton Udovychenko on 4/12/18. |
||||
|
// |
||||
|
|
||||
|
#import "AVCameraViewEnums.h" |
||||
|
#import "SCFeature.h" |
||||
|
|
||||
|
#import <Foundation/Foundation.h> |
||||
|
|
||||
|
@protocol SCFeatureLensSideButton; |
||||
|
@class SCGrowingButton, SCLens; |
||||
|
|
||||
|
NS_ASSUME_NONNULL_BEGIN |
||||
|
|
||||
|
@protocol SCFeatureLensSideButtonDelegate <NSObject> |
||||
|
- (void)featureLensSideButton:(id<SCFeatureLensSideButton>)featureLensSideButton |
||||
|
didPressLensButton:(SCGrowingButton *)lensButton; |
||||
|
- (nullable SCLens *)firstApplicableLens; |
||||
|
@end |
||||
|
|
||||
|
@protocol SCFeatureLensSideButton <SCFeature> |
||||
|
|
||||
|
@property (nonatomic, weak) id<SCFeatureLensSideButtonDelegate> delegate; |
||||
|
|
||||
|
- (void)updateLensButtonVisibility:(CGFloat)visibilityPercentage; |
||||
|
- (void)showLensButtonIfNeeded; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
NS_ASSUME_NONNULL_END |
@ -0,0 +1,24 @@ |
|||||
|
// |
||||
|
// SCLongPressGestureRecognizer.h |
||||
|
// SCCamera |
||||
|
// |
||||
|
// Created by Pavlo Antonenko on 4/28/15. |
||||
|
// Copyright (c) 2015 Snapchat, Inc. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
#import <UIKit/UIKit.h> |
||||
|
|
||||
|
// gesture recognizer cancels, if user moved finger more then defined value, even if long press started, unlike |
||||
|
// UILongPressGestureRecognizer. But if user haven't moved finger for defined time, unlimited movement is allowed. |
||||
|
@interface SCLongPressGestureRecognizer : UILongPressGestureRecognizer |
||||
|
|
||||
|
@property (nonatomic, assign) CGFloat allowableMovementAfterBegan; |
||||
|
@property (nonatomic, assign) CGFloat timeBeforeUnlimitedMovementAllowed; |
||||
|
@property (nonatomic, assign, readonly) CGFloat forceOfAllTouches; |
||||
|
@property (nonatomic, assign, readonly) CGFloat maximumPossibleForceOfAllTouches; |
||||
|
@property (nonatomic, strong) NSDictionary *userInfo; |
||||
|
@property (nonatomic, assign) BOOL failedByMovement; |
||||
|
|
||||
|
- (BOOL)isUnlimitedMovementAllowed; |
||||
|
|
||||
|
@end |
@ -0,0 +1,88 @@ |
|||||
|
// |
||||
|
// SCLongPressGestureRecognizer.m |
||||
|
// SCCamera |
||||
|
// |
||||
|
// Created by Pavlo Antonenko on 4/28/15. |
||||
|
// Copyright (c) 2015 Snapchat, Inc. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
#import "SCLongPressGestureRecognizer.h" |
||||
|
|
||||
|
#import <SCFoundation/SCLog.h> |
||||
|
|
||||
|
#import <UIKit/UIGestureRecognizerSubclass.h> |
||||
|
|
||||
|
@implementation SCLongPressGestureRecognizer { |
||||
|
CGPoint _initialPoint; |
||||
|
CGFloat _initialTime; |
||||
|
} |
||||
|
|
||||
|
- (instancetype)initWithTarget:(id)target action:(SEL)action |
||||
|
{ |
||||
|
self = [super initWithTarget:target action:action]; |
||||
|
if (self) { |
||||
|
_allowableMovementAfterBegan = FLT_MAX; |
||||
|
_timeBeforeUnlimitedMovementAllowed = 0.0; |
||||
|
} |
||||
|
return self; |
||||
|
} |
||||
|
|
||||
|
- (void)reset |
||||
|
{ |
||||
|
[super reset]; |
||||
|
_initialPoint = CGPointZero; |
||||
|
_initialTime = 0; |
||||
|
_forceOfAllTouches = 1.0; |
||||
|
_maximumPossibleForceOfAllTouches = 1.0; |
||||
|
self.failedByMovement = NO; |
||||
|
} |
||||
|
|
||||
|
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event |
||||
|
{ |
||||
|
[super touchesBegan:touches withEvent:event]; |
||||
|
_initialPoint = [self locationInView:self.view]; |
||||
|
_initialTime = CACurrentMediaTime(); |
||||
|
_forceOfAllTouches = 1.0; |
||||
|
for (UITouch *touch in touches) { |
||||
|
_maximumPossibleForceOfAllTouches = MAX(touch.maximumPossibleForce, _maximumPossibleForceOfAllTouches); |
||||
|
_forceOfAllTouches = MAX(touch.force, _forceOfAllTouches); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event |
||||
|
{ |
||||
|
[super touchesMoved:touches withEvent:event]; |
||||
|
|
||||
|
_forceOfAllTouches = 1.0; |
||||
|
for (UITouch *touch in touches) { |
||||
|
_maximumPossibleForceOfAllTouches = MAX(touch.maximumPossibleForce, _maximumPossibleForceOfAllTouches); |
||||
|
_forceOfAllTouches = MAX(touch.force, _forceOfAllTouches); |
||||
|
} |
||||
|
|
||||
|
if (!CGPointEqualToPoint(_initialPoint, CGPointZero)) { |
||||
|
CGPoint currentPoint = [self locationInView:self.view]; |
||||
|
|
||||
|
CGFloat distance = hypot(_initialPoint.x - currentPoint.x, _initialPoint.y - currentPoint.y); |
||||
|
CGFloat timeDifference = CACurrentMediaTime() - _initialTime; |
||||
|
|
||||
|
if (distance > self.allowableMovementAfterBegan && timeDifference < self.timeBeforeUnlimitedMovementAllowed) { |
||||
|
SCLogGeneralInfo(@"Long press moved %.2f > %.2f after %.3f < %.3f seconds, and is cancelled", distance, |
||||
|
self.allowableMovementAfterBegan, timeDifference, self.timeBeforeUnlimitedMovementAllowed); |
||||
|
self.state = UIGestureRecognizerStateFailed; |
||||
|
self.failedByMovement = YES; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
- (void)setEnabled:(BOOL)enabled |
||||
|
{ |
||||
|
SCLogGeneralInfo(@"Setting enabled: %d for %@", enabled, self); |
||||
|
[super setEnabled:enabled]; |
||||
|
} |
||||
|
|
||||
|
- (BOOL)isUnlimitedMovementAllowed |
||||
|
{ |
||||
|
return CACurrentMediaTime() - _initialTime > self.timeBeforeUnlimitedMovementAllowed; |
||||
|
} |
||||
|
|
||||
|
@end |
@ -0,0 +1,31 @@ |
|||||
|
// |
||||
|
// SCCameraVolumeButtonHandler.h |
||||
|
// Snapchat |
||||
|
// |
||||
|
// Created by Xiaomu Wu on 2/27/15. |
||||
|
// Copyright (c) 2015 Snapchat, Inc. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
#import <Foundation/Foundation.h> |
||||
|
|
||||
|
@class SCCameraVolumeButtonHandler; |
||||
|
|
||||
|
@protocol SCCameraVolumeButtonHandlerDelegate <NSObject> |
||||
|
|
||||
|
- (void)volumeButtonHandlerDidBeginPressingVolumeButton:(SCCameraVolumeButtonHandler *)handler; |
||||
|
- (void)volumeButtonHandlerDidEndPressingVolumeButton:(SCCameraVolumeButtonHandler *)handler; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
@interface SCCameraVolumeButtonHandler : NSObject |
||||
|
|
||||
|
@property (nonatomic, weak) id<SCCameraVolumeButtonHandlerDelegate> delegate; |
||||
|
|
||||
|
- (void)startHandlingVolumeButtonEvents; |
||||
|
- (void)stopHandlingVolumeButtonEvents; |
||||
|
- (void)stopHandlingVolumeButtonEventsWhenPressingEnds; |
||||
|
- (BOOL)isHandlingVolumeButtonEvents; |
||||
|
|
||||
|
- (BOOL)isPressingVolumeButton; |
||||
|
|
||||
|
@end |
@ -0,0 +1,190 @@ |
|||||
|
// |
||||
|
// SCCameraVolumeButtonHandler.m |
||||
|
// Snapchat |
||||
|
// |
||||
|
// Created by Xiaomu Wu on 2/27/15. |
||||
|
// Copyright (c) 2015 Snapchat, Inc. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
#import "SCCameraVolumeButtonHandler.h" |
||||
|
|
||||
|
#import <SCFoundation/SCLog.h> |
||||
|
#import <SCFoundation/UIApplication+SCSecretFeature2.h> |
||||
|
|
||||
|
@implementation SCCameraVolumeButtonHandler { |
||||
|
NSString *_secretFeatureToken; |
||||
|
BOOL _pressingButton1; // volume down button |
||||
|
BOOL _pressingButton2; // volume up button |
||||
|
BOOL _stopsHandlingWhenPressingEnds; |
||||
|
} |
||||
|
|
||||
|
#pragma mark - NSObject |
||||
|
|
||||
|
- (instancetype)init |
||||
|
{ |
||||
|
self = [super init]; |
||||
|
if (self) { |
||||
|
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; |
||||
|
UIApplication *application = [UIApplication sharedApplication]; |
||||
|
[notificationCenter addObserver:self |
||||
|
selector:@selector(_handleButton1Down:) |
||||
|
name:[application sc_eventNotificationName1] |
||||
|
object:nil]; |
||||
|
[notificationCenter addObserver:self |
||||
|
selector:@selector(_handleButton1Up:) |
||||
|
name:[application sc_eventNotificationName2] |
||||
|
object:nil]; |
||||
|
[notificationCenter addObserver:self |
||||
|
selector:@selector(_handleButton2Down:) |
||||
|
name:[application sc_eventNotificationName3] |
||||
|
object:nil]; |
||||
|
[notificationCenter addObserver:self |
||||
|
selector:@selector(_handleButton2Up:) |
||||
|
name:[application sc_eventNotificationName4] |
||||
|
object:nil]; |
||||
|
} |
||||
|
return self; |
||||
|
} |
||||
|
|
||||
|
- (void)dealloc |
||||
|
{ |
||||
|
if (_secretFeatureToken) { |
||||
|
[[UIApplication sharedApplication] sc_disableSecretFeature2:_secretFeatureToken]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#pragma mark - Public |
||||
|
|
||||
|
- (void)startHandlingVolumeButtonEvents |
||||
|
{ |
||||
|
_stopsHandlingWhenPressingEnds = NO; |
||||
|
[self _resetPressingButtons]; |
||||
|
if ([self isHandlingVolumeButtonEvents]) { |
||||
|
return; |
||||
|
} |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Start handling volume button events"); |
||||
|
_secretFeatureToken = [[[UIApplication sharedApplication] sc_enableSecretFeature2] copy]; |
||||
|
} |
||||
|
|
||||
|
- (void)stopHandlingVolumeButtonEvents |
||||
|
{ |
||||
|
if (![self isHandlingVolumeButtonEvents]) { |
||||
|
return; |
||||
|
} |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Stop handling volume button events"); |
||||
|
[[UIApplication sharedApplication] sc_disableSecretFeature2:_secretFeatureToken]; |
||||
|
_secretFeatureToken = nil; |
||||
|
_stopsHandlingWhenPressingEnds = NO; |
||||
|
} |
||||
|
|
||||
|
- (void)stopHandlingVolumeButtonEventsWhenPressingEnds |
||||
|
{ |
||||
|
if (![self isHandlingVolumeButtonEvents]) { |
||||
|
return; |
||||
|
} |
||||
|
if (![self isPressingVolumeButton]) { |
||||
|
return; |
||||
|
} |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Stop handling volume button events when pressing ends"); |
||||
|
_stopsHandlingWhenPressingEnds = YES; |
||||
|
} |
||||
|
|
||||
|
- (BOOL)isHandlingVolumeButtonEvents |
||||
|
{ |
||||
|
return (_secretFeatureToken != nil); |
||||
|
} |
||||
|
|
||||
|
- (BOOL)isPressingVolumeButton |
||||
|
{ |
||||
|
return _pressingButton1 || _pressingButton2; |
||||
|
} |
||||
|
|
||||
|
- (void)_resetPressingButtons |
||||
|
{ |
||||
|
_pressingButton1 = NO; |
||||
|
_pressingButton2 = NO; |
||||
|
} |
||||
|
|
||||
|
#pragma mark - Private |
||||
|
|
||||
|
- (void)_handleButton1Down:(NSNotification *)notification |
||||
|
{ |
||||
|
if (![self isHandlingVolumeButtonEvents]) { |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 down, not handled"); |
||||
|
return; |
||||
|
} |
||||
|
if (_pressingButton1) { |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 down, already down"); |
||||
|
return; |
||||
|
} |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 down"); |
||||
|
[self _changePressingButton:^{ |
||||
|
_pressingButton1 = YES; |
||||
|
}]; |
||||
|
} |
||||
|
|
||||
|
- (void)_handleButton1Up:(NSNotification *)notification |
||||
|
{ |
||||
|
if (![self isHandlingVolumeButtonEvents]) { |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 up, not handled"); |
||||
|
return; |
||||
|
} |
||||
|
if (!_pressingButton1) { |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 up, already up"); |
||||
|
return; |
||||
|
} |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 1 up"); |
||||
|
[self _changePressingButton:^{ |
||||
|
_pressingButton1 = NO; |
||||
|
}]; |
||||
|
} |
||||
|
|
||||
|
- (void)_handleButton2Down:(NSNotification *)notification |
||||
|
{ |
||||
|
if (![self isHandlingVolumeButtonEvents]) { |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 down, not handled"); |
||||
|
return; |
||||
|
} |
||||
|
if (_pressingButton2) { |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 down, already down"); |
||||
|
return; |
||||
|
} |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 down"); |
||||
|
[self _changePressingButton:^{ |
||||
|
_pressingButton2 = YES; |
||||
|
}]; |
||||
|
} |
||||
|
|
||||
|
- (void)_handleButton2Up:(NSNotification *)notification |
||||
|
{ |
||||
|
if (![self isHandlingVolumeButtonEvents]) { |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 up, not handled"); |
||||
|
return; |
||||
|
} |
||||
|
if (!_pressingButton2) { |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 up, already up"); |
||||
|
return; |
||||
|
} |
||||
|
SCLogGeneralInfo(@"[Volume Buttons] Volume button 2 up"); |
||||
|
[self _changePressingButton:^{ |
||||
|
_pressingButton2 = NO; |
||||
|
}]; |
||||
|
} |
||||
|
|
||||
|
- (void)_changePressingButton:(void (^)(void))change |
||||
|
{ |
||||
|
BOOL oldPressingVolumeButton = [self isPressingVolumeButton]; |
||||
|
change(); |
||||
|
BOOL newPressingVolumeButton = [self isPressingVolumeButton]; |
||||
|
|
||||
|
if (!oldPressingVolumeButton && newPressingVolumeButton) { |
||||
|
[_delegate volumeButtonHandlerDidBeginPressingVolumeButton:self]; |
||||
|
} else if (oldPressingVolumeButton && !newPressingVolumeButton) { |
||||
|
[_delegate volumeButtonHandlerDidEndPressingVolumeButton:self]; |
||||
|
if (_stopsHandlingWhenPressingEnds) { |
||||
|
[self stopHandlingVolumeButtonEvents]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@end |
@ -0,0 +1,109 @@ |
|||||
|
// |
||||
|
// SCCaptureWorker.h |
||||
|
// Snapchat |
||||
|
// |
||||
|
// Created by Lin Jia on 10/19/17. |
||||
|
// |
||||
|
// |
||||
|
|
||||
|
#import "SCCaptureResource.h" |
||||
|
|
||||
|
#import <SCFoundation/SCQueuePerformer.h> |
||||
|
|
||||
|
#import <Foundation/Foundation.h> |
||||
|
|
||||
|
/* |
||||
|
In general, the function of SCCapturer is to use some resources (such as SCManagedCapturerListenerAnnouncer), to do |
||||
|
something (such as announce an event). |
||||
|
|
||||
|
SCCaptureWorker abstract away the "do something" part of SCCapturer. It has very little internal states/resources. |
||||
|
|
||||
|
SCCaptureWorker is introduced to be shared between CaptureV1 and CaptureV2, to minimize duplication code. |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
@interface SCCaptureWorker : NSObject |
||||
|
|
||||
|
+ (SCCaptureResource *)generateCaptureResource; |
||||
|
|
||||
|
+ (void)setupWithCaptureResource:(SCCaptureResource *)captureResource |
||||
|
devicePosition:(SCManagedCaptureDevicePosition)devicePosition; |
||||
|
|
||||
|
+ (void)setupCapturePreviewLayerController; |
||||
|
|
||||
|
+ (void)startRunningWithCaptureResource:(SCCaptureResource *)captureResource |
||||
|
token:(SCCapturerToken *)token |
||||
|
completionHandler:(dispatch_block_t)completionHandler; |
||||
|
|
||||
|
+ (BOOL)stopRunningWithCaptureResource:(SCCaptureResource *)captureResource |
||||
|
token:(SCCapturerToken *)token |
||||
|
completionHandler:(sc_managed_capturer_stop_running_completion_handler_t)completionHandler; |
||||
|
|
||||
|
+ (void)setupVideoPreviewLayer:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)makeVideoPreviewLayer:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)redoVideoPreviewLayer:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)startStreaming:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)setupLivenessConsistencyTimerIfForeground:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)destroyLivenessConsistencyTimer:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)softwareZoomWithDevice:(SCManagedCaptureDevice *)device resource:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)captureStillImageWithCaptureResource:(SCCaptureResource *)captureResource |
||||
|
aspectRatio:(CGFloat)aspectRatio |
||||
|
captureSessionID:(NSString *)captureSessionID |
||||
|
shouldCaptureFromVideo:(BOOL)shouldCaptureFromVideo |
||||
|
completionHandler: |
||||
|
(sc_managed_capturer_capture_still_image_completion_handler_t)completionHandler |
||||
|
context:(NSString *)context; |
||||
|
|
||||
|
+ (void)startRecordingWithCaptureResource:(SCCaptureResource *)captureResource |
||||
|
outputSettings:(SCManagedVideoCapturerOutputSettings *)outputSettings |
||||
|
audioConfiguration:(SCAudioConfiguration *)configuration |
||||
|
maxDuration:(NSTimeInterval)maxDuration |
||||
|
fileURL:(NSURL *)fileURL |
||||
|
captureSessionID:(NSString *)captureSessionID |
||||
|
completionHandler:(sc_managed_capturer_start_recording_completion_handler_t)completionHandler; |
||||
|
|
||||
|
+ (void)stopRecordingWithCaptureResource:(SCCaptureResource *)captureResource; |
||||
|
|
||||
|
+ (void)cancelRecordingWithCaptureResource:(SCCaptureResource *)captureResource; |
||||
|
|
||||
|
+ (SCVideoCaptureSessionInfo)activeSession:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (BOOL)canRunARSession:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)turnARSessionOn:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)turnARSessionOff:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)clearARKitData:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)updateLensesFieldOfViewTracking:(SCCaptureResource *)captureResource; |
||||
|
|
||||
|
+ (CMTime)firstWrittenAudioBufferDelay:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (BOOL)audioQueueStarted:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (BOOL)isLensApplied:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (BOOL)isVideoMirrored:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (BOOL)shouldCaptureImageFromVideoWithResource:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)setPortraitModePointOfInterestAsynchronously:(CGPoint)pointOfInterest |
||||
|
completionHandler:(dispatch_block_t)completionHandler |
||||
|
resource:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)prepareForRecordingWithAudioConfiguration:(SCAudioConfiguration *)configuration |
||||
|
resource:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)stopScanWithCompletionHandler:(dispatch_block_t)completionHandler resource:(SCCaptureResource *)resource; |
||||
|
|
||||
|
+ (void)startScanWithScanConfiguration:(SCScanConfiguration *)configuration resource:(SCCaptureResource *)resource; |
||||
|
|
||||
|
@end |
1095
Worker/SCCaptureWorker.m
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue