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
173 lines
5.2 KiB
//
|
|
// SCManagedCapturePreviewView.m
|
|
// Snapchat
|
|
//
|
|
// Created by Liu Liu on 5/5/15.
|
|
// Copyright (c) 2015 Snapchat, Inc. All rights reserved.
|
|
//
|
|
|
|
#import "SCManagedCapturePreviewView.h"
|
|
|
|
#import "SCCameraTweaks.h"
|
|
#import "SCManagedCapturePreviewLayerController.h"
|
|
#import "SCManagedCapturePreviewViewDebugView.h"
|
|
#import "SCMetalUtils.h"
|
|
|
|
#import <SCFoundation/SCCoreGraphicsUtils.h>
|
|
#import <SCFoundation/SCLog.h>
|
|
#import <SCFoundation/SCTrace.h>
|
|
|
|
#import <Looksery/LSAGLView.h>
|
|
|
|
@implementation SCManagedCapturePreviewView {
|
|
CGFloat _aspectRatio;
|
|
CALayer *_containerLayer;
|
|
CALayer *_metalLayer;
|
|
SCManagedCapturePreviewViewDebugView *_debugView;
|
|
}
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame aspectRatio:(CGFloat)aspectRatio metalLayer:(CALayer *)metalLayer
|
|
{
|
|
SCTraceStart();
|
|
SCAssertMainThread();
|
|
self = [super initWithFrame:frame];
|
|
if (self) {
|
|
_aspectRatio = aspectRatio;
|
|
if (SCDeviceSupportsMetal()) {
|
|
[CATransaction begin];
|
|
[CATransaction setDisableActions:YES];
|
|
_metalLayer = metalLayer;
|
|
_metalLayer.frame = [self _layerFrame];
|
|
[self.layer insertSublayer:_metalLayer below:[self.layer sublayers][0]];
|
|
[CATransaction commit];
|
|
} else {
|
|
_containerLayer = [[CALayer alloc] init];
|
|
_containerLayer.frame = [self _layerFrame];
|
|
// Using a container layer such that the software zooming is happening on this layer
|
|
[self.layer insertSublayer:_containerLayer below:[self.layer sublayers][0]];
|
|
}
|
|
if ([self _shouldShowDebugView]) {
|
|
_debugView = [[SCManagedCapturePreviewViewDebugView alloc] init];
|
|
[self addSubview:_debugView];
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)_layoutVideoPreviewLayer
|
|
{
|
|
SCAssertMainThread();
|
|
[CATransaction begin];
|
|
[CATransaction setDisableActions:YES];
|
|
if (SCDeviceSupportsMetal()) {
|
|
_metalLayer.frame = [self _layerFrame];
|
|
} else {
|
|
if (_videoPreviewLayer) {
|
|
SCLogGeneralInfo(@"container layer frame %@, video preview layer frame %@",
|
|
NSStringFromCGRect(_containerLayer.frame), NSStringFromCGRect(_videoPreviewLayer.frame));
|
|
}
|
|
// Using bounds because we don't really care about the position at this point.
|
|
_containerLayer.frame = [self _layerFrame];
|
|
_videoPreviewLayer.frame = _containerLayer.bounds;
|
|
_videoPreviewLayer.position =
|
|
CGPointMake(CGRectGetWidth(_containerLayer.bounds) * 0.5, CGRectGetHeight(_containerLayer.bounds) * 0.5);
|
|
}
|
|
[CATransaction commit];
|
|
}
|
|
|
|
- (void)_layoutVideoPreviewGLView
|
|
{
|
|
SCCAssertMainThread();
|
|
_videoPreviewGLView.frame = [self _layerFrame];
|
|
}
|
|
|
|
- (CGRect)_layerFrame
|
|
{
|
|
CGRect frame = SCRectMakeWithCenterAndSize(
|
|
SCRectGetMid(self.bounds), SCSizeIntegral(SCSizeExpandToAspectRatio(self.bounds.size, _aspectRatio)));
|
|
|
|
CGFloat x = frame.origin.x;
|
|
x = isnan(x) ? 0.0 : (isfinite(x) ? x : INFINITY);
|
|
|
|
CGFloat y = frame.origin.y;
|
|
y = isnan(y) ? 0.0 : (isfinite(y) ? y : INFINITY);
|
|
|
|
CGFloat width = frame.size.width;
|
|
width = isnan(width) ? 0.0 : (isfinite(width) ? width : INFINITY);
|
|
|
|
CGFloat height = frame.size.height;
|
|
height = isnan(height) ? 0.0 : (isfinite(height) ? height : INFINITY);
|
|
|
|
return CGRectMake(x, y, width, height);
|
|
}
|
|
|
|
- (void)setVideoPreviewLayer:(AVCaptureVideoPreviewLayer *)videoPreviewLayer
|
|
{
|
|
SCAssertMainThread();
|
|
if (_videoPreviewLayer != videoPreviewLayer) {
|
|
[_videoPreviewLayer removeFromSuperlayer];
|
|
_videoPreviewLayer = videoPreviewLayer;
|
|
[_containerLayer addSublayer:_videoPreviewLayer];
|
|
[self _layoutVideoPreviewLayer];
|
|
}
|
|
}
|
|
|
|
- (void)setupMetalLayer:(CALayer *)metalLayer
|
|
{
|
|
SCAssert(!_metalLayer, @"_metalLayer should be nil.");
|
|
SCAssert(metalLayer, @"metalLayer must exists.");
|
|
SCAssertMainThread();
|
|
_metalLayer = metalLayer;
|
|
[self.layer insertSublayer:_metalLayer below:[self.layer sublayers][0]];
|
|
[self _layoutVideoPreviewLayer];
|
|
}
|
|
|
|
- (void)setVideoPreviewGLView:(LSAGLView *)videoPreviewGLView
|
|
{
|
|
SCAssertMainThread();
|
|
if (_videoPreviewGLView != videoPreviewGLView) {
|
|
[_videoPreviewGLView removeFromSuperview];
|
|
_videoPreviewGLView = videoPreviewGLView;
|
|
[self addSubview:_videoPreviewGLView];
|
|
[self _layoutVideoPreviewGLView];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Overridden methods
|
|
|
|
- (void)layoutSubviews
|
|
{
|
|
SCAssertMainThread();
|
|
[super layoutSubviews];
|
|
[self _layoutVideoPreviewLayer];
|
|
[self _layoutVideoPreviewGLView];
|
|
[self _layoutDebugViewIfNeeded];
|
|
}
|
|
|
|
- (void)setHidden:(BOOL)hidden
|
|
{
|
|
SCAssertMainThread();
|
|
[super setHidden:hidden];
|
|
if (hidden) {
|
|
SCLogGeneralInfo(@"[SCManagedCapturePreviewView] - isHidden is being set to YES");
|
|
}
|
|
}
|
|
|
|
#pragma mark - Debug View
|
|
|
|
- (BOOL)_shouldShowDebugView
|
|
{
|
|
// Only show debug view in internal builds and tweak settings are turned on.
|
|
return SCIsInternalBuild() &&
|
|
(SCCameraTweaksEnableFocusPointObservation() || SCCameraTweaksEnableExposurePointObservation());
|
|
}
|
|
|
|
- (void)_layoutDebugViewIfNeeded
|
|
{
|
|
SCAssertMainThread();
|
|
SC_GUARD_ELSE_RETURN([self _shouldShowDebugView]);
|
|
_debugView.frame = self.bounds;
|
|
[self bringSubviewToFront:_debugView];
|
|
}
|
|
|
|
@end
|