Merge pull request #1384 from nickgzzjr/master
Added filterEnabled flag and don't enable filter if source is an hls playlist
This commit is contained in:
commit
b7a351c043
10
README.md
10
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
|
||||
|
||||
|
1
Video.js
1
Video.js
@ -300,6 +300,7 @@ Video.propTypes = {
|
||||
FilterType.TRANSFER,
|
||||
FilterType.SEPIA
|
||||
]),
|
||||
filterEnabled: PropTypes.bool,
|
||||
/* Native only */
|
||||
src: PropTypes.object,
|
||||
seek: PropTypes.oneOfType([
|
||||
|
@ -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}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
@ -151,6 +188,21 @@ class VideoPlayer extends Component {
|
||||
{this.renderSkinControl('native')}
|
||||
{this.renderSkinControl('embed')}
|
||||
</View>
|
||||
{
|
||||
(this.state.filterEnabled) ?
|
||||
<View style={styles.skinControl}>
|
||||
<TouchableOpacity onPress={() => {
|
||||
this.setFilter(-1)
|
||||
}}>
|
||||
<Text style={styles.controlOption}>Previous Filter</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => {
|
||||
this.setFilter(1)
|
||||
}}>
|
||||
<Text style={styles.controlOption}>Next Filter</Text>
|
||||
</TouchableOpacity>
|
||||
</View> : null
|
||||
}
|
||||
</View>
|
||||
<View style={styles.generalControls}>
|
||||
<View style={styles.rateControl}>
|
||||
@ -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}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.controls}>
|
||||
@ -221,6 +275,21 @@ class VideoPlayer extends Component {
|
||||
{this.renderSkinControl('native')}
|
||||
{this.renderSkinControl('embed')}
|
||||
</View>
|
||||
{
|
||||
(this.state.filterEnabled) ?
|
||||
<View style={styles.skinControl}>
|
||||
<TouchableOpacity onPress={() => {
|
||||
this.setFilter(-1)
|
||||
}}>
|
||||
<Text style={styles.controlOption}>Previous Filter</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => {
|
||||
this.setFilter(1)
|
||||
}}>
|
||||
<Text style={styles.controlOption}>Next Filter</Text>
|
||||
</TouchableOpacity>
|
||||
</View> : null
|
||||
}
|
||||
</View>
|
||||
<View style={styles.generalControls}>
|
||||
<View style={styles.rateControl}>
|
||||
|
@ -26,6 +26,7 @@ static int const RCTVideoUnset = -1;
|
||||
{
|
||||
AVPlayer *_player;
|
||||
AVPlayerItem *_playerItem;
|
||||
NSDictionary *_source;
|
||||
BOOL _playerItemObserversSet;
|
||||
BOOL _playerBufferEmpty;
|
||||
AVPlayerLayer *_playerLayer;
|
||||
@ -70,6 +71,7 @@ static int const RCTVideoUnset = -1;
|
||||
NSString * _fullscreenOrientation;
|
||||
BOOL _fullscreenPlayerPresented;
|
||||
NSString *_filterName;
|
||||
BOOL _filterEnabled;
|
||||
UIViewController * _presentingViewController;
|
||||
#if __has_include(<react-native-video/RCTVideoCache.h>)
|
||||
RCTVideoCache * _videoCache;
|
||||
@ -328,6 +330,7 @@ static int const RCTVideoUnset = -1;
|
||||
|
||||
- (void)setSrc:(NSDictionary *)source
|
||||
{
|
||||
_source = source;
|
||||
[self removePlayerLayer];
|
||||
[self removePlayerTimeObserver];
|
||||
[self removePlayerItemObservers];
|
||||
@ -1279,18 +1282,18 @@ static int const RCTVideoUnset = -1;
|
||||
|
||||
- (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 @@ static int const RCTVideoUnset = -1;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setFilterEnabled:(BOOL)filterEnabled {
|
||||
_filterEnabled = filterEnabled;
|
||||
}
|
||||
|
||||
#pragma mark - React View Management
|
||||
|
||||
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
|
||||
|
@ -40,6 +40,7 @@ RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
|
||||
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);
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-video",
|
||||
"version": "4.2.0",
|
||||
"version": "4.2.1",
|
||||
"description": "A <Video /> element for react-native",
|
||||
"main": "Video.js",
|
||||
"license": "MIT",
|
||||
|
Loading…
Reference in New Issue
Block a user