Add files via upload
This commit is contained in:
parent
c69a609542
commit
53e8a5f244
233
Resource/SCCaptureResource.h
Normal file
233
Resource/SCCaptureResource.h
Normal file
@ -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
|
66
Resource/SCCaptureResource.m
Normal file
66
Resource/SCCaptureResource.m
Normal file
@ -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
|
377
Tweaks/SCCameraTweaks.h
Normal file
377
Tweaks/SCCameraTweaks.h
Normal file
@ -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);
|
||||||
|
}
|
396
Tweaks/SCCameraTweaks.m
Normal file
396
Tweaks/SCCameraTweaks.m
Normal file
@ -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;
|
||||||
|
}
|
47
UI/AVCameraViewEnums.h
Normal file
47
UI/AVCameraViewEnums.h
Normal file
@ -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
|
||||||
|
};
|
32
UI/Lenses/LensButtonZ/SCFeatureLensButtonZ.h
Normal file
32
UI/Lenses/LensButtonZ/SCFeatureLensButtonZ.h
Normal file
@ -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
|
33
UI/Lenses/LensSideButton/SCFeatureLensSideButton.h
Normal file
33
UI/Lenses/LensSideButton/SCFeatureLensSideButton.h
Normal file
@ -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
|
24
UI/SCLongPressGestureRecognizer.h
Normal file
24
UI/SCLongPressGestureRecognizer.h
Normal file
@ -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
|
88
UI/SCLongPressGestureRecognizer.m
Normal file
88
UI/SCLongPressGestureRecognizer.m
Normal file
@ -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
|
31
VolumeButton/SCCameraVolumeButtonHandler.h
Normal file
31
VolumeButton/SCCameraVolumeButtonHandler.h
Normal file
@ -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
|
190
VolumeButton/SCCameraVolumeButtonHandler.m
Normal file
190
VolumeButton/SCCameraVolumeButtonHandler.m
Normal file
@ -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
|
109
Worker/SCCaptureWorker.h
Normal file
109
Worker/SCCaptureWorker.h
Normal file
@ -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
Normal file
1095
Worker/SCCaptureWorker.m
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user