Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit 2e65339

Browse files
flovouinappleguy
authored andcommitted
[ASVideoNode, ASVideoPlayerNode] Add video composition and audio mix capabilities (#1800)
* [ASVideoNode] Add delegate method called when the currentItem is set. * [ASVideoNode] Add videoComposition and audioMix properties to the ASVideoNode. * [ASVideoPlayerNode] Add new initialiser with videoComposition and audioMix, and forward new delegate method. * [ASVideoPlayerNode] Forward missing ASVideoNodeDelegate methods.
1 parent 1044799 commit 2e65339

4 files changed

Lines changed: 178 additions & 7 deletions

File tree

AsyncDisplayKit/ASVideoNode.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#import <AsyncDisplayKit/ASButtonNode.h>
1313
#import <AsyncDisplayKit/ASNetworkImageNode.h>
1414

15-
@class AVAsset, AVPlayer, AVPlayerItem;
15+
@class AVAsset, AVPlayer, AVPlayerItem, AVVideoComposition, AVAudioMix;
1616
@protocol ASVideoNodeDelegate;
1717

1818
typedef enum {
@@ -41,6 +41,8 @@ NS_ASSUME_NONNULL_BEGIN
4141
- (BOOL)isPlaying;
4242

4343
@property (nullable, atomic, strong, readwrite) AVAsset *asset;
44+
@property (nullable, atomic, strong, readwrite) AVVideoComposition *videoComposition;
45+
@property (nullable, atomic, strong, readwrite) AVAudioMix *audioMix;
4446

4547
@property (nullable, atomic, strong, readonly) AVPlayer *player;
4648
@property (nullable, atomic, strong, readonly) AVPlayerItem *currentItem;
@@ -121,6 +123,12 @@ NS_ASSUME_NONNULL_BEGIN
121123
* @param videoNode The videoNode
122124
*/
123125
- (void)videoNodeDidFinishInitialLoading:(ASVideoNode *)videoNode;
126+
/**
127+
* @abstract Delegate method invoked when the AVPlayerItem for the asset has been set up and can be accessed throught currentItem.
128+
* @param videoNode The videoNode.
129+
* @param currentItem The AVPlayerItem that was constructed from the asset.
130+
*/
131+
- (void)videoNode:(ASVideoNode *)videoNode didSetCurrentItem:(AVPlayerItem *)currentItem;
124132
/**
125133
* @abstract Delegate method invoked when the video node has recovered from the stall
126134
* @param videoNode The videoNode

AsyncDisplayKit/ASVideoNode.mm

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ @interface ASVideoNode ()
4949
unsigned int delegateVideoNodeDidPlayToTimeInterval:1;
5050
unsigned int delegateVideoNodeDidStartInitialLoading:1;
5151
unsigned int delegateVideoNodeDidFinishInitialLoading:1;
52+
unsigned int delegateVideoNodeDidSetCurrentItem:1;
5253
unsigned int delegateVideoNodeDidStallAtTimeInterval:1;
5354
unsigned int delegateVideoNodeDidRecoverFromStall:1;
5455

@@ -68,6 +69,8 @@ @interface ASVideoNode ()
6869
ASVideoNodePlayerState _playerState;
6970

7071
AVAsset *_asset;
72+
AVVideoComposition *_videoComposition;
73+
AVAudioMix *_audioMix;
7174

7275
AVPlayerItem *_currentPlayerItem;
7376
AVPlayer *_player;
@@ -124,7 +127,10 @@ - (AVPlayerItem *)constructPlayerItem
124127
ASDN::MutexLocker l(_propertyLock);
125128

126129
if (_asset != nil) {
127-
return [[AVPlayerItem alloc] initWithAsset:_asset];
130+
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:_asset];
131+
playerItem.videoComposition = _videoComposition;
132+
playerItem.audioMix = _audioMix;
133+
return playerItem;
128134
}
129135

130136
return nil;
@@ -153,7 +159,11 @@ - (void)prepareToPlayAsset:(AVAsset *)asset withKeys:(NSArray<NSString *> *)requ
153159
} else {
154160
self.player = [AVPlayer playerWithPlayerItem:playerItem];
155161
}
156-
162+
163+
if (_delegateFlags.delegateVideoNodeDidSetCurrentItem) {
164+
[_delegate videoNode:self didSetCurrentItem:playerItem];
165+
}
166+
157167
if (self.image == nil && self.URL == nil) {
158168
[self generatePlaceholderImage];
159169
}
@@ -448,6 +458,34 @@ - (AVAsset *)asset
448458
return _asset;
449459
}
450460

461+
- (void)setVideoComposition:(AVVideoComposition *)videoComposition
462+
{
463+
ASDN::MutexLocker l(_propertyLock);
464+
465+
_videoComposition = videoComposition;
466+
_currentPlayerItem.videoComposition = videoComposition;
467+
}
468+
469+
- (AVVideoComposition *)videoComposition
470+
{
471+
ASDN::MutexLocker l(_propertyLock);
472+
return _videoComposition;
473+
}
474+
475+
- (void)setAudioMix:(AVAudioMix *)audioMix
476+
{
477+
ASDN::MutexLocker l(_propertyLock);
478+
479+
_audioMix = audioMix;
480+
_currentPlayerItem.audioMix = audioMix;
481+
}
482+
483+
- (AVAudioMix *)audioMix
484+
{
485+
ASDN::MutexLocker l(_propertyLock);
486+
return _audioMix;
487+
}
488+
451489
- (AVPlayer *)player
452490
{
453491
ASDN::MutexLocker l(_propertyLock);
@@ -473,6 +511,7 @@ - (void)setDelegate:(id<ASVideoNodeDelegate>)delegate
473511
_delegateFlags.delegateVideoNodeDidPlayToTimeInterval = [_delegate respondsToSelector:@selector(videoNode:didPlayToTimeInterval:)];
474512
_delegateFlags.delegateVideoNodeDidStartInitialLoading = [_delegate respondsToSelector:@selector(videoNodeDidStartInitialLoading:)];
475513
_delegateFlags.delegateVideoNodeDidFinishInitialLoading = [_delegate respondsToSelector:@selector(videoNodeDidFinishInitialLoading:)];
514+
_delegateFlags.delegateVideoNodeDidSetCurrentItem = [_delegate respondsToSelector:@selector(videoNode:didSetCurrentItem:)];
476515
_delegateFlags.delegateVideoNodeDidStallAtTimeInterval = [_delegate respondsToSelector:@selector(videoNode:didStallAtTimeInterval:)];
477516
_delegateFlags.delegateVideoNodeDidRecoverFromStall = [_delegate respondsToSelector:@selector(videoNodeDidRecoverFromStall:)];
478517

@@ -697,4 +736,4 @@ - (void)dealloc
697736
}
698737

699738
@end
700-
#endif
739+
#endif

AsyncDisplayKit/ASVideoPlayerNode.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ NS_ASSUME_NONNULL_BEGIN
5858

5959
- (instancetype)initWithUrl:(NSURL*)url;
6060
- (instancetype)initWithAsset:(AVAsset*)asset;
61+
- (instancetype)initWithAsset:(AVAsset *)asset videoComposition:(AVVideoComposition *)videoComposition audioMix:(AVAudioMix *)audioMix;
6162
- (instancetype)initWithUrl:(NSURL *)url loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
6263
- (instancetype)initWithAsset:(AVAsset *)asset loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
64+
- (instancetype)initWithAsset:(AVAsset *)asset videoComposition:(AVVideoComposition *)videoComposition audioMix:(AVAudioMix *)audioMix loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
6365

6466
#pragma mark - Public API
6567
- (void)seekToTime:(CGFloat)percentComplete;
@@ -156,10 +158,43 @@ NS_ASSUME_NONNULL_BEGIN
156158

157159
/**
158160
* @abstract Delegate method invoked when the ASVideoNode has played to its end time.
159-
* @param videoPlayerNode The video node has played to its end time.
161+
* @param videoPlayer The video node has played to its end time.
160162
*/
161163
- (void)videoPlayerNodeDidPlayToEnd:(ASVideoPlayerNode *)videoPlayer;
162164

165+
/**
166+
* @abstract Delegate method invoked when the ASVideoNode has constructed its AVPlayerItem for the asset.
167+
* @param videoPlayer The video player node.
168+
* @param currentItem The AVPlayerItem that was constructed from the asset.
169+
*/
170+
- (void)videoPlayerNode:(ASVideoPlayerNode *)videoPlayer didSetCurrentItem:(AVPlayerItem *)currentItem;
171+
172+
/**
173+
* @abstract Delegate method invoked when the ASVideoNode stalls.
174+
* @param videoPlayer The video player node that has experienced the stall
175+
* @param second Current playback time when the stall happens
176+
*/
177+
- (void)videoPlayerNode:(ASVideoPlayerNode *)videoPlayer didStallAtTimeInterval:(NSTimeInterval)timeInterval;
178+
179+
/**
180+
* @abstract Delegate method invoked when the ASVideoNode starts the inital asset loading
181+
* @param videoPlayer The videoPlayer
182+
*/
183+
- (void)videoPlayerNodeDidStartInitialLoading:(ASVideoPlayerNode *)videoPlayer;
184+
185+
/**
186+
* @abstract Delegate method invoked when the ASVideoNode is done loading the asset and can start the playback
187+
* @param videoPlayer The videoPlayer
188+
*/
189+
- (void)videoPlayerNodeDidFinishInitialLoading:(ASVideoPlayerNode *)videoPlayer;
190+
191+
/**
192+
* @abstract Delegate method invoked when the ASVideoNode has recovered from the stall
193+
* @param videoPlayer The videoplayer
194+
*/
195+
- (void)videoPlayerNodeDidRecoverFromStall:(ASVideoPlayerNode *)videoPlayer;
196+
197+
163198
@end
164199
NS_ASSUME_NONNULL_END
165200
#endif

AsyncDisplayKit/ASVideoPlayerNode.mm

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,17 @@ @interface ASVideoPlayerNode() <ASVideoNodeDelegate>
3737
unsigned int delegateVideoNodeShouldChangeState:1;
3838
unsigned int delegateVideoNodePlaybackDidFinish:1;
3939
unsigned int delegateDidTapVideoPlayerNode:1;
40+
unsigned int delegateVideoPlayerNodeDidSetCurrentItem:1;
41+
unsigned int delegateVideoPlayerNodeDidStallAtTimeInterval:1;
42+
unsigned int delegateVideoPlayerNodeDidStartInitialLoading:1;
43+
unsigned int delegateVideoPlayerNodeDidFinishInitialLoading:1;
44+
unsigned int delegateVideoPlayerNodeDidRecoverFromStall:1;
4045
} _delegateFlags;
4146

4247
NSURL *_url;
4348
AVAsset *_asset;
49+
AVVideoComposition *_videoComposition;
50+
AVAudioMix *_audioMix;
4451

4552
ASVideoNode *_videoNode;
4653

@@ -118,6 +125,22 @@ - (instancetype)initWithAsset:(AVAsset *)asset
118125
return self;
119126
}
120127

