new delegate methods

Added new delegate methods; updated Videos example project
This commit is contained in:
Erekle 2016-04-29 12:59:15 +04:00
parent f54dd0f5ef
commit 399703dbb2
5 changed files with 547 additions and 824 deletions

View File

@ -12,6 +12,14 @@
@class AVAsset, AVPlayer, AVPlayerItem;
@protocol ASVideoNodeDelegate;
typedef enum {
ASVideoNodePlayerStateUnknown,
ASVideoNodePlayerStatePlaying,
ASVideoNodePlayerStateLoading,
ASVideoNodePlayerStatePaused,
ASVideoNodePlayerStateFinished
} ASVideoNodePlayerState;
NS_ASSUME_NONNULL_BEGIN
// IMPORTANT NOTES:
@ -40,6 +48,10 @@ NS_ASSUME_NONNULL_BEGIN
@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
@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.
*/
- (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
NS_ASSUME_NONNULL_END
#endif

View File

@ -43,11 +43,17 @@ static NSString * const kStatus = @"status";
BOOL _muted;
ASVideoNodePlayerState _playerState;
AVAsset *_asset;
AVPlayerItem *_currentPlayerItem;
AVPlayer *_player;
id _timeObserver;
int32_t _periodicTimeObserverTimescale;
CMTime _timeObserverInterval;
ASImageNode *_placeholderImageNode; // TODO: Make ASVideoNode an ASImageNode subclass; remove this.
ASButtonNode *_playButton;
@ -72,6 +78,7 @@ static NSString * const kStatus = @"status";
self.playButton = [[ASDefaultPlayButton alloc] init];
self.gravity = AVLayerVideoGravityResizeAspect;
_periodicTimeObserverTimescale = 10000;
[self addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
return self;
@ -231,11 +238,13 @@ static NSString * const kStatus = @"status";
if ([change[NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) {
[_spinner removeFromSupernode];
_spinner = nil;
// If we don't yet have a placeholder image update it now that we should have data available for it
if (_placeholderImageNode.image == nil) {
[self generatePlaceholderImage];
}
if(_shouldBePlaying) {
self.playerState = ASVideoNodePlayerStatePlaying;
}
}
} else if ([keyPath isEqualToString:kPlaybackLikelyToKeepUpKey]) {
if (_shouldBePlaying && [change[NSKeyValueChangeNewKey] boolValue] == true && ASInterfaceStateIncludesVisible(self.interfaceState)) {
@ -276,6 +285,24 @@ static NSString * const kStatus = @"status";
if (_placeholderImageNode.image == nil) {
[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
- (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
{
@ -400,6 +444,10 @@ static NSString * const kStatus = @"status";
- (void)play
{
ASDN::MutexLocker l(_videoLock);
if(![self isStateChangeValid:ASVideoNodePlayerStatePlaying]){
return;
}
if (_player == nil) {
[self setNeedsDataFetch];
@ -415,13 +463,13 @@ static NSString * const kStatus = @"status";
}
}
[_player play];
_shouldBePlaying = YES;
[UIView animateWithDuration:0.15 animations:^{
_playButton.alpha = 0.0;
}];
if (![self ready]) {
if (!_spinner) {
_spinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{
@ -433,8 +481,10 @@ static NSString * const kStatus = @"status";
[self addSubnode:_spinner];
}
self.playerState = ASVideoNodePlayerStateLoading;
[(UIActivityIndicatorView *)_spinner.view startAnimating];
}else{
self.playerState = ASVideoNodePlayerStatePlaying;
}
}
@ -446,7 +496,10 @@ static NSString * const kStatus = @"status";
- (void)pause
{
ASDN::MutexLocker l(_videoLock);
if(![self isStateChangeValid:ASVideoNodePlayerStatePaused]){
return;
}
self.playerState = ASVideoNodePlayerStatePaused;
[_player pause];
[((UIActivityIndicatorView *)_spinner.view) stopAnimating];
_shouldBePlaying = NO;
@ -462,11 +515,22 @@ static NSString * const kStatus = @"status";
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
- (void)didPlayToEnd:(NSNotification *)notification
{
self.playerState = ASVideoNodePlayerStateFinished;
if ([_delegate respondsToSelector:@selector(videoPlaybackDidFinish:)]) {
[_delegate videoPlaybackDidFinish:self];
}
@ -563,6 +627,8 @@ static NSString * const kStatus = @"status";
- (void)dealloc
{
[_player removeTimeObserver:_timeObserver];
_timeObserver = nil;
[_playButton removeTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
[self removePlayerItemObservers:_currentPlayerItem];
}

File diff suppressed because it is too large Load Diff

View 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>

View File

@ -12,7 +12,7 @@
#import "ViewController.h"
@interface ViewController()<ASVideoNodeDelegate>
@property (nonatomic) ASVideoNode *videoNode;
@property (nonatomic,strong) ASVideoNode *guitarVideoNode;
@end
@implementation ViewController
@ -20,9 +20,8 @@
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
ASVideoNode *guitarVideo = [self guitarVideo];
[self.view addSubnode:guitarVideo];
[self.view addSubnode:self.guitarVideoNode];
ASVideoNode *nicCageVideo = [self nicCageVideo];
[self.view addSubnode:nicCageVideo];
@ -31,19 +30,26 @@
[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;
@ -62,7 +68,7 @@
nicCageVideo.shouldAutorepeat = YES;
nicCageVideo.shouldAutoplay = YES;
nicCageVideo.muted = YES;
return nicCageVideo;
}
@ -80,6 +86,7 @@
simonVideo.backgroundColor = [UIColor lightGrayColor];
simonVideo.shouldAutorepeat = YES;
simonVideo.shouldAutoplay = YES;
simonVideo.muted = YES;
return simonVideo;
}
@ -94,12 +101,20 @@
playButton.bounds = CGRectMake(0, 0, playButton.calculatedSize.width, playButton.calculatedSize.height);
playButton.position = CGPointMake([UIScreen mainScreen].bounds.size.width/4, ([UIScreen mainScreen].bounds.size.height/3)/2);
[playButton setImage:[UIImage imageNamed:@"playButtonSelected@2x.png"] forState:ASControlStateHighlighted];
return playButton;
}
- (void)videoNodeWasTapped:(ASVideoNode *)videoNode
{
if(videoNode == self.guitarVideoNode){
if(videoNode.playerState == ASVideoNodePlayerStatePlaying){
[videoNode pause];
}else{
[videoNode play];
}
return;
}
if (videoNode.player.muted == YES) {
videoNode.player.muted = NO;
} else {
@ -107,4 +122,28 @@
}
}
@end
#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