Merge branch 'master' into master
This commit is contained in:
@@ -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
|
||||
|
Reference in New Issue
Block a user