128+
-(instancetype)initWithAsset:(AVAsset *)asset videoComposition:(AVVideoComposition *)videoComposition audioMix:(AVAudioMix *)audioMix
129+
{
130+
if (!(self = [super init])) {
131+
return nil;
132+
}
133+
134+
_asset = asset;
135+
_videoComposition = videoComposition;
136+
_audioMix = audioMix;
137+
_loadAssetWhenNodeBecomesVisible = YES;
138+
139+
[self _init];
140+
141+
return self;
142+
}
143+
121144
- (instancetype)initWithUrl:(NSURL *)url loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible
122145
{
123146
if (!(self = [super init])) {
@@ -147,6 +170,22 @@ - (instancetype)initWithAsset:(AVAsset *)asset loadAssetWhenNodeBecomesVisible:(
147170
return self;
148171
}
149172

173+
-(instancetype)initWithAsset:(AVAsset *)asset videoComposition:(AVVideoComposition *)videoComposition audioMix:(AVAudioMix *)audioMix loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible
174+
{
175+
if (!(self = [super init])) {
176+
return nil;
177+
}
178+
179+
_asset = asset;
180+
_videoComposition = videoComposition;
181+
_audioMix = audioMix;
182+
_loadAssetWhenNodeBecomesVisible = loadAssetWhenNodeBecomesVisible;
183+
184+
[self _init];
185+
186+
return self;
187+
}
188+
150189
- (void)_init
151190
{
152191
_defaultControlsColor = [UIColor whiteColor];
@@ -156,6 +195,8 @@ - (void)_init
156195
_videoNode.delegate = self;
157196
if (_loadAssetWhenNodeBecomesVisible == NO) {
158197
_videoNode.asset = _asset;
198+
_videoNode.videoComposition = _videoComposition;
199+
_videoNode.audioMix = _audioMix;
159200
}
160201
[self addSubnode:_videoNode];
161202
}
@@ -175,8 +216,16 @@ - (void)visibleStateDidChange:(BOOL)isVisible
175216

176217
ASDN::MutexLocker l(_propertyLock);
177218

178-
if (isVisible && _loadAssetWhenNodeBecomesVisible && _asset != _videoNode.asset) {
179-
_videoNode.asset = _asset;
219+
if (isVisible && _loadAssetWhenNodeBecomesVisible) {
220+
if (_asset != _videoNode.asset) {
221+
_videoNode.asset = _asset;
222+
}
223+
if (_videoComposition != _videoNode.videoComposition) {
224+
_videoNode.videoComposition = _videoComposition;
225+
}
226+
if (_audioMix != _videoNode.audioMix) {
227+
_videoNode.audioMix = _audioMix;
228+
}
180229
}
181230
}
182231

@@ -480,6 +529,41 @@ - (void)didTapVideoNode:(ASVideoNode *)videoNode
480529
}
481530
}
482531

