Merge pull request #1076 from react-native-community/feature/ios-configurable-seek

Ability to specify seek tolerance on iOS
This commit is contained in:
Hampton Maxwell 2018-06-20 22:15:11 -07:00 committed by GitHub
commit 0418d8a94f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 13 deletions

View File

@ -240,6 +240,11 @@ var styles = StyleSheet.create({
* [onLoad](#onload) * [onLoad](#onload)
* [onLoadStart](#onloadstart) * [onLoadStart](#onloadstart)
### Methods
* [seek](#seek)
### Configurable props
#### allowsExternalPlayback #### allowsExternalPlayback
Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI. Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI.
* **true (default)** - allow switching to external playback mode * **true (default)** - allow switching to external playback mode
@ -502,6 +507,45 @@ Example:
Platforms: all Platforms: all
### Methods
Methods operate on a ref to the Video element. You can create a ref using code like:
```
return (
<Video source={...}
ref => (this.player = ref) />
);
```
#### seek()
`seek(seconds)`
Seek to the specified position represented by seconds. seconds is a float value.
`seek()` can only be called after the `onLoad` event has fired.
Example:
```
this.player.seek(200); // Seek to 3 minutes, 20 seconds
```
Platforms: all
##### Exact seek
By default iOS seeks within 100 milliseconds of the target position. If you need more accuracy, you can use the seek with tolerance method:
`seek(seconds, tolerance)`
tolerance is the max distance in milliseconds from the seconds position that's allowed. Using a more exact tolerance can cause seeks to take longer. If you want to seek exactly, set tolerance to 0.
Example:
```
this.player.seek(120, 50); // Seek to 2 minutes with +/- 50 milliseconds accuracy
```
Platforms: iOS
### Additional props ### Additional props
To see the full list of available props, you can check the [propTypes](https://github.com/react-native-community/react-native-video/blob/master/Video.js#L246) of the Video.js component. To see the full list of available props, you can check the [propTypes](https://github.com/react-native-community/react-native-video/blob/master/Video.js#L246) of the Video.js component.

View File

@ -1,6 +1,6 @@
import React, {Component} from 'react'; import React, {Component} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {StyleSheet, requireNativeComponent, NativeModules, View, ViewPropTypes, Image} from 'react-native'; import {StyleSheet, requireNativeComponent, NativeModules, View, ViewPropTypes, Image, Platform} from 'react-native';
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'; import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
import TextTrackType from './TextTrackType'; import TextTrackType from './TextTrackType';
import VideoResizeMode from './VideoResizeMode.js'; import VideoResizeMode from './VideoResizeMode.js';
@ -27,8 +27,17 @@ export default class Video extends Component {
this._root.setNativeProps(nativeProps); this._root.setNativeProps(nativeProps);
} }
seek = (time) => { seek = (time, tolerance = 100) => {
this.setNativeProps({ seek: time }); if (Platform.OS === 'ios') {
this.setNativeProps({
seek: {
time,
tolerance
}
});
} else {
this.setNativeProps({ seek: time });
}
}; };
presentFullscreenPlayer = () => { presentFullscreenPlayer = () => {
@ -250,7 +259,10 @@ export default class Video extends Component {
Video.propTypes = { Video.propTypes = {
/* Native only */ /* Native only */
src: PropTypes.object, src: PropTypes.object,
seek: PropTypes.number, seek: PropTypes.oneOfType([
PropTypes.number,
PropTypes.object
]),
fullscreen: PropTypes.bool, fullscreen: PropTypes.bool,
onVideoLoadStart: PropTypes.func, onVideoLoadStart: PropTypes.func,
onVideoLoad: PropTypes.func, onVideoLoad: PropTypes.func,

View File

@ -569,21 +569,28 @@ static NSString *const timedMetadata = @"timedMetadata";
- (void)setCurrentTime:(float)currentTime - (void)setCurrentTime:(float)currentTime
{ {
[self setSeek: currentTime]; NSDictionary *info = @{
@"time": [NSNumber numberWithFloat:currentTime],
@"tolerance": [NSNumber numberWithInt:100]
};
[self setSeek:info];
} }
- (void)setSeek:(float)seekTime - (void)setSeek:(NSDictionary *)info
{ {
int timeScale = 10000; NSNumber *seekTime = info[@"time"];
NSNumber *seekTolerance = info[@"tolerance"];
int timeScale = 1000;
AVPlayerItem *item = _player.currentItem; AVPlayerItem *item = _player.currentItem;
if (item && item.status == AVPlayerItemStatusReadyToPlay) { if (item && item.status == AVPlayerItemStatusReadyToPlay) {
// TODO check loadedTimeRanges // TODO check loadedTimeRanges
CMTime cmSeekTime = CMTimeMakeWithSeconds(seekTime, timeScale); CMTime cmSeekTime = CMTimeMakeWithSeconds([seekTime floatValue], timeScale);
CMTime current = item.currentTime; CMTime current = item.currentTime;
// TODO figure out a good tolerance level // TODO figure out a good tolerance level
CMTime tolerance = CMTimeMake(1000, timeScale); CMTime tolerance = CMTimeMake([seekTolerance floatValue], timeScale);
BOOL wasPaused = _paused; BOOL wasPaused = _paused;
if (CMTimeCompare(current, cmSeekTime) != 0) { if (CMTimeCompare(current, cmSeekTime) != 0) {
@ -593,11 +600,11 @@ static NSString *const timedMetadata = @"timedMetadata";
[self addPlayerTimeObserver]; [self addPlayerTimeObserver];
} }
if (!wasPaused) { if (!wasPaused) {
[self setPaused:false]; [self setPaused:false];
} }
if(self.onVideoSeek) { if(self.onVideoSeek) {
self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)], self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)],
@"seekTime": [NSNumber numberWithFloat:seekTime], @"seekTime": seekTime,
@"target": self.reactTag}); @"target": self.reactTag});
} }
}]; }];
@ -608,7 +615,7 @@ static NSString *const timedMetadata = @"timedMetadata";
} else { } else {
// TODO: See if this makes sense and if so, actually implement it // TODO: See if this makes sense and if so, actually implement it
_pendingSeek = true; _pendingSeek = true;
_pendingSeekTime = seekTime; _pendingSeekTime = [seekTime floatValue];
} }
} }

View File

@ -32,7 +32,7 @@ RCT_EXPORT_VIEW_PROPERTY(playInBackground, BOOL);
RCT_EXPORT_VIEW_PROPERTY(playWhenInactive, BOOL); RCT_EXPORT_VIEW_PROPERTY(playWhenInactive, BOOL);
RCT_EXPORT_VIEW_PROPERTY(ignoreSilentSwitch, NSString); RCT_EXPORT_VIEW_PROPERTY(ignoreSilentSwitch, NSString);
RCT_EXPORT_VIEW_PROPERTY(rate, float); RCT_EXPORT_VIEW_PROPERTY(rate, float);
RCT_EXPORT_VIEW_PROPERTY(seek, float); RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(currentTime, float); RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL); RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float); RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);