From d43a4c86a26a2597b3e264cf67f9d635259d292d Mon Sep 17 00:00:00 2001 From: YangJH Date: Fri, 17 Nov 2023 04:51:04 +0900 Subject: [PATCH 01/10] feat(android): implement startPosition --- .../com/brentvatne/exoplayer/ReactExoplayerView.java | 12 +++++++++++- .../exoplayer/ReactExoplayerViewManager.java | 6 ++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 5bad9ba371..53418b8704 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -207,6 +207,7 @@ public class ReactExoplayerView extends FrameLayout implements private boolean disableFocus; private boolean focusable = true; private boolean disableBuffering; + private long startPosition = -1L; private long contentStartTime = -1L; private boolean disableDisconnectError; private boolean preventsDisplaySleepDuringVideoPlayback = true; @@ -721,7 +722,12 @@ private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager d if (haveResumePosition) { player.seekTo(resumeWindow, resumePosition); } - player.prepare(mediaSource, !haveResumePosition, false); + if (startPosition >= 0) { + player.setMediaSource(mediaSource, startPosition); + } else { + player.setMediaSource(mediaSource, !haveResumePosition); + } + player.prepare(); playerNeedsSource = false; reLayout(exoPlayerView); @@ -1941,6 +1947,10 @@ public void setBackBufferDurationMs(int backBufferDurationMs) { this.backBufferDurationMs = backBufferDurationMs; } + public void setStartPosition(long startPosition) { + this.startPosition = startPosition; + } + public void setContentStartTime(int contentStartTime) { this.contentStartTime = contentStartTime; } diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index b4aa18e78e..f740143568 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -74,6 +74,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager Date: Fri, 17 Nov 2023 04:51:18 +0900 Subject: [PATCH 02/10] feat(ios): implement startPosition --- ios/Video/RCTVideo.swift | 14 ++++++++++++++ ios/Video/RCTVideoManager.m | 1 + 2 files changed, 15 insertions(+) diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index 6779dfaec9..3747e3cc53 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -66,6 +66,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH private var _filterEnabled:Bool = false private var _presentingViewController:UIViewController? private var _pictureInPictureEnabled = false + private var _startPosition:Float = -1 /* IMA Ads */ private var _adTagUrl:String? @@ -600,6 +601,11 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH _pendingSeek = false } + @objc + func setStartPosition(_ startPosition:Float) { + _startPosition = startPosition + } + @objc func setRate(_ rate:Float) { _rate = rate @@ -1180,6 +1186,14 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH _pendingSeek = false } + if _startPosition > 0 { + setSeek([ + "time": NSNumber(value: _cursor), + "tolerance": NSNumber(value: 100) + ]) + _startPosition = -1 + } + if _videoLoadStarted { let audioTracks = RCTVideoUtils.getAudioTrackInfo(_player) let textTracks = RCTVideoUtils.getTextTrackInfo(_player).map(\.json) diff --git a/ios/Video/RCTVideoManager.m b/ios/Video/RCTVideoManager.m index 291868eb71..6046b64895 100644 --- a/ios/Video/RCTVideoManager.m +++ b/ios/Video/RCTVideoManager.m @@ -29,6 +29,7 @@ @interface RCT_EXTERN_MODULE(RCTVideoManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(mixWithOthers, NSString); RCT_EXPORT_VIEW_PROPERTY(rate, float); RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary); +RCT_EXPORT_VIEW_PROPERTY(startPosition, float); RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL); RCT_EXPORT_VIEW_PROPERTY(fullscreenAutorotate, BOOL); RCT_EXPORT_VIEW_PROPERTY(fullscreenOrientation, NSString); From 41b8e324edc67bab20de3d7faf7424f41709f055 Mon Sep 17 00:00:00 2001 From: YangJH Date: Fri, 17 Nov 2023 04:51:52 +0900 Subject: [PATCH 03/10] feat: implement startPosition type --- src/VideoNativeComponent.ts | 1 + src/types/video.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/VideoNativeComponent.ts b/src/VideoNativeComponent.ts index c13991c9d3..4035f80fa0 100644 --- a/src/VideoNativeComponent.ts +++ b/src/VideoNativeComponent.ts @@ -274,6 +274,7 @@ export interface VideoNativeProps extends ViewProps { textTracks?: TextTracks; selectedTextTrack?: SelectedTextTrack; selectedAudioTrack?: SelectedAudioTrack; + startPosition?: number; paused?: boolean; muted?: boolean; controls?: boolean; diff --git a/src/types/video.ts b/src/types/video.ts index e3b03bc0ed..7e64d97981 100644 --- a/src/types/video.ts +++ b/src/types/video.ts @@ -208,6 +208,7 @@ export interface ReactVideoProps extends ReactVideoEvents { selectedAudioTrack?: SelectedTrack; selectedTextTrack?: SelectedTrack; selectedVideoTrack?: SelectedVideoTrack; // android + startPosition?: number; subtitleStyle?: SubtitleStyle; // android textTracks?: TextTracks; trackId?: string; // Android From 7a1d04a49e0f786008dd2d7fd3f1281f3abb91d1 Mon Sep 17 00:00:00 2001 From: YangJH Date: Fri, 17 Nov 2023 04:54:06 +0900 Subject: [PATCH 04/10] docs: fix typo --- docs/pages/component/props.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/pages/component/props.md b/docs/pages/component/props.md index 3cf74e67d1..965dfa7b36 100644 --- a/docs/pages/component/props.md +++ b/docs/pages/component/props.md @@ -160,10 +160,12 @@ Note on iOS, controls are always shown when in fullscreen mode. Note on Android, native controls are available by default. If needed, you can also add your controls or use a package like [react-native-video-controls](https://github.com/itsnubix/react-native-video-controls) or [react-native-media-console](https://github.com/criszz77/react-native-media-console), see [Useful Side Project](/projects). +Platforms: Android, iOS + ### `contentStartTime` The start time in ms for SSAI content. This determines at what time to load the video info like resolutions. Use this only when you have SSAI stream where ads resolution is not the same as content resolution. -Platforms: Android, iOS +Platforms: Android ### `debug` From 9e99e389988c933504e39424d234df0c6db2532c Mon Sep 17 00:00:00 2001 From: YangJH Date: Fri, 17 Nov 2023 05:11:42 +0900 Subject: [PATCH 05/10] docs: update startPosition --- docs/pages/component/props.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/pages/component/props.md b/docs/pages/component/props.md index 965dfa7b36..068457735c 100644 --- a/docs/pages/component/props.md +++ b/docs/pages/component/props.md @@ -691,6 +691,14 @@ source={{ Platforms: tvOS +### `startPosition` +The start time of video +* **1** - 1s +* **0** - ignore +* **Negative values** - ignore + +Platforms: Android, iOS + ### `subtitleStyle` Property | Description | Platforms From 6bb5816990088e48297f7389b9df27c22b448021 Mon Sep 17 00:00:00 2001 From: YangJH Date: Sun, 19 Nov 2023 23:52:19 +0900 Subject: [PATCH 06/10] refactor: put startPosition inside source prop - put startPosition inside source prop - rename existing prop (startTime, endTime) --- .../exoplayer/ReactExoplayerView.java | 44 +++++++++---------- .../exoplayer/ReactExoplayerViewManager.java | 17 +++---- ios/Video/DataStructures/VideoSource.swift | 15 ++++--- ios/Video/Features/RCTVideoUtils.swift | 8 ++-- ios/Video/RCTVideo.swift | 18 ++++---- ios/Video/RCTVideoManager.m | 1 - src/VideoNativeComponent.ts | 6 +-- src/types/video.ts | 6 +-- 8 files changed, 56 insertions(+), 59 deletions(-) diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 316a6c9a28..4c8278b42c 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -192,8 +192,9 @@ public class ReactExoplayerView extends FrameLayout implements // Props from React private int backBufferDurationMs = DefaultLoadControl.DEFAULT_BACK_BUFFER_DURATION_MS; private Uri srcUri; - private long startTimeMs = -1; - private long endTimeMs = -1; + private long startPositionMs = -1; + private long cropStartMs = -1; + private long cropEndMs = -1; private String extension; private boolean repeat; private String audioTrackType; @@ -206,7 +207,6 @@ public class ReactExoplayerView extends FrameLayout implements private boolean disableFocus; private boolean focusable = true; private boolean disableBuffering; - private long startPosition = -1L; private long contentStartTime = -1L; private boolean disableDisconnectError; private boolean preventsDisplaySleepDuringVideoPlayback = true; @@ -662,7 +662,7 @@ private DrmSessionManager initializePlayerDrm(ReactExoplayerView self) { private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager drmSessionManager) { ArrayList mediaSourceList = buildTextSources(); - MediaSource videoSource = buildMediaSource(self.srcUri, self.extension, drmSessionManager, startTimeMs, endTimeMs); + MediaSource videoSource = buildMediaSource(self.srcUri, self.extension, drmSessionManager, cropStartMs, cropEndMs); MediaSource mediaSourceWithAds = null; if (adTagUrl != null) { MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory) @@ -703,8 +703,8 @@ private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager d if (haveResumePosition) { player.seekTo(resumeWindow, resumePosition); } - if (startPosition >= 0) { - player.setMediaSource(mediaSource, startPosition); + if (startPositionMs > 0) { + player.setMediaSource(mediaSource, startPositionMs); } else { player.setMediaSource(mediaSource, !haveResumePosition); } @@ -766,7 +766,7 @@ private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, S } } - private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager, long startTimeMs, long endTimeMs) { + private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager, long cropStartMs, long cropEndMs) { if (uri == null) { throw new IllegalStateException("Invalid video uri"); } @@ -827,12 +827,12 @@ private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessi ) .createMediaSource(mediaItem); - if (startTimeMs >= 0 && endTimeMs >= 0) { - return new ClippingMediaSource(mediaSource, startTimeMs * 1000, endTimeMs * 1000); - } else if (startTimeMs >= 0) { - return new ClippingMediaSource(mediaSource, startTimeMs * 1000, TIME_END_OF_SOURCE); - } else if (endTimeMs >= 0) { - return new ClippingMediaSource(mediaSource, 0, endTimeMs * 1000); + if (cropStartMs >= 0 && cropEndMs >= 0) { + return new ClippingMediaSource(mediaSource, cropStartMs * 1000, cropEndMs * 1000); + } else if (cropStartMs >= 0) { + return new ClippingMediaSource(mediaSource, cropStartMs * 1000, TIME_END_OF_SOURCE); + } else if (cropEndMs >= 0) { + return new ClippingMediaSource(mediaSource, 0, cropEndMs * 1000); } return mediaSource; @@ -1506,13 +1506,14 @@ public void onMetadata(@NonNull Metadata metadata) { // ReactExoplayerViewManager public api - public void setSrc(final Uri uri, final long startTimeMs, final long endTimeMs, final String extension, Map headers) { + public void setSrc(final Uri uri, final long startPositionMs, final long cropStartMs, final long cropEndMs, final String extension, Map headers) { if (uri != null) { - boolean isSourceEqual = uri.equals(srcUri) && startTimeMs == this.startTimeMs && endTimeMs == this.endTimeMs; + boolean isSourceEqual = uri.equals(srcUri) && cropStartMs == this.cropStartMs && cropEndMs == this.cropEndMs; hasDrmFailed = false; this.srcUri = uri; - this.startTimeMs = startTimeMs; - this.endTimeMs = endTimeMs; + this.startPositionMs = startPositionMs; + this.cropStartMs = cropStartMs; + this.cropEndMs = cropEndMs; this.extension = extension; this.requestHeaders = headers; this.mediaDataSourceFactory = @@ -1530,8 +1531,9 @@ public void clearSrc() { player.stop(); player.clearMediaItems(); this.srcUri = null; - this.startTimeMs = -1; - this.endTimeMs = -1; + this.startPositionMs = -1; + this.cropStartMs = -1; + this.cropEndMs = -1; this.extension = null; this.requestHeaders = null; this.mediaDataSourceFactory = null; @@ -1923,10 +1925,6 @@ public void setBackBufferDurationMs(int backBufferDurationMs) { this.backBufferDurationMs = backBufferDurationMs; } - public void setStartPosition(long startPosition) { - this.startPosition = startPosition; - } - public void setContentStartTime(int contentStartTime) { this.contentStartTime = contentStartTime; } diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index edf0eda63b..7cf6cbb24d 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -36,8 +36,9 @@ public class ReactExoplayerViewManager extends ViewGroupManager headers = src.hasKey(PROP_SRC_HEADERS) ? ReactBridgeUtils.toStringMap(src.getMap(PROP_SRC_HEADERS)) : new HashMap<>(); @@ -167,7 +169,7 @@ public void setSrc(final ReactExoplayerView videoView, @Nullable ReadableMap src Uri srcUri = Uri.parse(uriString); if (srcUri != null) { - videoView.setSrc(srcUri, startTimeMs, endTimeMs, extension, headers); + videoView.setSrc(srcUri, startPositionMs, cropStartMs, cropEndMs, extension, headers); } } else { int identifier = context.getResources().getIdentifier( @@ -346,11 +348,6 @@ public void setBackBufferDurationMs(final ReactExoplayerView videoView, final in videoView.setBackBufferDurationMs(backBufferDurationMs); } - @ReactProp(name = PROP_START_POSITION, defaultFloat = -1.0f) - public void setStartPosition(final ReactExoplayerView videoView, final float startPosition) { - videoView.setStartPosition(Math.round(startPosition * 1000f)); - } - @ReactProp(name = PROP_CONTENT_START_TIME, defaultInt = -1) public void setContentStartTime(final ReactExoplayerView videoView, final int contentStartTime) { videoView.setContentStartTime(contentStartTime); diff --git a/ios/Video/DataStructures/VideoSource.swift b/ios/Video/DataStructures/VideoSource.swift index 59dca89f54..368310b5ca 100644 --- a/ios/Video/DataStructures/VideoSource.swift +++ b/ios/Video/DataStructures/VideoSource.swift @@ -6,8 +6,9 @@ struct VideoSource { let isAsset: Bool let shouldCache: Bool let requestHeaders: Dictionary? - let startTime: Int64? - let endTime: Int64? + let startPosition: Int64? + let cropStart: Int64? + let cropEnd: Int64? // Custom Metadata let title: String? let subtitle: String? @@ -25,8 +26,9 @@ struct VideoSource { self.isAsset = false self.shouldCache = false self.requestHeaders = nil - self.startTime = nil - self.endTime = nil + self.startPosition = nil + self.cropStart = nil + self.cropEnd = nil self.title = nil self.subtitle = nil self.description = nil @@ -40,8 +42,9 @@ struct VideoSource { self.isAsset = json["isAsset"] as? Bool ?? false self.shouldCache = json["shouldCache"] as? Bool ?? false self.requestHeaders = json["requestHeaders"] as? Dictionary - self.startTime = json["startTime"] as? Int64 - self.endTime = json["endTime"] as? Int64 + self.startPosition = json["startPosition"] as? Int64 + self.cropStart = json["cropStart"] as? Int64 + self.cropEnd = json["cropEnd"] as? Int64 self.title = json["title"] as? String self.subtitle = json["subtitle"] as? String self.description = json["description"] as? String diff --git a/ios/Video/Features/RCTVideoUtils.swift b/ios/Video/Features/RCTVideoUtils.swift index 3e0ef3bb36..bde3f309dd 100644 --- a/ios/Video/Features/RCTVideoUtils.swift +++ b/ios/Video/Features/RCTVideoUtils.swift @@ -19,8 +19,8 @@ enum RCTVideoUtils { return 0 } - if (source?.startTime != nil && source?.endTime != nil) { - return NSNumber(value: (Float64(source?.endTime ?? 0) - Float64(source?.startTime ?? 0)) / 1000) + if (source?.cropStart != nil && source?.cropEnd != nil) { + return NSNumber(value: (Float64(source?.cropEnd ?? 0) - Float64(source?.cropStart ?? 0)) / 1000) } var effectiveTimeRange:CMTimeRange? @@ -35,8 +35,8 @@ enum RCTVideoUtils { if let effectiveTimeRange = effectiveTimeRange { let playableDuration:Float64 = CMTimeGetSeconds(CMTimeRangeGetEnd(effectiveTimeRange)) if playableDuration > 0 { - if (source?.startTime != nil) { - return NSNumber(value: (playableDuration - Float64(source?.startTime ?? 0) / 1000)) + if (source?.cropStart != nil) { + return NSNumber(value: (playableDuration - Float64(source?.cropStart ?? 0) / 1000)) } return playableDuration as NSNumber diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index 56d12c8a47..1646904e0f 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -66,7 +66,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH private var _filterEnabled:Bool = false private var _presentingViewController:UIViewController? private var _pictureInPictureEnabled = false - private var _startPosition:Float = -1 + private var _startPosition:Float64 = -1 /* IMA Ads */ private var _adTagUrl:String? @@ -252,8 +252,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH } var currentTime = _player?.currentTime() - if (currentTime != nil && _source?.startTime != nil) { - currentTime = CMTimeSubtract(currentTime!, CMTimeMake(value: _source?.startTime ?? 0, timescale: 1000)) + if (currentTime != nil && _source?.cropStart != nil) { + currentTime = CMTimeSubtract(currentTime!, CMTimeMake(value: _source?.cropStart ?? 0, timescale: 1000)) } let currentPlaybackTime = _player?.currentItem?.currentDate() let duration = CMTimeGetSeconds(playerDuration) @@ -317,6 +317,10 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH throw NSError(domain: "", code: 0, userInfo: nil) } + if let startPosition = self._source?.startPosition { + self._startPosition = Float64(startPosition) / 1000 + } + #if USE_VIDEO_CACHING if self._videoCache.shouldCache(source:source, textTracks:self._textTracks) { return self._videoCache.playerItemForSourceUsingCache(uri: source.uri, assetOptions:assetOptions) @@ -342,7 +346,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH self._playerItem = playerItem self._playerObserver.playerItem = self._playerItem self.setPreferredForwardBufferDuration(self._preferredForwardBufferDuration) - self.setPlaybackRange(playerItem, withVideoStart: self._source?.startTime, withVideoEnd: self._source?.endTime) + self.setPlaybackRange(playerItem, withVideoStart: self._source?.cropStart, withVideoEnd: self._source?.cropEnd) self.setFilter(self._filterName) if let maxBitRate = self._maxBitRate { self._playerItem?.preferredPeakBitRate = Double(maxBitRate) @@ -602,10 +606,6 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH _pendingSeek = false } - @objc - func setStartPosition(_ startPosition:Float) { - _startPosition = startPosition - } @objc func setRate(_ rate:Float) { @@ -1185,7 +1185,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH if _startPosition > 0 { setSeek([ - "time": NSNumber(value: _cursor), + "time": NSNumber(value: _startPosition), "tolerance": NSNumber(value: 100) ]) _startPosition = -1 diff --git a/ios/Video/RCTVideoManager.m b/ios/Video/RCTVideoManager.m index 6046b64895..291868eb71 100644 --- a/ios/Video/RCTVideoManager.m +++ b/ios/Video/RCTVideoManager.m @@ -29,7 +29,6 @@ @interface RCT_EXTERN_MODULE(RCTVideoManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(mixWithOthers, NSString); RCT_EXPORT_VIEW_PROPERTY(rate, float); RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary); -RCT_EXPORT_VIEW_PROPERTY(startPosition, float); RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL); RCT_EXPORT_VIEW_PROPERTY(fullscreenAutorotate, BOOL); RCT_EXPORT_VIEW_PROPERTY(fullscreenOrientation, NSString); diff --git a/src/VideoNativeComponent.ts b/src/VideoNativeComponent.ts index 4035f80fa0..bcafd137b6 100644 --- a/src/VideoNativeComponent.ts +++ b/src/VideoNativeComponent.ts @@ -23,8 +23,9 @@ type VideoSrc = Readonly<{ mainVer?: number; patchVer?: number; requestHeaders?: Headers; - startTime?: number; - endTime?: number; + startPosition?: number; + cropStart?: number; + cropEnd?: number; title?: string; subtitle?: string; description?: string; @@ -274,7 +275,6 @@ export interface VideoNativeProps extends ViewProps { textTracks?: TextTracks; selectedTextTrack?: SelectedTextTrack; selectedAudioTrack?: SelectedAudioTrack; - startPosition?: number; paused?: boolean; muted?: boolean; controls?: boolean; diff --git a/src/types/video.ts b/src/types/video.ts index 28461d2a0b..34b0b3d5f1 100644 --- a/src/types/video.ts +++ b/src/types/video.ts @@ -15,8 +15,9 @@ export type ReactVideoSourceProperties = { mainVer?: number; patchVer?: number; headers?: Headers; - startTime?: number; - endTime?: number; + startPosition?: number; + cropStart?: number; + cropEnd?: number; title?: string; subtitle?: string; description?: string; @@ -212,7 +213,6 @@ export interface ReactVideoProps extends ReactVideoEvents { selectedAudioTrack?: SelectedTrack; selectedTextTrack?: SelectedTrack; selectedVideoTrack?: SelectedVideoTrack; // android - startPosition?: number; subtitleStyle?: SubtitleStyle; // android textTracks?: TextTracks; trackId?: string; // Android From 0369f8c16f937179092c5ec9de1ec739d10e40aa Mon Sep 17 00:00:00 2001 From: YangJH Date: Mon, 20 Nov 2023 00:03:36 +0900 Subject: [PATCH 07/10] docs: update startPosition property description --- docs/pages/component/props.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/pages/component/props.md b/docs/pages/component/props.md index ad4c3bcd30..d132d9d9ab 100644 --- a/docs/pages/component/props.md +++ b/docs/pages/component/props.md @@ -658,18 +658,24 @@ type: 'mpd' }} The following other types are supported on some platforms, but aren't fully documented yet: `content://, ms-appx://, ms-appdata://, assets-library://` +#### Start playback at a specific point in time + +Provide an optional `startPosition` for video. Value is in milliseconds. If the `cropStart` prop is applied, it will be applied from that point forward. +(If it is zero or negative, it is ignored) + +Platforms: Android, iOS #### Playing only a portion of the video (start & end time) -Provide an optional `startTime` and/or `endTime` for the video. Value is in milliseconds. Useful when you want to play only a portion of a large video. +Provide an optional `cropStart` and/or `cropEnd` for the video. Value is in milliseconds. Useful when you want to play only a portion of a large video. Example ```javascript -source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', startTime: 36012, endTime: 48500 }} +source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', cropStart: 36012, cropEnd: 48500 }} -source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', startTime: 36012 }} +source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', cropStart: 36012 }} -source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', endTime: 48500 }} +source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', cropEnd: 48500 }} ``` Platforms: iOS, Android @@ -693,14 +699,6 @@ source={{ Platforms: tvOS -### `startPosition` -The start time of video -* **1** - 1s -* **0** - ignore -* **Negative values** - ignore - -Platforms: Android, iOS - ### `subtitleStyle` Property | Description | Platforms From c0f3d3dd8c05c2eb44ac4b46e67613eb99bf0515 Mon Sep 17 00:00:00 2001 From: YangJH Date: Mon, 20 Nov 2023 00:16:10 +0900 Subject: [PATCH 08/10] fix: fix invalid assignments --- src/Video.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Video.tsx b/src/Video.tsx index a0193a8737..e1ab7fdb6b 100644 --- a/src/Video.tsx +++ b/src/Video.tsx @@ -148,8 +148,9 @@ const Video = forwardRef( mainVer: resolvedSource.mainVer || 0, patchVer: resolvedSource.patchVer || 0, requestHeaders: resolvedSource?.headers || {}, - startTime: resolvedSource.startTime || 0, - endTime: resolvedSource.endTime, + startPosition: resolvedSource.startPosition || -1, + cropStart: resolvedSource.cropStart || 0, + cropEnd: resolvedSource.cropEnd, title: resolvedSource.title, subtitle: resolvedSource.subtitle, description: resolvedSource.description, From 4fb8b038ac34dfffcd35f7989f8b65708e4d8e56 Mon Sep 17 00:00:00 2001 From: YangJH Date: Mon, 20 Nov 2023 00:17:41 +0900 Subject: [PATCH 09/10] refactor: remove redundant optional chaining --- src/Video.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Video.tsx b/src/Video.tsx index e1ab7fdb6b..61441ed8c5 100644 --- a/src/Video.tsx +++ b/src/Video.tsx @@ -147,7 +147,7 @@ const Video = forwardRef( type: resolvedSource.type || '', mainVer: resolvedSource.mainVer || 0, patchVer: resolvedSource.patchVer || 0, - requestHeaders: resolvedSource?.headers || {}, + requestHeaders: resolvedSource.headers || {}, startPosition: resolvedSource.startPosition || -1, cropStart: resolvedSource.cropStart || 0, cropEnd: resolvedSource.cropEnd, From dcf1434f112c441f31794ebd9987057e0da8a0be Mon Sep 17 00:00:00 2001 From: YangJH Date: Mon, 20 Nov 2023 09:23:10 +0900 Subject: [PATCH 10/10] feat: allow "0" to work too --- .../main/java/com/brentvatne/exoplayer/ReactExoplayerView.java | 2 +- docs/pages/component/props.md | 2 +- ios/Video/RCTVideo.swift | 2 +- src/Video.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 4c8278b42c..d9fc534be0 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -703,7 +703,7 @@ private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager d if (haveResumePosition) { player.seekTo(resumeWindow, resumePosition); } - if (startPositionMs > 0) { + if (startPositionMs >= 0) { player.setMediaSource(mediaSource, startPositionMs); } else { player.setMediaSource(mediaSource, !haveResumePosition); diff --git a/docs/pages/component/props.md b/docs/pages/component/props.md index d132d9d9ab..7b27244344 100644 --- a/docs/pages/component/props.md +++ b/docs/pages/component/props.md @@ -661,7 +661,7 @@ The following other types are supported on some platforms, but aren't fully docu #### Start playback at a specific point in time Provide an optional `startPosition` for video. Value is in milliseconds. If the `cropStart` prop is applied, it will be applied from that point forward. -(If it is zero or negative, it is ignored) +(If it is negative or undefined or null, it is ignored) Platforms: Android, iOS diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index 1646904e0f..dfdde5c566 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -1183,7 +1183,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH _pendingSeek = false } - if _startPosition > 0 { + if _startPosition >= 0 { setSeek([ "time": NSNumber(value: _startPosition), "tolerance": NSNumber(value: 100) diff --git a/src/Video.tsx b/src/Video.tsx index 61441ed8c5..7f99651e7d 100644 --- a/src/Video.tsx +++ b/src/Video.tsx @@ -148,7 +148,7 @@ const Video = forwardRef( mainVer: resolvedSource.mainVer || 0, patchVer: resolvedSource.patchVer || 0, requestHeaders: resolvedSource.headers || {}, - startPosition: resolvedSource.startPosition || -1, + startPosition: resolvedSource.startPosition ?? -1, cropStart: resolvedSource.cropStart || 0, cropEnd: resolvedSource.cropEnd, title: resolvedSource.title,