mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-08 05:30:47 +00:00
293 lines
6.9 KiB
Plaintext
293 lines
6.9 KiB
Plaintext
|
|
|
|
#import "ASVideoNode.h"
|
|
|
|
@interface ASVideoNode () {
|
|
ASDN::RecursiveMutex _lock;
|
|
|
|
__weak id<ASVideoNodeDatasource> _datasource;
|
|
|
|
BOOL _shouldBePlaying;
|
|
AVAsset *_asset;
|
|
AVPlayerItem *_currentItem;
|
|
ASButtonNode *_playButton;
|
|
ASDisplayNode *_playerNode;
|
|
ASDisplayNode *_spinner;
|
|
}
|
|
|
|
@end
|
|
|
|
@interface ASDisplayNode ()
|
|
- (void)setInterfaceState:(ASInterfaceState)newState;
|
|
@end
|
|
|
|
@implementation ASVideoNode
|
|
|
|
- (instancetype)init {
|
|
if (!(self = [super init])) { return nil; }
|
|
|
|
_playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{ return [[AVPlayerLayer alloc] init]; }];
|
|
[self addSubnode:_playerNode];
|
|
|
|
self.gravity = ASVideoGravityResizeAspect;
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(restartVideo:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)setInterfaceState:(ASInterfaceState)newState
|
|
{
|
|
[super setInterfaceState:newState];
|
|
|
|
if (!(newState & ASInterfaceStateVisible)) {
|
|
[self pause];
|
|
[_spinner removeFromSupernode];
|
|
} else {
|
|
if (_shouldBePlaying) {
|
|
[self play];
|
|
}
|
|
if (_spinner) {
|
|
[self addSubnode:_spinner];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
|
{
|
|
if ([[change objectForKey:@"new"] integerValue] == AVPlayerItemStatusReadyToPlay) {
|
|
if ([self.subnodes containsObject:_spinner]) {
|
|
[_spinner removeFromSupernode];
|
|
_spinner = nil;
|
|
}
|
|
}
|
|
|
|
if ([[change objectForKey:@"new"] integerValue] == AVPlayerItemStatusFailed) {
|
|
|
|
}
|
|
}
|
|
|
|
- (void)restartVideo:(NSNotification *)notification
|
|
{
|
|
if ( [[[notification object] asset] isEqual:_asset]) {
|
|
[[((AVPlayerLayer *)_playerNode.layer) player] seekToTime:CMTimeMakeWithSeconds(0, 1)];
|
|
|
|
if (_autorepeat) {
|
|
[self play];
|
|
} else {
|
|
[self pause];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)layoutDidFinish
|
|
{
|
|
_playerNode.frame = self.bounds;
|
|
}
|
|
|
|
- (void)didLoad {
|
|
[super didLoad];
|
|
|
|
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped)];
|
|
[self.view addGestureRecognizer:tap];
|
|
}
|
|
|
|
- (void)tapped
|
|
{
|
|
if (_shouldBePlaying) {
|
|
[self pause];
|
|
} else {
|
|
[self play];
|
|
}
|
|
}
|
|
|
|
- (instancetype)initWithViewBlock:(ASDisplayNodeViewBlock)viewBlock didLoadBlock:(ASDisplayNodeDidLoadBlock)didLoadBlock
|
|
{
|
|
ASDisplayNodeAssertNotSupported();
|
|
return nil;
|
|
}
|
|
|
|
- (void)fetchData
|
|
{
|
|
[super fetchData];
|
|
|
|
@try {
|
|
[_currentItem removeObserver:self forKeyPath:NSStringFromSelector(@selector(status))];
|
|
}
|
|
@catch (NSException * __unused exception) {
|
|
NSLog(@"unnecessary removal in fetch data");
|
|
}
|
|
|
|
{
|
|
ASDN::MutexLocker l(_lock);
|
|
_currentItem = [[AVPlayerItem alloc] initWithAsset:_asset];
|
|
[_currentItem addObserver:self forKeyPath:NSStringFromSelector(@selector(status)) options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL];
|
|
|
|
if (((AVPlayerLayer *)_playerNode.layer).player) {
|
|
[((AVPlayerLayer *)_playerNode.layer).player replaceCurrentItemWithPlayerItem:_currentItem];
|
|
} else {
|
|
((AVPlayerLayer *)_playerNode.layer).player = [[AVPlayer alloc] initWithPlayerItem:_currentItem];
|
|
}
|
|
|
|
}
|
|
if (_shouldAutoPlay) {
|
|
[self play];
|
|
}
|
|
}
|
|
|
|
//- (void)fetchData
|
|
//{
|
|
// [super fetchData];
|
|
//
|
|
// @try {
|
|
// [_currentItem removeObserver:self forKeyPath:NSStringFromSelector(@selector(status))];
|
|
// }
|
|
// @catch (NSException * __unused exception) {
|
|
// NSLog(@"unnecessary removal in fetch data");
|
|
// }
|
|
//
|
|
// {
|
|
// ASDN::MutexLocker l(_lock);
|
|
//
|
|
// _currentItem = [[AVPlayerItem alloc] initWithAsset:_asset];
|
|
// [_currentItem addObserver:self forKeyPath:NSStringFromSelector(@selector(status)) options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL];
|
|
//
|
|
// [((AVPlayerLayer *)_playerNode.layer).player replaceCurrentItemWithPlayerItem:_currentItem];
|
|
// }
|
|
//
|
|
// if (_shouldAutoPlay) {
|
|
// [self play];
|
|
// }
|
|
//}
|
|
|
|
- (void)clearFetchedData
|
|
{
|
|
[super clearFetchedData];
|
|
|
|
{
|
|
ASDN::MutexLocker l(_lock);
|
|
((AVPlayerLayer *)_playerNode.layer).player = nil;
|
|
_shouldBePlaying = NO;
|
|
}
|
|
}
|
|
|
|
- (void)setPlayButton:(ASButtonNode *)playButton
|
|
{
|
|
ASDN::MutexLocker l(_lock);
|
|
|
|
_playButton = playButton;
|
|
|
|
[self addSubnode:playButton];
|
|
|
|
[_playButton addTarget:self action:@selector(play) forControlEvents:ASControlNodeEventTouchUpInside];
|
|
}
|
|
|
|
- (ASButtonNode *)playButton
|
|
{
|
|
ASDN::MutexLocker l(_lock);
|
|
|
|
return _playButton;
|
|
}
|
|
|
|
- (void)setAsset:(AVAsset *)asset
|
|
{
|
|
ASDN::MutexLocker l(_lock);
|
|
|
|
if (ASObjectIsEqual(((AVURLAsset *)asset).URL, ((AVURLAsset *)_asset).URL)) {
|
|
return;
|
|
}
|
|
|
|
_asset = asset;
|
|
|
|
if (self.interfaceState & ASInterfaceStateFetchData) {
|
|
[self fetchData];
|
|
}
|
|
}
|
|
|
|
- (AVAsset *)asset
|
|
{
|
|
ASDN::MutexLocker l(_lock);
|
|
return _asset;
|
|
}
|
|
|
|
- (void)setGravity:(ASVideoGravity)gravity {
|
|
ASDN::MutexLocker l(_lock);
|
|
|
|
switch (gravity) {
|
|
case ASVideoGravityResize:
|
|
((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResize;
|
|
break;
|
|
case ASVideoGravityResizeAspect:
|
|
((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspect;
|
|
break;
|
|
case ASVideoGravityResizeAspectFill:
|
|
((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspectFill;
|
|
break;
|
|
default:
|
|
((AVPlayerLayer *)_playerNode.layer).videoGravity = AVLayerVideoGravityResizeAspect;
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (ASVideoGravity)gravity;
|
|
{
|
|
ASDN::MutexLocker l(_lock);
|
|
|
|
if ([((AVPlayerLayer *)_playerNode.layer).contentsGravity isEqualToString:AVLayerVideoGravityResize]) {
|
|
return ASVideoGravityResize;
|
|
}
|
|
if ([((AVPlayerLayer *)_playerNode.layer).contentsGravity isEqualToString:AVLayerVideoGravityResizeAspectFill]) {
|
|
return ASVideoGravityResizeAspectFill;
|
|
}
|
|
|
|
return ASVideoGravityResizeAspect;
|
|
}
|
|
|
|
- (void)play;
|
|
{
|
|
ASDN::MutexLocker l(_lock);
|
|
|
|
[[((AVPlayerLayer *)_playerNode.layer) player] play];
|
|
_shouldBePlaying = YES;
|
|
_playButton.alpha = 0.0;
|
|
if ([self ready] && ![self.subnodes containsObject:_spinner]) {
|
|
_spinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{
|
|
UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc] initWithFrame:_playButton.frame];
|
|
spinnnerView.color = [UIColor whiteColor];
|
|
[spinnnerView startAnimating];
|
|
|
|
return spinnnerView;
|
|
}];
|
|
|
|
[self addSubnode:_spinner];
|
|
}
|
|
}
|
|
|
|
- (BOOL)ready;
|
|
{
|
|
return [((AVPlayerLayer *)_playerNode.layer) player].currentItem.status != AVPlayerItemStatusReadyToPlay;
|
|
}
|
|
|
|
- (void)pause;
|
|
{
|
|
ASDN::MutexLocker l(_lock);
|
|
|
|
[[((AVPlayerLayer *)_playerNode.layer) player] pause];
|
|
_shouldBePlaying = NO;
|
|
_playButton.alpha = 1.0;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
@try {
|
|
[_currentItem removeObserver:self forKeyPath:NSStringFromSelector(@selector(status))];
|
|
}
|
|
@catch (NSException * __unused exception) {
|
|
NSLog(@"unnecessary removal in dealloc");
|
|
}
|
|
}
|
|
|
|
@end
|
|
|