Add cache property; Make playerItemForSource in 'RCTVideoManager.m' async
This commit is contained in:
parent
6b2c1046dd
commit
438aa79494
1
Video.js
1
Video.js
@ -247,6 +247,7 @@ export default class Video extends Component {
|
|||||||
Video.propTypes = {
|
Video.propTypes = {
|
||||||
/* Native only */
|
/* Native only */
|
||||||
src: PropTypes.object,
|
src: PropTypes.object,
|
||||||
|
cache: PropTypes.bool,
|
||||||
seek: PropTypes.number,
|
seek: PropTypes.number,
|
||||||
fullscreen: PropTypes.bool,
|
fullscreen: PropTypes.bool,
|
||||||
onVideoLoadStart: PropTypes.func,
|
onVideoLoadStart: PropTypes.func,
|
||||||
|
547
ios/RCTVideo.m
547
ios/RCTVideo.m
@ -20,20 +20,20 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
AVPlayerLayer *_playerLayer;
|
AVPlayerLayer *_playerLayer;
|
||||||
AVPlayerViewController *_playerViewController;
|
AVPlayerViewController *_playerViewController;
|
||||||
NSURL *_videoURL;
|
NSURL *_videoURL;
|
||||||
|
|
||||||
/* Required to publish events */
|
/* Required to publish events */
|
||||||
RCTEventDispatcher *_eventDispatcher;
|
RCTEventDispatcher *_eventDispatcher;
|
||||||
BOOL _playbackRateObserverRegistered;
|
BOOL _playbackRateObserverRegistered;
|
||||||
|
|
||||||
bool _pendingSeek;
|
bool _pendingSeek;
|
||||||
float _pendingSeekTime;
|
float _pendingSeekTime;
|
||||||
float _lastSeekTime;
|
float _lastSeekTime;
|
||||||
|
|
||||||
/* For sending videoProgress events */
|
/* For sending videoProgress events */
|
||||||
Float64 _progressUpdateInterval;
|
Float64 _progressUpdateInterval;
|
||||||
BOOL _controls;
|
BOOL _controls;
|
||||||
id _timeObserver;
|
id _timeObserver;
|
||||||
|
|
||||||
/* Keep track of any modifiers, need to be applied after each play */
|
/* Keep track of any modifiers, need to be applied after each play */
|
||||||
float _volume;
|
float _volume;
|
||||||
float _rate;
|
float _rate;
|
||||||
@ -53,7 +53,7 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
{
|
{
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_eventDispatcher = eventDispatcher;
|
_eventDispatcher = eventDispatcher;
|
||||||
|
|
||||||
_playbackRateObserverRegistered = NO;
|
_playbackRateObserverRegistered = NO;
|
||||||
_playbackStalled = NO;
|
_playbackStalled = NO;
|
||||||
_rate = 1.0;
|
_rate = 1.0;
|
||||||
@ -68,34 +68,34 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
_playInBackground = false;
|
_playInBackground = false;
|
||||||
_playWhenInactive = false;
|
_playWhenInactive = false;
|
||||||
_ignoreSilentSwitch = @"inherit"; // inherit, ignore, obey
|
_ignoreSilentSwitch = @"inherit"; // inherit, ignore, obey
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(applicationWillResignActive:)
|
selector:@selector(applicationWillResignActive:)
|
||||||
name:UIApplicationWillResignActiveNotification
|
name:UIApplicationWillResignActiveNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(applicationDidEnterBackground:)
|
selector:@selector(applicationDidEnterBackground:)
|
||||||
name:UIApplicationDidEnterBackgroundNotification
|
name:UIApplicationDidEnterBackgroundNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(applicationWillEnterForeground:)
|
selector:@selector(applicationWillEnterForeground:)
|
||||||
name:UIApplicationWillEnterForegroundNotification
|
name:UIApplicationWillEnterForegroundNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem {
|
- (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem {
|
||||||
RCTVideoPlayerViewController* playerLayer= [[RCTVideoPlayerViewController alloc] init];
|
RCTVideoPlayerViewController* playerLayer= [[RCTVideoPlayerViewController alloc] init];
|
||||||
playerLayer.showsPlaybackControls = NO;
|
playerLayer.showsPlaybackControls = NO;
|
||||||
playerLayer.rctDelegate = self;
|
playerLayer.rctDelegate = self;
|
||||||
playerLayer.view.frame = self.bounds;
|
playerLayer.view.frame = self.bounds;
|
||||||
playerLayer.player = _player;
|
playerLayer.player = _player;
|
||||||
playerLayer.view.frame = self.bounds;
|
playerLayer.view.frame = self.bounds;
|
||||||
return playerLayer;
|
return playerLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------
|
/* ---------------------------------------------------------
|
||||||
@ -104,35 +104,35 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
|
|
||||||
- (CMTime)playerItemDuration
|
- (CMTime)playerItemDuration
|
||||||
{
|
{
|
||||||
AVPlayerItem *playerItem = [_player currentItem];
|
AVPlayerItem *playerItem = [_player currentItem];
|
||||||
if (playerItem.status == AVPlayerItemStatusReadyToPlay)
|
if (playerItem.status == AVPlayerItemStatusReadyToPlay)
|
||||||
{
|
{
|
||||||
return([playerItem duration]);
|
return([playerItem duration]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(kCMTimeInvalid);
|
return(kCMTimeInvalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CMTimeRange)playerItemSeekableTimeRange
|
- (CMTimeRange)playerItemSeekableTimeRange
|
||||||
{
|
{
|
||||||
AVPlayerItem *playerItem = [_player currentItem];
|
AVPlayerItem *playerItem = [_player currentItem];
|
||||||
if (playerItem.status == AVPlayerItemStatusReadyToPlay)
|
if (playerItem.status == AVPlayerItemStatusReadyToPlay)
|
||||||
{
|
{
|
||||||
return [playerItem seekableTimeRanges].firstObject.CMTimeRangeValue;
|
return [playerItem seekableTimeRanges].firstObject.CMTimeRangeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (kCMTimeRangeZero);
|
return (kCMTimeRangeZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Cancels the previously registered time observer. */
|
/* Cancels the previously registered time observer. */
|
||||||
-(void)removePlayerTimeObserver
|
-(void)removePlayerTimeObserver
|
||||||
{
|
{
|
||||||
if (_timeObserver)
|
if (_timeObserver)
|
||||||
{
|
{
|
||||||
[_player removeTimeObserver:_timeObserver];
|
[_player removeTimeObserver:_timeObserver];
|
||||||
_timeObserver = nil;
|
_timeObserver = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Progress
|
#pragma mark - Progress
|
||||||
@ -150,7 +150,7 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
- (void)applicationWillResignActive:(NSNotification *)notification
|
- (void)applicationWillResignActive:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
if (_playInBackground || _playWhenInactive || _paused) return;
|
if (_playInBackground || _playWhenInactive || _paused) return;
|
||||||
|
|
||||||
[_player pause];
|
[_player pause];
|
||||||
[_player setRate:0.0];
|
[_player setRate:0.0];
|
||||||
}
|
}
|
||||||
@ -175,32 +175,32 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
|
|
||||||
- (void)sendProgressUpdate
|
- (void)sendProgressUpdate
|
||||||
{
|
{
|
||||||
AVPlayerItem *video = [_player currentItem];
|
AVPlayerItem *video = [_player currentItem];
|
||||||
if (video == nil || video.status != AVPlayerItemStatusReadyToPlay) {
|
if (video == nil || video.status != AVPlayerItemStatusReadyToPlay) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMTime playerDuration = [self playerItemDuration];
|
CMTime playerDuration = [self playerItemDuration];
|
||||||
if (CMTIME_IS_INVALID(playerDuration)) {
|
if (CMTIME_IS_INVALID(playerDuration)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMTime currentTime = _player.currentTime;
|
CMTime currentTime = _player.currentTime;
|
||||||
const Float64 duration = CMTimeGetSeconds(playerDuration);
|
const Float64 duration = CMTimeGetSeconds(playerDuration);
|
||||||
const Float64 currentTimeSecs = CMTimeGetSeconds(currentTime);
|
const Float64 currentTimeSecs = CMTimeGetSeconds(currentTime);
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"RCTVideo_progress" object:nil userInfo:@{@"progress": [NSNumber numberWithDouble: currentTimeSecs / duration]}];
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"RCTVideo_progress" object:nil userInfo:@{@"progress": [NSNumber numberWithDouble: currentTimeSecs / duration]}];
|
||||||
|
|
||||||
if( currentTimeSecs >= 0 && self.onVideoProgress) {
|
if( currentTimeSecs >= 0 && self.onVideoProgress) {
|
||||||
self.onVideoProgress(@{
|
self.onVideoProgress(@{
|
||||||
@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(currentTime)],
|
@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(currentTime)],
|
||||||
@"playableDuration": [self calculatePlayableDuration],
|
@"playableDuration": [self calculatePlayableDuration],
|
||||||
@"atValue": [NSNumber numberWithLongLong:currentTime.value],
|
@"atValue": [NSNumber numberWithLongLong:currentTime.value],
|
||||||
@"atTimescale": [NSNumber numberWithInt:currentTime.timescale],
|
@"atTimescale": [NSNumber numberWithInt:currentTime.timescale],
|
||||||
@"target": self.reactTag,
|
@"target": self.reactTag,
|
||||||
@"seekableDuration": [self calculateSeekableDuration],
|
@"seekableDuration": [self calculateSeekableDuration],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -230,12 +230,12 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
|
|
||||||
- (NSNumber *)calculateSeekableDuration
|
- (NSNumber *)calculateSeekableDuration
|
||||||
{
|
{
|
||||||
CMTimeRange timeRange = [self playerItemSeekableTimeRange];
|
CMTimeRange timeRange = [self playerItemSeekableTimeRange];
|
||||||
if (CMTIME_IS_NUMERIC(timeRange.duration))
|
if (CMTIME_IS_NUMERIC(timeRange.duration))
|
||||||
{
|
{
|
||||||
return [NSNumber numberWithFloat:CMTimeGetSeconds(timeRange.duration)];
|
return [NSNumber numberWithFloat:CMTimeGetSeconds(timeRange.duration)];
|
||||||
}
|
}
|
||||||
return [NSNumber numberWithInteger:0];
|
return [NSNumber numberWithInteger:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addPlayerItemObservers
|
- (void)addPlayerItemObservers
|
||||||
@ -266,29 +266,41 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
|
|
||||||
#pragma mark - Player and source
|
#pragma mark - Player and source
|
||||||
|
|
||||||
|
- (void)setCache:(BOOL *)cache
|
||||||
|
{
|
||||||
|
// @TODO: Implement
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setSrc:(NSDictionary *)source
|
- (void)setSrc:(NSDictionary *)source
|
||||||
{
|
{
|
||||||
[self removePlayerTimeObserver];
|
[self removePlayerTimeObserver];
|
||||||
[self removePlayerItemObservers];
|
[self removePlayerItemObservers];
|
||||||
_playerItem = [self playerItemForSource:source];
|
[self playerItemForSource:source withCallback:^(AVPlayerItem * playerItem) {
|
||||||
[self addPlayerItemObservers];
|
[self didSetPlayerItemWithSource:source playerItem:playerItem];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) didSetPlayerItemWithSource:(NSDictionary *)source playerItem:(AVPlayerItem *) playerItem
|
||||||
|
{
|
||||||
|
_playerItem = playerItem;
|
||||||
|
[self addPlayerItemObservers];
|
||||||
|
|
||||||
[_player pause];
|
[_player pause];
|
||||||
[self removePlayerLayer];
|
[self removePlayerLayer];
|
||||||
[_playerViewController.view removeFromSuperview];
|
[_playerViewController.view removeFromSuperview];
|
||||||
_playerViewController = nil;
|
_playerViewController = nil;
|
||||||
|
|
||||||
if (_playbackRateObserverRegistered) {
|
if (_playbackRateObserverRegistered) {
|
||||||
[_player removeObserver:self forKeyPath:playbackRate context:nil];
|
[_player removeObserver:self forKeyPath:playbackRate context:nil];
|
||||||
_playbackRateObserverRegistered = NO;
|
_playbackRateObserverRegistered = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
||||||
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
||||||
|
|
||||||
[_player addObserver:self forKeyPath:playbackRate options:0 context:nil];
|
[_player addObserver:self forKeyPath:playbackRate options:0 context:nil];
|
||||||
_playbackRateObserverRegistered = YES;
|
_playbackRateObserverRegistered = YES;
|
||||||
|
|
||||||
const Float64 progressUpdateIntervalMS = _progressUpdateInterval / 1000;
|
const Float64 progressUpdateIntervalMS = _progressUpdateInterval / 1000;
|
||||||
// @see endScrubbing in AVPlayerDemoPlaybackViewController.m of https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html
|
// @see endScrubbing in AVPlayerDemoPlaybackViewController.m of https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html
|
||||||
__weak RCTVideo *weakSelf = self;
|
__weak RCTVideo *weakSelf = self;
|
||||||
@ -296,107 +308,110 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
queue:NULL
|
queue:NULL
|
||||||
usingBlock:^(CMTime time) { [weakSelf sendProgressUpdate]; }
|
usingBlock:^(CMTime time) { [weakSelf sendProgressUpdate]; }
|
||||||
];
|
];
|
||||||
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
//Perform on next run loop, otherwise onVideoLoadStart is nil
|
//Perform on next run loop, otherwise onVideoLoadStart is nil
|
||||||
if(self.onVideoLoadStart) {
|
if(self.onVideoLoadStart) {
|
||||||
id uri = [source objectForKey:@"uri"];
|
id uri = [source objectForKey:@"uri"];
|
||||||
id type = [source objectForKey:@"type"];
|
id type = [source objectForKey:@"type"];
|
||||||
self.onVideoLoadStart(@{@"src": @{
|
self.onVideoLoadStart(@{@"src": @{
|
||||||
@"uri": uri ? uri : [NSNull null],
|
@"uri": uri ? uri : [NSNull null],
|
||||||
@"type": type ? type : [NSNull null],
|
@"type": type ? type : [NSNull null],
|
||||||
@"isNetwork": [NSNumber numberWithBool:(bool)[source objectForKey:@"isNetwork"]]},
|
@"isNetwork": [NSNumber numberWithBool:(bool)[source objectForKey:@"isNetwork"]]},
|
||||||
@"target": self.reactTag
|
@"target": self.reactTag
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (AVPlayerItem*)playerItemForSource:(NSDictionary *)source
|
- (void)playerItemForSource:(NSDictionary *)source withCallback:(void(^)(AVPlayerItem *))handler
|
||||||
{
|
{
|
||||||
bool isNetwork = [RCTConvert BOOL:[source objectForKey:@"isNetwork"]];
|
bool isNetwork = [RCTConvert BOOL:[source objectForKey:@"isNetwork"]];
|
||||||
bool isAsset = [RCTConvert BOOL:[source objectForKey:@"isAsset"]];
|
bool isAsset = [RCTConvert BOOL:[source objectForKey:@"isAsset"]];
|
||||||
NSString *uri = [source objectForKey:@"uri"];
|
NSString *uri = [source objectForKey:@"uri"];
|
||||||
NSString *type = [source objectForKey:@"type"];
|
NSString *type = [source objectForKey:@"type"];
|
||||||
|
|
||||||
NSURL *url = (isNetwork || isAsset) ?
|
NSURL *url = (isNetwork || isAsset) ?
|
||||||
[NSURL URLWithString:uri] :
|
[NSURL URLWithString:uri] :
|
||||||
[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]];
|
[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]];
|
||||||
|
|
||||||
if (isNetwork) {
|
if (isNetwork) {
|
||||||
|
// @TODO: Check if item is cached an if so use the cached asset
|
||||||
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
|
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
|
||||||
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:@{AVURLAssetHTTPCookiesKey : cookies}];
|
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:@{AVURLAssetHTTPCookiesKey : cookies}];
|
||||||
return [AVPlayerItem playerItemWithAsset:asset];
|
handler([AVPlayerItem playerItemWithAsset:asset]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (isAsset) {
|
else if (isAsset) {
|
||||||
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
|
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
|
||||||
return [AVPlayerItem playerItemWithAsset:asset];
|
handler([AVPlayerItem playerItemWithAsset:asset]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
handler([AVPlayerItem playerItemWithURL:url]);
|
||||||
return [AVPlayerItem playerItemWithURL:url];
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||||
{
|
{
|
||||||
if (object == _playerItem) {
|
if (object == _playerItem) {
|
||||||
|
|
||||||
// When timeMetadata is read the event onTimedMetadata is triggered
|
// When timeMetadata is read the event onTimedMetadata is triggered
|
||||||
if ([keyPath isEqualToString: timedMetadata])
|
if ([keyPath isEqualToString: timedMetadata])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
NSArray<AVMetadataItem *> *items = [change objectForKey:@"new"];
|
NSArray<AVMetadataItem *> *items = [change objectForKey:@"new"];
|
||||||
if (items && ![items isEqual:[NSNull null]] && items.count > 0) {
|
if (items && ![items isEqual:[NSNull null]] && items.count > 0) {
|
||||||
|
|
||||||
NSMutableArray *array = [NSMutableArray new];
|
NSMutableArray *array = [NSMutableArray new];
|
||||||
for (AVMetadataItem *item in items) {
|
for (AVMetadataItem *item in items) {
|
||||||
|
|
||||||
NSString *value = item.value;
|
NSString *value = item.value;
|
||||||
NSString *identifier = item.identifier;
|
NSString *identifier = item.identifier;
|
||||||
|
|
||||||
if (![value isEqual: [NSNull null]]) {
|
if (![value isEqual: [NSNull null]]) {
|
||||||
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjects:@[value, identifier] forKeys:@[@"value", @"identifier"]];
|
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjects:@[value, identifier] forKeys:@[@"value", @"identifier"]];
|
||||||
|
|
||||||
[array addObject:dictionary];
|
[array addObject:dictionary];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.onTimedMetadata(@{
|
|
||||||
@"target": self.reactTag,
|
|
||||||
@"metadata": array
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.onTimedMetadata(@{
|
||||||
|
@"target": self.reactTag,
|
||||||
|
@"metadata": array
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([keyPath isEqualToString:statusKeyPath]) {
|
if ([keyPath isEqualToString:statusKeyPath]) {
|
||||||
// Handle player item status change.
|
// Handle player item status change.
|
||||||
if (_playerItem.status == AVPlayerItemStatusReadyToPlay) {
|
if (_playerItem.status == AVPlayerItemStatusReadyToPlay) {
|
||||||
float duration = CMTimeGetSeconds(_playerItem.asset.duration);
|
float duration = CMTimeGetSeconds(_playerItem.asset.duration);
|
||||||
|
|
||||||
if (isnan(duration)) {
|
if (isnan(duration)) {
|
||||||
duration = 0.0;
|
duration = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSObject *width = @"undefined";
|
NSObject *width = @"undefined";
|
||||||
NSObject *height = @"undefined";
|
NSObject *height = @"undefined";
|
||||||
NSString *orientation = @"undefined";
|
NSString *orientation = @"undefined";
|
||||||
|
|
||||||
if ([_playerItem.asset tracksWithMediaType:AVMediaTypeVideo].count > 0) {
|
if ([_playerItem.asset tracksWithMediaType:AVMediaTypeVideo].count > 0) {
|
||||||
AVAssetTrack *videoTrack = [[_playerItem.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
|
AVAssetTrack *videoTrack = [[_playerItem.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
|
||||||
width = [NSNumber numberWithFloat:videoTrack.naturalSize.width];
|
width = [NSNumber numberWithFloat:videoTrack.naturalSize.width];
|
||||||
height = [NSNumber numberWithFloat:videoTrack.naturalSize.height];
|
height = [NSNumber numberWithFloat:videoTrack.naturalSize.height];
|
||||||
CGAffineTransform preferredTransform = [videoTrack preferredTransform];
|
CGAffineTransform preferredTransform = [videoTrack preferredTransform];
|
||||||
|
|
||||||
if ((videoTrack.naturalSize.width == preferredTransform.tx
|
if ((videoTrack.naturalSize.width == preferredTransform.tx
|
||||||
&& videoTrack.naturalSize.height == preferredTransform.ty)
|
&& videoTrack.naturalSize.height == preferredTransform.ty)
|
||||||
|| (preferredTransform.tx == 0 && preferredTransform.ty == 0))
|
|| (preferredTransform.tx == 0 && preferredTransform.ty == 0))
|
||||||
{
|
{
|
||||||
orientation = @"landscape";
|
orientation = @"landscape";
|
||||||
} else
|
} else
|
||||||
orientation = @"portrait";
|
orientation = @"portrait";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(self.onVideoLoad) {
|
if(self.onVideoLoad) {
|
||||||
self.onVideoLoad(@{@"duration": [NSNumber numberWithFloat:duration],
|
self.onVideoLoad(@{@"duration": [NSNumber numberWithFloat:duration],
|
||||||
@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)],
|
@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)],
|
||||||
@"canPlayReverse": [NSNumber numberWithBool:_playerItem.canPlayReverse],
|
@"canPlayReverse": [NSNumber numberWithBool:_playerItem.canPlayReverse],
|
||||||
@ -406,20 +421,20 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
@"canStepBackward": [NSNumber numberWithBool:_playerItem.canStepBackward],
|
@"canStepBackward": [NSNumber numberWithBool:_playerItem.canStepBackward],
|
||||||
@"canStepForward": [NSNumber numberWithBool:_playerItem.canStepForward],
|
@"canStepForward": [NSNumber numberWithBool:_playerItem.canStepForward],
|
||||||
@"naturalSize": @{
|
@"naturalSize": @{
|
||||||
@"width": width,
|
@"width": width,
|
||||||
@"height": height,
|
@"height": height,
|
||||||
@"orientation": orientation
|
@"orientation": orientation
|
||||||
},
|
},
|
||||||
@"target": self.reactTag});
|
@"target": self.reactTag});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[self attachListeners];
|
[self attachListeners];
|
||||||
[self applyModifiers];
|
[self applyModifiers];
|
||||||
} else if(_playerItem.status == AVPlayerItemStatusFailed && self.onVideoError) {
|
} else if(_playerItem.status == AVPlayerItemStatusFailed && self.onVideoError) {
|
||||||
self.onVideoError(@{@"error": @{@"code": [NSNumber numberWithInteger: _playerItem.error.code],
|
self.onVideoError(@{@"error": @{@"code": [NSNumber numberWithInteger: _playerItem.error.code],
|
||||||
@"domain": _playerItem.error.domain},
|
@"domain": _playerItem.error.domain},
|
||||||
@"target": self.reactTag});
|
@"target": self.reactTag});
|
||||||
}
|
}
|
||||||
} else if ([keyPath isEqualToString:playbackBufferEmptyKeyPath]) {
|
} else if ([keyPath isEqualToString:playbackBufferEmptyKeyPath]) {
|
||||||
_playerBufferEmpty = YES;
|
_playerBufferEmpty = YES;
|
||||||
@ -432,28 +447,28 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
_playerBufferEmpty = NO;
|
_playerBufferEmpty = NO;
|
||||||
self.onVideoBuffer(@{@"isBuffering": @(NO), @"target": self.reactTag});
|
self.onVideoBuffer(@{@"isBuffering": @(NO), @"target": self.reactTag});
|
||||||
}
|
}
|
||||||
} else if (object == _playerLayer) {
|
} else if (object == _playerLayer) {
|
||||||
if([keyPath isEqualToString:readyForDisplayKeyPath] && [change objectForKey:NSKeyValueChangeNewKey]) {
|
if([keyPath isEqualToString:readyForDisplayKeyPath] && [change objectForKey:NSKeyValueChangeNewKey]) {
|
||||||
if([change objectForKey:NSKeyValueChangeNewKey] && self.onReadyForDisplay) {
|
if([change objectForKey:NSKeyValueChangeNewKey] && self.onReadyForDisplay) {
|
||||||
self.onReadyForDisplay(@{@"target": self.reactTag});
|
self.onReadyForDisplay(@{@"target": self.reactTag});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (object == _player) {
|
} else if (object == _player) {
|
||||||
if([keyPath isEqualToString:playbackRate]) {
|
if([keyPath isEqualToString:playbackRate]) {
|
||||||
if(self.onPlaybackRateChange) {
|
if(self.onPlaybackRateChange) {
|
||||||
self.onPlaybackRateChange(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate],
|
self.onPlaybackRateChange(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate],
|
||||||
@"target": self.reactTag});
|
@"target": self.reactTag});
|
||||||
}
|
|
||||||
if(_playbackStalled && _player.rate > 0) {
|
|
||||||
if(self.onPlaybackResume) {
|
|
||||||
self.onPlaybackResume(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate],
|
|
||||||
@"target": self.reactTag});
|
|
||||||
}
|
|
||||||
_playbackStalled = NO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if(_playbackStalled && _player.rate > 0) {
|
||||||
|
if(self.onPlaybackResume) {
|
||||||
|
self.onPlaybackResume(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate],
|
||||||
|
@"target": self.reactTag});
|
||||||
|
}
|
||||||
|
_playbackStalled = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,9 +496,9 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
- (void)playerItemDidReachEnd:(NSNotification *)notification
|
- (void)playerItemDidReachEnd:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
if(self.onVideoEnd) {
|
if(self.onVideoEnd) {
|
||||||
self.onVideoEnd(@{@"target": self.reactTag});
|
self.onVideoEnd(@{@"target": self.reactTag});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_repeat) {
|
if (_repeat) {
|
||||||
AVPlayerItem *item = [notification object];
|
AVPlayerItem *item = [notification object];
|
||||||
[item seekToTime:kCMTimeZero];
|
[item seekToTime:kCMTimeZero];
|
||||||
@ -536,7 +551,7 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
[_player play];
|
[_player play];
|
||||||
[_player setRate:_rate];
|
[_player setRate:_rate];
|
||||||
}
|
}
|
||||||
|
|
||||||
_paused = paused;
|
_paused = paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,31 +568,31 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
- (void)setSeek:(float)seekTime
|
- (void)setSeek:(float)seekTime
|
||||||
{
|
{
|
||||||
int timeScale = 10000;
|
int timeScale = 10000;
|
||||||
|
|
||||||
AVPlayerItem *item = _player.currentItem;
|
AVPlayerItem *item = _player.currentItem;
|
||||||
if (item && item.status == AVPlayerItemStatusReadyToPlay) {
|
if (item && item.status == AVPlayerItemStatusReadyToPlay) {
|
||||||
// TODO check loadedTimeRanges
|
// TODO check loadedTimeRanges
|
||||||
|
|
||||||
CMTime cmSeekTime = CMTimeMakeWithSeconds(seekTime, timeScale);
|
CMTime cmSeekTime = CMTimeMakeWithSeconds(seekTime, timeScale);
|
||||||
CMTime current = item.currentTime;
|
CMTime current = item.currentTime;
|
||||||
// TODO figure out a good tolerance level
|
// TODO figure out a good tolerance level
|
||||||
CMTime tolerance = CMTimeMake(1000, timeScale);
|
CMTime tolerance = CMTimeMake(1000, timeScale);
|
||||||
BOOL wasPaused = _paused;
|
BOOL wasPaused = _paused;
|
||||||
|
|
||||||
if (CMTimeCompare(current, cmSeekTime) != 0) {
|
if (CMTimeCompare(current, cmSeekTime) != 0) {
|
||||||
if (!wasPaused) [_player pause];
|
if (!wasPaused) [_player pause];
|
||||||
[_player seekToTime:cmSeekTime toleranceBefore:tolerance toleranceAfter:tolerance completionHandler:^(BOOL finished) {
|
[_player seekToTime:cmSeekTime toleranceBefore:tolerance toleranceAfter:tolerance completionHandler:^(BOOL finished) {
|
||||||
if (!wasPaused) [_player play];
|
if (!wasPaused) [_player play];
|
||||||
if(self.onVideoSeek) {
|
if(self.onVideoSeek) {
|
||||||
self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)],
|
self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)],
|
||||||
@"seekTime": [NSNumber numberWithFloat:seekTime],
|
@"seekTime": [NSNumber numberWithFloat:seekTime],
|
||||||
@"target": self.reactTag});
|
@"target": self.reactTag});
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
_pendingSeek = false;
|
_pendingSeek = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: See if this makes sense and if so, actually implement it
|
// TODO: See if this makes sense and if so, actually implement it
|
||||||
_pendingSeek = true;
|
_pendingSeek = true;
|
||||||
@ -612,7 +627,7 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
[_player setVolume:_volume];
|
[_player setVolume:_volume];
|
||||||
[_player setMuted:NO];
|
[_player setMuted:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setResizeMode:_resizeMode];
|
[self setResizeMode:_resizeMode];
|
||||||
[self setRepeat:_repeat];
|
[self setRepeat:_repeat];
|
||||||
[self setPaused:_paused];
|
[self setPaused:_paused];
|
||||||
@ -625,103 +640,103 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
|
|
||||||
- (BOOL)getFullscreen
|
- (BOOL)getFullscreen
|
||||||
{
|
{
|
||||||
return _fullscreenPlayerPresented;
|
return _fullscreenPlayerPresented;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFullscreen:(BOOL)fullscreen
|
- (void)setFullscreen:(BOOL)fullscreen
|
||||||
{
|
{
|
||||||
if( fullscreen && !_fullscreenPlayerPresented )
|
if( fullscreen && !_fullscreenPlayerPresented )
|
||||||
|
{
|
||||||
|
// Ensure player view controller is not null
|
||||||
|
if( !_playerViewController )
|
||||||
{
|
{
|
||||||
// Ensure player view controller is not null
|
[self usePlayerViewController];
|
||||||
if( !_playerViewController )
|
|
||||||
{
|
|
||||||
[self usePlayerViewController];
|
|
||||||
}
|
|
||||||
// Set presentation style to fullscreen
|
|
||||||
[_playerViewController setModalPresentationStyle:UIModalPresentationFullScreen];
|
|
||||||
|
|
||||||
// Find the nearest view controller
|
|
||||||
UIViewController *viewController = [self firstAvailableUIViewController];
|
|
||||||
if( !viewController )
|
|
||||||
{
|
|
||||||
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
|
|
||||||
viewController = keyWindow.rootViewController;
|
|
||||||
if( viewController.childViewControllers.count > 0 )
|
|
||||||
{
|
|
||||||
viewController = viewController.childViewControllers.lastObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( viewController )
|
|
||||||
{
|
|
||||||
_presentingViewController = viewController;
|
|
||||||
if(self.onVideoFullscreenPlayerWillPresent) {
|
|
||||||
self.onVideoFullscreenPlayerWillPresent(@{@"target": self.reactTag});
|
|
||||||
}
|
|
||||||
[viewController presentViewController:_playerViewController animated:true completion:^{
|
|
||||||
_playerViewController.showsPlaybackControls = YES;
|
|
||||||
_fullscreenPlayerPresented = fullscreen;
|
|
||||||
if(self.onVideoFullscreenPlayerDidPresent) {
|
|
||||||
self.onVideoFullscreenPlayerDidPresent(@{@"target": self.reactTag});
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if ( !fullscreen && _fullscreenPlayerPresented )
|
// Set presentation style to fullscreen
|
||||||
|
[_playerViewController setModalPresentationStyle:UIModalPresentationFullScreen];
|
||||||
|
|
||||||
|
// Find the nearest view controller
|
||||||
|
UIViewController *viewController = [self firstAvailableUIViewController];
|
||||||
|
if( !viewController )
|
||||||
{
|
{
|
||||||
[self videoPlayerViewControllerWillDismiss:_playerViewController];
|
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
|
||||||
[_presentingViewController dismissViewControllerAnimated:true completion:^{
|
viewController = keyWindow.rootViewController;
|
||||||
[self videoPlayerViewControllerDidDismiss:_playerViewController];
|
if( viewController.childViewControllers.count > 0 )
|
||||||
}];
|
{
|
||||||
|
viewController = viewController.childViewControllers.lastObject;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if( viewController )
|
||||||
|
{
|
||||||
|
_presentingViewController = viewController;
|
||||||
|
if(self.onVideoFullscreenPlayerWillPresent) {
|
||||||
|
self.onVideoFullscreenPlayerWillPresent(@{@"target": self.reactTag});
|
||||||
|
}
|
||||||
|
[viewController presentViewController:_playerViewController animated:true completion:^{
|
||||||
|
_playerViewController.showsPlaybackControls = YES;
|
||||||
|
_fullscreenPlayerPresented = fullscreen;
|
||||||
|
if(self.onVideoFullscreenPlayerDidPresent) {
|
||||||
|
self.onVideoFullscreenPlayerDidPresent(@{@"target": self.reactTag});
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( !fullscreen && _fullscreenPlayerPresented )
|
||||||
|
{
|
||||||
|
[self videoPlayerViewControllerWillDismiss:_playerViewController];
|
||||||
|
[_presentingViewController dismissViewControllerAnimated:true completion:^{
|
||||||
|
[self videoPlayerViewControllerDidDismiss:_playerViewController];
|
||||||
|
}];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)usePlayerViewController
|
- (void)usePlayerViewController
|
||||||
{
|
{
|
||||||
if( _player )
|
if( _player )
|
||||||
{
|
{
|
||||||
_playerViewController = [self createPlayerViewController:_player withPlayerItem:_playerItem];
|
_playerViewController = [self createPlayerViewController:_player withPlayerItem:_playerItem];
|
||||||
// to prevent video from being animated when resizeMode is 'cover'
|
// to prevent video from being animated when resizeMode is 'cover'
|
||||||
// resize mode must be set before subview is added
|
// resize mode must be set before subview is added
|
||||||
[self setResizeMode:_resizeMode];
|
[self setResizeMode:_resizeMode];
|
||||||
[self addSubview:_playerViewController.view];
|
[self addSubview:_playerViewController.view];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)usePlayerLayer
|
- (void)usePlayerLayer
|
||||||
{
|
{
|
||||||
if( _player )
|
if( _player )
|
||||||
{
|
{
|
||||||
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
|
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
|
||||||
_playerLayer.frame = self.bounds;
|
_playerLayer.frame = self.bounds;
|
||||||
_playerLayer.needsDisplayOnBoundsChange = YES;
|
_playerLayer.needsDisplayOnBoundsChange = YES;
|
||||||
|
|
||||||
// to prevent video from being animated when resizeMode is 'cover'
|
// to prevent video from being animated when resizeMode is 'cover'
|
||||||
// resize mode must be set before layer is added
|
// resize mode must be set before layer is added
|
||||||
[self setResizeMode:_resizeMode];
|
[self setResizeMode:_resizeMode];
|
||||||
[_playerLayer addObserver:self forKeyPath:readyForDisplayKeyPath options:NSKeyValueObservingOptionNew context:nil];
|
[_playerLayer addObserver:self forKeyPath:readyForDisplayKeyPath options:NSKeyValueObservingOptionNew context:nil];
|
||||||
|
|
||||||
[self.layer addSublayer:_playerLayer];
|
[self.layer addSublayer:_playerLayer];
|
||||||
self.layer.needsDisplayOnBoundsChange = YES;
|
self.layer.needsDisplayOnBoundsChange = YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setControls:(BOOL)controls
|
- (void)setControls:(BOOL)controls
|
||||||
{
|
{
|
||||||
if( _controls != controls || (!_playerLayer && !_playerViewController) )
|
if( _controls != controls || (!_playerLayer && !_playerViewController) )
|
||||||
|
{
|
||||||
|
_controls = controls;
|
||||||
|
if( _controls )
|
||||||
{
|
{
|
||||||
_controls = controls;
|
[self removePlayerLayer];
|
||||||
if( _controls )
|
[self usePlayerViewController];
|
||||||
{
|
|
||||||
[self removePlayerLayer];
|
|
||||||
[self usePlayerViewController];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[_playerViewController.view removeFromSuperview];
|
|
||||||
_playerViewController = nil;
|
|
||||||
[self usePlayerLayer];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_playerViewController.view removeFromSuperview];
|
||||||
|
_playerViewController = nil;
|
||||||
|
[self usePlayerLayer];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setProgressUpdateInterval:(float)progressUpdateInterval
|
- (void)setProgressUpdateInterval:(float)progressUpdateInterval
|
||||||
@ -731,33 +746,33 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
|
|
||||||
- (void)removePlayerLayer
|
- (void)removePlayerLayer
|
||||||
{
|
{
|
||||||
[_playerLayer removeFromSuperlayer];
|
[_playerLayer removeFromSuperlayer];
|
||||||
[_playerLayer removeObserver:self forKeyPath:readyForDisplayKeyPath];
|
[_playerLayer removeObserver:self forKeyPath:readyForDisplayKeyPath];
|
||||||
_playerLayer = nil;
|
_playerLayer = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - RCTVideoPlayerViewControllerDelegate
|
#pragma mark - RCTVideoPlayerViewControllerDelegate
|
||||||
|
|
||||||
- (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController
|
- (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController
|
||||||
{
|
{
|
||||||
if (_playerViewController == playerViewController && _fullscreenPlayerPresented && self.onVideoFullscreenPlayerWillDismiss)
|
if (_playerViewController == playerViewController && _fullscreenPlayerPresented && self.onVideoFullscreenPlayerWillDismiss)
|
||||||
{
|
{
|
||||||
self.onVideoFullscreenPlayerWillDismiss(@{@"target": self.reactTag});
|
self.onVideoFullscreenPlayerWillDismiss(@{@"target": self.reactTag});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)videoPlayerViewControllerDidDismiss:(AVPlayerViewController *)playerViewController
|
- (void)videoPlayerViewControllerDidDismiss:(AVPlayerViewController *)playerViewController
|
||||||
{
|
{
|
||||||
if (_playerViewController == playerViewController && _fullscreenPlayerPresented)
|
if (_playerViewController == playerViewController && _fullscreenPlayerPresented)
|
||||||
{
|
{
|
||||||
_fullscreenPlayerPresented = false;
|
_fullscreenPlayerPresented = false;
|
||||||
_presentingViewController = nil;
|
_presentingViewController = nil;
|
||||||
_playerViewController = nil;
|
_playerViewController = nil;
|
||||||
[self applyModifiers];
|
[self applyModifiers];
|
||||||
if(self.onVideoFullscreenPlayerDidDismiss) {
|
if(self.onVideoFullscreenPlayerDidDismiss) {
|
||||||
self.onVideoFullscreenPlayerDidDismiss(@{@"target": self.reactTag});
|
self.onVideoFullscreenPlayerDidDismiss(@{@"target": self.reactTag});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - React View Management
|
#pragma mark - React View Management
|
||||||
@ -770,15 +785,15 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
{
|
{
|
||||||
[self setControls:true];
|
[self setControls:true];
|
||||||
}
|
}
|
||||||
|
|
||||||
if( _controls )
|
if( _controls )
|
||||||
{
|
{
|
||||||
view.frame = self.bounds;
|
view.frame = self.bounds;
|
||||||
[_playerViewController.contentOverlayView insertSubview:view atIndex:atIndex];
|
[_playerViewController.contentOverlayView insertSubview:view atIndex:atIndex];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RCTLogError(@"video cannot have any subviews");
|
RCTLogError(@"video cannot have any subviews");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -787,7 +802,7 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
{
|
{
|
||||||
if( _controls )
|
if( _controls )
|
||||||
{
|
{
|
||||||
[subview removeFromSuperview];
|
[subview removeFromSuperview];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -802,7 +817,7 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
if( _controls )
|
if( _controls )
|
||||||
{
|
{
|
||||||
_playerViewController.view.frame = self.bounds;
|
_playerViewController.view.frame = self.bounds;
|
||||||
|
|
||||||
// also adjust all subviews of contentOverlayView
|
// also adjust all subviews of contentOverlayView
|
||||||
for (UIView* subview in _playerViewController.contentOverlayView.subviews) {
|
for (UIView* subview in _playerViewController.contentOverlayView.subviews) {
|
||||||
subview.frame = self.bounds;
|
subview.frame = self.bounds;
|
||||||
@ -810,10 +825,10 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[CATransaction begin];
|
[CATransaction begin];
|
||||||
[CATransaction setAnimationDuration:0];
|
[CATransaction setAnimationDuration:0];
|
||||||
_playerLayer.frame = self.bounds;
|
_playerLayer.frame = self.bounds;
|
||||||
[CATransaction commit];
|
[CATransaction commit];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -827,18 +842,18 @@ static NSString *const timedMetadata = @"timedMetadata";
|
|||||||
_playbackRateObserverRegistered = NO;
|
_playbackRateObserverRegistered = NO;
|
||||||
}
|
}
|
||||||
_player = nil;
|
_player = nil;
|
||||||
|
|
||||||
[self removePlayerLayer];
|
[self removePlayerLayer];
|
||||||
|
|
||||||
[_playerViewController.view removeFromSuperview];
|
[_playerViewController.view removeFromSuperview];
|
||||||
_playerViewController = nil;
|
_playerViewController = nil;
|
||||||
|
|
||||||
[self removePlayerTimeObserver];
|
[self removePlayerTimeObserver];
|
||||||
[self removePlayerItemObservers];
|
[self removePlayerItemObservers];
|
||||||
|
|
||||||
_eventDispatcher = nil;
|
_eventDispatcher = nil;
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
|
||||||
[super removeFromSuperview];
|
[super removeFromSuperview];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ RCT_EXPORT_MODULE();
|
|||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary);
|
RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary);
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(cache, BOOL);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);
|
RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(paused, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(paused, BOOL);
|
||||||
|
Loading…
Reference in New Issue
Block a user