merge
This commit is contained in:
commit
c2d9fb4301
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,5 +1,17 @@
|
|||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
### Version 4.2.0
|
||||||
|
* Don't initialize filters on iOS unless a filter is set. This was causing a startup performance regression [#1360](https://github.com/react-native-community/react-native-video/pull/1360)
|
||||||
|
* Support setting the maxBitRate [#1310](https://github.com/react-native-community/react-native-video/pull/1310)
|
||||||
|
* Fix useTextureView not defaulting to true [#1383](https://github.com/react-native-community/react-native-video/pull/1383)
|
||||||
|
* Fix crash on MediaPlayer w/ Android 4.4 & avoid memory leak [#1328](https://github.com/react-native-community/react-native-video/pull/1328)
|
||||||
|
|
||||||
|
### Version 4.1.0
|
||||||
|
* Generate onSeek on Android ExoPlayer & MediaPlayer after seek completes [#1351](https://github.com/react-native-community/react-native-video/pull/1351)
|
||||||
|
* Remove unneeded onVideoSaved event [#1350](https://github.com/react-native-community/react-native-video/pull/1350)
|
||||||
|
* Disable AirPlay if sidecar text tracks are enabled [#1304](https://github.com/react-native-community/react-native-video/pull/1304)
|
||||||
|
* Add possibility to remove black screen while video is loading in Exoplayer [#1355](https://github.com/react-native-community/react-native-video/pull/1355)
|
||||||
|
|
||||||
### Version 4.0.1
|
### Version 4.0.1
|
||||||
* Add missing files to package.json [#1342](https://github.com/react-native-community/react-native-video/pull/1342)
|
* Add missing files to package.json [#1342](https://github.com/react-native-community/react-native-video/pull/1342)
|
||||||
|
|
||||||
|
25
README.md
25
README.md
@ -265,8 +265,10 @@ var styles = StyleSheet.create({
|
|||||||
* [fullscreenAutorotate](#fullscreenautorotate)
|
* [fullscreenAutorotate](#fullscreenautorotate)
|
||||||
* [fullscreenOrientation](#fullscreenorientation)
|
* [fullscreenOrientation](#fullscreenorientation)
|
||||||
* [headers](#headers)
|
* [headers](#headers)
|
||||||
|
* [hideShutterView](#hideshutterview)
|
||||||
* [id](#id)
|
* [id](#id)
|
||||||
* [ignoreSilentSwitch](#ignoresilentswitch)
|
* [ignoreSilentSwitch](#ignoresilentswitch)
|
||||||
|
* [maxBitRate](#maxbitrate)
|
||||||
* [muted](#muted)
|
* [muted](#muted)
|
||||||
* [paused](#paused)
|
* [paused](#paused)
|
||||||
* [playInBackground](#playinbackground)
|
* [playInBackground](#playinbackground)
|
||||||
@ -427,6 +429,14 @@ headers={{
|
|||||||
|
|
||||||
Platforms: Android ExoPlayer
|
Platforms: Android ExoPlayer
|
||||||
|
|
||||||
|
#### hideShutterView
|
||||||
|
Controls whether the ExoPlayer shutter view (black screen while loading) is enabled.
|
||||||
|
|
||||||
|
* **false (default)** - Show shutter view
|
||||||
|
* **true** - Hide shutter view
|
||||||
|
|
||||||
|
Platforms: Android ExoPlayer
|
||||||
|
|
||||||
#### id
|
#### id
|
||||||
Set the DOM id element so you can use document.getElementById on web platforms. Accepts string values.
|
Set the DOM id element so you can use document.getElementById on web platforms. Accepts string values.
|
||||||
|
|
||||||
@ -445,6 +455,18 @@ Controls the iOS silent switch behavior
|
|||||||
|
|
||||||
Platforms: iOS
|
Platforms: iOS
|
||||||
|
|
||||||
|
#### maxBitRate
|
||||||
|
Sets the desired limit, in bits per second, of network bandwidth consumption when multiple video streams are available for a playlist.
|
||||||
|
|
||||||
|
Default: 0. Don't limit the maxBitRate.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
maxBitRate={2000000} // 2 megabits
|
||||||
|
```
|
||||||
|
|
||||||
|
Platforms: Android ExoPlayer, iOS
|
||||||
|
|
||||||
#### muted
|
#### muted
|
||||||
Controls whether the audio is muted
|
Controls whether the audio is muted
|
||||||
* **false (default)** - Don't mute audio
|
* **false (default)** - Don't mute audio
|
||||||
@ -594,6 +616,7 @@ Sets the media source. You can pass an asset loaded via require or an object wit
|
|||||||
|
|
||||||
The docs for this prop are incomplete and will be updated as each option is investigated and tested.
|
The docs for this prop are incomplete and will be updated as each option is investigated and tested.
|
||||||
|
|
||||||
|
|
||||||
##### Asset loaded via require
|
##### Asset loaded via require
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@ -666,6 +689,8 @@ uri | URL for the text track. Currently, only tracks hosted on a webserver are s
|
|||||||
|
|
||||||
On iOS, sidecar text tracks are only supported for individual files, not HLS playlists. For HLS, you should include the text tracks as part of the playlist.
|
On iOS, sidecar text tracks are only supported for individual files, not HLS playlists. For HLS, you should include the text tracks as part of the playlist.
|
||||||
|
|
||||||
|
Note: Due to iOS limitations, sidecar text tracks are not compatible with Airplay. If textTracks are specified, AirPlay support will be automatically disabled.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```
|
```
|
||||||
import { TextTrackType }, Video from 'react-native-video';
|
import { TextTrackType }, Video from 'react-native-video';
|
||||||
|
2
Video.js
2
Video.js
@ -331,6 +331,7 @@ Video.propTypes = {
|
|||||||
// Opaque type returned by require('./video.mp4')
|
// Opaque type returned by require('./video.mp4')
|
||||||
PropTypes.number
|
PropTypes.number
|
||||||
]),
|
]),
|
||||||
|
maxBitRate: PropTypes.number,
|
||||||
resizeMode: PropTypes.string,
|
resizeMode: PropTypes.string,
|
||||||
poster: PropTypes.string,
|
poster: PropTypes.string,
|
||||||
posterResizeMode: Image.propTypes.resizeMode,
|
posterResizeMode: Image.propTypes.resizeMode,
|
||||||
@ -384,6 +385,7 @@ Video.propTypes = {
|
|||||||
fullscreenOrientation: PropTypes.oneOf(['all','landscape','portrait']),
|
fullscreenOrientation: PropTypes.oneOf(['all','landscape','portrait']),
|
||||||
progressUpdateInterval: PropTypes.number,
|
progressUpdateInterval: PropTypes.number,
|
||||||
useTextureView: PropTypes.bool,
|
useTextureView: PropTypes.bool,
|
||||||
|
hideShutterView: PropTypes.bool,
|
||||||
onLoadStart: PropTypes.func,
|
onLoadStart: PropTypes.func,
|
||||||
onLoad: PropTypes.func,
|
onLoad: PropTypes.func,
|
||||||
onBuffer: PropTypes.func,
|
onBuffer: PropTypes.func,
|
||||||
|
@ -38,7 +38,8 @@ public final class ExoPlayerView extends FrameLayout {
|
|||||||
private Context context;
|
private Context context;
|
||||||
private ViewGroup.LayoutParams layoutParams;
|
private ViewGroup.LayoutParams layoutParams;
|
||||||
|
|
||||||
private boolean useTextureView = false;
|
private boolean useTextureView = true;
|
||||||
|
private boolean hideShutterView = false;
|
||||||
|
|
||||||
public ExoPlayerView(Context context) {
|
public ExoPlayerView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
@ -106,6 +107,10 @@ public final class ExoPlayerView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateShutterViewVisibility() {
|
||||||
|
shutterView.setVisibility(this.hideShutterView ? View.INVISIBLE : View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#setTextOutput} and
|
* Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#setTextOutput} and
|
||||||
* {@link SimpleExoPlayer#setVideoListener} method of the player will be called and previous
|
* {@link SimpleExoPlayer#setVideoListener} method of the player will be called and previous
|
||||||
@ -157,9 +162,16 @@ public final class ExoPlayerView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setUseTextureView(boolean useTextureView) {
|
public void setUseTextureView(boolean useTextureView) {
|
||||||
|
if (useTextureView != this.useTextureView) {
|
||||||
this.useTextureView = useTextureView;
|
this.useTextureView = useTextureView;
|
||||||
updateSurfaceView();
|
updateSurfaceView();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHideShutterView(boolean hideShutterView) {
|
||||||
|
this.hideShutterView = hideShutterView;
|
||||||
|
updateShutterViewVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
private final Runnable measureAndLayout = new Runnable() {
|
private final Runnable measureAndLayout = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,6 +110,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
private boolean isBuffering;
|
private boolean isBuffering;
|
||||||
private float rate = 1f;
|
private float rate = 1f;
|
||||||
private float audioVolume = 1f;
|
private float audioVolume = 1f;
|
||||||
|
private int maxBitRate = 0;
|
||||||
private long seekTime = C.TIME_UNSET;
|
private long seekTime = C.TIME_UNSET;
|
||||||
|
|
||||||
private int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
|
private int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
|
||||||
@ -130,7 +131,6 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
private boolean disableFocus;
|
private boolean disableFocus;
|
||||||
private float mProgressUpdateInterval = 250.0f;
|
private float mProgressUpdateInterval = 250.0f;
|
||||||
private boolean playInBackground = false;
|
private boolean playInBackground = false;
|
||||||
private boolean useTextureView = false;
|
|
||||||
private Map<String, String> requestHeaders;
|
private Map<String, String> requestHeaders;
|
||||||
// \ End props
|
// \ End props
|
||||||
|
|
||||||
@ -245,6 +245,9 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
if (player == null) {
|
if (player == null) {
|
||||||
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
|
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
|
||||||
trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
|
trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
|
||||||
|
trackSelector.setParameters(trackSelector.buildUponParameters()
|
||||||
|
.setMaxVideoBitrate(maxBitRate == 0 ? Integer.MAX_VALUE : maxBitRate));
|
||||||
|
|
||||||
DefaultAllocator allocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
DefaultAllocator allocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
||||||
DefaultLoadControl defaultLoadControl = new DefaultLoadControl(allocator, minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs, -1, true);
|
DefaultLoadControl defaultLoadControl = new DefaultLoadControl(allocator, minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs, -1, true);
|
||||||
player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, defaultLoadControl);
|
player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, defaultLoadControl);
|
||||||
@ -908,6 +911,14 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxBitRateModifier(int newMaxBitRate) {
|
||||||
|
maxBitRate = newMaxBitRate;
|
||||||
|
if (player != null) {
|
||||||
|
trackSelector.setParameters(trackSelector.buildUponParameters()
|
||||||
|
.setMaxVideoBitrate(maxBitRate == 0 ? Integer.MAX_VALUE : maxBitRate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setPlayInBackground(boolean playInBackground) {
|
public void setPlayInBackground(boolean playInBackground) {
|
||||||
this.playInBackground = playInBackground;
|
this.playInBackground = playInBackground;
|
||||||
@ -954,6 +965,10 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
exoPlayerView.setUseTextureView(useTextureView);
|
exoPlayerView.setUseTextureView(useTextureView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHideShutterView(boolean hideShutterView) {
|
||||||
|
exoPlayerView.setHideShutterView(hideShutterView);
|
||||||
|
}
|
||||||
|
|
||||||
public void setBufferConfig(int newMinBufferMs, int newMaxBufferMs, int newBufferForPlaybackMs, int newBufferForPlaybackAfterRebufferMs) {
|
public void setBufferConfig(int newMinBufferMs, int newMaxBufferMs, int newBufferForPlaybackMs, int newBufferForPlaybackAfterRebufferMs) {
|
||||||
minBufferMs = newMinBufferMs;
|
minBufferMs = newMinBufferMs;
|
||||||
maxBufferMs = newMaxBufferMs;
|
maxBufferMs = newMaxBufferMs;
|
||||||
|
@ -47,10 +47,12 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
|||||||
private static final String PROP_PROGRESS_UPDATE_INTERVAL = "progressUpdateInterval";
|
private static final String PROP_PROGRESS_UPDATE_INTERVAL = "progressUpdateInterval";
|
||||||
private static final String PROP_SEEK = "seek";
|
private static final String PROP_SEEK = "seek";
|
||||||
private static final String PROP_RATE = "rate";
|
private static final String PROP_RATE = "rate";
|
||||||
|
private static final String PROP_MAXIMUM_BIT_RATE = "maxBitRate";
|
||||||
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
|
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
|
||||||
private static final String PROP_DISABLE_FOCUS = "disableFocus";
|
private static final String PROP_DISABLE_FOCUS = "disableFocus";
|
||||||
private static final String PROP_FULLSCREEN = "fullscreen";
|
private static final String PROP_FULLSCREEN = "fullscreen";
|
||||||
private static final String PROP_USE_TEXTURE_VIEW = "useTextureView";
|
private static final String PROP_USE_TEXTURE_VIEW = "useTextureView";
|
||||||
|
private static final String PROP_HIDE_SHUTTER_VIEW = "hideShutterView";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -200,6 +202,11 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
|||||||
videoView.setRateModifier(rate);
|
videoView.setRateModifier(rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = PROP_MAXIMUM_BIT_RATE)
|
||||||
|
public void setMaxBitRate(final ReactExoplayerView videoView, final int maxBitRate) {
|
||||||
|
videoView.setMaxBitRateModifier(maxBitRate);
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = PROP_PLAY_IN_BACKGROUND, defaultBoolean = false)
|
@ReactProp(name = PROP_PLAY_IN_BACKGROUND, defaultBoolean = false)
|
||||||
public void setPlayInBackground(final ReactExoplayerView videoView, final boolean playInBackground) {
|
public void setPlayInBackground(final ReactExoplayerView videoView, final boolean playInBackground) {
|
||||||
videoView.setPlayInBackground(playInBackground);
|
videoView.setPlayInBackground(playInBackground);
|
||||||
@ -220,6 +227,11 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
|||||||
videoView.setUseTextureView(useTextureView);
|
videoView.setUseTextureView(useTextureView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = PROP_HIDE_SHUTTER_VIEW, defaultBoolean = false)
|
||||||
|
public void setHideShutterView(final ReactExoplayerView videoView, final boolean hideShutterView) {
|
||||||
|
videoView.setHideShutterView(hideShutterView);
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = PROP_BUFFER_CONFIG)
|
@ReactProp(name = PROP_BUFFER_CONFIG)
|
||||||
public void setBufferConfig(final ReactExoplayerView videoView, @Nullable ReadableMap bufferConfig) {
|
public void setBufferConfig(final ReactExoplayerView videoView, @Nullable ReadableMap bufferConfig) {
|
||||||
int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
|
int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
|
||||||
|
@ -235,12 +235,19 @@ public class ReactVideoView extends ScalableVideoView implements
|
|||||||
mediaController.hide();
|
mediaController.hide();
|
||||||
}
|
}
|
||||||
if ( mMediaPlayer != null ) {
|
if ( mMediaPlayer != null ) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
mMediaPlayer.setOnTimedMetaDataAvailableListener(null);
|
||||||
|
}
|
||||||
mMediaPlayerValid = false;
|
mMediaPlayerValid = false;
|
||||||
release();
|
release();
|
||||||
}
|
}
|
||||||
if (mIsFullscreen) {
|
if (mIsFullscreen) {
|
||||||
setFullscreen(false);
|
setFullscreen(false);
|
||||||
}
|
}
|
||||||
|
if (mThemedReactContext != null) {
|
||||||
|
mThemedReactContext.removeLifecycleEventListener(this);
|
||||||
|
mThemedReactContext = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders) {
|
public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders) {
|
||||||
@ -567,8 +574,7 @@ public class ReactVideoView extends ScalableVideoView implements
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select track (so we can use it to listen to timed meta data updates)
|
selectTimedMetadataTrack(mp);
|
||||||
mp.selectTrack(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -603,9 +609,7 @@ public class ReactVideoView extends ScalableVideoView implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
||||||
// Select track (so we can use it to listen to timed meta data updates)
|
selectTimedMetadataTrack(mp);
|
||||||
mp.selectTrack(0);
|
|
||||||
|
|
||||||
mVideoBufferedDuration = (int) Math.round((double) (mVideoDuration * percent) / 100.0);
|
mVideoBufferedDuration = (int) Math.round((double) (mVideoDuration * percent) / 100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -761,4 +765,20 @@ public class ReactVideoView extends ScalableVideoView implements
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select track (so we can use it to listen to timed meta data updates)
|
||||||
|
private void selectTimedMetadataTrack(MediaPlayer mp) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try { // It's possible this could throw an exception if the framework doesn't support getting track info
|
||||||
|
MediaPlayer.TrackInfo[] trackInfo = mp.getTrackInfo();
|
||||||
|
for (int i = 0; i < trackInfo.length; ++i) {
|
||||||
|
if (trackInfo[i].getTrackType() == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
|
||||||
|
mp.selectTrack(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ RCT_EXPORT_MODULE();
|
|||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary);
|
RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary);
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(maxBitRate, float);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);
|
RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(allowsExternalPlayback, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(allowsExternalPlayback, BOOL);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-native-video",
|
"name": "react-native-video",
|
||||||
"version": "4.0.2",
|
"version": "4.2.1",
|
||||||
"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