added video filter
This commit is contained in:
parent
2c391f5807
commit
18e8895712
3
Video.js
3
Video.js
@ -274,7 +274,10 @@ export default class Video extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
Video.filterTypes = ['Normal', 'Country', 'Winter', 'Black N White', 'Sunrise', 'Artistic'];
|
||||
|
||||
Video.propTypes = {
|
||||
filter: PropTypes.oneOf(Video.filterTypes),
|
||||
/* Native only */
|
||||
src: PropTypes.object,
|
||||
seek: PropTypes.oneOfType([
|
||||
|
@ -13,6 +13,7 @@ static NSString *const readyForDisplayKeyPath = @"readyForDisplay";
|
||||
static NSString *const playbackRate = @"rate";
|
||||
static NSString *const timedMetadata = @"timedMetadata";
|
||||
static NSString *const externalPlaybackActive = @"externalPlaybackActive";
|
||||
static NSDictionary* filters = nil;
|
||||
|
||||
static int const RCTVideoUnset = -1;
|
||||
|
||||
@ -32,22 +33,22 @@ static int const RCTVideoUnset = -1;
|
||||
BOOL _playerLayerObserverSet;
|
||||
RCTVideoPlayerViewController *_playerViewController;
|
||||
NSURL *_videoURL;
|
||||
|
||||
|
||||
/* Required to publish events */
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
BOOL _playbackRateObserverRegistered;
|
||||
BOOL _isExternalPlaybackActiveObserverRegistered;
|
||||
BOOL _videoLoadStarted;
|
||||
|
||||
|
||||
bool _pendingSeek;
|
||||
float _pendingSeekTime;
|
||||
float _lastSeekTime;
|
||||
|
||||
|
||||
/* For sending videoProgress events */
|
||||
Float64 _progressUpdateInterval;
|
||||
BOOL _controls;
|
||||
id _timeObserver;
|
||||
|
||||
|
||||
/* Keep track of any modifiers, need to be applied after each play */
|
||||
float _volume;
|
||||
float _rate;
|
||||
@ -63,6 +64,7 @@ static int const RCTVideoUnset = -1;
|
||||
BOOL _playWhenInactive;
|
||||
NSString * _ignoreSilentSwitch;
|
||||
NSString * _resizeMode;
|
||||
NSString * _filter;
|
||||
BOOL _fullscreen;
|
||||
NSString * _fullscreenOrientation;
|
||||
BOOL _fullscreenPlayerPresented;
|
||||
@ -75,8 +77,18 @@ static int const RCTVideoUnset = -1;
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
|
||||
filters = @{
|
||||
@"Normal": @"",
|
||||
@"Country": @"CISepiaTone",
|
||||
@"Winter": @"CIPhotoEffectProcess",
|
||||
@"Black N White": @"CIPhotoEffectNoir",
|
||||
@"Sunrise": @"CIPhotoEffectTransfer",
|
||||
@"Artistic": @"CIColorPosterize",
|
||||
};
|
||||
|
||||
_eventDispatcher = eventDispatcher;
|
||||
|
||||
|
||||
_playbackRateObserverRegistered = NO;
|
||||
_isExternalPlaybackActiveObserverRegistered = NO;
|
||||
_playbackStalled = NO;
|
||||
@ -101,23 +113,23 @@ static int const RCTVideoUnset = -1;
|
||||
selector:@selector(applicationWillResignActive:)
|
||||
name:UIApplicationWillResignActiveNotification
|
||||
object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationDidEnterBackground:)
|
||||
name:UIApplicationDidEnterBackgroundNotification
|
||||
object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationWillEnterForeground:)
|
||||
name:UIApplicationWillEnterForegroundNotification
|
||||
object:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(audioRouteChanged:)
|
||||
name:AVAudioSessionRouteChangeNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -127,7 +139,7 @@ static int const RCTVideoUnset = -1;
|
||||
viewController.showsPlaybackControls = YES;
|
||||
viewController.rctDelegate = self;
|
||||
viewController.preferredOrientation = _fullscreenOrientation;
|
||||
|
||||
|
||||
viewController.view.frame = self.bounds;
|
||||
viewController.player = player;
|
||||
viewController.view.frame = self.bounds;
|
||||
@ -145,7 +157,7 @@ static int const RCTVideoUnset = -1;
|
||||
{
|
||||
return([playerItem duration]);
|
||||
}
|
||||
|
||||
|
||||
return(kCMTimeInvalid);
|
||||
}
|
||||
|
||||
@ -156,7 +168,7 @@ static int const RCTVideoUnset = -1;
|
||||
{
|
||||
return [playerItem seekableTimeRanges].firstObject.CMTimeRangeValue;
|
||||
}
|
||||
|
||||
|
||||
return (kCMTimeRangeZero);
|
||||
}
|
||||
|
||||
@ -197,7 +209,7 @@ static int const RCTVideoUnset = -1;
|
||||
- (void)applicationWillResignActive:(NSNotification *)notification
|
||||
{
|
||||
if (_playInBackground || _playWhenInactive || _paused) return;
|
||||
|
||||
|
||||
[_player pause];
|
||||
[_player setRate:0.0];
|
||||
}
|
||||
@ -237,18 +249,18 @@ static int const RCTVideoUnset = -1;
|
||||
if (video == nil || video.status != AVPlayerItemStatusReadyToPlay) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CMTime playerDuration = [self playerItemDuration];
|
||||
if (CMTIME_IS_INVALID(playerDuration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CMTime currentTime = _player.currentTime;
|
||||
const Float64 duration = CMTimeGetSeconds(playerDuration);
|
||||
const Float64 currentTimeSecs = CMTimeGetSeconds(currentTime);
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"RCTVideo_progress" object:nil userInfo:@{@"progress": [NSNumber numberWithDouble: currentTimeSecs / duration]}];
|
||||
|
||||
|
||||
if( currentTimeSecs >= 0 && self.onVideoProgress) {
|
||||
self.onVideoProgress(@{
|
||||
@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(currentTime)],
|
||||
@ -333,11 +345,11 @@ static int const RCTVideoUnset = -1;
|
||||
[self playerItemForSource:source withCallback:^(AVPlayerItem * playerItem) {
|
||||
_playerItem = playerItem;
|
||||
[self addPlayerItemObservers];
|
||||
|
||||
|
||||
[_player pause];
|
||||
[_playerViewController.view removeFromSuperview];
|
||||
_playerViewController = nil;
|
||||
|
||||
|
||||
if (_playbackRateObserverRegistered) {
|
||||
[_player removeObserver:self forKeyPath:playbackRate context:nil];
|
||||
_playbackRateObserverRegistered = NO;
|
||||
@ -346,16 +358,16 @@ static int const RCTVideoUnset = -1;
|
||||
[_player removeObserver:self forKeyPath:externalPlaybackActive context:nil];
|
||||
_isExternalPlaybackActiveObserverRegistered = NO;
|
||||
}
|
||||
|
||||
|
||||
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
||||
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
|
||||
|
||||
|
||||
[_player addObserver:self forKeyPath:playbackRate options:0 context:nil];
|
||||
_playbackRateObserverRegistered = YES;
|
||||
|
||||
|
||||
[_player addObserver:self forKeyPath:externalPlaybackActive options:0 context:nil];
|
||||
_isExternalPlaybackActiveObserverRegistered = YES;
|
||||
|
||||
|
||||
[self addPlayerTimeObserver];
|
||||
|
||||
//Perform on next run loop, otherwise onVideoLoadStart is nil
|
||||
@ -378,7 +390,7 @@ static int const RCTVideoUnset = -1;
|
||||
if ([filepath containsString:@"file://"]) {
|
||||
return [NSURL URLWithString:filepath];
|
||||
}
|
||||
|
||||
|
||||
// if no file found, check if the file exists in the Document directory
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString* relativeFilePath = [filepath lastPathComponent];
|
||||
@ -387,7 +399,7 @@ static int const RCTVideoUnset = -1;
|
||||
if (fileComponents.count > 1) {
|
||||
relativeFilePath = [fileComponents objectAtIndex:1];
|
||||
}
|
||||
|
||||
|
||||
NSString *path = [paths.firstObject stringByAppendingPathComponent:relativeFilePath];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
||||
return [NSURL fileURLWithPath:path];
|
||||
@ -404,21 +416,21 @@ static int const RCTVideoUnset = -1;
|
||||
|
||||
// sideload text tracks
|
||||
AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
|
||||
|
||||
|
||||
AVAssetTrack *videoAsset = [asset tracksWithMediaType:AVMediaTypeVideo].firstObject;
|
||||
AVMutableCompositionTrack *videoCompTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||
[videoCompTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.timeRange.duration)
|
||||
ofTrack:videoAsset
|
||||
atTime:kCMTimeZero
|
||||
error:nil];
|
||||
|
||||
|
||||
AVAssetTrack *audioAsset = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;
|
||||
AVMutableCompositionTrack *audioCompTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
|
||||
[audioCompTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.timeRange.duration)
|
||||
ofTrack:audioAsset
|
||||
atTime:kCMTimeZero
|
||||
error:nil];
|
||||
|
||||
|
||||
NSMutableArray* validTextTracks = [NSMutableArray array];
|
||||
for (int i = 0; i < _textTracks.count; ++i) {
|
||||
AVURLAsset *textURLAsset;
|
||||
@ -457,7 +469,7 @@ static int const RCTVideoUnset = -1;
|
||||
? [NSURL URLWithString:uri]
|
||||
: [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]];
|
||||
NSMutableDictionary *assetOptions = [[NSMutableDictionary alloc] init];
|
||||
|
||||
|
||||
if (isNetwork) {
|
||||
/* Per #1091, this is not a public API.
|
||||
* We need to either get approval from Apple to use this or use a different approach.
|
||||
@ -560,40 +572,40 @@ static int const RCTVideoUnset = -1;
|
||||
for (AVMetadataItem *item in items) {
|
||||
NSString *value = (NSString *)item.value;
|
||||
NSString *identifier = item.identifier;
|
||||
|
||||
|
||||
if (![value isEqual: [NSNull null]]) {
|
||||
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjects:@[value, identifier] forKeys:@[@"value", @"identifier"]];
|
||||
|
||||
|
||||
[array addObject:dictionary];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self.onTimedMetadata(@{
|
||||
@"target": self.reactTag,
|
||||
@"metadata": array
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ([keyPath isEqualToString:statusKeyPath]) {
|
||||
// Handle player item status change.
|
||||
if (_playerItem.status == AVPlayerItemStatusReadyToPlay) {
|
||||
float duration = CMTimeGetSeconds(_playerItem.asset.duration);
|
||||
|
||||
|
||||
if (isnan(duration)) {
|
||||
duration = 0.0;
|
||||
}
|
||||
|
||||
|
||||
NSObject *width = @"undefined";
|
||||
NSObject *height = @"undefined";
|
||||
NSString *orientation = @"undefined";
|
||||
|
||||
|
||||
if ([_playerItem.asset tracksWithMediaType:AVMediaTypeVideo].count > 0) {
|
||||
AVAssetTrack *videoTrack = [[_playerItem.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
|
||||
width = [NSNumber numberWithFloat:videoTrack.naturalSize.width];
|
||||
height = [NSNumber numberWithFloat:videoTrack.naturalSize.height];
|
||||
CGAffineTransform preferredTransform = [videoTrack preferredTransform];
|
||||
|
||||
|
||||
if ((videoTrack.naturalSize.width == preferredTransform.tx
|
||||
&& videoTrack.naturalSize.height == preferredTransform.ty)
|
||||
|| (preferredTransform.tx == 0 && preferredTransform.ty == 0))
|
||||
@ -603,7 +615,7 @@ static int const RCTVideoUnset = -1;
|
||||
orientation = @"portrait";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (self.onVideoLoad && _videoLoadStarted) {
|
||||
self.onVideoLoad(@{@"duration": [NSNumber numberWithFloat:duration],
|
||||
@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)],
|
||||
@ -623,7 +635,7 @@ static int const RCTVideoUnset = -1;
|
||||
@"target": self.reactTag});
|
||||
}
|
||||
_videoLoadStarted = NO;
|
||||
|
||||
|
||||
[self attachListeners];
|
||||
[self applyModifiers];
|
||||
} else if (_playerItem.status == AVPlayerItemStatusFailed && self.onVideoError) {
|
||||
@ -683,7 +695,7 @@ static int const RCTVideoUnset = -1;
|
||||
selector:@selector(playerItemDidReachEnd:)
|
||||
name:AVPlayerItemDidPlayToEndTimeNotification
|
||||
object:[_player currentItem]];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:AVPlayerItemPlaybackStalledNotification
|
||||
object:nil];
|
||||
@ -706,7 +718,7 @@ static int const RCTVideoUnset = -1;
|
||||
if(self.onVideoEnd) {
|
||||
self.onVideoEnd(@{@"target": self.reactTag});
|
||||
}
|
||||
|
||||
|
||||
if (_repeat) {
|
||||
AVPlayerItem *item = [notification object];
|
||||
[item seekToTime:kCMTimeZero];
|
||||
@ -767,7 +779,7 @@ static int const RCTVideoUnset = -1;
|
||||
[_player play];
|
||||
[_player setRate:_rate];
|
||||
}
|
||||
|
||||
|
||||
_paused = paused;
|
||||
}
|
||||
|
||||
@ -789,19 +801,19 @@ static int const RCTVideoUnset = -1;
|
||||
{
|
||||
NSNumber *seekTime = info[@"time"];
|
||||
NSNumber *seekTolerance = info[@"tolerance"];
|
||||
|
||||
|
||||
int timeScale = 1000;
|
||||
|
||||
|
||||
AVPlayerItem *item = _player.currentItem;
|
||||
if (item && item.status == AVPlayerItemStatusReadyToPlay) {
|
||||
// TODO check loadedTimeRanges
|
||||
|
||||
|
||||
CMTime cmSeekTime = CMTimeMakeWithSeconds([seekTime floatValue], timeScale);
|
||||
CMTime current = item.currentTime;
|
||||
// TODO figure out a good tolerance level
|
||||
CMTime tolerance = CMTimeMake([seekTolerance floatValue], timeScale);
|
||||
BOOL wasPaused = _paused;
|
||||
|
||||
|
||||
if (CMTimeCompare(current, cmSeekTime) != 0) {
|
||||
if (!wasPaused) [_player pause];
|
||||
[_player seekToTime:cmSeekTime toleranceBefore:tolerance toleranceAfter:tolerance completionHandler:^(BOOL finished) {
|
||||
@ -817,10 +829,10 @@ static int const RCTVideoUnset = -1;
|
||||
@"target": self.reactTag});
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
_pendingSeek = false;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// TODO: See if this makes sense and if so, actually implement it
|
||||
_pendingSeek = true;
|
||||
@ -855,12 +867,13 @@ static int const RCTVideoUnset = -1;
|
||||
[_player setVolume:_volume];
|
||||
[_player setMuted:NO];
|
||||
}
|
||||
|
||||
|
||||
[self setSelectedAudioTrack:_selectedAudioTrack];
|
||||
[self setSelectedTextTrack:_selectedTextTrack];
|
||||
[self setResizeMode:_resizeMode];
|
||||
[self setRepeat:_repeat];
|
||||
[self setPaused:_paused];
|
||||
[self setFilter:_filter];
|
||||
[self setControls:_controls];
|
||||
[self setAllowsExternalPlayback:_allowsExternalPlayback];
|
||||
}
|
||||
@ -876,7 +889,7 @@ static int const RCTVideoUnset = -1;
|
||||
AVMediaSelectionGroup *group = [_player.currentItem.asset
|
||||
mediaSelectionGroupForMediaCharacteristic:characteristic];
|
||||
AVMediaSelectionOption *mediaOption;
|
||||
|
||||
|
||||
if ([type isEqualToString:@"disabled"]) {
|
||||
// Do nothing. We want to ensure option is nil
|
||||
} else if ([type isEqualToString:@"language"] || [type isEqualToString:@"title"]) {
|
||||
@ -909,7 +922,7 @@ static int const RCTVideoUnset = -1;
|
||||
[_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];
|
||||
}
|
||||
@ -933,7 +946,7 @@ static int const RCTVideoUnset = -1;
|
||||
- (void) setSideloadedText {
|
||||
NSString *type = _selectedTextTrack[@"type"];
|
||||
NSArray *textTracks = [self getTextTrackInfo];
|
||||
|
||||
|
||||
// The first few tracks will be audio & video track
|
||||
int firstTextIndex = 0;
|
||||
for (firstTextIndex = 0; firstTextIndex < _player.currentItem.tracks.count; ++firstTextIndex) {
|
||||
@ -941,9 +954,9 @@ static int const RCTVideoUnset = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int selectedTrackIndex = RCTVideoUnset;
|
||||
|
||||
|
||||
if ([type isEqualToString:@"disabled"]) {
|
||||
// Do nothing. We want to ensure option is nil
|
||||
} else if ([type isEqualToString:@"language"]) {
|
||||
@ -972,7 +985,7 @@ static int const RCTVideoUnset = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// in the situation that a selected text track is not available (eg. specifies a textTrack not available)
|
||||
if (![type isEqualToString:@"disabled"] && selectedTrackIndex == RCTVideoUnset) {
|
||||
CFArrayRef captioningMediaCharacteristics = MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics(kMACaptionAppearanceDomainUser);
|
||||
@ -989,7 +1002,7 @@ static int const RCTVideoUnset = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = firstTextIndex; i < _player.currentItem.tracks.count; ++i) {
|
||||
BOOL isEnabled = NO;
|
||||
if (selectedTrackIndex != RCTVideoUnset) {
|
||||
@ -1004,7 +1017,7 @@ static int const RCTVideoUnset = -1;
|
||||
AVMediaSelectionGroup *group = [_player.currentItem.asset
|
||||
mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible];
|
||||
AVMediaSelectionOption *mediaOption;
|
||||
|
||||
|
||||
if ([type isEqualToString:@"disabled"]) {
|
||||
// Do nothing. We want to ensure option is nil
|
||||
} else if ([type isEqualToString:@"language"] || [type isEqualToString:@"title"]) {
|
||||
@ -1037,7 +1050,7 @@ static int const RCTVideoUnset = -1;
|
||||
[_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];
|
||||
}
|
||||
@ -1045,7 +1058,7 @@ static int const RCTVideoUnset = -1;
|
||||
- (void)setTextTracks:(NSArray*) textTracks;
|
||||
{
|
||||
_textTracks = textTracks;
|
||||
|
||||
|
||||
// in case textTracks was set after selectedTextTrack
|
||||
if (_selectedTextTrack) [self setSelectedTextTrack:_selectedTextTrack];
|
||||
}
|
||||
@ -1077,7 +1090,7 @@ static int const RCTVideoUnset = -1;
|
||||
{
|
||||
// if sideloaded, textTracks will already be set
|
||||
if (_textTracks) return _textTracks;
|
||||
|
||||
|
||||
// if streaming video, we extract the text tracks
|
||||
NSMutableArray *textTracks = [[NSMutableArray alloc] init];
|
||||
AVMediaSelectionGroup *group = [_player.currentItem.asset
|
||||
@ -1115,7 +1128,7 @@ static int const RCTVideoUnset = -1;
|
||||
}
|
||||
// Set presentation style to fullscreen
|
||||
[_playerViewController setModalPresentationStyle:UIModalPresentationFullScreen];
|
||||
|
||||
|
||||
// Find the nearest view controller
|
||||
UIViewController *viewController = [self firstAvailableUIViewController];
|
||||
if( !viewController )
|
||||
@ -1151,6 +1164,43 @@ static int const RCTVideoUnset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFilter:(NSString *)filter {
|
||||
|
||||
_filter = filter;
|
||||
|
||||
AVAsset *asset = _playerItem.asset;
|
||||
|
||||
if (asset != nil) {
|
||||
|
||||
NSString *filterName = filters[filter];
|
||||
CIFilter *filter = [CIFilter filterWithName:filterName];
|
||||
|
||||
_playerItem.videoComposition = [AVVideoComposition
|
||||
videoCompositionWithAsset:asset
|
||||
applyingCIFiltersWithHandler:^(AVAsynchronousCIImageFilteringRequest *_Nonnull request) {
|
||||
|
||||
if (filter == nil) {
|
||||
|
||||
[request finishWithImage:request.sourceImage context:nil];
|
||||
|
||||
} else {
|
||||
|
||||
CIImage *image = request.sourceImage.imageByClampingToExtent;
|
||||
|
||||
[filter setValue:image forKey:kCIInputImageKey];
|
||||
|
||||
CIImage *output = [filter.outputImage imageByCroppingToRect:request.sourceImage.extent];
|
||||
|
||||
[request finishWithImage:output context:nil];
|
||||
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)setFullscreenOrientation:(NSString *)orientation {
|
||||
_fullscreenOrientation = orientation;
|
||||
if (_fullscreenPlayerPresented) {
|
||||
@ -1177,13 +1227,13 @@ static int const RCTVideoUnset = -1;
|
||||
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
|
||||
_playerLayer.frame = self.bounds;
|
||||
_playerLayer.needsDisplayOnBoundsChange = YES;
|
||||
|
||||
|
||||
// to prevent video from being animated when resizeMode is 'cover'
|
||||
// resize mode must be set before layer is added
|
||||
[self setResizeMode:_resizeMode];
|
||||
[_playerLayer addObserver:self forKeyPath:readyForDisplayKeyPath options:NSKeyValueObservingOptionNew context:nil];
|
||||
_playerLayerObserverSet = YES;
|
||||
|
||||
|
||||
[self.layer addSublayer:_playerLayer];
|
||||
self.layer.needsDisplayOnBoundsChange = YES;
|
||||
}
|
||||
@ -1211,7 +1261,7 @@ static int const RCTVideoUnset = -1;
|
||||
- (void)setProgressUpdateInterval:(float)progressUpdateInterval
|
||||
{
|
||||
_progressUpdateInterval = progressUpdateInterval;
|
||||
|
||||
|
||||
if (_timeObserver) {
|
||||
[self removePlayerTimeObserver];
|
||||
[self addPlayerTimeObserver];
|
||||
@ -1262,7 +1312,7 @@ static int const RCTVideoUnset = -1;
|
||||
{
|
||||
[self setControls:true];
|
||||
}
|
||||
|
||||
|
||||
if( _controls )
|
||||
{
|
||||
view.frame = self.bounds;
|
||||
@ -1294,7 +1344,7 @@ static int const RCTVideoUnset = -1;
|
||||
if( _controls )
|
||||
{
|
||||
_playerViewController.view.frame = self.bounds;
|
||||
|
||||
|
||||
// also adjust all subviews of contentOverlayView
|
||||
for (UIView* subview in _playerViewController.contentOverlayView.subviews) {
|
||||
subview.frame = self.bounds;
|
||||
@ -1323,18 +1373,18 @@ static int const RCTVideoUnset = -1;
|
||||
_isExternalPlaybackActiveObserverRegistered = NO;
|
||||
}
|
||||
_player = nil;
|
||||
|
||||
|
||||
[self removePlayerLayer];
|
||||
|
||||
|
||||
[_playerViewController.view removeFromSuperview];
|
||||
_playerViewController = nil;
|
||||
|
||||
|
||||
[self removePlayerTimeObserver];
|
||||
[self removePlayerItemObservers];
|
||||
|
||||
|
||||
_eventDispatcher = nil;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
|
||||
[super removeFromSuperview];
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary);
|
||||
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
|
||||
RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
|
||||
RCT_EXPORT_VIEW_PROPERTY(fullscreenOrientation, NSString);
|
||||
RCT_EXPORT_VIEW_PROPERTY(filter, NSString);
|
||||
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
|
||||
/* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */
|
||||
RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock);
|
||||
|
Loading…
Reference in New Issue
Block a user