Merge branch 'master' into master

This commit is contained in:
Hampton Maxwell
2018-12-31 21:36:49 -08:00
committed by GitHub
20 changed files with 575 additions and 60 deletions

View File

@@ -26,6 +26,7 @@ static int const RCTVideoUnset = -1;
{
AVPlayer *_player;
AVPlayerItem *_playerItem;
NSDictionary *_source;
BOOL _playerItemObserversSet;
BOOL _playerBufferEmpty;
AVPlayerLayer *_playerLayer;
@@ -51,6 +52,8 @@ static int const RCTVideoUnset = -1;
/* Keep track of any modifiers, need to be applied after each play */
float _volume;
float _rate;
float _maxBitRate;
BOOL _muted;
BOOL _paused;
BOOL _repeat;
@@ -64,8 +67,11 @@ static int const RCTVideoUnset = -1;
NSString * _ignoreSilentSwitch;
NSString * _resizeMode;
BOOL _fullscreen;
BOOL _fullscreenAutorotate;
NSString * _fullscreenOrientation;
BOOL _fullscreenPlayerPresented;
NSString *_filterName;
BOOL _filterEnabled;
UIViewController * _presentingViewController;
#if __has_include(<react-native-video/RCTVideoCache.h>)
RCTVideoCache * _videoCache;
@@ -83,6 +89,7 @@ static int const RCTVideoUnset = -1;
_rate = 1.0;
_volume = 1.0;
_resizeMode = @"AVLayerVideoGravityResizeAspectFill";
_fullscreenAutorotate = YES;
_fullscreenOrientation = @"all";
_pendingSeek = false;
_pendingSeekTime = 0.0f;
@@ -323,6 +330,7 @@ static int const RCTVideoUnset = -1;
- (void)setSrc:(NSDictionary *)source
{
_source = source;
[self removePlayerLayer];
[self removePlayerTimeObserver];
[self removePlayerItemObservers];
@@ -333,6 +341,8 @@ static int const RCTVideoUnset = -1;
[self playerItemForSource:source withCallback:^(AVPlayerItem * playerItem) {
_playerItem = playerItem;
[self addPlayerItemObservers];
[self setFilter:_filterName];
[self setMaxBitRate:_maxBitRate];
[_player pause];
[_playerViewController.view removeFromSuperview];
@@ -397,10 +407,13 @@ static int const RCTVideoUnset = -1;
- (void)playerItemPrepareText:(AVAsset *)asset assetOptions:(NSDictionary * __nullable)assetOptions withCallback:(void(^)(AVPlayerItem *))handler
{
if (!_textTracks) {
if (!_textTracks || _textTracks.count==0) {
handler([AVPlayerItem playerItemWithAsset:asset]);
return;
}
// AVPlayer can't airplay AVMutableCompositions
_allowsExternalPlayback = NO;
// sideload text tracks
AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
@@ -864,6 +877,12 @@ static int const RCTVideoUnset = -1;
[self applyModifiers];
}
- (void)setMaxBitRate:(float) maxBitRate {
_maxBitRate = maxBitRate;
_playerItem.preferredPeakBitRate = maxBitRate;
}
- (void)applyModifiers
{
if (_muted) {
@@ -874,6 +893,7 @@ static int const RCTVideoUnset = -1;
[_player setMuted:NO];
}
[self setMaxBitRate:_maxBitRate];
[self setSelectedAudioTrack:_selectedAudioTrack];
[self setSelectedTextTrack:_selectedTextTrack];
[self setResizeMode:_resizeMode];
@@ -1154,6 +1174,7 @@ static int const RCTVideoUnset = -1;
[viewController presentViewController:_playerViewController animated:true completion:^{
_playerViewController.showsPlaybackControls = YES;
_fullscreenPlayerPresented = fullscreen;
_playerViewController.autorotate = _fullscreenAutorotate;
if(self.onVideoFullscreenPlayerDidPresent) {
self.onVideoFullscreenPlayerDidPresent(@{@"target": self.reactTag});
}
@@ -1169,6 +1190,13 @@ static int const RCTVideoUnset = -1;
}
}
- (void)setFullscreenAutorotate:(BOOL)autorotate {
_fullscreenAutorotate = autorotate;
if (_fullscreenPlayerPresented) {
_playerViewController.autorotate = autorotate;
}
}
- (void)setFullscreenOrientation:(NSString *)orientation {
_fullscreenOrientation = orientation;
if (_fullscreenPlayerPresented) {
@@ -1270,6 +1298,36 @@ static int const RCTVideoUnset = -1;
}
}
- (void)setFilter:(NSString *)filterName {
_filterName = filterName;
if (!_filterEnabled) {
return;
} else if ([[_source objectForKey:@"uri"] rangeOfString:@"m3u8"].location != NSNotFound) {
return; // filters don't work for HLS... return
} else if (!_playerItem.asset) {
return;
}
CIFilter *filter = [CIFilter filterWithName:filterName];
_playerItem.videoComposition = [AVVideoComposition
videoCompositionWithAsset:_playerItem.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)setFilterEnabled:(BOOL)filterEnabled {
_filterEnabled = filterEnabled;
}
#pragma mark - React View Management
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
@@ -1356,4 +1414,78 @@ static int const RCTVideoUnset = -1;
[super removeFromSuperview];
}
#pragma mark - Export
- (void)save:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
AVAsset *asset = _playerItem.asset;
if (asset != nil) {
AVAssetExportSession *exportSession = [AVAssetExportSession
exportSessionWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
if (exportSession != nil) {
NSString *path = nil;
NSArray *array = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
path = [self generatePathInDirectory:[[self cacheDirectoryPath] stringByAppendingPathComponent:@"Videos"]
withExtension:@".mp4"];
NSURL *url = [NSURL fileURLWithPath:path];
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.outputURL = url;
exportSession.videoComposition = _playerItem.videoComposition;
exportSession.shouldOptimizeForNetworkUse = true;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
reject(@"ERROR_COULD_NOT_EXPORT_VIDEO", @"Could not export video", exportSession.error);
break;
case AVAssetExportSessionStatusCancelled:
reject(@"ERROR_EXPORT_SESSION_CANCELLED", @"Export session was cancelled", exportSession.error);
break;
default:
resolve(@{@"uri": url.absoluteString});
break;
}
}];
} else {
reject(@"ERROR_COULD_NOT_CREATE_EXPORT_SESSION", @"Could not create export session", nil);
}
} else {
reject(@"ERROR_ASSET_NIL", @"Asset is nil", nil);
}
}
- (BOOL)ensureDirExistsWithPath:(NSString *)path {
BOOL isDir = NO;
NSError *error;
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
if (!(exists && isDir)) {
[[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];
if (error) {
return NO;
}
}
return YES;
}
- (NSString *)generatePathInDirectory:(NSString *)directory withExtension:(NSString *)extension {
NSString *fileName = [[[NSUUID UUID] UUIDString] stringByAppendingString:extension];
[self ensureDirExistsWithPath:directory];
return [directory stringByAppendingPathComponent:fileName];
}
- (NSString *)cacheDirectoryPath {
NSArray *array = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
return array[0];
}
@end