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

173 lines
5.2 KiB

  1. //
  2. // SCManagedCapturePreviewView.m
  3. // Snapchat
  4. //
  5. // Created by Liu Liu on 5/5/15.
  6. // Copyright (c) 2015 Snapchat, Inc. All rights reserved.
  7. //
  8. #import "SCManagedCapturePreviewView.h"
  9. #import "SCCameraTweaks.h"
  10. #import "SCManagedCapturePreviewLayerController.h"
  11. #import "SCManagedCapturePreviewViewDebugView.h"
  12. #import "SCMetalUtils.h"
  13. #import <SCFoundation/SCCoreGraphicsUtils.h>
  14. #import <SCFoundation/SCLog.h>
  15. #import <SCFoundation/SCTrace.h>
  16. #import <Looksery/LSAGLView.h>
  17. @implementation SCManagedCapturePreviewView {
  18. CGFloat _aspectRatio;
  19. CALayer *_containerLayer;
  20. CALayer *_metalLayer;
  21. SCManagedCapturePreviewViewDebugView *_debugView;
  22. }
  23. - (instancetype)initWithFrame:(CGRect)frame aspectRatio:(CGFloat)aspectRatio metalLayer:(CALayer *)metalLayer
  24. {
  25. SCTraceStart();
  26. SCAssertMainThread();
  27. self = [super initWithFrame:frame];
  28. if (self) {
  29. _aspectRatio = aspectRatio;
  30. if (SCDeviceSupportsMetal()) {
  31. [CATransaction begin];
  32. [CATransaction setDisableActions:YES];
  33. _metalLayer = metalLayer;
  34. _metalLayer.frame = [self _layerFrame];
  35. [self.layer insertSublayer:_metalLayer below:[self.layer sublayers][0]];
  36. [CATransaction commit];
  37. } else {
  38. _containerLayer = [[CALayer alloc] init];
  39. _containerLayer.frame = [self _layerFrame];
  40. // Using a container layer such that the software zooming is happening on this layer
  41. [self.layer insertSublayer:_containerLayer below:[self.layer sublayers][0]];
  42. }
  43. if ([self _shouldShowDebugView]) {
  44. _debugView = [[SCManagedCapturePreviewViewDebugView alloc] init];
  45. [self addSubview:_debugView];
  46. }
  47. }
  48. return self;
  49. }
  50. - (void)_layoutVideoPreviewLayer
  51. {
  52. SCAssertMainThread();
  53. [CATransaction begin];
  54. [CATransaction setDisableActions:YES];
  55. if (SCDeviceSupportsMetal()) {
  56. _metalLayer.frame = [self _layerFrame];
  57. } else {
  58. if (_videoPreviewLayer) {
  59. SCLogGeneralInfo(@"container layer frame %@, video preview layer frame %@",
  60. NSStringFromCGRect(_containerLayer.frame), NSStringFromCGRect(_videoPreviewLayer.frame));
  61. }
  62. // Using bounds because we don't really care about the position at this point.
  63. _containerLayer.frame = [self _layerFrame];
  64. _videoPreviewLayer.frame = _containerLayer.bounds;
  65. _videoPreviewLayer.position =
  66. CGPointMake(CGRectGetWidth(_containerLayer.bounds) * 0.5, CGRectGetHeight(_containerLayer.bounds) * 0.5);
  67. }
  68. [CATransaction commit];
  69. }
  70. - (void)_layoutVideoPreviewGLView
  71. {
  72. SCCAssertMainThread();
  73. _videoPreviewGLView.frame = [self _layerFrame];
  74. }
  75. - (CGRect)_layerFrame
  76. {
  77. CGRect frame = SCRectMakeWithCenterAndSize(
  78. SCRectGetMid(self.bounds), SCSizeIntegral(SCSizeExpandToAspectRatio(self.bounds.size, _aspectRatio)));
  79. CGFloat x = frame.origin.x;
  80. x = isnan(x) ? 0.0 : (isfinite(x) ? x : INFINITY);
  81. CGFloat y = frame.origin.y;
  82. y = isnan(y) ? 0.0 : (isfinite(y) ? y : INFINITY);
  83. CGFloat width = frame.size.width;
  84. width = isnan(width) ? 0.0 : (isfinite(width) ? width : INFINITY);
  85. CGFloat height = frame.size.height;
  86. height = isnan(height) ? 0.0 : (isfinite(height) ? height : INFINITY);
  87. return CGRectMake(x, y, width, height);
  88. }
  89. - (void)setVideoPreviewLayer:(AVCaptureVideoPreviewLayer *)videoPreviewLayer
  90. {
  91. SCAssertMainThread();
  92. if (_videoPreviewLayer != videoPreviewLayer) {
  93. [_videoPreviewLayer removeFromSuperlayer];
  94. _videoPreviewLayer = videoPreviewLayer;
  95. [_containerLayer addSublayer:_videoPreviewLayer];
  96. [self _layoutVideoPreviewLayer];
  97. }
  98. }
  99. - (void)setupMetalLayer:(CALayer *)metalLayer
  100. {
  101. SCAssert(!_metalLayer, @"_metalLayer should be nil.");
  102. SCAssert(metalLayer, @"metalLayer must exists.");
  103. SCAssertMainThread();
  104. _metalLayer = metalLayer;
  105. [self.layer insertSublayer:_metalLayer below:[self.layer sublayers][0]];
  106. [self _layoutVideoPreviewLayer];
  107. }
  108. - (void)setVideoPreviewGLView:(LSAGLView *)videoPreviewGLView
  109. {
  110. SCAssertMainThread();
  111. if (_videoPreviewGLView != videoPreviewGLView) {
  112. [_videoPreviewGLView removeFromSuperview];
  113. _videoPreviewGLView = videoPreviewGLView;
  114. [self addSubview:_videoPreviewGLView];
  115. [self _layoutVideoPreviewGLView];
  116. }
  117. }
  118. #pragma mark - Overridden methods
  119. - (void)layoutSubviews
  120. {
  121. SCAssertMainThread();
  122. [super layoutSubviews];
  123. [self _layoutVideoPreviewLayer];
  124. [self _layoutVideoPreviewGLView];
  125. [self _layoutDebugViewIfNeeded];
  126. }
  127. - (void)setHidden:(BOOL)hidden
  128. {
  129. SCAssertMainThread();
  130. [super setHidden:hidden];
  131. if (hidden) {
  132. SCLogGeneralInfo(@"[SCManagedCapturePreviewView] - isHidden is being set to YES");
  133. }
  134. }
  135. #pragma mark - Debug View
  136. - (BOOL)_shouldShowDebugView
  137. {
  138. // Only show debug view in internal builds and tweak settings are turned on.
  139. return SCIsInternalBuild() &&
  140. (SCCameraTweaksEnableFocusPointObservation() || SCCameraTweaksEnableExposurePointObservation());
  141. }
  142. - (void)_layoutDebugViewIfNeeded
  143. {
  144. SCAssertMainThread();
  145. SC_GUARD_ELSE_RETURN([self _shouldShowDebugView]);
  146. _debugView.frame = self.bounds;
  147. [self bringSubviewToFront:_debugView];
  148. }
  149. @end