Loading RCTVideo.h +5 −0 Changes for RCTVideo.h: 5 added lines, 0 removed lines. Original line number Diff line number Diff line #import "RCTView.h" extern NSString *const RNVideoLoadedEvent; extern NSString *const RNVideoLoadingEvent; extern NSString *const RNVideoProgressEvent; extern NSString *const RNVideoLoadingErrorEvent; @class RCTEventDispatcher; @interface RCTVideo : UIView Loading RCTVideo.m +69 −39 Changes for RCTVideo.m: 69 added lines, 39 removed lines. Original line number Diff line number Diff line Loading @@ -5,9 +5,17 @@ #import "UIView+React.h" #import <AVFoundation/AVFoundation.h> NSString *const RNVideoLoadedEvent = @"videoLoaded"; NSString *const RNVideoLoadingEvent = @"videoLoading"; NSString *const RNVideoProgressEvent = @"videoProgress"; NSString *const RNVideoLoadingErrorEvent = @"videoLoadError"; static NSString *const statusKeyPath = @"status"; @implementation RCTVideo { AVPlayer *_player; AVPlayerItem *_playerItem; AVPlayerLayer *_playerLayer; NSURL *_videoURL; Loading @@ -25,8 +33,7 @@ BOOL _muted; } - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher { - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher { if ((self = [super init])) { _eventDispatcher = eventDispatcher; Loading @@ -39,16 +46,15 @@ return self; } - (void)sendProgressUpdate { - (void)sendProgressUpdate { AVPlayerItem *video = [_player currentItem]; if (video == nil) { if (video == nil || video.status != AVPlayerItemStatusReadyToPlay) { return; } if (_prevProgressUpdateTime == nil || (([_prevProgressUpdateTime timeIntervalSinceNow] * -1000.0) >= _progressUpdateInterval)) { [_eventDispatcher sendInputEventWithName:@"videoProgress" body:@{ [_eventDispatcher sendInputEventWithName:RNVideoProgressEvent body:@{ @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(video.currentTime)], @"target": self.reactTag }]; Loading @@ -56,17 +62,25 @@ } } - (void)setSrc:(NSString *)source { BOOL isHttpPrefix = [source hasPrefix:@"http://"]; if (isHttpPrefix) { _videoURL = [NSURL URLWithString:source]; } else { _videoURL = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:source ofType:@"mp4"]]; } _player = [AVPlayer playerWithURL:_videoURL]; - (void)setSrc:(NSDictionary *)source { bool isNetwork = [source objectForKey:@"isNetwork"]; NSString *uri = [source objectForKey:@"uri"]; NSString *type = [source objectForKey:@"type"]; _videoURL = isNetwork ? [NSURL URLWithString:uri] : [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]]; [_playerItem removeObserver:self forKeyPath:statusKeyPath]; _playerItem = [AVPlayerItem playerItemWithURL:_videoURL]; [_playerItem addObserver:self forKeyPath:statusKeyPath options:0 context:nil]; [_player pause]; [_playerLayer removeFromSuperlayer]; _player = [AVPlayer playerWithPlayerItem:_playerItem]; _player.actionAtItemEnd = AVPlayerActionAtItemEndNone; _playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player]; _playerLayer.frame = self.bounds; _playerLayer.needsDisplayOnBoundsChange = YES; Loading @@ -74,28 +88,48 @@ [self.layer addSublayer:_playerLayer]; self.layer.needsDisplayOnBoundsChange = YES; AVPlayerItem *video = [_player currentItem]; [_eventDispatcher sendInputEventWithName:RNVideoLoadingEvent body:@{ @"src": @{ @"uri":uri, @"type": type, @"isNetwork":[NSNumber numberWithBool:isNetwork] }, @"target": self.reactTag }]; } [_eventDispatcher sendInputEventWithName:@"videoLoaded" body:@{ @"duration": [NSNumber numberWithFloat:CMTimeGetSeconds(video.asset.duration)], @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(video.currentTime)], @"canPlayReverse": [NSNumber numberWithBool:video.canPlayReverse], @"canPlayFastForward": [NSNumber numberWithBool:video.canPlayFastForward], @"canPlaySlowForward": [NSNumber numberWithBool:video.canPlaySlowForward], @"canPlaySlowReverse": [NSNumber numberWithBool:video.canPlaySlowReverse], @"canStepBackward": [NSNumber numberWithBool:video.canStepBackward], @"canStepForward": [NSNumber numberWithBool:video.canStepForward], - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == _playerItem) { if (_playerItem.status == AVPlayerItemStatusReadyToPlay) { [_eventDispatcher sendInputEventWithName:RNVideoLoadedEvent body:@{ @"duration": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.duration)], @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)], @"canPlayReverse": [NSNumber numberWithBool:_playerItem.canPlayReverse], @"canPlayFastForward": [NSNumber numberWithBool:_playerItem.canPlayFastForward], @"canPlaySlowForward": [NSNumber numberWithBool:_playerItem.canPlaySlowForward], @"canPlaySlowReverse": [NSNumber numberWithBool:_playerItem.canPlaySlowReverse], @"canStepBackward": [NSNumber numberWithBool:_playerItem.canStepBackward], @"canStepForward": [NSNumber numberWithBool:_playerItem.canStepForward], @"target": self.reactTag }]; [_player play]; /* rate and volume must be set after play is called */ [self applyModifiers]; } else if(_playerItem.status == AVPlayerItemStatusFailed) { [_eventDispatcher sendInputEventWithName:RNVideoLoadingErrorEvent body:@{ @"error": @{ @"code": [NSNumber numberWithInt:_playerItem.error.code], @"domain": _playerItem.error.domain }, @"target": self.reactTag }]; } } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } - (void)setResizeMode:(NSString*)mode { - (void)setResizeMode:(NSString*)mode { _playerLayer.videoGravity = mode; } Loading Loading @@ -147,7 +181,6 @@ [self applyModifiers]; } - (void)setRepeatEnabled { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) Loading @@ -159,8 +192,7 @@ [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)setRepeat:(BOOL)repeat { - (void)setRepeat:(BOOL)repeat { if (repeat) { [self setRepeatEnabled]; } else { Loading @@ -168,20 +200,17 @@ } } - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex { - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex { RCTLogError(@"video cannot have any subviews"); return; } - (void)removeReactSubview:(UIView *)subview { - (void)removeReactSubview:(UIView *)subview { RCTLogError(@"video cannot have any subviews"); return; } - (void)layoutSubviews { - (void)layoutSubviews { [super layoutSubviews]; _playerLayer.frame = self.bounds; } Loading @@ -194,6 +223,7 @@ _player = nil; _prevProgressUpdateTime = nil; _eventDispatcher = nil; [_playerItem removeObserver:self forKeyPath:statusKeyPath]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } Loading RCTVideoManager.m +9 −3 Changes for RCTVideoManager.m: 9 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -17,16 +17,22 @@ - (NSDictionary *)customDirectEventTypes { return @{ @"videoLoaded": @{ RNVideoLoadingEvent: @{ @"registrationName": @"onLoadStart" }, RNVideoLoadedEvent: @{ @"registrationName": @"onLoad" }, @"videoProgress": @{ RNVideoLoadingErrorEvent: @{ @"registrationName": @"onError" }, RNVideoProgressEvent: @{ @"registrationName": @"onProgress" }, }; } RCT_EXPORT_VIEW_PROPERTY(src, NSString); RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary); RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString); RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL); RCT_EXPORT_VIEW_PROPERTY(paused, BOOL); Loading Video.ios.js +20 −3 Changes for Video.ios.js: 20 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -10,18 +10,21 @@ var VideoStylePropTypes = require('./VideoStylePropTypes'); var NativeMethodsMixin = require('NativeMethodsMixin'); var flattenStyle = require('flattenStyle'); var merge = require('merge'); var deepDiffer = require('deepDiffer'); var Video = React.createClass({ propTypes: { source: PropTypes.string, style: StyleSheetPropType(VideoStylePropTypes), source: PropTypes.object, resizeMode: PropTypes.string, repeat: PropTypes.bool, paused: PropTypes.bool, muted: PropTypes.bool, volume: PropTypes.number, rate: PropTypes.number, onLoadStart: PropTypes.func, onLoad: PropTypes.func, onError: PropTypes.func, onProgress: PropTypes.func, }, Loading @@ -32,10 +35,18 @@ var Video = React.createClass({ validAttributes: ReactIOSViewAttributes.UIView }, _onLoadStart(event) { this.props.onLoadStart && this.props.onLoadStart(event.nativeEvent); }, _onLoad(event) { this.props.onLoad && this.props.onLoad(event.nativeEvent); }, _onError(event) { this.props.onError && this.props.onError(event.nativeEvent); }, _onProgress(event) { this.props.onProgress && this.props.onProgress(event.nativeEvent); }, Loading @@ -43,6 +54,7 @@ var Video = React.createClass({ render() { var style = flattenStyle([styles.base, this.props.style]); var source = this.props.source; var isNetwork = !!(source.uri && source.uri.match(/^https?:/)); var resizeMode; if (this.props.resizeMode === VideoResizeMode.stretch) { Loading @@ -58,9 +70,14 @@ var Video = React.createClass({ var nativeProps = merge(this.props, { style, resizeMode: resizeMode, src: source, src: { uri: source.uri, isNetwork, type: source.type || 'mp4' }, onLoad: this._onLoad, onProgress: this._onProgress, }); return <RCTVideo {... nativeProps} /> Loading @@ -69,7 +86,7 @@ var Video = React.createClass({ var RCTVideo = createReactIOSNativeComponentClass({ validAttributes: merge(ReactIOSViewAttributes.UIView, {src: true, resizeMode: true, repeat: true, paused: true, muted: true, {src: {diff: deepDiffer}, resizeMode: true, repeat: true, paused: true, muted: true, volume: true, rate: true}), uiViewClassName: 'RCTVideo', }); Loading Loading
RCTVideo.h +5 −0 Changes for RCTVideo.h: 5 added lines, 0 removed lines. Original line number Diff line number Diff line #import "RCTView.h" extern NSString *const RNVideoLoadedEvent; extern NSString *const RNVideoLoadingEvent; extern NSString *const RNVideoProgressEvent; extern NSString *const RNVideoLoadingErrorEvent; @class RCTEventDispatcher; @interface RCTVideo : UIView Loading
RCTVideo.m +69 −39 Changes for RCTVideo.m: 69 added lines, 39 removed lines. Original line number Diff line number Diff line Loading @@ -5,9 +5,17 @@ #import "UIView+React.h" #import <AVFoundation/AVFoundation.h> NSString *const RNVideoLoadedEvent = @"videoLoaded"; NSString *const RNVideoLoadingEvent = @"videoLoading"; NSString *const RNVideoProgressEvent = @"videoProgress"; NSString *const RNVideoLoadingErrorEvent = @"videoLoadError"; static NSString *const statusKeyPath = @"status"; @implementation RCTVideo { AVPlayer *_player; AVPlayerItem *_playerItem; AVPlayerLayer *_playerLayer; NSURL *_videoURL; Loading @@ -25,8 +33,7 @@ BOOL _muted; } - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher { - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher { if ((self = [super init])) { _eventDispatcher = eventDispatcher; Loading @@ -39,16 +46,15 @@ return self; } - (void)sendProgressUpdate { - (void)sendProgressUpdate { AVPlayerItem *video = [_player currentItem]; if (video == nil) { if (video == nil || video.status != AVPlayerItemStatusReadyToPlay) { return; } if (_prevProgressUpdateTime == nil || (([_prevProgressUpdateTime timeIntervalSinceNow] * -1000.0) >= _progressUpdateInterval)) { [_eventDispatcher sendInputEventWithName:@"videoProgress" body:@{ [_eventDispatcher sendInputEventWithName:RNVideoProgressEvent body:@{ @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(video.currentTime)], @"target": self.reactTag }]; Loading @@ -56,17 +62,25 @@ } } - (void)setSrc:(NSString *)source { BOOL isHttpPrefix = [source hasPrefix:@"http://"]; if (isHttpPrefix) { _videoURL = [NSURL URLWithString:source]; } else { _videoURL = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:source ofType:@"mp4"]]; } _player = [AVPlayer playerWithURL:_videoURL]; - (void)setSrc:(NSDictionary *)source { bool isNetwork = [source objectForKey:@"isNetwork"]; NSString *uri = [source objectForKey:@"uri"]; NSString *type = [source objectForKey:@"type"]; _videoURL = isNetwork ? [NSURL URLWithString:uri] : [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]]; [_playerItem removeObserver:self forKeyPath:statusKeyPath]; _playerItem = [AVPlayerItem playerItemWithURL:_videoURL]; [_playerItem addObserver:self forKeyPath:statusKeyPath options:0 context:nil]; [_player pause]; [_playerLayer removeFromSuperlayer]; _player = [AVPlayer playerWithPlayerItem:_playerItem]; _player.actionAtItemEnd = AVPlayerActionAtItemEndNone; _playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player]; _playerLayer.frame = self.bounds; _playerLayer.needsDisplayOnBoundsChange = YES; Loading @@ -74,28 +88,48 @@ [self.layer addSublayer:_playerLayer]; self.layer.needsDisplayOnBoundsChange = YES; AVPlayerItem *video = [_player currentItem]; [_eventDispatcher sendInputEventWithName:RNVideoLoadingEvent body:@{ @"src": @{ @"uri":uri, @"type": type, @"isNetwork":[NSNumber numberWithBool:isNetwork] }, @"target": self.reactTag }]; } [_eventDispatcher sendInputEventWithName:@"videoLoaded" body:@{ @"duration": [NSNumber numberWithFloat:CMTimeGetSeconds(video.asset.duration)], @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(video.currentTime)], @"canPlayReverse": [NSNumber numberWithBool:video.canPlayReverse], @"canPlayFastForward": [NSNumber numberWithBool:video.canPlayFastForward], @"canPlaySlowForward": [NSNumber numberWithBool:video.canPlaySlowForward], @"canPlaySlowReverse": [NSNumber numberWithBool:video.canPlaySlowReverse], @"canStepBackward": [NSNumber numberWithBool:video.canStepBackward], @"canStepForward": [NSNumber numberWithBool:video.canStepForward], - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == _playerItem) { if (_playerItem.status == AVPlayerItemStatusReadyToPlay) { [_eventDispatcher sendInputEventWithName:RNVideoLoadedEvent body:@{ @"duration": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.duration)], @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)], @"canPlayReverse": [NSNumber numberWithBool:_playerItem.canPlayReverse], @"canPlayFastForward": [NSNumber numberWithBool:_playerItem.canPlayFastForward], @"canPlaySlowForward": [NSNumber numberWithBool:_playerItem.canPlaySlowForward], @"canPlaySlowReverse": [NSNumber numberWithBool:_playerItem.canPlaySlowReverse], @"canStepBackward": [NSNumber numberWithBool:_playerItem.canStepBackward], @"canStepForward": [NSNumber numberWithBool:_playerItem.canStepForward], @"target": self.reactTag }]; [_player play]; /* rate and volume must be set after play is called */ [self applyModifiers]; } else if(_playerItem.status == AVPlayerItemStatusFailed) { [_eventDispatcher sendInputEventWithName:RNVideoLoadingErrorEvent body:@{ @"error": @{ @"code": [NSNumber numberWithInt:_playerItem.error.code], @"domain": _playerItem.error.domain }, @"target": self.reactTag }]; } } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } - (void)setResizeMode:(NSString*)mode { - (void)setResizeMode:(NSString*)mode { _playerLayer.videoGravity = mode; } Loading Loading @@ -147,7 +181,6 @@ [self applyModifiers]; } - (void)setRepeatEnabled { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) Loading @@ -159,8 +192,7 @@ [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)setRepeat:(BOOL)repeat { - (void)setRepeat:(BOOL)repeat { if (repeat) { [self setRepeatEnabled]; } else { Loading @@ -168,20 +200,17 @@ } } - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex { - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex { RCTLogError(@"video cannot have any subviews"); return; } - (void)removeReactSubview:(UIView *)subview { - (void)removeReactSubview:(UIView *)subview { RCTLogError(@"video cannot have any subviews"); return; } - (void)layoutSubviews { - (void)layoutSubviews { [super layoutSubviews]; _playerLayer.frame = self.bounds; } Loading @@ -194,6 +223,7 @@ _player = nil; _prevProgressUpdateTime = nil; _eventDispatcher = nil; [_playerItem removeObserver:self forKeyPath:statusKeyPath]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } Loading
RCTVideoManager.m +9 −3 Changes for RCTVideoManager.m: 9 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -17,16 +17,22 @@ - (NSDictionary *)customDirectEventTypes { return @{ @"videoLoaded": @{ RNVideoLoadingEvent: @{ @"registrationName": @"onLoadStart" }, RNVideoLoadedEvent: @{ @"registrationName": @"onLoad" }, @"videoProgress": @{ RNVideoLoadingErrorEvent: @{ @"registrationName": @"onError" }, RNVideoProgressEvent: @{ @"registrationName": @"onProgress" }, }; } RCT_EXPORT_VIEW_PROPERTY(src, NSString); RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary); RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString); RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL); RCT_EXPORT_VIEW_PROPERTY(paused, BOOL); Loading
Video.ios.js +20 −3 Changes for Video.ios.js: 20 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -10,18 +10,21 @@ var VideoStylePropTypes = require('./VideoStylePropTypes'); var NativeMethodsMixin = require('NativeMethodsMixin'); var flattenStyle = require('flattenStyle'); var merge = require('merge'); var deepDiffer = require('deepDiffer'); var Video = React.createClass({ propTypes: { source: PropTypes.string, style: StyleSheetPropType(VideoStylePropTypes), source: PropTypes.object, resizeMode: PropTypes.string, repeat: PropTypes.bool, paused: PropTypes.bool, muted: PropTypes.bool, volume: PropTypes.number, rate: PropTypes.number, onLoadStart: PropTypes.func, onLoad: PropTypes.func, onError: PropTypes.func, onProgress: PropTypes.func, }, Loading @@ -32,10 +35,18 @@ var Video = React.createClass({ validAttributes: ReactIOSViewAttributes.UIView }, _onLoadStart(event) { this.props.onLoadStart && this.props.onLoadStart(event.nativeEvent); }, _onLoad(event) { this.props.onLoad && this.props.onLoad(event.nativeEvent); }, _onError(event) { this.props.onError && this.props.onError(event.nativeEvent); }, _onProgress(event) { this.props.onProgress && this.props.onProgress(event.nativeEvent); }, Loading @@ -43,6 +54,7 @@ var Video = React.createClass({ render() { var style = flattenStyle([styles.base, this.props.style]); var source = this.props.source; var isNetwork = !!(source.uri && source.uri.match(/^https?:/)); var resizeMode; if (this.props.resizeMode === VideoResizeMode.stretch) { Loading @@ -58,9 +70,14 @@ var Video = React.createClass({ var nativeProps = merge(this.props, { style, resizeMode: resizeMode, src: source, src: { uri: source.uri, isNetwork, type: source.type || 'mp4' }, onLoad: this._onLoad, onProgress: this._onProgress, }); return <RCTVideo {... nativeProps} /> Loading @@ -69,7 +86,7 @@ var Video = React.createClass({ var RCTVideo = createReactIOSNativeComponentClass({ validAttributes: merge(ReactIOSViewAttributes.UIView, {src: true, resizeMode: true, repeat: true, paused: true, muted: true, {src: {diff: deepDiffer}, resizeMode: true, repeat: true, paused: true, muted: true, volume: true, rate: true}), uiViewClassName: 'RCTVideo', }); Loading