Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement startPosition #3355

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
private static final String PROP_MIN_LOAD_RETRY_COUNT = "minLoadRetryCount";
private static final String PROP_MAXIMUM_BIT_RATE = "maxBitRate";
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
private static final String PROP_START_POSITION = "startPosition";
private static final String PROP_CONTENT_START_TIME = "contentStartTime";
private static final String PROP_DISABLE_FOCUS = "disableFocus";
private static final String PROP_DISABLE_BUFFERING = "disableBuffering";
Expand Down Expand Up @@ -345,6 +346,11 @@ 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);
Expand Down
12 changes: 11 additions & 1 deletion docs/pages/component/props.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch !


### `debug`

Expand Down Expand Up @@ -689,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
Expand Down
14 changes: 14 additions & 0 deletions ios/Video/RCTVideo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1180,6 +1186,14 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
_pendingSeek = false
}

if _startPosition > 0 {
freeboub marked this conversation as resolved.
Show resolved Hide resolved
setSeek([
"time": NSNumber(value: _cursor),
"tolerance": NSNumber(value: 100)
])
_startPosition = -1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it really need to force _startPosition to -1 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was assuming that the playback would work fine, then an error would occur, and then it would work again.

When the source is unchanged and the lifecycle is as follows,

(1) readyToPlay → (2) failed → (3) readyToPlay

I forced it to -1 because I would expect startPosition to not work in state (3).

But I'm not very experienced with iOS, and I don't know much about it. If my assumptions are wrong, feel free to let me know and I'll correct above code.

}

if _videoLoadStarted {
let audioTracks = RCTVideoUtils.getAudioTrackInfo(_player)
let textTracks = RCTVideoUtils.getTextTrackInfo(_player).map(\.json)
Expand Down
1 change: 1 addition & 0 deletions ios/Video/RCTVideoManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/VideoNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ export interface VideoNativeProps extends ViewProps {
textTracks?: TextTracks;
selectedTextTrack?: SelectedTextTrack;
selectedAudioTrack?: SelectedAudioTrack;
startPosition?: number;
paused?: boolean;
muted?: boolean;
controls?: boolean;
Expand Down
1 change: 1 addition & 0 deletions src/types/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down