mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
421 lines
10 KiB
Objective-C
421 lines
10 KiB
Objective-C
#import "TGCameraPreviewView.h"
|
|
|
|
#import "LegacyComponentsInternal.h"
|
|
#import "TGImageUtils.h"
|
|
|
|
#import <AVFoundation/AVFoundation.h>
|
|
|
|
#import <LegacyComponents/PGCamera.h>
|
|
#import <LegacyComponents/PGCameraCaptureSession.h>
|
|
|
|
@protocol TGCameraPreviewLayerView <NSObject>
|
|
|
|
@property (nonatomic, strong) NSString *videoGravity;
|
|
@property (nonatomic, readonly) AVCaptureConnection *connection;
|
|
- (CGPoint)captureDevicePointOfInterestForPoint:(CGPoint)point;
|
|
|
|
@optional
|
|
- (AVSampleBufferDisplayLayer *)displayLayer;
|
|
- (AVCaptureVideoPreviewLayer *)previewLayer;
|
|
|
|
@end
|
|
|
|
|
|
@interface TGCameraPreviewLayerWrapperView : UIView <TGCameraPreviewLayerView>
|
|
{
|
|
__weak AVCaptureConnection *_connection;
|
|
}
|
|
|
|
@property (nonatomic, readonly) AVSampleBufferDisplayLayer *displayLayer;
|
|
|
|
- (void)enqueueSampleBuffer:(CMSampleBufferRef)buffer connection:(AVCaptureConnection *)connection;
|
|
|
|
@end
|
|
|
|
|
|
@interface TGCameraLegacyPreviewLayerWrapperView : UIView <TGCameraPreviewLayerView>
|
|
|
|
@property (nonatomic, readonly) AVCaptureVideoPreviewLayer *previewLayer;
|
|
|
|
@end
|
|
|
|
|
|
@interface TGCameraPreviewView ()
|
|
{
|
|
UIView<TGCameraPreviewLayerView> *_wrapperView;
|
|
UIView *_fadeView;
|
|
UIView *_snapshotView;
|
|
|
|
PGCamera *_camera;
|
|
}
|
|
@end
|
|
|
|
@implementation TGCameraPreviewView
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
{
|
|
self = [super initWithFrame:frame];
|
|
if (self != nil)
|
|
{
|
|
self.backgroundColor = [UIColor blackColor];
|
|
self.clipsToBounds = true;
|
|
|
|
_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 (@available(iOS 11.0, *)) {
|
|
_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;
|
|
}
|
|
|
|
- (void)setupWithCamera:(PGCamera *)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 {
|
|
if (strongSelf->_snapshotView != nil) {
|
|
[strongSelf endTransitionAnimated: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];
|
|
};
|
|
}
|
|
|
|
- (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;
|
|
}
|
|
|
|
- (PGCamera *)camera
|
|
{
|
|
return _camera;
|
|
}
|
|
|
|
- (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;
|
|
}
|
|
}
|
|
|
|
- (void)fadeOutAnimated:(bool)animated
|
|
{
|
|
if (animated)
|
|
{
|
|
[UIView animateWithDuration:0.3f animations:^
|
|
{
|
|
_fadeView.alpha = 1.0f;
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
_fadeView.alpha = 1.0f;
|
|
}
|
|
}
|
|
|
|
- (void)blink
|
|
{
|
|
[UIView animateWithDuration:0.07f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^
|
|
{
|
|
_fadeView.alpha = 1.0f;
|
|
} completion:^(BOOL finished)
|
|
{
|
|
[UIView animateWithDuration:0.15f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^
|
|
{
|
|
_fadeView.alpha = 0.0f;
|
|
} completion:^(BOOL finished)
|
|
{
|
|
|
|
}];
|
|
}];
|
|
}
|
|
|
|
- (void)beginTransitionWithSnapshotImage:(UIImage *)image animated:(bool)animated
|
|
{
|
|
[_snapshotView removeFromSuperview];
|
|
|
|
UIImageView *snapshotView = [[UIImageView alloc] initWithFrame:_wrapperView.frame];
|
|
snapshotView.contentMode = UIViewContentModeScaleAspectFill;
|
|
snapshotView.image = image;
|
|
[self insertSubview:snapshotView aboveSubview:_wrapperView];
|
|
|
|
if (@available(iOS 11.0, *)) {
|
|
snapshotView.accessibilityIgnoresInvertColors = true;
|
|
}
|
|
|
|
_snapshotView = snapshotView;
|
|
|
|
if (animated)
|
|
{
|
|
_snapshotView.alpha = 0.0f;
|
|
[UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:^
|
|
{
|
|
_snapshotView.alpha = 1.0f;
|
|
} completion:nil];
|
|
}
|
|
}
|
|
|
|
- (void)endTransitionAnimated:(bool)animated
|
|
{
|
|
if (animated)
|
|
{
|
|
UIView *snapshotView = _snapshotView;
|
|
_snapshotView = nil;
|
|
|
|
[UIView animateWithDuration:0.4f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState animations:^
|
|
{
|
|
snapshotView.alpha = 0.0f;
|
|
} completion:^(__unused BOOL finished)
|
|
{
|
|
[snapshotView removeFromSuperview];
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
[_snapshotView removeFromSuperview];
|
|
_snapshotView = nil;
|
|
}
|
|
}
|
|
|
|
- (bool)hasTransitionSnapshot {
|
|
return _snapshotView != nil;
|
|
}
|
|
|
|
- (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;
|
|
}
|
|
}
|
|
|
|
- (CGPoint)devicePointOfInterestForPoint:(CGPoint)point
|
|
{
|
|
return [_wrapperView captureDevicePointOfInterestForPoint:point];
|
|
}
|
|
|
|
- (void)layoutSubviews
|
|
{
|
|
_wrapperView.frame = self.bounds;
|
|
|
|
if (_snapshotView != nil)
|
|
{
|
|
CGSize imageSize = _snapshotView.frame.size;
|
|
if ([_snapshotView isKindOfClass:[UIImageView class]]) {
|
|
imageSize = ((UIImageView *)_snapshotView).image.size;
|
|
}
|
|
|
|
CGSize size = TGScaleToFill(imageSize, _wrapperView.frame.size);
|
|
_snapshotView.frame = CGRectMake(floor((self.frame.size.width - size.width) / 2.0f), floor((self.frame.size.height - size.height) / 2.0f), size.width, size.height);
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation 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];
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation TGCameraLegacyPreviewLayerWrapperView
|
|
|
|
- (NSString *)videoGravity
|
|
{
|
|
return self.previewLayer.videoGravity;
|
|
}
|
|
|
|
- (void)setVideoGravity:(NSString *)videoGravity
|
|
{
|
|
self.previewLayer.videoGravity = videoGravity;
|
|
}
|
|
|
|
- (AVCaptureConnection *)connection
|
|
{
|
|
return self.previewLayer.connection;
|
|
}
|
|
|
|
- (CGPoint)captureDevicePointOfInterestForPoint:(CGPoint)point
|
|
{
|
|
return [self.previewLayer captureDevicePointOfInterestForPoint:point];
|
|
}
|
|
|
|
- (AVCaptureVideoPreviewLayer *)previewLayer
|
|
{
|
|
return (AVCaptureVideoPreviewLayer *)self.layer;
|
|
}
|
|
|
|
+ (Class)layerClass
|
|
{
|
|
return [AVCaptureVideoPreviewLayer class];
|
|
}
|
|
|
|
@end
|