updated basic example, added filterEnabled flag, check for HLS playlist before applying filter
This commit is contained in:
parent
bba7e9ed07
commit
67a963328a
10
README.md
10
README.md
@ -260,6 +260,7 @@ var styles = StyleSheet.create({
|
|||||||
* [bufferConfig](#bufferconfig)
|
* [bufferConfig](#bufferconfig)
|
||||||
* [controls](#controls)
|
* [controls](#controls)
|
||||||
* [filter](#filter)
|
* [filter](#filter)
|
||||||
|
* [filterEnabled](#filterEnabled)
|
||||||
* [fullscreen](#fullscreen)
|
* [fullscreen](#fullscreen)
|
||||||
* [fullscreenAutorotate](#fullscreenautorotate)
|
* [fullscreenAutorotate](#fullscreenautorotate)
|
||||||
* [fullscreenOrientation](#fullscreenorientation)
|
* [fullscreenOrientation](#fullscreenorientation)
|
||||||
@ -379,6 +380,15 @@ For more details on these filters refer to the [iOS docs](https://developer.appl
|
|||||||
Notes:
|
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.
|
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.
|
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
|
Platforms: iOS
|
||||||
|
|
||||||
|
1
Video.js
1
Video.js
@ -300,6 +300,7 @@ Video.propTypes = {
|
|||||||
FilterType.TRANSFER,
|
FilterType.TRANSFER,
|
||||||
FilterType.SEPIA
|
FilterType.SEPIA
|
||||||
]),
|
]),
|
||||||
|
filterEnabled: PropTypes.bool,
|
||||||
/* Native only */
|
/* Native only */
|
||||||
src: PropTypes.object,
|
src: PropTypes.object,
|
||||||
seek: PropTypes.oneOfType([
|
seek: PropTypes.oneOfType([
|
||||||
|
@ -13,7 +13,26 @@ import {
|
|||||||
View,
|
View,
|
||||||
} from 'react-native';
|
} 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 {
|
class VideoPlayer extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -34,6 +53,8 @@ class VideoPlayer extends Component {
|
|||||||
skin: 'custom',
|
skin: 'custom',
|
||||||
ignoreSilentSwitch: null,
|
ignoreSilentSwitch: null,
|
||||||
isBuffering: false,
|
isBuffering: false,
|
||||||
|
filter: FilterType.NONE,
|
||||||
|
filterEnabled: true
|
||||||
};
|
};
|
||||||
|
|
||||||
onLoad(data) {
|
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) {
|
renderSkinControl(skin) {
|
||||||
const isSelected = this.state.skin == skin;
|
const isSelected = this.state.skin == skin;
|
||||||
const selectControls = skin == 'native' || skin == 'embed';
|
const selectControls = skin == 'native' || skin == 'embed';
|
||||||
@ -141,6 +176,8 @@ class VideoPlayer extends Component {
|
|||||||
onProgress={this.onProgress}
|
onProgress={this.onProgress}
|
||||||
onEnd={() => { AlertIOS.alert('Done!') }}
|
onEnd={() => { AlertIOS.alert('Done!') }}
|
||||||
repeat={true}
|
repeat={true}
|
||||||
|
filter={this.state.filter}
|
||||||
|
filterEnabled={this.state.filterEnabled}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
@ -151,6 +188,21 @@ class VideoPlayer extends Component {
|
|||||||
{this.renderSkinControl('native')}
|
{this.renderSkinControl('native')}
|
||||||
{this.renderSkinControl('embed')}
|
{this.renderSkinControl('embed')}
|
||||||
</View>
|
</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>
|
||||||
<View style={styles.generalControls}>
|
<View style={styles.generalControls}>
|
||||||
<View style={styles.rateControl}>
|
<View style={styles.rateControl}>
|
||||||
@ -212,6 +264,8 @@ class VideoPlayer extends Component {
|
|||||||
onEnd={() => { AlertIOS.alert('Done!') }}
|
onEnd={() => { AlertIOS.alert('Done!') }}
|
||||||
repeat={true}
|
repeat={true}
|
||||||
controls={this.state.controls}
|
controls={this.state.controls}
|
||||||
|
filter={this.state.filter}
|
||||||
|
filterEnabled={this.state.filterEnabled}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.controls}>
|
<View style={styles.controls}>
|
||||||
@ -221,6 +275,21 @@ class VideoPlayer extends Component {
|
|||||||
{this.renderSkinControl('native')}
|
{this.renderSkinControl('native')}
|
||||||
{this.renderSkinControl('embed')}
|
{this.renderSkinControl('embed')}
|
||||||
</View>
|
</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>
|
||||||
<View style={styles.generalControls}>
|
<View style={styles.generalControls}>
|
||||||
<View style={styles.rateControl}>
|
<View style={styles.rateControl}>
|
||||||
|
@ -26,6 +26,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
{
|
{
|
||||||
AVPlayer *_player;
|
AVPlayer *_player;
|
||||||
AVPlayerItem *_playerItem;
|
AVPlayerItem *_playerItem;
|
||||||
|
NSDictionary *_source;
|
||||||
BOOL _playerItemObserversSet;
|
BOOL _playerItemObserversSet;
|
||||||
BOOL _playerBufferEmpty;
|
BOOL _playerBufferEmpty;
|
||||||
AVPlayerLayer *_playerLayer;
|
AVPlayerLayer *_playerLayer;
|
||||||
@ -68,6 +69,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
NSString * _fullscreenOrientation;
|
NSString * _fullscreenOrientation;
|
||||||
BOOL _fullscreenPlayerPresented;
|
BOOL _fullscreenPlayerPresented;
|
||||||
NSString *_filterName;
|
NSString *_filterName;
|
||||||
|
BOOL _filterEnabled;
|
||||||
UIViewController * _presentingViewController;
|
UIViewController * _presentingViewController;
|
||||||
#if __has_include(<react-native-video/RCTVideoCache.h>)
|
#if __has_include(<react-native-video/RCTVideoCache.h>)
|
||||||
RCTVideoCache * _videoCache;
|
RCTVideoCache * _videoCache;
|
||||||
@ -326,6 +328,7 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
- (void)setSrc:(NSDictionary *)source
|
- (void)setSrc:(NSDictionary *)source
|
||||||
{
|
{
|
||||||
|
_source = source;
|
||||||
[self removePlayerLayer];
|
[self removePlayerLayer];
|
||||||
[self removePlayerTimeObserver];
|
[self removePlayerTimeObserver];
|
||||||
[self removePlayerItemObservers];
|
[self removePlayerItemObservers];
|
||||||
@ -1266,12 +1269,17 @@ static int const RCTVideoUnset = -1;
|
|||||||
|
|
||||||
- (void)setFilter:(NSString *)filterName {
|
- (void)setFilter:(NSString *)filterName {
|
||||||
_filterName = filterName;
|
_filterName = filterName;
|
||||||
|
|
||||||
|
if (!_filterEnabled) {
|
||||||
|
return;
|
||||||
|
} else if ([[_source objectForKey:@"uri"] rangeOfString:@"m3u8"].location != NSNotFound) {
|
||||||
|
return; // filters don't work for HLS... return
|
||||||
|
}
|
||||||
|
|
||||||
AVAsset *asset = _playerItem.asset;
|
AVAsset *asset = _playerItem.asset;
|
||||||
|
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
return;
|
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
|
// TODO: filters don't work for HLS, check & return
|
||||||
|
|
||||||
@ -1290,6 +1298,10 @@ static int const RCTVideoUnset = -1;
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setFilterEnabled:(BOOL)filterEnabled {
|
||||||
|
_filterEnabled = filterEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - React View Management
|
#pragma mark - React View Management
|
||||||
|
|
||||||
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
|
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
|
||||||
|
@ -39,6 +39,7 @@ RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
|
|||||||
RCT_EXPORT_VIEW_PROPERTY(fullscreenAutorotate, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(fullscreenAutorotate, BOOL);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(fullscreenOrientation, NSString);
|
RCT_EXPORT_VIEW_PROPERTY(fullscreenOrientation, NSString);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(filter, NSString);
|
RCT_EXPORT_VIEW_PROPERTY(filter, NSString);
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(filterEnabled, BOOL);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
|
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
|
||||||
/* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */
|
/* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */
|
||||||
RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock);
|
RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTBubblingEventBlock);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-native-video",
|
"name": "react-native-video",
|
||||||
"version": "4.0.1",
|
"version": "4.0.2",
|
||||||
"description": "A <Video /> element for react-native",
|
"description": "A <Video /> element for react-native",
|
||||||
"main": "Video.js",
|
"main": "Video.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
Loading…
Reference in New Issue
Block a user