Merge remote-tracking branch 'upstream/master' into implement-ios-caching
This commit is contained in:
		
							
								
								
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,9 +1,17 @@ | |||||||
| ## Changelog | ## Changelog | ||||||
|  |  | ||||||
| ### Next Version | ### 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) | * 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) | * 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 | ### Version 3.1.0 | ||||||
| * Support sidecar text tracks on iOS [#1109](https://github.com/react-native-community/react-native-video/pull/1109) | * Support sidecar text tracks on iOS [#1109](https://github.com/react-native-community/react-native-video/pull/1109) | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
									
									
									
									
								
							| @@ -236,6 +236,7 @@ var styles = StyleSheet.create({ | |||||||
| ### Configurable props | ### Configurable props | ||||||
| * [allowsExternalPlayback](#allowsexternalplayback) | * [allowsExternalPlayback](#allowsexternalplayback) | ||||||
| * [audioOnly](#audioonly) | * [audioOnly](#audioonly) | ||||||
|  | * [bufferConfig](#bufferconfig) | ||||||
| * [ignoreSilentSwitch](#ignoresilentswitch) | * [ignoreSilentSwitch](#ignoresilentswitch) | ||||||
| * [muted](#muted) | * [muted](#muted) | ||||||
| * [paused](#paused) | * [paused](#paused) | ||||||
| @@ -288,6 +289,30 @@ For this to work, the poster prop must be set. | |||||||
|  |  | ||||||
| Platforms: all | 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 | #### ignoreSilentSwitch | ||||||
| Controls the iOS silent switch behavior | Controls the iOS silent switch behavior | ||||||
| * **"inherit" (default)** - Use the default AVPlayer behavior | * **"inherit" (default)** - Use the default AVPlayer behavior | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								Video.js
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Video.js
									
									
									
									
									
								
							| @@ -345,6 +345,12 @@ Video.propTypes = { | |||||||
|   paused: PropTypes.bool, |   paused: PropTypes.bool, | ||||||
|   muted: PropTypes.bool, |   muted: PropTypes.bool, | ||||||
|   volume: PropTypes.number, |   volume: PropTypes.number, | ||||||
|  |   bufferConfig: PropTypes.shape({ | ||||||
|  |     minBufferMs: PropTypes.number, | ||||||
|  |     maxBufferMs: PropTypes.number, | ||||||
|  |     bufferForPlaybackMs: PropTypes.number, | ||||||
|  |     bufferForPlaybackAfterRebufferMs: PropTypes.number, | ||||||
|  |   }), | ||||||
|   stereoPan: PropTypes.number, |   stereoPan: PropTypes.number, | ||||||
|   rate: PropTypes.number, |   rate: PropTypes.number, | ||||||
|   playInBackground: PropTypes.bool, |   playInBackground: PropTypes.bool, | ||||||
|   | |||||||
| @@ -58,6 +58,7 @@ import com.google.android.exoplayer2.trackselection.MappingTrackSelector; | |||||||
| import com.google.android.exoplayer2.trackselection.TrackSelection; | import com.google.android.exoplayer2.trackselection.TrackSelection; | ||||||
| import com.google.android.exoplayer2.trackselection.TrackSelectionArray; | import com.google.android.exoplayer2.trackselection.TrackSelectionArray; | ||||||
| import com.google.android.exoplayer2.upstream.DataSource; | 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.upstream.DefaultBandwidthMeter; | ||||||
| import com.google.android.exoplayer2.util.MimeTypes; | import com.google.android.exoplayer2.util.MimeTypes; | ||||||
| import com.google.android.exoplayer2.util.Util; | import com.google.android.exoplayer2.util.Util; | ||||||
| @@ -109,6 +110,11 @@ class ReactExoplayerView extends FrameLayout implements | |||||||
|     private boolean isBuffering; |     private boolean isBuffering; | ||||||
|     private float rate = 1f; |     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 |     // Props from React | ||||||
|     private Uri srcUri; |     private Uri srcUri; | ||||||
|     private String extension; |     private String extension; | ||||||
| @@ -234,7 +240,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); | ||||||
|             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.addListener(this); | ||||||
|             player.setMetadataOutput(this); |             player.setMetadataOutput(this); | ||||||
|             exoPlayerView.setPlayer(player); |             exoPlayerView.setPlayer(player); | ||||||
| @@ -320,7 +328,6 @@ class ReactExoplayerView extends FrameLayout implements | |||||||
|  |  | ||||||
|     private void releasePlayer() { |     private void releasePlayer() { | ||||||
|         if (player != null) { |         if (player != null) { | ||||||
|             isPaused = player.getPlayWhenReady(); |  | ||||||
|             updateResumePosition(); |             updateResumePosition(); | ||||||
|             player.release(); |             player.release(); | ||||||
|             player.setMetadataOutput(null); |             player.setMetadataOutput(null); | ||||||
| @@ -931,4 +938,13 @@ class ReactExoplayerView extends FrameLayout implements | |||||||
|     public void setUseTextureView(boolean useTextureView) { |     public void setUseTextureView(boolean useTextureView) { | ||||||
|         exoPlayerView.setUseTextureView(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(); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ import com.facebook.react.common.MapBuilder; | |||||||
| import com.facebook.react.uimanager.ThemedReactContext; | import com.facebook.react.uimanager.ThemedReactContext; | ||||||
| import com.facebook.react.uimanager.ViewGroupManager; | import com.facebook.react.uimanager.ViewGroupManager; | ||||||
| import com.facebook.react.uimanager.annotations.ReactProp; | import com.facebook.react.uimanager.annotations.ReactProp; | ||||||
|  | import com.google.android.exoplayer2.DefaultLoadControl; | ||||||
| import com.google.android.exoplayer2.upstream.RawResourceDataSource; | import com.google.android.exoplayer2.upstream.RawResourceDataSource; | ||||||
|  |  | ||||||
| import java.util.HashMap; | 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_PAUSED = "paused"; | ||||||
|     private static final String PROP_MUTED = "muted"; |     private static final String PROP_MUTED = "muted"; | ||||||
|     private static final String PROP_VOLUME = "volume"; |     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_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"; | ||||||
| @@ -214,6 +220,25 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi | |||||||
|         videoView.setUseTextureView(useTextureView); |         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) { |     private boolean startsWithValidScheme(String uriString) { | ||||||
|         return uriString.startsWith("http://") |         return uriString.startsWith("http://") | ||||||
|                 || uriString.startsWith("https://") |                 || uriString.startsWith("https://") | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import android.os.Build; | |||||||
| import android.os.Handler; | import android.os.Handler; | ||||||
| import android.util.Log; | import android.util.Log; | ||||||
| import android.view.MotionEvent; | import android.view.MotionEvent; | ||||||
|  | import android.view.WindowManager; | ||||||
| import android.view.View; | import android.view.View; | ||||||
| import android.view.Window; | import android.view.Window; | ||||||
| import android.webkit.CookieManager; | import android.webkit.CookieManager; | ||||||
| @@ -96,7 +97,6 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP | |||||||
|     private Handler videoControlHandler = new Handler(); |     private Handler videoControlHandler = new Handler(); | ||||||
|     private MediaController mediaController; |     private MediaController mediaController; | ||||||
|  |  | ||||||
|  |  | ||||||
|     private String mSrcUriString = null; |     private String mSrcUriString = null; | ||||||
|     private String mSrcType = "mp4"; |     private String mSrcType = "mp4"; | ||||||
|     private ReadableMap mRequestHeaders = null; |     private ReadableMap mRequestHeaders = null; | ||||||
| @@ -359,7 +359,6 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setPausedModifier(final boolean paused) { |     public void setPausedModifier(final boolean paused) { | ||||||
|  |  | ||||||
|         mPaused = paused; |         mPaused = paused; | ||||||
|  |  | ||||||
|         if (!mMediaPlayerValid) { |         if (!mMediaPlayerValid) { | ||||||
| @@ -382,6 +381,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP | |||||||
|                 mProgressUpdateHandler.post(mProgressUpdateRunnable); |                 mProgressUpdateHandler.post(mProgressUpdateRunnable); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         setKeepScreenOn(!mPaused); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // reduces the volume based on stereoPan |     // reduces the volume based on stereoPan | ||||||
| @@ -501,7 +501,6 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP | |||||||
|         this.mUseNativeControls = controls; |         this.mUseNativeControls = controls; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void onPrepared(MediaPlayer mp) { |     public void onPrepared(MediaPlayer mp) { | ||||||
|  |  | ||||||
| @@ -625,21 +624,22 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void onCompletion(MediaPlayer mp) { |     public void onCompletion(MediaPlayer mp) { | ||||||
|  |  | ||||||
|         isCompleted = true; |         isCompleted = true; | ||||||
|         mEventEmitter.receiveEvent(getId(), Events.EVENT_END.toString(), null); |         mEventEmitter.receiveEvent(getId(), Events.EVENT_END.toString(), null); | ||||||
|  |         if (!mRepeat) { | ||||||
|  |             setKeepScreenOn(false); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void onDetachedFromWindow() { |     protected void onDetachedFromWindow() { | ||||||
|  |  | ||||||
|         mMediaPlayerValid = false; |         mMediaPlayerValid = false; | ||||||
|         super.onDetachedFromWindow(); |         super.onDetachedFromWindow(); | ||||||
|  |         setKeepScreenOn(false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void onAttachedToWindow() { |     protected void onAttachedToWindow() { | ||||||
|  |  | ||||||
|         super.onAttachedToWindow(); |         super.onAttachedToWindow(); | ||||||
|  |  | ||||||
|         if(mMainVer>0) { |         if(mMainVer>0) { | ||||||
| @@ -648,7 +648,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP | |||||||
|         else { |         else { | ||||||
|             setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders); |             setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders); | ||||||
|         } |         } | ||||||
|  |         setKeepScreenOn(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -313,7 +313,7 @@ static int const RCTVideoUnset = -1; | |||||||
|   [self removePlayerItemObservers]; |   [self removePlayerItemObservers]; | ||||||
|  |  | ||||||
|   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ |   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 |     // perform on next run loop, otherwise other passed react-props may not be set | ||||||
|     [self playerItemForSource:source withCallback:^(AVPlayerItem * playerItem) { |     [self playerItemForSource:source withCallback:^(AVPlayerItem * playerItem) { | ||||||
|       _playerItem = playerItem; |       _playerItem = playerItem; | ||||||
| @@ -353,8 +353,12 @@ static int const RCTVideoUnset = -1; | |||||||
| } | } | ||||||
|  |  | ||||||
| - (NSURL*) urlFilePath:(NSString*) filepath { | - (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]; |   NSString* relativeFilePath = [filepath lastPathComponent]; | ||||||
|   // the file may be multiple levels below the documents directory |   // the file may be multiple levels below the documents directory | ||||||
|   NSArray* fileComponents = [filepath componentsSeparatedByString:@"Documents/"]; |   NSArray* fileComponents = [filepath componentsSeparatedByString:@"Documents/"]; | ||||||
| @@ -392,6 +396,7 @@ static int const RCTVideoUnset = -1; | |||||||
|                            atTime:kCMTimeZero |                            atTime:kCMTimeZero | ||||||
|                             error:nil]; |                             error:nil]; | ||||||
|  |  | ||||||
|  |   NSMutableArray* validTextTracks = [NSMutableArray array]; | ||||||
|   for (int i = 0; i < _textTracks.count; ++i) { |   for (int i = 0; i < _textTracks.count; ++i) { | ||||||
|     AVURLAsset *textURLAsset; |     AVURLAsset *textURLAsset; | ||||||
|     NSString *textUri = [_textTracks objectAtIndex:i][@"uri"]; |     NSString *textUri = [_textTracks objectAtIndex:i][@"uri"]; | ||||||
| @@ -401,6 +406,8 @@ static int const RCTVideoUnset = -1; | |||||||
|       textURLAsset = [AVURLAsset URLAssetWithURL:[self urlFilePath:textUri] options:nil]; |       textURLAsset = [AVURLAsset URLAssetWithURL:[self urlFilePath:textUri] options:nil]; | ||||||
|     } |     } | ||||||
|     AVAssetTrack *textTrackAsset = [textURLAsset tracksWithMediaType:AVMediaTypeText].firstObject; |     AVAssetTrack *textTrackAsset = [textURLAsset tracksWithMediaType:AVMediaTypeText].firstObject; | ||||||
|  |     if (!textTrackAsset) continue; // fix when there's no textTrackAsset | ||||||
|  |     [validTextTracks addObject:[_textTracks objectAtIndex:i]]; | ||||||
|     AVMutableCompositionTrack *textCompTrack = [mixComposition |     AVMutableCompositionTrack *textCompTrack = [mixComposition | ||||||
|                                                 addMutableTrackWithMediaType:AVMediaTypeText |                                                 addMutableTrackWithMediaType:AVMediaTypeText | ||||||
|                                                 preferredTrackID:kCMPersistentTrackID_Invalid]; |                                                 preferredTrackID:kCMPersistentTrackID_Invalid]; | ||||||
| @@ -409,6 +416,9 @@ static int const RCTVideoUnset = -1; | |||||||
|                                 atTime:kCMTimeZero |                                 atTime:kCMTimeZero | ||||||
|                                  error:nil]; |                                  error:nil]; | ||||||
|   } |   } | ||||||
|  |   if (validTextTracks.count != _textTracks.count) { | ||||||
|  |     [self setTextTracks:validTextTracks]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   handler([AVPlayerItem playerItemWithAsset:mixComposition]); |   handler([AVPlayerItem playerItemWithAsset:mixComposition]); | ||||||
| } | } | ||||||
| @@ -892,7 +902,10 @@ static int const RCTVideoUnset = -1; | |||||||
|         selectedTrackIndex = index; |         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); |     CFArrayRef captioningMediaCharacteristics = MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics(kMACaptionAppearanceDomainUser); | ||||||
|     NSArray *captionSettings = (__bridge NSArray*)captioningMediaCharacteristics; |     NSArray *captionSettings = (__bridge NSArray*)captioningMediaCharacteristics; | ||||||
|     if ([captionSettings containsObject:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility]) { |     if ([captionSettings containsObject:AVMediaCharacteristicTranscribesSpokenDialogForAccessibility]) { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|     "name": "react-native-video", |     "name": "react-native-video", | ||||||
|     "version": "3.1.0", |     "version": "3.2.0", | ||||||
|     "description": "A <Video /> element for react-native", |     "description": "A <Video /> element for react-native", | ||||||
|     "main": "Video.js", |     "main": "Video.js", | ||||||
|     "license": "MIT", |     "license": "MIT", | ||||||
|   | |||||||
| @@ -29,8 +29,8 @@ | |||||||
|     <OutputPath>bin\x86\Release\</OutputPath> |     <OutputPath>bin\x86\Release\</OutputPath> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> |     <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> | ||||||
|       <HintPath>$(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> |       <HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath> | ||||||
|       <Private>True</Private> |       <Private>True</Private> | ||||||
|     </Reference> |     </Reference> | ||||||
|     <Reference Include="PresentationCore" /> |     <Reference Include="PresentationCore" /> | ||||||
| @@ -71,4 +71,4 @@ | |||||||
|   <Target Name="AfterBuild"> |   <Target Name="AfterBuild"> | ||||||
|   </Target> |   </Target> | ||||||
|   --> |   --> | ||||||
| </Project> | </Project> | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <packages> | <packages> | ||||||
|   <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net46" /> |   <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net46" /> | ||||||
| </packages> | </packages> | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| { | { | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2", |     "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2", | ||||||
|     "Newtonsoft.Json": "9.0.1" |     "Newtonsoft.Json": "10.0.3" | ||||||
|   }, |   }, | ||||||
|   "frameworks": { |   "frameworks": { | ||||||
|     "uap10.0": {} |     "uap10.0": {} | ||||||
| @@ -14,4 +14,4 @@ | |||||||
|     "win10-x64": {}, |     "win10-x64": {}, | ||||||
|     "win10-x64-aot": {} |     "win10-x64-aot": {} | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user