mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
First working version for HLS streams
This commit is contained in:
@@ -15,7 +15,7 @@
|
|||||||
// in an issue on GitHub: https://github.com/facebook/AsyncDisplayKit/issues
|
// in an issue on GitHub: https://github.com/facebook/AsyncDisplayKit/issues
|
||||||
|
|
||||||
@interface ASVideoNode : ASControlNode
|
@interface ASVideoNode : ASControlNode
|
||||||
@property (atomic, strong, readwrite) AVAsset *asset;
|
@property (atomic, strong, readonly) AVAsset *asset;
|
||||||
@property (atomic, strong, readonly) AVPlayer *player;
|
@property (atomic, strong, readonly) AVPlayer *player;
|
||||||
@property (atomic, strong, readonly) AVPlayerItem *currentItem;
|
@property (atomic, strong, readonly) AVPlayerItem *currentItem;
|
||||||
|
|
||||||
@@ -31,6 +31,10 @@
|
|||||||
|
|
||||||
@property (atomic, weak, readwrite) id<ASVideoNodeDelegate> delegate;
|
@property (atomic, weak, readwrite) id<ASVideoNodeDelegate> delegate;
|
||||||
|
|
||||||
|
// Mirror the construction of AVPlayerItem with the URL or AVAsset
|
||||||
|
- (instancetype)initWithURL:(NSURL*)url;
|
||||||
|
- (instancetype)initWithAsset:(AVAsset*)asset;
|
||||||
|
|
||||||
- (void)play;
|
- (void)play;
|
||||||
- (void)pause;
|
- (void)pause;
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
BOOL _muted;
|
BOOL _muted;
|
||||||
|
|
||||||
AVAsset *_asset;
|
AVAsset *_asset;
|
||||||
|
NSURL *_url;
|
||||||
|
|
||||||
AVPlayerItem *_currentItem;
|
AVPlayerItem *_currentItem;
|
||||||
AVPlayer *_player;
|
AVPlayer *_player;
|
||||||
@@ -41,26 +42,51 @@
|
|||||||
|
|
||||||
@implementation ASVideoNode
|
@implementation ASVideoNode
|
||||||
|
|
||||||
|
//TODO: Have a bash at getting the preview images sorted for the URL types - might need to observe until it's loaded
|
||||||
|
|
||||||
|
//TODO: Have a bash at supplying a preview image node so that we're deferring the construction of the video as it eats memory at the moment
|
||||||
|
// [[[[playerItem tracks] objectAtIndex:0] assetTrack] asset]
|
||||||
|
|
||||||
#pragma mark - Construction and Layout
|
#pragma mark - Construction and Layout
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)initWithURL:(NSURL*)url
|
||||||
{
|
{
|
||||||
|
ASDisplayNodeAssertNotNil(url, @"URL must be supplied in initWithURL:");
|
||||||
if (!(self = [super init])) {
|
if (!(self = [super init])) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_url = url;
|
||||||
|
return [self commonInit];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithAsset:(AVAsset*)asset
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssertNotNil(asset, @"Asset must be supplied in initWithAsset:");
|
||||||
|
if (!(self = [super init])) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
_asset = asset;
|
||||||
|
return [self commonInit];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)commonInit
|
||||||
|
{
|
||||||
_previewQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
|
_previewQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
|
||||||
|
|
||||||
self.playButton = [[ASDefaultPlayButton alloc] init];
|
self.playButton = [[ASDefaultPlayButton alloc] init];
|
||||||
|
|
||||||
self.gravity = AVLayerVideoGravityResizeAspect;
|
self.gravity = AVLayerVideoGravityResizeAspect;
|
||||||
|
|
||||||
[self addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
|
[self addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (instancetype)init
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssertNotSupported();
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (instancetype)initWithViewBlock:(ASDisplayNodeViewBlock)viewBlock didLoadBlock:(ASDisplayNodeDidLoadBlock)didLoadBlock
|
- (instancetype)initWithViewBlock:(ASDisplayNodeViewBlock)viewBlock didLoadBlock:(ASDisplayNodeDidLoadBlock)didLoadBlock
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertNotSupported();
|
ASDisplayNodeAssertNotSupported();
|
||||||
@@ -71,7 +97,7 @@
|
|||||||
ASDisplayNode* playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{
|
ASDisplayNode* playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{
|
||||||
AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init];
|
AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init];
|
||||||
if (!_player) {
|
if (!_player) {
|
||||||
_player = [AVPlayer playerWithPlayerItem:[[AVPlayerItem alloc] initWithAsset:_asset]];
|
_player = [AVPlayer playerWithPlayerItem:[self constructPlayerItemFromInitData]];
|
||||||
_player.muted = _muted;
|
_player.muted = _muted;
|
||||||
}
|
}
|
||||||
playerLayer.player = _player;
|
playerLayer.player = _player;
|
||||||
@@ -82,6 +108,18 @@
|
|||||||
return playerNode;
|
return playerNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (AVPlayerItem*) constructPlayerItemFromInitData {
|
||||||
|
ASDisplayNodeAssert(_asset || _url, @"Must be initialised with an AVAsset or URL");
|
||||||
|
|
||||||
|
if (_asset) {
|
||||||
|
return [[AVPlayerItem alloc] initWithAsset:_asset];
|
||||||
|
} else if (_url) {
|
||||||
|
return [[AVPlayerItem alloc] initWithURL:_url];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)didLoad
|
- (void)didLoad
|
||||||
{
|
{
|
||||||
[super didLoad];
|
[super didLoad];
|
||||||
@@ -90,7 +128,7 @@
|
|||||||
if (_shouldBePlaying) {
|
if (_shouldBePlaying) {
|
||||||
_playerNode = [self constructPlayerNode];
|
_playerNode = [self constructPlayerNode];
|
||||||
[self insertSubnode:_playerNode atIndex:0];
|
[self insertSubnode:_playerNode atIndex:0];
|
||||||
} else {
|
} else if (_asset) {
|
||||||
dispatch_async(_previewQueue, ^{
|
dispatch_async(_previewQueue, ^{
|
||||||
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:_asset];
|
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:_asset];
|
||||||
imageGenerator.appliesPreferredTrackTransform = YES;
|
imageGenerator.appliesPreferredTrackTransform = YES;
|
||||||
@@ -214,7 +252,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_videoLock);
|
ASDN::MutexLocker l(_videoLock);
|
||||||
_currentItem = [[AVPlayerItem alloc] initWithAsset:_asset];
|
_currentItem = [self constructPlayerItemFromInitData];
|
||||||
[_currentItem addObserver:self forKeyPath:NSStringFromSelector(@selector(status)) options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL];
|
[_currentItem addObserver:self forKeyPath:NSStringFromSelector(@selector(status)) options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL];
|
||||||
|
|
||||||
if (_player) {
|
if (_player) {
|
||||||
@@ -249,7 +287,7 @@
|
|||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
if (_playerNode.isNodeLoaded) {
|
if (_playerNode.isNodeLoaded) {
|
||||||
if (!_player) {
|
if (!_player) {
|
||||||
_player = [AVPlayer playerWithPlayerItem:[[AVPlayerItem alloc] initWithAsset:_asset]];
|
_player = [AVPlayer playerWithPlayerItem:[self constructPlayerItemFromInitData]];
|
||||||
_player.muted = _muted;
|
_player.muted = _muted;
|
||||||
}
|
}
|
||||||
((AVPlayerLayer *)_playerNode.layer).player = _player;
|
((AVPlayerLayer *)_playerNode.layer).player = _player;
|
||||||
|
|||||||
@@ -81,15 +81,35 @@ static const CGFloat kInnerPadding = 10.0f;
|
|||||||
|
|
||||||
_kittenSize = size;
|
_kittenSize = size;
|
||||||
|
|
||||||
_videoNode = [[ASVideoNode alloc] init];
|
u_int32_t videoInitMethod = arc4random_uniform(3);
|
||||||
|
NSArray* methodArray = @[@"AVAsset", @"File URL", @"HLS URL"];
|
||||||
|
|
||||||
|
switch (videoInitMethod) {
|
||||||
|
case 0:
|
||||||
|
// Construct an AVAsset from a URL
|
||||||
|
_videoNode = [[ASVideoNode alloc] initWithAsset:
|
||||||
|
[AVAsset assetWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-753fe655-86bb-46da-89b7-aa59c60e49c0-niccage.mp4"]]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Construct the video node directly from the .mp4 URL
|
||||||
|
_videoNode = [[ASVideoNode alloc] initWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-753fe655-86bb-46da-89b7-aa59c60e49c0-niccage.mp4"]];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Construct the video node from an HTTP Live Streaming URL
|
||||||
|
// URL from https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/02_Playback.html
|
||||||
|
_videoNode = [[ASVideoNode alloc] initWithURL:[NSURL URLWithString:@"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"]];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// _videoNode.shouldAutoplay = YES;
|
// _videoNode.shouldAutoplay = YES;
|
||||||
_videoNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor();
|
_videoNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor();
|
||||||
_videoNode.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-753fe655-86bb-46da-89b7-aa59c60e49c0-niccage.mp4"]];
|
|
||||||
|
|
||||||
[self addSubnode:_videoNode];
|
[self addSubnode:_videoNode];
|
||||||
|
|
||||||
_textNode = [[ASTextNode alloc] init];
|
_textNode = [[ASTextNode alloc] init];
|
||||||
_textNode.attributedString = [[NSAttributedString alloc] initWithString:[self kittyIpsum]
|
_textNode.attributedString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ %@", methodArray[videoInitMethod], [self kittyIpsum]]
|
||||||
attributes:[self textStyle]];
|
attributes:[self textStyle]];
|
||||||
[self addSubnode:_textNode];
|
[self addSubnode:_textNode];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user