diff --git a/README.md b/README.md index 90b615fe8c..e9e514e971 100644 --- a/README.md +++ b/README.md @@ -260,6 +260,7 @@ var styles = StyleSheet.create({ * [bufferConfig](#bufferconfig) * [controls](#controls) * [filter](#filter) +* [filterEnabled](#filterEnabled) * [fullscreen](#fullscreen) * [fullscreenAutorotate](#fullscreenautorotate) * [fullscreenOrientation](#fullscreenorientation) @@ -381,6 +382,15 @@ For more details on these filters refer to the [iOS docs](https://developer.appl Notes: 1. Using a filter can impact CPU usage. A workaround is to save the video with the filter and then load the saved video. 2. Video filter is currently not supported on HLS playlists. +3. `filterEnabled` must be set to `true` + +Platforms: iOS + +#### filterEnabled +Enable video filter. + +* **false (default)** - Don't enable filter +* **true** - Enable filter Platforms: iOS diff --git a/Video.js b/Video.js index a43b2e0e10..e726f401a7 100644 --- a/Video.js +++ b/Video.js @@ -300,6 +300,7 @@ Video.propTypes = { FilterType.TRANSFER, FilterType.SEPIA ]), + filterEnabled: PropTypes.bool, /* Native only */ src: PropTypes.object, seek: PropTypes.oneOfType([ diff --git a/examples/basic/index.ios.js b/examples/basic/index.ios.js index 2abd3b9ff3..1bc0ac4739 100644 --- a/examples/basic/index.ios.js +++ b/examples/basic/index.ios.js @@ -13,7 +13,26 @@ import { View, } from 'react-native'; -import Video from 'react-native-video'; +import Video,{FilterType} from 'react-native-video'; + +const filterTypes = [ + FilterType.NONE, + FilterType.INVERT, + FilterType.MONOCHROME, + FilterType.POSTERIZE, + FilterType.FALSE, + FilterType.MAXIMUMCOMPONENT, + FilterType.MINIMUMCOMPONENT, + FilterType.CHROME, + FilterType.FADE, + FilterType.INSTANT, + FilterType.MONO, + FilterType.NOIR, + FilterType.PROCESS, + FilterType.TONAL, + FilterType.TRANSFER, + FilterType.SEPIA +]; class VideoPlayer extends Component { constructor(props) { @@ -34,6 +53,8 @@ class VideoPlayer extends Component { skin: 'custom', ignoreSilentSwitch: null, isBuffering: false, + filter: FilterType.NONE, + filterEnabled: true }; onLoad(data) { @@ -57,6 +78,20 @@ class VideoPlayer extends Component { } } + setFilter(step) { + let index = filterTypes.indexOf(this.state.filter) + step; + + if (index === filterTypes.length) { + index = 0; + } else if (index === -1) { + index = filterTypes.length - 1; + } + + this.setState({ + filter: filterTypes[index] + }) + } + renderSkinControl(skin) { const isSelected = this.state.skin == skin; const selectControls = skin == 'native' || skin == 'embed'; @@ -141,6 +176,8 @@ class VideoPlayer extends Component { onProgress={this.onProgress} onEnd={() => { AlertIOS.alert('Done!') }} repeat={true} + filter={this.state.filter} + filterEnabled={this.state.filterEnabled} /> @@ -151,6 +188,21 @@ class VideoPlayer extends Component { {this.renderSkinControl('native')} {this.renderSkinControl('embed')} + { + (this.state.filterEnabled) ? + + { + this.setFilter(-1) + }}> + Previous Filter + + { + this.setFilter(1) + }}> + Next Filter + + : null + } @@ -212,6 +264,8 @@ class VideoPlayer extends Component { onEnd={() => { AlertIOS.alert('Done!') }} repeat={true} controls={this.state.controls} + filter={this.state.filter} + filterEnabled={this.state.filterEnabled} /> @@ -221,6 +275,21 @@ class VideoPlayer extends Component { {this.renderSkinControl('native')} {this.renderSkinControl('embed')} + { + (this.state.filterEnabled) ? + + { + this.setFilter(-1) + }}> + Previous Filter + + { + this.setFilter(1) + }}> + Next Filter + + : null + } diff --git a/ios/Video/RCTVideo.m b/ios/Video/RCTVideo.m index 90ecf05780..9c7e8b79f5 100644 --- a/ios/Video/RCTVideo.m +++ b/ios/Video/RCTVideo.m @@ -26,6 +26,7 @@ @implementation RCTVideo { AVPlayer *_player; AVPlayerItem *_playerItem; + NSDictionary *_source; BOOL _playerItemObserversSet; BOOL _playerBufferEmpty; AVPlayerLayer *_playerLayer; @@ -70,6 +71,7 @@ @implementation RCTVideo NSString * _fullscreenOrientation; BOOL _fullscreenPlayerPresented; NSString *_filterName; + BOOL _filterEnabled; UIViewController * _presentingViewController; #if __has_include() RCTVideoCache * _videoCache; @@ -328,6 +330,7 @@ - (void)removePlayerItemObservers - (void)setSrc:(NSDictionary *)source { + _source = source; [self removePlayerLayer]; [self removePlayerTimeObserver]; [self removePlayerItemObservers]; @@ -1279,18 +1282,18 @@ - (void)videoPlayerViewControllerDidDismiss:(AVPlayerViewController *)playerView - (void)setFilter:(NSString *)filterName { _filterName = filterName; - AVAsset *asset = _playerItem.asset; - - if (!asset) { + + 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; - } else if (!_playerItem.videoComposition && (filterName == nil || [filterName isEqualToString:@""])) { - return; // Setting up an empty filter has a cost so avoid whenever possible } - // TODO: filters don't work for HLS, check & return - + CIFilter *filter = [CIFilter filterWithName:filterName]; _playerItem.videoComposition = [AVVideoComposition - videoCompositionWithAsset:asset + videoCompositionWithAsset:_playerItem.asset applyingCIFiltersWithHandler:^(AVAsynchronousCIImageFilteringRequest *_Nonnull request) { if (filter == nil) { [request finishWithImage:request.sourceImage context:nil]; @@ -1303,6 +1306,10 @@ - (void)setFilter:(NSString *)filterName { }]; } +- (void)setFilterEnabled:(BOOL)filterEnabled { + _filterEnabled = filterEnabled; +} + #pragma mark - React View Management - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex diff --git a/ios/Video/RCTVideoManager.m b/ios/Video/RCTVideoManager.m index b5d94ebc2c..f7e6666a8a 100644 --- a/ios/Video/RCTVideoManager.m +++ b/ios/Video/RCTVideoManager.m @@ -40,6 +40,7 @@ - (dispatch_queue_t)methodQueue RCT_EXPORT_VIEW_PROPERTY(fullscreenAutorotate, BOOL); RCT_EXPORT_VIEW_PROPERTY(fullscreenOrientation, NSString); RCT_EXPORT_VIEW_PROPERTY(filter, NSString); +RCT_EXPORT_VIEW_PROPERTY(filterEnabled, BOOL); RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float); /* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */ RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock); diff --git a/package.json b/package.json index cf314b4218..0c690a04f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-video", - "version": "4.2.0", + "version": "4.2.1", "description": "A