532+
- (void)videoNode:(ASVideoNode *)videoNode didSetCurrentItem:(AVPlayerItem *)currentItem
533+
{
534+
if (_delegateFlags.delegateVideoPlayerNodeDidSetCurrentItem) {
535+
[_delegate videoPlayerNode:self didSetCurrentItem:currentItem];
536+
}
537+
}
538+
539+
- (void)videoNode:(ASVideoNode *)videoNode didStallAtTimeInterval:(NSTimeInterval)timeInterval
540+
{
541+
if (_delegateFlags.delegateVideoPlayerNodeDidStallAtTimeInterval) {
542+
[_delegate videoPlayerNode:self didStallAtTimeInterval:timeInterval];
543+
}
544+
}
545+
546+
- (void)videoNodeDidStartInitialLoading:(ASVideoNode *)videoNode
547+
{
548+
if (_delegateFlags.delegateVideoPlayerNodeDidStartInitialLoading) {
549+
[_delegate videoPlayerNodeDidStartInitialLoading:self];
550+
}
551+
}
552+
553+
- (void)videoNodeDidFinishInitialLoading:(ASVideoNode *)videoNode
554+
{
555+
if (_delegateFlags.delegateVideoPlayerNodeDidFinishInitialLoading) {
556+
[_delegate videoPlayerNodeDidFinishInitialLoading:self];
557+
}
558+
}
559+
560+
- (void)videoNodeDidRecoverFromStall:(ASVideoNode *)videoNode
561+
{
562+
if (_delegateFlags.delegateVideoPlayerNodeDidRecoverFromStall) {
563+
[_delegate videoPlayerNodeDidRecoverFromStall:self];
564+
}
565+
}
566+
483567
#pragma mark - Actions
484568
- (void)togglePlayPause
485569
{
@@ -702,6 +786,11 @@ - (void)setDelegate:(id<ASVideoPlayerNodeDelegate>)delegate
702786
_delegateFlags.delegateTimeLabelAttributedString = [_delegate respondsToSelector:@selector(videoPlayerNode:timeStringForTimeLabelType:forTime:)];
703787
_delegateFlags.delegatePlaybackButtonTint = [_delegate respondsToSelector:@selector(videoPlayerNodePlaybackButtonTint:)];
704788
_delegateFlags.delegateDidTapVideoPlayerNode = [_delegate respondsToSelector:@selector(didTapVideoPlayerNode:)];
789+
_delegateFlags.delegateVideoPlayerNodeDidSetCurrentItem = [_delegate respondsToSelector:@selector(videoPlayerNode:didSetCurrentItem:)];
790+
_delegateFlags.delegateVideoPlayerNodeDidStallAtTimeInterval = [_delegate respondsToSelector:@selector(videoPlayerNode:didStallAtTimeInterval:)];
791+
_delegateFlags.delegateVideoPlayerNodeDidStartInitialLoading = [_delegate respondsToSelector:@selector(videoPlayerNodeDidStartInitialLoading:)];
792+
_delegateFlags.delegateVideoPlayerNodeDidFinishInitialLoading = [_delegate respondsToSelector:@selector(videoPlayerNodeDidFinishInitialLoading:)];
793+
_delegateFlags.delegateVideoPlayerNodeDidRecoverFromStall = [_delegate respondsToSelector:@selector(videoPlayerNodeDidRecoverFromStall:)];
705794
}
706795
}
707796

0 commit comments

Comments
 (0)