Home telegram - tgCameraPreviewView
Post
Cancel

telegram - tgCameraPreviewView

class TGCameraPreviewView

@property (nonatomic, readonly) TGPGCamera *camera;
@property (nonatomic, readonly) AVCaptureConnection *captureConnection;


- (void)setupWithCamera:(TGPGCamera *)camera;
- (void)invalidate;

- (void)beginTransitionWithSnapshotImage:(UIImage *)image animated:(bool)animated;
- (void)endTransitionAnimated:(bool)animated;

- (void)beginResetTransitionAnimated:(bool)animated;
- (void)endResetTransitionAnimated:(bool)animated;

- (void)fadeInAnimated:(bool)animated;
- (void)fadeOutAnimated:(bool)animated;

- (void)blink;

- (CGPoint)devicePointOfInterestForPoint:(CGPoint)point;

// private extension
UIView<TGCameraPreviewLayerView> *_wrapperView;
UIView *_fadeView;
UIView *_snapshotView;

TGPGCamera *_camera;

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self != nil)
    {
        self.backgroundColor = [UIColor blackColor];
        self.clipsToBounds = true;
        
        if (false && iosMajorVersion() >= 8)
            _wrapperView = [[TGCameraPreviewLayerWrapperView alloc] init];
        else
            _wrapperView = [[TGCameraLegacyPreviewLayerWrapperView alloc] init];
        [self addSubview:_wrapperView];
        
        _wrapperView.videoGravity = AVLayerVideoGravityResizeAspectFill;
        
        _fadeView = [[UIView alloc] initWithFrame:self.bounds];
        _fadeView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _fadeView.backgroundColor = [UIColor blackColor];
        _fadeView.userInteractionEnabled = false;
        [self addSubview:_fadeView];
        
        if (iosMajorVersion() >= 11)
            _fadeView.accessibilityIgnoresInvertColors = true;
        
#if TARGET_IPHONE_SIMULATOR
        _fadeView.backgroundColor = [UIColor redColor];
#endif
    }
    return self;
}

- (AVCaptureConnection *)captureConnection
{
    return _wrapperView.connection;
}

- (AVSampleBufferDisplayLayer *)displayLayer
{
    return _wrapperView.displayLayer;
}

- (AVCaptureVideoPreviewLayer *)legacyPreviewLayer
{
    return _wrapperView.previewLayer;
}

// setupCamera
- (void)setupWithCamera:(TGPGCamera *)camera
{
    _camera = camera;
    
    __weak TGCameraPreviewView *weakSelf = self;
    if ([_wrapperView isKindOfClass:[TGCameraPreviewLayerWrapperView class]])
    {
        [self.displayLayer flushAndRemoveImage];
        camera.captureSession.outputSampleBuffer = ^(CMSampleBufferRef buffer, AVCaptureConnection *connection)
        {
            __strong TGCameraPreviewView *strongSelf = weakSelf;
            if (strongSelf == nil)
                return;
            
            [(TGCameraPreviewLayerWrapperView *)strongSelf->_wrapperView enqueueSampleBuffer:buffer connection:connection];
        };
    }
    else
    {
#if !TARGET_IPHONE_SIMULATOR
        [self.legacyPreviewLayer setSession:camera.captureSession];
#endif
    }
    
    camera.captureStarted = ^(bool resume)
    {
        __strong TGCameraPreviewView *strongSelf = weakSelf;
        if (strongSelf == nil)
            return;
        
        if (resume)
            [strongSelf endResetTransitionAnimated:true];
        else
            [strongSelf fadeInAnimated:true];
    };
    
    camera.captureStopped = ^(bool pause)
    {
        __strong TGCameraPreviewView *strongSelf = weakSelf;
        if (strongSelf == nil)
            return;
        
        if (pause)
            [strongSelf beginResetTransitionAnimated:true];
        else
            [strongSelf fadeOutAnimated:true];
    };
}


