Added fullscreen options for iOS Player
This commit is contained in:
parent
0c03932ada
commit
f41831ceac
5
Video.js
5
Video.js
@ -289,6 +289,11 @@ Video.propTypes = {
|
|||||||
PropTypes.object
|
PropTypes.object
|
||||||
]),
|
]),
|
||||||
fullscreen: PropTypes.bool,
|
fullscreen: PropTypes.bool,
|
||||||
|
fullscreenOptions: PropTypes.shape({
|
||||||
|
enabled: PropTypes.bool,
|
||||||
|
preferredOrientation: PropTypes.string,
|
||||||
|
autorotate: PropTypes.bool
|
||||||
|
}),
|
||||||
onVideoLoadStart: PropTypes.func,
|
onVideoLoadStart: PropTypes.func,
|
||||||
onVideoLoad: PropTypes.func,
|
onVideoLoad: PropTypes.func,
|
||||||
onVideoBuffer: PropTypes.func,
|
onVideoBuffer: PropTypes.func,
|
||||||
|
560
ios/RCTVideo.m
560
ios/RCTVideo.m
@ -25,21 +25,21 @@ static int const RCTVideoUnset = -1;
|
|||||||
BOOL _playerLayerObserverSet;
|
BOOL _playerLayerObserverSet;
|
||||||
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 _videoLoadStarted;
|
BOOL _videoLoadStarted;
|
||||||
|
|
||||||
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;
|
||||||
@ -56,6 +56,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
NSString * _ignoreSilentSwitch;
|
NSString * _ignoreSilentSwitch;
|
||||||
NSString * _resizeMode;
|
NSString * _resizeMode;
|
||||||
BOOL _fullscreen;
|
BOOL _fullscreen;
|
||||||
|
NSDictionary* _fullscreenOptions;
|
||||||
BOOL _fullscreenPlayerPresented;
|
BOOL _fullscreenPlayerPresented;
|
||||||
UIViewController * _presentingViewController;
|
UIViewController * _presentingViewController;
|
||||||
}
|
}
|
||||||
@ -64,7 +65,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
{
|
{
|
||||||
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;
|
||||||
@ -80,39 +81,46 @@ static int const RCTVideoUnset = -1;
|
|||||||
_allowsExternalPlayback = YES;
|
_allowsExternalPlayback = YES;
|
||||||
_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];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(audioRouteChanged:)
|
selector:@selector(audioRouteChanged:)
|
||||||
name:AVAudioSessionRouteChangeNotification
|
name:AVAudioSessionRouteChangeNotification
|
||||||
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];
|
|
||||||
playerLayer.showsPlaybackControls = YES;
|
RCTVideoPlayerViewController* playerLayer= [[RCTVideoPlayerViewController alloc] init];
|
||||||
playerLayer.rctDelegate = self;
|
playerLayer.showsPlaybackControls = YES;
|
||||||
playerLayer.view.frame = self.bounds;
|
playerLayer.rctDelegate = self;
|
||||||
playerLayer.player = player;
|
|
||||||
playerLayer.view.frame = self.bounds;
|
if (_fullscreenOptions) {
|
||||||
return playerLayer;
|
playerLayer.preferredOrientation = [RCTConvert NSString:[_fullscreenOptions objectForKey:@"preferredOrientation"]];
|
||||||
|
playerLayer.autorotate = [RCTConvert BOOL:[_fullscreenOptions objectForKey:@"autorotate"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
playerLayer.view.frame = self.bounds;
|
||||||
|
playerLayer.player = player;
|
||||||
|
playerLayer.view.frame = self.bounds;
|
||||||
|
return playerLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------
|
/* ---------------------------------------------------------
|
||||||
@ -121,24 +129,24 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
- (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);
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)addPlayerTimeObserver
|
-(void)addPlayerTimeObserver
|
||||||
@ -156,11 +164,11 @@ static int const RCTVideoUnset = -1;
|
|||||||
/* 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
|
||||||
@ -178,7 +186,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
- (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];
|
||||||
}
|
}
|
||||||
@ -203,43 +211,43 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
- (void)audioRouteChanged:(NSNotification *)notification
|
- (void)audioRouteChanged:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
NSNumber *reason = [[notification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey];
|
NSNumber *reason = [[notification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey];
|
||||||
NSNumber *previousRoute = [[notification userInfo] objectForKey:AVAudioSessionRouteChangePreviousRouteKey];
|
NSNumber *previousRoute = [[notification userInfo] objectForKey:AVAudioSessionRouteChangePreviousRouteKey];
|
||||||
if (reason.unsignedIntValue == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
|
if (reason.unsignedIntValue == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
|
||||||
self.onVideoAudioBecomingNoisy(@{@"target": self.reactTag});
|
self.onVideoAudioBecomingNoisy(@{@"target": self.reactTag});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Progress
|
#pragma mark - Progress
|
||||||
|
|
||||||
- (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],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -269,12 +277,12 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
- (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
|
||||||
@ -309,42 +317,42 @@ static int const RCTVideoUnset = -1;
|
|||||||
[self removePlayerItemObservers];
|
[self removePlayerItemObservers];
|
||||||
|
|
||||||
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 other passed react-props may not be set
|
// perform on next run loop, otherwise other passed react-props may not be set
|
||||||
_playerItem = [self playerItemForSource:source];
|
_playerItem = [self playerItemForSource:source];
|
||||||
[self addPlayerItemObservers];
|
[self addPlayerItemObservers];
|
||||||
|
|
||||||
[_player pause];
|
[_player pause];
|
||||||
[_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;
|
||||||
|
|
||||||
[self addPlayerTimeObserver];
|
[self addPlayerTimeObserver];
|
||||||
|
|
||||||
[self setFullscreen:_fullscreen];
|
[self setFullscreenOptions:_fullscreenOptions];
|
||||||
|
|
||||||
//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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
_videoLoadStarted = YES;
|
_videoLoadStarted = YES;
|
||||||
}
|
}
|
||||||
@ -379,15 +387,15 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
AVURLAsset *asset;
|
AVURLAsset *asset;
|
||||||
NSMutableDictionary *assetOptions = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *assetOptions = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
if (isNetwork) {
|
if (isNetwork) {
|
||||||
/* Per #1091, this is not a public API. We need to either get approval from Apple to use this
|
/* Per #1091, this is not a public API. We need to either get approval from Apple to use this
|
||||||
* or use a different approach.
|
* or use a different approach.
|
||||||
NSDictionary *headers = [source objectForKey:@"requestHeaders"];
|
NSDictionary *headers = [source objectForKey:@"requestHeaders"];
|
||||||
if ([headers count] > 0) {
|
if ([headers count] > 0) {
|
||||||
[assetOptions setObject:headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"];
|
[assetOptions setObject:headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"];
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
|
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
|
||||||
[assetOptions setObject:cookies forKey:AVURLAssetHTTPCookiesKey];
|
[assetOptions setObject:cookies forKey:AVURLAssetHTTPCookiesKey];
|
||||||
asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:uri] options:assetOptions];
|
asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:uri] options:assetOptions];
|
||||||
@ -410,14 +418,14 @@ static int const RCTVideoUnset = -1;
|
|||||||
ofTrack:videoAsset
|
ofTrack:videoAsset
|
||||||
atTime:kCMTimeZero
|
atTime:kCMTimeZero
|
||||||
error:nil];
|
error:nil];
|
||||||
|
|
||||||
AVAssetTrack *audioAsset = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;
|
AVAssetTrack *audioAsset = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;
|
||||||
AVMutableCompositionTrack *audioCompTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
|
AVMutableCompositionTrack *audioCompTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||||
[audioCompTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.timeRange.duration)
|
[audioCompTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.timeRange.duration)
|
||||||
ofTrack:audioAsset
|
ofTrack:audioAsset
|
||||||
atTime:kCMTimeZero
|
atTime:kCMTimeZero
|
||||||
error:nil];
|
error:nil];
|
||||||
|
|
||||||
NSMutableArray* validTextTracks = [NSMutableArray array];
|
NSMutableArray* validTextTracks = [NSMutableArray array];
|
||||||
for (int i = 0; i < _textTracks.count; ++i) {
|
for (int i = 0; i < _textTracks.count; ++i) {
|
||||||
AVURLAsset *textURLAsset;
|
AVURLAsset *textURLAsset;
|
||||||
@ -434,14 +442,14 @@ static int const RCTVideoUnset = -1;
|
|||||||
addMutableTrackWithMediaType:AVMediaTypeText
|
addMutableTrackWithMediaType:AVMediaTypeText
|
||||||
preferredTrackID:kCMPersistentTrackID_Invalid];
|
preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||||
[textCompTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.timeRange.duration)
|
[textCompTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.timeRange.duration)
|
||||||
ofTrack:textTrackAsset
|
ofTrack:textTrackAsset
|
||||||
atTime:kCMTimeZero
|
atTime:kCMTimeZero
|
||||||
error:nil];
|
error:nil];
|
||||||
}
|
}
|
||||||
if (validTextTracks.count != _textTracks.count) {
|
if (validTextTracks.count != _textTracks.count) {
|
||||||
[self setTextTracks:validTextTracks];
|
[self setTextTracks:validTextTracks];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [AVPlayerItem playerItemWithAsset:mixComposition];
|
return [AVPlayerItem playerItemWithAsset:mixComposition];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,7 +581,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
selector:@selector(playerItemDidReachEnd:)
|
selector:@selector(playerItemDidReachEnd:)
|
||||||
name:AVPlayerItemDidPlayToEndTimeNotification
|
name:AVPlayerItemDidPlayToEndTimeNotification
|
||||||
object:[_player currentItem]];
|
object:[_player currentItem]];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||||
name:AVPlayerItemPlaybackStalledNotification
|
name:AVPlayerItemPlaybackStalledNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
@ -594,9 +602,9 @@ static int const RCTVideoUnset = -1;
|
|||||||
- (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];
|
||||||
@ -628,8 +636,8 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
- (void)setAllowsExternalPlayback:(BOOL)allowsExternalPlayback
|
- (void)setAllowsExternalPlayback:(BOOL)allowsExternalPlayback
|
||||||
{
|
{
|
||||||
_allowsExternalPlayback = allowsExternalPlayback;
|
_allowsExternalPlayback = allowsExternalPlayback;
|
||||||
_player.allowsExternalPlayback = _allowsExternalPlayback;
|
_player.allowsExternalPlayback = _allowsExternalPlayback;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPlayWhenInactive:(BOOL)playWhenInactive
|
- (void)setPlayWhenInactive:(BOOL)playWhenInactive
|
||||||
@ -657,7 +665,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
[_player play];
|
[_player play];
|
||||||
[_player setRate:_rate];
|
[_player setRate:_rate];
|
||||||
}
|
}
|
||||||
|
|
||||||
_paused = paused;
|
_paused = paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,7 +753,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
[_player setVolume:_volume];
|
[_player setVolume:_volume];
|
||||||
[_player setMuted:NO];
|
[_player setMuted:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setSelectedAudioTrack:_selectedAudioTrack];
|
[self setSelectedAudioTrack:_selectedAudioTrack];
|
||||||
[self setSelectedTextTrack:_selectedTextTrack];
|
[self setSelectedTextTrack:_selectedTextTrack];
|
||||||
[self setResizeMode:_resizeMode];
|
[self setResizeMode:_resizeMode];
|
||||||
@ -762,52 +770,52 @@ static int const RCTVideoUnset = -1;
|
|||||||
- (void)setMediaSelectionTrackForCharacteristic:(AVMediaCharacteristic)characteristic
|
- (void)setMediaSelectionTrackForCharacteristic:(AVMediaCharacteristic)characteristic
|
||||||
withCriteria:(NSDictionary *)criteria
|
withCriteria:(NSDictionary *)criteria
|
||||||
{
|
{
|
||||||
NSString *type = criteria[@"type"];
|
NSString *type = criteria[@"type"];
|
||||||
AVMediaSelectionGroup *group = [_player.currentItem.asset
|
AVMediaSelectionGroup *group = [_player.currentItem.asset
|
||||||
mediaSelectionGroupForMediaCharacteristic:characteristic];
|
mediaSelectionGroupForMediaCharacteristic:characteristic];
|
||||||
AVMediaSelectionOption *mediaOption;
|
AVMediaSelectionOption *mediaOption;
|
||||||
|
|
||||||
if ([type isEqualToString:@"disabled"]) {
|
if ([type isEqualToString:@"disabled"]) {
|
||||||
// Do nothing. We want to ensure option is nil
|
// Do nothing. We want to ensure option is nil
|
||||||
} else if ([type isEqualToString:@"language"] || [type isEqualToString:@"title"]) {
|
} else if ([type isEqualToString:@"language"] || [type isEqualToString:@"title"]) {
|
||||||
NSString *value = criteria[@"value"];
|
NSString *value = criteria[@"value"];
|
||||||
for (int i = 0; i < group.options.count; ++i) {
|
for (int i = 0; i < group.options.count; ++i) {
|
||||||
AVMediaSelectionOption *currentOption = [group.options objectAtIndex:i];
|
AVMediaSelectionOption *currentOption = [group.options objectAtIndex:i];
|
||||||
NSString *optionValue;
|
NSString *optionValue;
|
||||||
if ([type isEqualToString:@"language"]) {
|
if ([type isEqualToString:@"language"]) {
|
||||||
optionValue = [currentOption extendedLanguageTag];
|
optionValue = [currentOption extendedLanguageTag];
|
||||||
} else {
|
} else {
|
||||||
optionValue = [[[currentOption commonMetadata]
|
optionValue = [[[currentOption commonMetadata]
|
||||||
valueForKey:@"value"]
|
valueForKey:@"value"]
|
||||||
objectAtIndex:0];
|
objectAtIndex:0];
|
||||||
}
|
}
|
||||||
if ([value isEqualToString:optionValue]) {
|
if ([value isEqualToString:optionValue]) {
|
||||||
mediaOption = currentOption;
|
mediaOption = currentOption;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
//} else if ([type isEqualToString:@"default"]) {
|
|
||||||
// option = group.defaultOption; */
|
|
||||||
} else if ([type isEqualToString:@"index"]) {
|
|
||||||
if ([criteria[@"value"] isKindOfClass:[NSNumber class]]) {
|
|
||||||
int index = [criteria[@"value"] intValue];
|
|
||||||
if (group.options.count > index) {
|
|
||||||
mediaOption = [group.options objectAtIndex:index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // default. invalid type or "system"
|
|
||||||
[_player.currentItem selectMediaOptionAutomaticallyInMediaSelectionGroup:group];
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
//} else if ([type isEqualToString:@"default"]) {
|
||||||
// If a match isn't found, option will be nil and text tracks will be disabled
|
// option = group.defaultOption; */
|
||||||
[_player.currentItem selectMediaOption:mediaOption inMediaSelectionGroup:group];
|
} else if ([type isEqualToString:@"index"]) {
|
||||||
|
if ([criteria[@"value"] isKindOfClass:[NSNumber class]]) {
|
||||||
|
int index = [criteria[@"value"] intValue];
|
||||||
|
if (group.options.count > index) {
|
||||||
|
mediaOption = [group.options objectAtIndex:index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // default. invalid type or "system"
|
||||||
|
[_player.currentItem selectMediaOptionAutomaticallyInMediaSelectionGroup:group];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a match isn't found, option will be nil and text tracks will be disabled
|
||||||
|
[_player.currentItem selectMediaOption:mediaOption inMediaSelectionGroup:group];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setSelectedAudioTrack:(NSDictionary *)selectedAudioTrack {
|
- (void)setSelectedAudioTrack:(NSDictionary *)selectedAudioTrack {
|
||||||
_selectedAudioTrack = selectedAudioTrack;
|
_selectedAudioTrack = selectedAudioTrack;
|
||||||
[self setMediaSelectionTrackForCharacteristic:AVMediaCharacteristicAudible
|
[self setMediaSelectionTrackForCharacteristic:AVMediaCharacteristicAudible
|
||||||
withCriteria:_selectedAudioTrack];
|
withCriteria:_selectedAudioTrack];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setSelectedTextTrack:(NSDictionary *)selectedTextTrack {
|
- (void)setSelectedTextTrack:(NSDictionary *)selectedTextTrack {
|
||||||
@ -879,7 +887,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = firstTextIndex; i < _player.currentItem.tracks.count; ++i) {
|
for (int i = firstTextIndex; i < _player.currentItem.tracks.count; ++i) {
|
||||||
BOOL isEnabled = NO;
|
BOOL isEnabled = NO;
|
||||||
if (selectedTrackIndex != RCTVideoUnset) {
|
if (selectedTrackIndex != RCTVideoUnset) {
|
||||||
@ -935,32 +943,32 @@ static int const RCTVideoUnset = -1;
|
|||||||
- (void)setTextTracks:(NSArray*) textTracks;
|
- (void)setTextTracks:(NSArray*) textTracks;
|
||||||
{
|
{
|
||||||
_textTracks = textTracks;
|
_textTracks = textTracks;
|
||||||
|
|
||||||
// in case textTracks was set after selectedTextTrack
|
// in case textTracks was set after selectedTextTrack
|
||||||
if (_selectedTextTrack) [self setSelectedTextTrack:_selectedTextTrack];
|
if (_selectedTextTrack) [self setSelectedTextTrack:_selectedTextTrack];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)getAudioTrackInfo
|
- (NSArray *)getAudioTrackInfo
|
||||||
{
|
{
|
||||||
NSMutableArray *audioTracks = [[NSMutableArray alloc] init];
|
NSMutableArray *audioTracks = [[NSMutableArray alloc] init];
|
||||||
AVMediaSelectionGroup *group = [_player.currentItem.asset
|
AVMediaSelectionGroup *group = [_player.currentItem.asset
|
||||||
mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible];
|
mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible];
|
||||||
for (int i = 0; i < group.options.count; ++i) {
|
for (int i = 0; i < group.options.count; ++i) {
|
||||||
AVMediaSelectionOption *currentOption = [group.options objectAtIndex:i];
|
AVMediaSelectionOption *currentOption = [group.options objectAtIndex:i];
|
||||||
NSString *title = @"";
|
NSString *title = @"";
|
||||||
NSArray *values = [[currentOption commonMetadata] valueForKey:@"value"];
|
NSArray *values = [[currentOption commonMetadata] valueForKey:@"value"];
|
||||||
if (values.count > 0) {
|
if (values.count > 0) {
|
||||||
title = [values objectAtIndex:0];
|
title = [values objectAtIndex:0];
|
||||||
}
|
|
||||||
NSString *language = [currentOption extendedLanguageTag] ? [currentOption extendedLanguageTag] : @"";
|
|
||||||
NSDictionary *audioTrack = @{
|
|
||||||
@"index": [NSNumber numberWithInt:i],
|
|
||||||
@"title": title,
|
|
||||||
@"language": language
|
|
||||||
};
|
|
||||||
[audioTracks addObject:audioTrack];
|
|
||||||
}
|
}
|
||||||
return audioTracks;
|
NSString *language = [currentOption extendedLanguageTag] ? [currentOption extendedLanguageTag] : @"";
|
||||||
|
NSDictionary *audioTrack = @{
|
||||||
|
@"index": [NSNumber numberWithInt:i],
|
||||||
|
@"title": title,
|
||||||
|
@"language": language
|
||||||
|
};
|
||||||
|
[audioTracks addObject:audioTrack];
|
||||||
|
}
|
||||||
|
return audioTracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)getTextTrackInfo
|
- (NSArray *)getTextTrackInfo
|
||||||
@ -992,67 +1000,91 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
- (BOOL)getFullscreen
|
- (BOOL)getFullscreen
|
||||||
{
|
{
|
||||||
return _fullscreenPlayerPresented;
|
return _fullscreenPlayerPresented;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFullscreen:(BOOL)fullscreen
|
- (void)setFullscreen:(BOOL) fullscreen {
|
||||||
{
|
_fullscreen = fullscreen;
|
||||||
_fullscreen = fullscreen;
|
|
||||||
if( fullscreen && !_fullscreenPlayerPresented && _player )
|
NSString* enabled = _fullscreen ? @"1" : @"0";
|
||||||
{
|
|
||||||
// Ensure player view controller is not null
|
if (!_fullscreenOptions) {
|
||||||
if( !_playerViewController )
|
[self setFullscreenOptions:
|
||||||
{
|
@{
|
||||||
[self usePlayerViewController];
|
@"enabled": enabled,
|
||||||
}
|
@"autorotate": @"0",
|
||||||
// Set presentation style to fullscreen
|
@"preferredOrientation": @"default"
|
||||||
[_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 )
|
|
||||||
{
|
|
||||||
[self videoPlayerViewControllerWillDismiss:_playerViewController];
|
|
||||||
[_presentingViewController dismissViewControllerAnimated:true completion:^{
|
|
||||||
[self videoPlayerViewControllerDidDismiss:_playerViewController];
|
|
||||||
}];
|
}];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[_fullscreenOptions setValue:enabled forKey:@"enabled"];
|
||||||
|
[self setFullscreenOptions:_fullscreenOptions];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFullscreenOptions:(NSDictionary*) fullscreenOptions
|
||||||
|
{
|
||||||
|
_fullscreenOptions = fullscreenOptions;
|
||||||
|
|
||||||
|
if (!_fullscreenOptions) return;
|
||||||
|
|
||||||
|
BOOL fullscreenEnabled = [RCTConvert BOOL:[_fullscreenOptions objectForKey:@"enabled"]];
|
||||||
|
|
||||||
|
if( fullscreenEnabled && !_fullscreenPlayerPresented && _player )
|
||||||
|
{
|
||||||
|
// Ensure player view controller is not null
|
||||||
|
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 = fullscreenEnabled;
|
||||||
|
if(self.onVideoFullscreenPlayerDidPresent) {
|
||||||
|
self.onVideoFullscreenPlayerDidPresent(@{@"target": self.reactTag});
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( !fullscreenEnabled && _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
|
||||||
@ -1076,27 +1108,27 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
- (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
|
||||||
{
|
{
|
||||||
_progressUpdateInterval = progressUpdateInterval;
|
_progressUpdateInterval = progressUpdateInterval;
|
||||||
|
|
||||||
if (_timeObserver) {
|
if (_timeObserver) {
|
||||||
[self removePlayerTimeObserver];
|
[self removePlayerTimeObserver];
|
||||||
[self addPlayerTimeObserver];
|
[self addPlayerTimeObserver];
|
||||||
@ -1117,24 +1149,24 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
- (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
|
||||||
@ -1147,15 +1179,15 @@ static int const RCTVideoUnset = -1;
|
|||||||
{
|
{
|
||||||
[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;
|
||||||
}
|
}
|
||||||
@ -1164,7 +1196,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
{
|
{
|
||||||
if( _controls )
|
if( _controls )
|
||||||
{
|
{
|
||||||
[subview removeFromSuperview];
|
[subview removeFromSuperview];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1179,7 +1211,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
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;
|
||||||
@ -1187,10 +1219,10 @@ static int const RCTVideoUnset = -1;
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[CATransaction begin];
|
[CATransaction begin];
|
||||||
[CATransaction setAnimationDuration:0];
|
[CATransaction setAnimationDuration:0];
|
||||||
_playerLayer.frame = self.bounds;
|
_playerLayer.frame = self.bounds;
|
||||||
[CATransaction commit];
|
[CATransaction commit];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1204,18 +1236,18 @@ static int const RCTVideoUnset = -1;
|
|||||||
_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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,8 @@ RCT_EXPORT_VIEW_PROPERTY(ignoreSilentSwitch, NSString);
|
|||||||
RCT_EXPORT_VIEW_PROPERTY(rate, float);
|
RCT_EXPORT_VIEW_PROPERTY(rate, float);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary);
|
RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
|
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL); // deprecated property
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(fullscreenOptions, NSDictionary);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
|
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
|
||||||
/* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */
|
/* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */
|
||||||
RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock);
|
RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock);
|
||||||
|
@ -12,4 +12,9 @@
|
|||||||
|
|
||||||
@interface RCTVideoPlayerViewController : AVPlayerViewController
|
@interface RCTVideoPlayerViewController : AVPlayerViewController
|
||||||
@property (nonatomic, weak) id<RCTVideoPlayerViewControllerDelegate> rctDelegate;
|
@property (nonatomic, weak) id<RCTVideoPlayerViewControllerDelegate> rctDelegate;
|
||||||
|
|
||||||
|
// Optional paramters
|
||||||
|
@property (nonatomic, weak) NSString* preferredOrientation;
|
||||||
|
@property (nonatomic) BOOL autorotate;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -6,6 +6,14 @@
|
|||||||
|
|
||||||
@implementation RCTVideoPlayerViewController
|
@implementation RCTVideoPlayerViewController
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
self.autorotate = false;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewDidDisappear:(BOOL)animated
|
- (void)viewDidDisappear:(BOOL)animated
|
||||||
{
|
{
|
||||||
[super viewDidDisappear:animated];
|
[super viewDidDisappear:animated];
|
||||||
@ -14,17 +22,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)shouldAutorotate {
|
- (BOOL)shouldAutorotate {
|
||||||
return YES;
|
return self.autorotate;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||||
|
|
||||||
return UIInterfaceOrientationMaskLandscape;
|
return UIInterfaceOrientationMaskAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||||
|
if ([self.preferredOrientation.lowercaseString isEqualToString:@"landscape"]) {
|
||||||
return UIInterfaceOrientationLandscapeLeft;
|
return UIInterfaceOrientationLandscapeLeft;
|
||||||
|
}
|
||||||
|
else if ([self.preferredOrientation.lowercaseString isEqualToString:@"portrait"]) {
|
||||||
|
return UIInterfaceOrientationPortrait;
|
||||||
|
}
|
||||||
|
else { // default case
|
||||||
|
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
|
||||||
|
return orientation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
Loading…
Reference in New Issue
Block a user