Merge remote-tracking branch 'upstream/master' into implement-ios-caching

This commit is contained in:
Laurin Quast 2018-08-06 10:39:39 +02:00
commit 8fcdc6e02a
11 changed files with 114 additions and 21 deletions

View File

@ -1,9 +1,17 @@
## Changelog
### Next Version
* Support video cachging for iOS ([#955](https://github.com/react-native-community/react-native-video/pull/955))
### Version 3.2.0
* Basic fullscreen support for Android MediaPlayer [#1138](https://github.com/react-native-community/react-native-video/pull/1138)
* Simplify default Android SDK code [#1145](https://github.com/react-native-community/react-native-video/pull/1145) [#1146](https://github.com/react-native-community/react-native-video/pull/1146)
* Support video cachging for iOS ([#955](https://github.com/react-native-community/react-native-video/pull/955))
* Various iOS sideloaded text track fixes [#1157](https://github.com/react-native-community/react-native-video/pull/1157)
* Fix #1150 where assets with bundled assets don't work on iOS in release mode [#1162](https://github.com/react-native-community/react-native-video/pull/1162)
* Support configuring the buffer on Android ExoPlayer [#1160](https://github.com/react-native-community/react-native-video/pull/1160)
* Prevent sleep from sleeping while videos are playing on Android MediaPlayer [#1117](https://github.com/react-native-community/react-native-video/pull/1117)
* Update NewtonSoft JSON to match react-native-windows version [#1169](https://github.com/react-native-community/react-native-video/pull/1169)
### Version 3.1.0
* Support sidecar text tracks on iOS [#1109](https://github.com/react-native-community/react-native-video/pull/1109)

View File

@ -236,6 +236,7 @@ var styles = StyleSheet.create({
### Configurable props
* [allowsExternalPlayback](#allowsexternalplayback)
* [audioOnly](#audioonly)
* [bufferConfig](#bufferconfig)
* [ignoreSilentSwitch](#ignoresilentswitch)
* [muted](#muted)
* [paused](#paused)
@ -288,6 +289,30 @@ For this to work, the poster prop must be set.
Platforms: all
#### bufferConfig
Adjust the buffer settings. This prop takes an object with one or more of the properties listed below.
Property | Type | Description
--- | --- | ---
minBufferMs | number | The default minimum duration of media that the player will attempt to ensure is buffered at all times, in milliseconds.
maxBufferMs | number | The default maximum duration of media that the player will attempt to buffer, in milliseconds.
bufferForPlaybackMs | number | The default duration of media that must be buffered for playback to start or resume following a user action such as a seek, in milliseconds.
playbackAfterRebufferMs | number | The default duration of media that must be buffered for playback to resume after a rebuffer, in milliseconds. A rebuffer is defined to be caused by buffer depletion rather than a user action.
This prop should only be set when you are setting the source, changing it after the media is loaded will cause it to be reloaded.
Example with default values:
```
bufferConfig={{
minBufferMs: 15000,
maxBufferMs: 50000,
bufferForPlaybackMs: 2500,
bufferForPlaybackAfterRebufferMs: 5000
}}
```
Platforms: Android ExoPlayer
#### ignoreSilentSwitch
Controls the iOS silent switch behavior
* **"inherit" (default)** - Use the default AVPlayer behavior

View File

@ -345,6 +345,12 @@ Video.propTypes = {
paused: PropTypes.bool,
muted: PropTypes.bool,
volume: PropTypes.number,
bufferConfig: PropTypes.shape({
minBufferMs: PropTypes.number,
maxBufferMs: PropTypes.number,
bufferForPlaybackMs: PropTypes.number,
bufferForPlaybackAfterRebufferMs: PropTypes.number,
}),
stereoPan: PropTypes.number,
rate: PropTypes.number,
playInBackground: PropTypes.bool,

View File

@ -58,6 +58,7 @@ import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultAllocator;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
@ -109,6 +110,11 @@ class ReactExoplayerView extends FrameLayout implements
private boolean isBuffering;
private float rate = 1f;
private int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
private int maxBufferMs = DefaultLoadControl.DEFAULT_MAX_BUFFER_MS;
private int bufferForPlaybackMs = DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS;
private int bufferForPlaybackAfterRebufferMs = DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS;
// Props from React
private Uri srcUri;
private String extension;
@ -234,7 +240,9 @@ class ReactExoplayerView extends FrameLayout implements
if (player == null) {
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, new DefaultLoadControl());
DefaultAllocator allocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE);
DefaultLoadControl defaultLoadControl = new DefaultLoadControl(allocator, minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs, -1, true);
player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, defaultLoadControl);
player.addListener(this);
player.setMetadataOutput(this);
exoPlayerView.setPlayer(player);
@ -320,7 +328,6 @@ class ReactExoplayerView extends FrameLayout implements
private void releasePlayer() {
if (player != null) {
isPaused = player.getPlayWhenReady();
updateResumePosition();
player.release();
player.setMetadataOutput(null);
@ -931,4 +938,13 @@ class ReactExoplayerView extends FrameLayout implements
public void setUseTextureView(boolean useTextureView) {
exoPlayerView.setUseTextureView(useTextureView);
}
public void setBufferConfig(int newMinBufferMs, int newMaxBufferMs, int newBufferForPlaybackMs, int newBufferForPlaybackAfterRebufferMs) {
minBufferMs = newMinBufferMs;
maxBufferMs = newMaxBufferMs;
bufferForPlaybackMs = newBufferForPlaybackMs;
bufferForPlaybackAfterRebufferMs = newBufferForPlaybackAfterRebufferMs;
releasePlayer();
initializePlayer();
}
}

View File

@ -11,6 +11,7 @@ import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.upstream.RawResourceDataSource;
import java.util.HashMap;
@ -38,6 +39,11 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
private static final String PROP_PAUSED = "paused";
private static final String PROP_MUTED = "muted";
private static final String PROP_VOLUME = "volume";
private static final String PROP_BUFFER_CONFIG = "bufferConfig";
private static final String PROP_BUFFER_CONFIG_MIN_BUFFER_MS = "minBufferMs";
private static final String PROP_BUFFER_CONFIG_MAX_BUFFER_MS = "maxBufferMs";
private static final String PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_MS = "bufferForPlaybackMs";
private static final String PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = "bufferForPlaybackAfterRebufferMs";
private static final String PROP_PROGRESS_UPDATE_INTERVAL = "progressUpdateInterval";
private static final String PROP_SEEK = "seek";
private static final String PROP_RATE = "rate";
@ -214,6 +220,25 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
videoView.setUseTextureView(useTextureView);
}
@ReactProp(name = PROP_BUFFER_CONFIG)
public void setBufferConfig(final ReactExoplayerView videoView, @Nullable ReadableMap bufferConfig) {
int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
int maxBufferMs = DefaultLoadControl.DEFAULT_MAX_BUFFER_MS;
int bufferForPlaybackMs = DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS;
int bufferForPlaybackAfterRebufferMs = DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS;
if (bufferConfig != null) {
minBufferMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MIN_BUFFER_MS)
? bufferConfig.getInt(PROP_BUFFER_CONFIG_MIN_BUFFER_MS) : minBufferMs;
maxBufferMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MAX_BUFFER_MS)
? bufferConfig.getInt(PROP_BUFFER_CONFIG_MAX_BUFFER_MS) : maxBufferMs;
bufferForPlaybackMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_MS)
? bufferConfig.getInt(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_MS) : bufferForPlaybackMs;
bufferForPlaybackAfterRebufferMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS)
? bufferConfig.getInt(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS) : bufferForPlaybackAfterRebufferMs;
videoView.setBufferConfig(minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs);
}
}
private boolean startsWithValidScheme(String uriString) {
return uriString.startsWith("http://")
|| uriString.startsWith("https://")

View File

@ -10,6 +10,7 @@ import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.View;
import android.view.Window;
import android.webkit.CookieManager;
@ -96,7 +97,6 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
private Handler videoControlHandler = new Handler();
private MediaController mediaController;
private String mSrcUriString = null;
private String mSrcType = "mp4";
private ReadableMap mRequestHeaders = null;
@ -359,7 +359,6 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
}
public void setPausedModifier(final boolean paused) {
mPaused = paused;
if (!mMediaPlayerValid) {
@ -382,6 +381,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
mProgressUpdateHandler.post(mProgressUpdateRunnable);
}
}
setKeepScreenOn(!mPaused);
}
// reduces the volume based on stereoPan
@ -501,7 +501,6 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
this.mUseNativeControls = controls;
}
@Override
public void onPrepared(MediaPlayer mp) {
@ -625,21 +624,22 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
@Override
public void onCompletion(MediaPlayer mp) {
isCompleted = true;
mEventEmitter.receiveEvent(getId(), Events.EVENT_END.toString(), null);
if (!mRepeat) {
setKeepScreenOn(false);
}
}
@Override
protected void onDetachedFromWindow() {
mMediaPlayerValid = false;
super.onDetachedFromWindow();
setKeepScreenOn(false);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if(mMainVer>0) {
@ -648,7 +648,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
else {
setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders);
}
setKeepScreenOn(true);
}
@Override

View File

@ -313,7 +313,7 @@ static int const RCTVideoUnset = -1;
[self removePlayerItemObservers];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// perform on next run loop, otherwise other passed react-props may not be set
[self playerItemForSource:source withCallback:^(AVPlayerItem * playerItem) {
_playerItem = playerItem;
@ -353,8 +353,12 @@ static int const RCTVideoUnset = -1;
}
- (NSURL*) urlFilePath:(NSString*) filepath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if ([filepath containsString:@"file://"]) {
return [NSURL URLWithString:filepath];
}
// code to support local caching
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* relativeFilePath = [filepath lastPathComponent];
// the file may be multiple levels below the documents directory
NSArray* fileComponents = [filepath componentsSeparatedByString:@"Documents/"];
@ -392,6 +396,7 @@ static int const RCTVideoUnset = -1;
atTime:kCMTimeZero
error:nil];
NSMutableArray* validTextTracks = [NSMutableArray array];
for (int i = 0; i < _textTracks.count; ++i) {
AVURLAsset *textURLAsset;
NSString *textUri = [_textTracks objectAtIndex:i][@"uri"];
@ -401,6 +406,8 @@ static int const RCTVideoUnset = -1;
textURLAsset = [AVURLAsset URLAssetWithURL:[self urlFilePath:textUri] options:nil];
}
AVAssetTrack *textTrackAsset = [textURLAsset tracksWithMediaType:AVMediaTypeText].firstObject;
if (!textTrackAsset) continue; // fix when there's no textTrackAsset
[validTextTracks addObject:[_textTracks objectAtIndex:i]];
AVMutableCompositionTrack *textCompTrack = [mixComposition
addMutableTrackWithMediaType:AVMediaTypeText
preferredTrackID:kCMPersistentTrackID_Invalid];
@ -409,6 +416,9 @@ static int const RCTVideoUnset = -1;
atTime:kCMTimeZero
error:nil];
}
if (validTextTracks.count != _textTracks.count) {
[self setTextTracks:validTextTracks];
}
handler([AVPlayerItem playerItemWithAsset:mixComposition]);
}
@ -892,7 +902,10 @@ static int const RCTVideoUnset = -1;
selectedTrackIndex = index;
}
}
} else { // type "system"
}
// in the situation that a selected text track is not available (eg. specifies a textTrack not available)
if (![type isEqualToString:@"disabled"] && selectedTrackIndex == RCTVideoUnset) {
CFArrayRef captioningMediaCharacteristics = MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics(kMACaptionAppearanceDomainUser);
NSArray *captionSettings = (__bridge NSArray*)captioningMediaCharacteristics;
if ([captionSettings containsObject:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility]) {

View File

@ -1,6 +1,6 @@
{
"name": "react-native-video",
"version": "3.1.0",
"version": "3.2.0",
"description": "A <Video /> element for react-native",
"main": "Video.js",
"license": "MIT",

View File

@ -29,8 +29,8 @@
<OutputPath>bin\x86\Release\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PresentationCore" />
@ -71,4 +71,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net46" />
</packages>
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net46" />
</packages>

View File

@ -1,7 +1,7 @@
{
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2",
"Newtonsoft.Json": "9.0.1"
"Newtonsoft.Json": "10.0.3"
},
"frameworks": {
"uap10.0": {}
@ -14,4 +14,4 @@
"win10-x64": {},
"win10-x64-aot": {}
}
}
}