Initial commit for seeking

This commit is contained in:
Johannes Lumpe 2015-04-09 01:15:57 +03:00
parent ac3e4cf773
commit 45d79b701e
4 changed files with 70 additions and 10 deletions

View File

@ -3,6 +3,7 @@
extern NSString *const RNVideoEventLoaded; extern NSString *const RNVideoEventLoaded;
extern NSString *const RNVideoEventLoading; extern NSString *const RNVideoEventLoading;
extern NSString *const RNVideoEventProgress; extern NSString *const RNVideoEventProgress;
extern NSString *const RNVideoEventSeek;
extern NSString *const RNVideoEventLoadingError; extern NSString *const RNVideoEventLoadingError;
@class RCTEventDispatcher; @class RCTEventDispatcher;

View File

@ -9,6 +9,7 @@
NSString *const RNVideoEventLoaded = @"videoLoaded"; NSString *const RNVideoEventLoaded = @"videoLoaded";
NSString *const RNVideoEventLoading = @"videoLoading"; NSString *const RNVideoEventLoading = @"videoLoading";
NSString *const RNVideoEventProgress = @"videoProgress"; NSString *const RNVideoEventProgress = @"videoProgress";
NSString *const RNVideoEventSeek = @"videoSeek";
NSString *const RNVideoEventLoadingError = @"videoLoadError"; NSString *const RNVideoEventLoadingError = @"videoLoadError";
static NSString *const statusKeyPath = @"status"; static NSString *const statusKeyPath = @"status";
@ -23,6 +24,10 @@ static NSString *const statusKeyPath = @"status";
/* Required to publish events */ /* Required to publish events */
RCTEventDispatcher *_eventDispatcher; RCTEventDispatcher *_eventDispatcher;
bool _pendingSeek;
float _pendingSeekTime;
float _lastSeekTime;
/* For sending videoProgress events */ /* For sending videoProgress events */
id _progressUpdateTimer; id _progressUpdateTimer;
int _progressUpdateInterval; int _progressUpdateInterval;
@ -39,6 +44,10 @@ static NSString *const statusKeyPath = @"status";
_eventDispatcher = eventDispatcher; _eventDispatcher = eventDispatcher;
_rate = 1.0; _rate = 1.0;
_volume = 1.0; _volume = 1.0;
_pendingSeek = false;
_pendingSeekTime = 0.0f;
_lastSeekTime = 0.0f;
} }
return self; return self;
} }
@ -169,8 +178,7 @@ static NSString *const statusKeyPath = @"status";
_playerLayer.videoGravity = mode; _playerLayer.videoGravity = mode;
} }
- (void)setPaused:(BOOL)paused - (void)setPaused:(BOOL)paused {
{
if (paused) { if (paused) {
[self stopProgressTimer]; [self stopProgressTimer];
[_player pause]; [_player pause];
@ -181,14 +189,54 @@ static NSString *const statusKeyPath = @"status";
} }
} }
- (void)setRate:(float)rate - (void)setSeek:(NSDictionary*)seek {
{ NSNumber *seekValue = [seek objectForKey:@"time"];
if (!seekValue) {
return;
}
int timeScale = 10000;
float seekTime = [RCTConvert float:seekValue];
bool force = [RCTConvert BOOL:[seek objectForKey:@"force"]];
if (seekTime == _lastSeekTime && !force) {
return;
}
AVPlayerItem *item = _player.currentItem;
if (item && item.status == AVPlayerItemStatusReadyToPlay) {
// TODO check loadedTimeRanges
CMTime cmSeekTime = CMTimeMakeWithSeconds(seekTime, timeScale);
CMTime current = item.currentTime;
// TODO figure out a good tolerance level
CMTime tolerance = CMTimeMake(1000, timeScale);
if (CMTimeCompare(current, cmSeekTime) != 0) {
[_player seekToTime:cmSeekTime toleranceBefore:tolerance toleranceAfter:tolerance];
_pendingSeek = false;
_lastSeekTime = seekTime;
[_eventDispatcher sendInputEventWithName:RNVideoEventSeek body:@{
@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)],
@"seekTime": seekValue,
@"target": self.reactTag
}];
}
} else {
// TODO see if this makes sense and if so,
// actually implement it
_pendingSeek = true;
_pendingSeekTime = seekTime;
}
}
- (void)setRate:(float)rate {
_rate = rate; _rate = rate;
[self applyModifiers]; [self applyModifiers];
} }
- (void)setMuted:(BOOL)muted - (void)setMuted:(BOOL)muted {
{
_muted = muted; _muted = muted;
[self applyModifiers]; [self applyModifiers];
} }
@ -198,8 +246,7 @@ static NSString *const statusKeyPath = @"status";
[self applyModifiers]; [self applyModifiers];
} }
- (void)applyModifiers - (void)applyModifiers {
{
/* volume must be set to 0 if muted is YES, or the video freezes playback */ /* volume must be set to 0 if muted is YES, or the video freezes playback */
if (_muted) { if (_muted) {
[_player setVolume:0]; [_player setVolume:0];

View File

@ -29,6 +29,9 @@
RNVideoEventProgress: @{ RNVideoEventProgress: @{
@"registrationName": @"onProgress" @"registrationName": @"onProgress"
}, },
RNVideoEventSeek: @{
@"registrationName": @"onSeek"
}
}; };
} }
@ -39,6 +42,7 @@ RCT_EXPORT_VIEW_PROPERTY(paused, BOOL);
RCT_EXPORT_VIEW_PROPERTY(muted, BOOL); RCT_EXPORT_VIEW_PROPERTY(muted, BOOL);
RCT_EXPORT_VIEW_PROPERTY(volume, float); RCT_EXPORT_VIEW_PROPERTY(volume, float);
RCT_EXPORT_VIEW_PROPERTY(rate, float); RCT_EXPORT_VIEW_PROPERTY(rate, float);
RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary);
- (NSDictionary *)constantsToExport - (NSDictionary *)constantsToExport
{ {

View File

@ -21,6 +21,7 @@ var Video = React.createClass({
resizeMode: PropTypes.string, resizeMode: PropTypes.string,
repeat: PropTypes.bool, repeat: PropTypes.bool,
paused: PropTypes.bool, paused: PropTypes.bool,
seek: PropTypes.number,
muted: PropTypes.bool, muted: PropTypes.bool,
volume: PropTypes.number, volume: PropTypes.number,
rate: PropTypes.number, rate: PropTypes.number,
@ -53,6 +54,10 @@ var Video = React.createClass({
this.props.onProgress && this.props.onProgress(event.nativeEvent); this.props.onProgress && this.props.onProgress(event.nativeEvent);
}, },
_onSeek(event) {
this.props.onSeek && this.props.onSeek(event.nativeEvent);
},
render() { render() {
var style = flattenStyle([styles.base, this.props.style]); var style = flattenStyle([styles.base, this.props.style]);
var source = this.props.source; var source = this.props.source;
@ -71,6 +76,10 @@ var Video = React.createClass({
} }
var nativeProps = merge(this.props, { var nativeProps = merge(this.props, {
seek: {
time: this.props.seek,
force: this.props.forceSeek
},
style, style,
resizeMode: resizeMode, resizeMode: resizeMode,
src: { src: {
@ -81,7 +90,6 @@ var Video = React.createClass({
}, },
onLoad: this._onLoad, onLoad: this._onLoad,
onProgress: this._onProgress, onProgress: this._onProgress,
}); });
return <RCTVideo {... nativeProps} /> return <RCTVideo {... nativeProps} />
@ -91,7 +99,7 @@ var Video = React.createClass({
var RCTVideo = createReactIOSNativeComponentClass({ var RCTVideo = createReactIOSNativeComponentClass({
validAttributes: merge(ReactIOSViewAttributes.UIView, validAttributes: merge(ReactIOSViewAttributes.UIView,
{src: {diff: deepDiffer}, resizeMode: true, repeat: true, {src: {diff: deepDiffer}, resizeMode: true, repeat: true,
paused: true, muted: true, volume: true, rate: true}), seek: {diff: () => true}, paused: true, muted: true, volume: true, rate: true}),
uiViewClassName: 'RCTVideo', uiViewClassName: 'RCTVideo',
}); });