// transition animation
- (void)beginResetTransitionAnimated:(bool)animated
{
    if (iosMajorVersion() < 7)
        return;
    
    [_snapshotView removeFromSuperview];
    
    _snapshotView = [_wrapperView snapshotViewAfterScreenUpdates:false];
    _snapshotView.frame = _wrapperView.frame;
    [self insertSubview:_snapshotView aboveSubview:_wrapperView];
    
    if (animated)
    {
        _snapshotView.alpha = 0.0f;
        [UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:^
        {
            _snapshotView.alpha = 1.0f;
        } completion:nil];
    }
}

- (void)endResetTransitionAnimated:(bool)animated
{
    if (iosMajorVersion() < 7)
        return;
    
    if (animated)
    {
        UIView *snapshotView = _snapshotView;
        _snapshotView = nil;
        
        [UIView animateWithDuration:0.4f delay:0.05f options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState animations:^
        {
            snapshotView.alpha = 0.0f;
        } completion:^(__unused BOOL finished)
        {
            [snapshotView removeFromSuperview];
        }];
    }
    else
    {
        [_snapshotView removeFromSuperview];
        _snapshotView = nil;
    }
}

// blink
- (void)blink
{
    [UIView animateWithDuration:0.07f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^
    {
        _fadeView.alpha = 1.0f;
    } completion:^(BOOL finished)
    {
        [UIView animateWithDuration:0.07f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^
        {
            _fadeView.alpha = 0.0f;
        } completion:^(BOOL finished)
        {    
            
        }];
    }];
}

// fade in
- (void)fadeInAnimated:(bool)animated
{
    if (animated)
    {
        [UIView animateWithDuration:0.3f delay:0.05f options:UIViewAnimationOptionCurveLinear animations:^
        {
            _fadeView.alpha = 0.0f;
        } completion:nil];
    }
    else
    {
        _fadeView.alpha = 0.0f;
    }
}

// fade out
- (void)fadeOutAnimated:(bool)animated
{
    if (animated)
    {
        [UIView animateWithDuration:0.3f animations:^
        {
            _fadeView.alpha = 1.0f;
        }];
    }
    else
    {
        _fadeView.alpha = 1.0f;
    }
}

// invalidate
- (void)invalidate
{
    if ([_wrapperView isKindOfClass:[TGCameraPreviewLayerWrapperView class]])
    {
        [self.displayLayer flushAndRemoveImage];
        _camera.captureSession.outputSampleBuffer = nil;
    }
    else
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.legacyPreviewLayer setSession:nil];
        });
    }
    _wrapperView = nil;
}

protocol TGCameraPreviewLayerView

@property (nonatomic, strong) NSString *videoGravity;
@property (nonatomic, readonly) AVCaptureConnection *connection;
- (CGPoint)captureDevicePointOfInterestForPoint:(CGPoint)point;

@optional
- (AVSampleBufferDisplayLayer *)displayLayer;
- (AVCaptureVideoPreviewLayer *)previewLayer;

class TGCameraLegacyPreviewLayerWrapperView

@property (nonatomic, readonly) AVCaptureVideoPreviewLayer *previewLayer;

class TGCameraPreviewLayerWrapperView

- (NSString *)videoGravity
{
    return [self displayLayer].videoGravity;
}

- (void)setVideoGravity:(NSString *)videoGravity
{
    self.displayLayer.videoGravity = videoGravity;
}

- (AVCaptureConnection *)connection
{
    return _connection;
}

- (CGPoint)captureDevicePointOfInterestForPoint:(CGPoint)point
{
    return CGPointZero;
}

- (void)enqueueSampleBuffer:(CMSampleBufferRef)buffer connection:(AVCaptureConnection *)connection
{
    _connection = connection;
    
    //self.orientation = connection.videoOrientation;
    //self.mirrored = connection.videoMirrored;
    
    [self.displayLayer enqueueSampleBuffer:buffer];
}

- (AVSampleBufferDisplayLayer *)displayLayer
{
    return (AVSampleBufferDisplayLayer *)self.layer;
}

+ (Class)layerClass
{
    return [AVSampleBufferDisplayLayer class];
}
This post is licensed under CC BY 4.0 by the author.