mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
[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.
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
#import <AsyncDisplayKit/ASButtonNode.h>
|
||||
#import <AsyncDisplayKit/ASNetworkImageNode.h>
|
||||
|
||||
@class AVAsset, AVPlayer, AVPlayerItem;
|
||||
@class AVAsset, AVPlayer, AVPlayerItem, AVVideoComposition, AVAudioMix;
|
||||
@protocol ASVideoNodeDelegate;
|
||||
|
||||
typedef enum {
|
||||
@@ -41,6 +41,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (BOOL)isPlaying;
|
||||
|
||||
@property (nullable, atomic, strong, readwrite) AVAsset *asset;
|
||||
@property (nullable, atomic, strong, readwrite) AVVideoComposition *videoComposition;
|
||||
@property (nullable, atomic, strong, readwrite) AVAudioMix *audioMix;
|
||||
|
||||
@property (nullable, atomic, strong, readonly) AVPlayer *player;
|
||||
@property (nullable, atomic, strong, readonly) AVPlayerItem *currentItem;
|
||||
@@ -121,6 +123,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* @param videoNode The videoNode
|
||||
*/
|
||||
- (void)videoNodeDidFinishInitialLoading:(ASVideoNode *)videoNode;
|
||||
/**
|
||||
* @abstract Delegate method invoked when the AVPlayerItem for the asset has been set up and can be accessed throught currentItem.
|
||||
* @param videoNode The videoNode.
|
||||
* @param currentItem The AVPlayerItem that was constructed from the asset.
|
||||
*/
|
||||
- (void)videoNode:(ASVideoNode *)videoNode didSetCurrentItem:(AVPlayerItem *)currentItem;
|
||||
/**
|
||||
* @abstract Delegate method invoked when the video node has recovered from the stall
|
||||
* @param videoNode The videoNode
|
||||
|
||||
@@ -49,6 +49,7 @@ static NSString * const kStatus = @"status";
|
||||
unsigned int delegateVideoNodeDidPlayToTimeInterval:1;
|
||||
unsigned int delegateVideoNodeDidStartInitialLoading:1;
|
||||
unsigned int delegateVideoNodeDidFinishInitialLoading:1;
|
||||
unsigned int delegateVideoNodeDidSetCurrentItem:1;
|
||||
unsigned int delegateVideoNodeDidStallAtTimeInterval:1;
|
||||
unsigned int delegateVideoNodeDidRecoverFromStall:1;
|
||||
|
||||
@@ -68,6 +69,8 @@ static NSString * const kStatus = @"status";
|
||||
ASVideoNodePlayerState _playerState;
|
||||
|
||||
AVAsset *_asset;
|
||||
AVVideoComposition *_videoComposition;
|
||||
AVAudioMix *_audioMix;
|
||||
|
||||
AVPlayerItem *_currentPlayerItem;
|
||||
AVPlayer *_player;
|
||||
@@ -124,7 +127,10 @@ static NSString * const kStatus = @"status";
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
|
||||
if (_asset != nil) {
|
||||
return [[AVPlayerItem alloc] initWithAsset:_asset];
|
||||
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:_asset];
|
||||
playerItem.videoComposition = _videoComposition;
|
||||
playerItem.audioMix = _audioMix;
|
||||
return playerItem;
|
||||
}
|
||||
|
||||
return nil;
|
||||
@@ -153,7 +159,11 @@ static NSString * const kStatus = @"status";
|
||||
} else {
|
||||
self.player = [AVPlayer playerWithPlayerItem:playerItem];
|
||||
}
|
||||
|
||||
|
||||
if (_delegateFlags.delegateVideoNodeDidSetCurrentItem) {
|
||||
[_delegate videoNode:self didSetCurrentItem:playerItem];
|
||||
}
|
||||
|
||||
if (self.image == nil && self.URL == nil) {
|
||||
[self generatePlaceholderImage];
|
||||
}
|
||||
@@ -448,6 +458,34 @@ static NSString * const kStatus = @"status";
|
||||
return _asset;
|
||||
}
|
||||
|
||||
- (void)setVideoComposition:(AVVideoComposition *)videoComposition
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
|
||||
_videoComposition = videoComposition;
|
||||
_currentPlayerItem.videoComposition = videoComposition;
|
||||
}
|
||||
|
||||
- (AVVideoComposition *)videoComposition
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
return _videoComposition;
|
||||
}
|
||||
|
||||
- (void)setAudioMix:(AVAudioMix *)audioMix
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
|
||||
_audioMix = audioMix;
|
||||
_currentPlayerItem.audioMix = audioMix;
|
||||
}
|
||||
|
||||
- (AVAudioMix *)audioMix
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
return _audioMix;
|
||||
}
|
||||
|
||||
- (AVPlayer *)player
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
@@ -473,6 +511,7 @@ static NSString * const kStatus = @"status";
|
||||
_delegateFlags.delegateVideoNodeDidPlayToTimeInterval = [_delegate respondsToSelector:@selector(videoNode:didPlayToTimeInterval:)];
|
||||
_delegateFlags.delegateVideoNodeDidStartInitialLoading = [_delegate respondsToSelector:@selector(videoNodeDidStartInitialLoading:)];
|
||||
_delegateFlags.delegateVideoNodeDidFinishInitialLoading = [_delegate respondsToSelector:@selector(videoNodeDidFinishInitialLoading:)];
|
||||
_delegateFlags.delegateVideoNodeDidSetCurrentItem = [_delegate respondsToSelector:@selector(videoNode:didSetCurrentItem:)];
|
||||
_delegateFlags.delegateVideoNodeDidStallAtTimeInterval = [_delegate respondsToSelector:@selector(videoNode:didStallAtTimeInterval:)];
|
||||
_delegateFlags.delegateVideoNodeDidRecoverFromStall = [_delegate respondsToSelector:@selector(videoNodeDidRecoverFromStall:)];
|
||||
|
||||
@@ -697,4 +736,4 @@ static NSString * const kStatus = @"status";
|
||||
}
|
||||
|
||||
@end
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -58,8 +58,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (instancetype)initWithUrl:(NSURL*)url;
|
||||
- (instancetype)initWithAsset:(AVAsset*)asset;
|
||||
- (instancetype)initWithAsset:(AVAsset *)asset videoComposition:(AVVideoComposition *)videoComposition audioMix:(AVAudioMix *)audioMix;
|
||||
- (instancetype)initWithUrl:(NSURL *)url loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
|
||||
- (instancetype)initWithAsset:(AVAsset *)asset loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
|
||||
- (instancetype)initWithAsset:(AVAsset *)asset videoComposition:(AVVideoComposition *)videoComposition audioMix:(AVAudioMix *)audioMix loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible;
|
||||
|
||||
#pragma mark - Public API
|
||||
- (void)seekToTime:(CGFloat)percentComplete;
|
||||
@@ -156,10 +158,43 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* @abstract Delegate method invoked when the ASVideoNode has played to its end time.
|
||||
* @param videoPlayerNode The video node has played to its end time.
|
||||
* @param videoPlayer The video node has played to its end time.
|
||||
*/
|
||||
- (void)videoPlayerNodeDidPlayToEnd:(ASVideoPlayerNode *)videoPlayer;
|
||||
|
||||
/**
|
||||
* @abstract Delegate method invoked when the ASVideoNode has constructed its AVPlayerItem for the asset.
|
||||
* @param videoPlayer The video player node.
|
||||
* @param currentItem The AVPlayerItem that was constructed from the asset.
|
||||
*/
|
||||
- (void)videoPlayerNode:(ASVideoPlayerNode *)videoPlayer didSetCurrentItem:(AVPlayerItem *)currentItem;
|
||||
|
||||
/**
|
||||
* @abstract Delegate method invoked when the ASVideoNode stalls.
|
||||
* @param videoPlayer The video player node that has experienced the stall
|
||||
* @param second Current playback time when the stall happens
|
||||
*/
|
||||
- (void)videoPlayerNode:(ASVideoPlayerNode *)videoPlayer didStallAtTimeInterval:(NSTimeInterval)timeInterval;
|
||||
|
||||
/**
|
||||
* @abstract Delegate method invoked when the ASVideoNode starts the inital asset loading
|
||||
* @param videoPlayer The videoPlayer
|
||||
*/
|
||||
- (void)videoPlayerNodeDidStartInitialLoading:(ASVideoPlayerNode *)videoPlayer;
|
||||
|
||||
/**
|
||||
* @abstract Delegate method invoked when the ASVideoNode is done loading the asset and can start the playback
|
||||
* @param videoPlayer The videoPlayer
|
||||
*/
|
||||
- (void)videoPlayerNodeDidFinishInitialLoading:(ASVideoPlayerNode *)videoPlayer;
|
||||
|
||||
/**
|
||||
* @abstract Delegate method invoked when the ASVideoNode has recovered from the stall
|
||||
* @param videoPlayer The videoplayer
|
||||
*/
|
||||
- (void)videoPlayerNodeDidRecoverFromStall:(ASVideoPlayerNode *)videoPlayer;
|
||||
|
||||
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
#endif
|
||||
|
||||
@@ -37,10 +37,17 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
|
||||
unsigned int delegateVideoNodeShouldChangeState:1;
|
||||
unsigned int delegateVideoNodePlaybackDidFinish:1;
|
||||
unsigned int delegateDidTapVideoPlayerNode:1;
|
||||
unsigned int delegateVideoPlayerNodeDidSetCurrentItem:1;
|
||||
unsigned int delegateVideoPlayerNodeDidStallAtTimeInterval:1;
|
||||
unsigned int delegateVideoPlayerNodeDidStartInitialLoading:1;
|
||||
unsigned int delegateVideoPlayerNodeDidFinishInitialLoading:1;
|
||||
unsigned int delegateVideoPlayerNodeDidRecoverFromStall:1;
|
||||
} _delegateFlags;
|
||||
|
||||
NSURL *_url;
|
||||
AVAsset *_asset;
|
||||
AVVideoComposition *_videoComposition;
|
||||
AVAudioMix *_audioMix;
|
||||
|
||||
ASVideoNode *_videoNode;
|
||||
|
||||
@@ -118,6 +125,22 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
|
||||
return self;
|
||||
}
|
||||
|
||||
-(instancetype)initWithAsset:(AVAsset *)asset videoComposition:(AVVideoComposition *)videoComposition audioMix:(AVAudioMix *)audioMix
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_asset = asset;
|
||||
_videoComposition = videoComposition;
|
||||
_audioMix = audioMix;
|
||||
_loadAssetWhenNodeBecomesVisible = YES;
|
||||
|
||||
[self _init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithUrl:(NSURL *)url loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
@@ -147,6 +170,22 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
|
||||
return self;
|
||||
}
|
||||
|
||||
-(instancetype)initWithAsset:(AVAsset *)asset videoComposition:(AVVideoComposition *)videoComposition audioMix:(AVAudioMix *)audioMix loadAssetWhenNodeBecomesVisible:(BOOL)loadAssetWhenNodeBecomesVisible
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_asset = asset;
|
||||
_videoComposition = videoComposition;
|
||||
_audioMix = audioMix;
|
||||
_loadAssetWhenNodeBecomesVisible = loadAssetWhenNodeBecomesVisible;
|
||||
|
||||
[self _init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_defaultControlsColor = [UIColor whiteColor];
|
||||
@@ -156,6 +195,8 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
|
||||
_videoNode.delegate = self;
|
||||
if (_loadAssetWhenNodeBecomesVisible == NO) {
|
||||
_videoNode.asset = _asset;
|
||||
_videoNode.videoComposition = _videoComposition;
|
||||
_videoNode.audioMix = _audioMix;
|
||||
}
|
||||
[self addSubnode:_videoNode];
|
||||
}
|
||||
@@ -175,8 +216,16 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
|
||||
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
|
||||
if (isVisible && _loadAssetWhenNodeBecomesVisible && _asset != _videoNode.asset) {
|
||||
_videoNode.asset = _asset;
|
||||
if (isVisible && _loadAssetWhenNodeBecomesVisible) {
|
||||
if (_asset != _videoNode.asset) {
|
||||
_videoNode.asset = _asset;
|
||||
}
|
||||
if (_videoComposition != _videoNode.videoComposition) {
|
||||
_videoNode.videoComposition = _videoComposition;
|
||||
}
|
||||
if (_audioMix != _videoNode.audioMix) {
|
||||
_videoNode.audioMix = _audioMix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,6 +529,41 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoNode:(ASVideoNode *)videoNode didSetCurrentItem:(AVPlayerItem *)currentItem
|
||||
{
|
||||
if (_delegateFlags.delegateVideoPlayerNodeDidSetCurrentItem) {
|
||||
[_delegate videoPlayerNode:self didSetCurrentItem:currentItem];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoNode:(ASVideoNode *)videoNode didStallAtTimeInterval:(NSTimeInterval)timeInterval
|
||||
{
|
||||
if (_delegateFlags.delegateVideoPlayerNodeDidStallAtTimeInterval) {
|
||||
[_delegate videoPlayerNode:self didStallAtTimeInterval:timeInterval];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoNodeDidStartInitialLoading:(ASVideoNode *)videoNode
|
||||
{
|
||||
if (_delegateFlags.delegateVideoPlayerNodeDidStartInitialLoading) {
|
||||
[_delegate videoPlayerNodeDidStartInitialLoading:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoNodeDidFinishInitialLoading:(ASVideoNode *)videoNode
|
||||
{
|
||||
if (_delegateFlags.delegateVideoPlayerNodeDidFinishInitialLoading) {
|
||||
[_delegate videoPlayerNodeDidFinishInitialLoading:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoNodeDidRecoverFromStall:(ASVideoNode *)videoNode
|
||||
{
|
||||
if (_delegateFlags.delegateVideoPlayerNodeDidRecoverFromStall) {
|
||||
[_delegate videoPlayerNodeDidRecoverFromStall:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
- (void)togglePlayPause
|
||||
{
|
||||
@@ -702,6 +786,11 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
|
||||
_delegateFlags.delegateTimeLabelAttributedString = [_delegate respondsToSelector:@selector(videoPlayerNode:timeStringForTimeLabelType:forTime:)];
|
||||
_delegateFlags.delegatePlaybackButtonTint = [_delegate respondsToSelector:@selector(videoPlayerNodePlaybackButtonTint:)];
|
||||
_delegateFlags.delegateDidTapVideoPlayerNode = [_delegate respondsToSelector:@selector(didTapVideoPlayerNode:)];
|
||||
_delegateFlags.delegateVideoPlayerNodeDidSetCurrentItem = [_delegate respondsToSelector:@selector(videoPlayerNode:didSetCurrentItem:)];
|
||||
_delegateFlags.delegateVideoPlayerNodeDidStallAtTimeInterval = [_delegate respondsToSelector:@selector(videoPlayerNode:didStallAtTimeInterval:)];
|
||||
_delegateFlags.delegateVideoPlayerNodeDidStartInitialLoading = [_delegate respondsToSelector:@selector(videoPlayerNodeDidStartInitialLoading:)];
|
||||
_delegateFlags.delegateVideoPlayerNodeDidFinishInitialLoading = [_delegate respondsToSelector:@selector(videoPlayerNodeDidFinishInitialLoading:)];
|
||||
_delegateFlags.delegateVideoPlayerNodeDidRecoverFromStall = [_delegate respondsToSelector:@selector(videoPlayerNodeDidRecoverFromStall:)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user