mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 19:30:29 +00:00
new delegate methods
Added new delegate methods; updated Videos example project
This commit is contained in:
parent
f54dd0f5ef
commit
399703dbb2
@ -12,6 +12,14 @@
|
|||||||
@class AVAsset, AVPlayer, AVPlayerItem;
|
@class AVAsset, AVPlayer, AVPlayerItem;
|
||||||
@protocol ASVideoNodeDelegate;
|
@protocol ASVideoNodeDelegate;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ASVideoNodePlayerStateUnknown,
|
||||||
|
ASVideoNodePlayerStatePlaying,
|
||||||
|
ASVideoNodePlayerStateLoading,
|
||||||
|
ASVideoNodePlayerStatePaused,
|
||||||
|
ASVideoNodePlayerStateFinished
|
||||||
|
} ASVideoNodePlayerState;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
// IMPORTANT NOTES:
|
// IMPORTANT NOTES:
|
||||||
@ -40,6 +48,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@property (nonatomic, assign, readwrite) BOOL muted;
|
@property (nonatomic, assign, readwrite) BOOL muted;
|
||||||
|
|
||||||
|
@property (nonatomic, assign, readonly) ASVideoNodePlayerState playerState;
|
||||||
|
//! Defaults to 100
|
||||||
|
@property (nonatomic, assign, readwrite) int32_t periodicTimeObserverTimescale;
|
||||||
|
|
||||||
//! Defaults to AVLayerVideoGravityResizeAspect
|
//! Defaults to AVLayerVideoGravityResizeAspect
|
||||||
@property (atomic) NSString *gravity;
|
@property (atomic) NSString *gravity;
|
||||||
|
|
||||||
@ -63,6 +75,31 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
* @discussion The video's play state is toggled if this method is not implemented.
|
* @discussion The video's play state is toggled if this method is not implemented.
|
||||||
*/
|
*/
|
||||||
- (void)videoNodeWasTapped:(ASVideoNode *)videoNode;
|
- (void)videoNodeWasTapped:(ASVideoNode *)videoNode;
|
||||||
|
/**
|
||||||
|
* @abstract Delegate method invoked when player changes state.
|
||||||
|
* @param videoNode The video node that was tapped.
|
||||||
|
* @param state player state before this change.
|
||||||
|
* @param toSate player new state.
|
||||||
|
* @discussion This method is called after each state change
|
||||||
|
*/
|
||||||
|
- (void)videoNode:(ASVideoNode *)videoNode willChangePlayerState:(ASVideoNodePlayerState)state toState:(ASVideoNodePlayerState)toSate;
|
||||||
|
/**
|
||||||
|
* @abstract Ssks delegate if state change is allowed
|
||||||
|
* ASVideoNodePlayerStatePlaying or ASVideoNodePlayerStatePaused.
|
||||||
|
* asks delegate if state change is allowed.
|
||||||
|
* @param videoNode The video node that was tapped.
|
||||||
|
* @param state player state that is going to be set.
|
||||||
|
* @discussion Delegate method invoked when player changes it's state to
|
||||||
|
* ASVideoNodePlayerStatePlaying or ASVideoNodePlayerStatePaused
|
||||||
|
* and asks delegate if state change is valid
|
||||||
|
*/
|
||||||
|
- (BOOL)videoNode:(ASVideoNode*)videoNode shouldChangePlayerStateTo:(ASVideoNodePlayerState)state;
|
||||||
|
/**
|
||||||
|
* @abstract Delegate method invoked when player playback time is updated.
|
||||||
|
* @param videoNode The video node that was tapped.
|
||||||
|
* @param second current playback time in seconds.
|
||||||
|
*/
|
||||||
|
- (void)videoNode:(ASVideoNode *)videoNode didPlayToSecond:(NSTimeInterval)second;
|
||||||
@end
|
@end
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -43,11 +43,17 @@ static NSString * const kStatus = @"status";
|
|||||||
|
|
||||||
BOOL _muted;
|
BOOL _muted;
|
||||||
|
|
||||||
|
ASVideoNodePlayerState _playerState;
|
||||||
|
|
||||||
AVAsset *_asset;
|
AVAsset *_asset;
|
||||||
|
|
||||||
AVPlayerItem *_currentPlayerItem;
|
AVPlayerItem *_currentPlayerItem;
|
||||||
AVPlayer *_player;
|
AVPlayer *_player;
|
||||||
|
|
||||||
|
id _timeObserver;
|
||||||
|
int32_t _periodicTimeObserverTimescale;
|
||||||
|
CMTime _timeObserverInterval;
|
||||||
|
|
||||||
ASImageNode *_placeholderImageNode; // TODO: Make ASVideoNode an ASImageNode subclass; remove this.
|
ASImageNode *_placeholderImageNode; // TODO: Make ASVideoNode an ASImageNode subclass; remove this.
|
||||||
|
|
||||||
ASButtonNode *_playButton;
|
ASButtonNode *_playButton;
|
||||||
@ -72,6 +78,7 @@ static NSString * const kStatus = @"status";
|
|||||||
|
|
||||||
self.playButton = [[ASDefaultPlayButton alloc] init];
|
self.playButton = [[ASDefaultPlayButton alloc] init];
|
||||||
self.gravity = AVLayerVideoGravityResizeAspect;
|
self.gravity = AVLayerVideoGravityResizeAspect;
|
||||||
|
_periodicTimeObserverTimescale = 10000;
|
||||||
[self addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
|
[self addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@ -231,11 +238,13 @@ static NSString * const kStatus = @"status";
|
|||||||
if ([change[NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) {
|
if ([change[NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) {
|
||||||
[_spinner removeFromSupernode];
|
[_spinner removeFromSupernode];
|
||||||
_spinner = nil;
|
_spinner = nil;
|
||||||
|
|
||||||
// If we don't yet have a placeholder image update it now that we should have data available for it
|
// If we don't yet have a placeholder image update it now that we should have data available for it
|
||||||
if (_placeholderImageNode.image == nil) {
|
if (_placeholderImageNode.image == nil) {
|
||||||
[self generatePlaceholderImage];
|
[self generatePlaceholderImage];
|
||||||
}
|
}
|
||||||
|
if(_shouldBePlaying) {
|
||||||
|
self.playerState = ASVideoNodePlayerStatePlaying;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if ([keyPath isEqualToString:kPlaybackLikelyToKeepUpKey]) {
|
} else if ([keyPath isEqualToString:kPlaybackLikelyToKeepUpKey]) {
|
||||||
if (_shouldBePlaying && [change[NSKeyValueChangeNewKey] boolValue] == true && ASInterfaceStateIncludesVisible(self.interfaceState)) {
|
if (_shouldBePlaying && [change[NSKeyValueChangeNewKey] boolValue] == true && ASInterfaceStateIncludesVisible(self.interfaceState)) {
|
||||||
@ -276,6 +285,24 @@ static NSString * const kStatus = @"status";
|
|||||||
if (_placeholderImageNode.image == nil) {
|
if (_placeholderImageNode.image == nil) {
|
||||||
[self generatePlaceholderImage];
|
[self generatePlaceholderImage];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak __typeof(self) weakSelf = self;
|
||||||
|
_timeObserverInterval = CMTimeMake(1, _periodicTimeObserverTimescale);
|
||||||
|
_timeObserver = [_player addPeriodicTimeObserverForInterval:_timeObserverInterval queue:NULL usingBlock:^(CMTime time){
|
||||||
|
[weakSelf periodicTimeObserver:time];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)periodicTimeObserver:(CMTime)time
|
||||||
|
{
|
||||||
|
NSTimeInterval timeInSeconds = CMTimeGetSeconds(time);
|
||||||
|
if (timeInSeconds <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_delegate && [_delegate respondsToSelector:@selector(videoNode:didPlayToSecond:)]){
|
||||||
|
[_delegate videoNode:self didPlayToSecond:timeInSeconds];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,6 +337,23 @@ static NSString * const kStatus = @"status";
|
|||||||
|
|
||||||
|
|
||||||
#pragma mark - Video Properties
|
#pragma mark - Video Properties
|
||||||
|
- (void)setPlayerState:(ASVideoNodePlayerState)playerState
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_videoLock);
|
||||||
|
|
||||||
|
ASVideoNodePlayerState oldState = _playerState;
|
||||||
|
|
||||||
|
if(oldState == playerState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(videoNode:willChangePlayerState:toState:)]) {
|
||||||
|
[_delegate videoNode:self willChangePlayerState:oldState toState:playerState];
|
||||||
|
}
|
||||||
|
|
||||||
|
_playerState = playerState;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setPlayButton:(ASButtonNode *)playButton
|
- (void)setPlayButton:(ASButtonNode *)playButton
|
||||||
{
|
{
|
||||||
@ -401,6 +445,10 @@ static NSString * const kStatus = @"status";
|
|||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_videoLock);
|
ASDN::MutexLocker l(_videoLock);
|
||||||
|
|
||||||
|
if(![self isStateChangeValid:ASVideoNodePlayerStatePlaying]){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_player == nil) {
|
if (_player == nil) {
|
||||||
[self setNeedsDataFetch];
|
[self setNeedsDataFetch];
|
||||||
}
|
}
|
||||||
@ -415,13 +463,13 @@ static NSString * const kStatus = @"status";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[_player play];
|
[_player play];
|
||||||
_shouldBePlaying = YES;
|
_shouldBePlaying = YES;
|
||||||
|
|
||||||
[UIView animateWithDuration:0.15 animations:^{
|
[UIView animateWithDuration:0.15 animations:^{
|
||||||
_playButton.alpha = 0.0;
|
_playButton.alpha = 0.0;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
if (![self ready]) {
|
if (![self ready]) {
|
||||||
if (!_spinner) {
|
if (!_spinner) {
|
||||||
_spinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{
|
_spinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{
|
||||||
@ -433,8 +481,10 @@ static NSString * const kStatus = @"status";
|
|||||||
|
|
||||||
[self addSubnode:_spinner];
|
[self addSubnode:_spinner];
|
||||||
}
|
}
|
||||||
|
self.playerState = ASVideoNodePlayerStateLoading;
|
||||||
[(UIActivityIndicatorView *)_spinner.view startAnimating];
|
[(UIActivityIndicatorView *)_spinner.view startAnimating];
|
||||||
|
}else{
|
||||||
|
self.playerState = ASVideoNodePlayerStatePlaying;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,7 +496,10 @@ static NSString * const kStatus = @"status";
|
|||||||
- (void)pause
|
- (void)pause
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_videoLock);
|
ASDN::MutexLocker l(_videoLock);
|
||||||
|
if(![self isStateChangeValid:ASVideoNodePlayerStatePaused]){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.playerState = ASVideoNodePlayerStatePaused;
|
||||||
[_player pause];
|
[_player pause];
|
||||||
[((UIActivityIndicatorView *)_spinner.view) stopAnimating];
|
[((UIActivityIndicatorView *)_spinner.view) stopAnimating];
|
||||||
_shouldBePlaying = NO;
|
_shouldBePlaying = NO;
|
||||||
@ -462,11 +515,22 @@ static NSString * const kStatus = @"status";
|
|||||||
return (_player.rate > 0 && !_player.error);
|
return (_player.rate > 0 && !_player.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isStateChangeValid:(ASVideoNodePlayerState)state
|
||||||
|
{
|
||||||
|
if([_delegate respondsToSelector:@selector(videoNode:shouldChangePlayerStateTo:)]){
|
||||||
|
if(![_delegate videoNode:self shouldChangePlayerStateTo:state]){
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Playback observers
|
#pragma mark - Playback observers
|
||||||
|
|
||||||
- (void)didPlayToEnd:(NSNotification *)notification
|
- (void)didPlayToEnd:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
|
self.playerState = ASVideoNodePlayerStateFinished;
|
||||||
if ([_delegate respondsToSelector:@selector(videoPlaybackDidFinish:)]) {
|
if ([_delegate respondsToSelector:@selector(videoPlaybackDidFinish:)]) {
|
||||||
[_delegate videoPlaybackDidFinish:self];
|
[_delegate videoPlaybackDidFinish:self];
|
||||||
}
|
}
|
||||||
@ -563,6 +627,8 @@ static NSString * const kStatus = @"status";
|
|||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
|
[_player removeTimeObserver:_timeObserver];
|
||||||
|
_timeObserver = nil;
|
||||||
[_playButton removeTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
|
[_playButton removeTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
|
||||||
[self removePlayerItemObservers:_currentPlayerItem];
|
[self removePlayerItemObservers:_currentPlayerItem];
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
10
examples/Videos/Sample.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
examples/Videos/Sample.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:Sample.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
#import "ViewController.h"
|
#import "ViewController.h"
|
||||||
|
|
||||||
@interface ViewController()<ASVideoNodeDelegate>
|
@interface ViewController()<ASVideoNodeDelegate>
|
||||||
@property (nonatomic) ASVideoNode *videoNode;
|
@property (nonatomic,strong) ASVideoNode *guitarVideoNode;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ViewController
|
@implementation ViewController
|
||||||
@ -21,8 +21,7 @@
|
|||||||
{
|
{
|
||||||
[super viewWillAppear:animated];
|
[super viewWillAppear:animated];
|
||||||
|
|
||||||
ASVideoNode *guitarVideo = [self guitarVideo];
|
[self.view addSubnode:self.guitarVideoNode];
|
||||||
[self.view addSubnode:guitarVideo];
|
|
||||||
|
|
||||||
ASVideoNode *nicCageVideo = [self nicCageVideo];
|
ASVideoNode *nicCageVideo = [self nicCageVideo];
|
||||||
[self.view addSubnode:nicCageVideo];
|
[self.view addSubnode:nicCageVideo];
|
||||||
@ -31,19 +30,26 @@
|
|||||||
[self.view addSubnode:simonVideo];
|
[self.view addSubnode:simonVideo];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASVideoNode *)guitarVideo;
|
- (ASVideoNode *)guitarVideoNode;
|
||||||
{
|
{
|
||||||
ASVideoNode *videoNode = [[ASVideoNode alloc] init];
|
if(_guitarVideoNode){
|
||||||
|
return _guitarVideoNode;
|
||||||
|
}
|
||||||
|
_guitarVideoNode = [[ASVideoNode alloc] init];
|
||||||
|
|
||||||
videoNode.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-3045b261-7e93-4492-b7e5-5d6358376c9f-editedLiveAndDie.mov"]];
|
_guitarVideoNode.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-3045b261-7e93-4492-b7e5-5d6358376c9f-editedLiveAndDie.mov"]];
|
||||||
|
|
||||||
videoNode.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height/3);
|
_guitarVideoNode.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height/3);
|
||||||
|
|
||||||
videoNode.gravity = AVLayerVideoGravityResizeAspectFill;
|
_guitarVideoNode.gravity = AVLayerVideoGravityResizeAspectFill;
|
||||||
|
|
||||||
videoNode.backgroundColor = [UIColor lightGrayColor];
|
_guitarVideoNode.backgroundColor = [UIColor lightGrayColor];
|
||||||
|
|
||||||
return videoNode;
|
_guitarVideoNode.periodicTimeObserverTimescale = 1; //Default is 100
|
||||||
|
|
||||||
|
_guitarVideoNode.delegate = self;
|
||||||
|
|
||||||
|
return _guitarVideoNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASVideoNode *)nicCageVideo;
|
- (ASVideoNode *)nicCageVideo;
|
||||||
@ -80,6 +86,7 @@
|
|||||||
simonVideo.backgroundColor = [UIColor lightGrayColor];
|
simonVideo.backgroundColor = [UIColor lightGrayColor];
|
||||||
simonVideo.shouldAutorepeat = YES;
|
simonVideo.shouldAutorepeat = YES;
|
||||||
simonVideo.shouldAutoplay = YES;
|
simonVideo.shouldAutoplay = YES;
|
||||||
|
simonVideo.muted = YES;
|
||||||
|
|
||||||
return simonVideo;
|
return simonVideo;
|
||||||
}
|
}
|
||||||
@ -100,6 +107,14 @@
|
|||||||
|
|
||||||
- (void)videoNodeWasTapped:(ASVideoNode *)videoNode
|
- (void)videoNodeWasTapped:(ASVideoNode *)videoNode
|
||||||
{
|
{
|
||||||
|
if(videoNode == self.guitarVideoNode){
|
||||||
|
if(videoNode.playerState == ASVideoNodePlayerStatePlaying){
|
||||||
|
[videoNode pause];
|
||||||
|
}else{
|
||||||
|
[videoNode play];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (videoNode.player.muted == YES) {
|
if (videoNode.player.muted == YES) {
|
||||||
videoNode.player.muted = NO;
|
videoNode.player.muted = NO;
|
||||||
} else {
|
} else {
|
||||||
@ -107,4 +122,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - ASVideoNodeDelegate
|
||||||
|
- (void)videoNode:(ASVideoNode *)videoNode willChangePlayerState:(ASVideoNodePlayerState)state toState:(ASVideoNodePlayerState)toSate{
|
||||||
|
//Ignore nicCageVideo
|
||||||
|
if(videoNode != _guitarVideoNode){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(toSate == ASVideoNodePlayerStatePlaying){
|
||||||
|
NSLog(@"guitarVideoNode is playing");
|
||||||
|
}else if(toSate == ASVideoNodePlayerStateFinished){
|
||||||
|
NSLog(@"guitarVideoNode finished");
|
||||||
|
}else if(toSate == ASVideoNodePlayerStateLoading){
|
||||||
|
NSLog(@"guitarVideoNode is buffering");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)videoNode:(ASVideoNode *)videoNode didPlayToSecond:(NSTimeInterval)second{
|
||||||
|
if(videoNode != _guitarVideoNode){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"guitarVideoNode playback time is: %f",second);
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
Loading…
x
Reference in New Issue
Block a user