66import android .os .Looper ;
77
88import androidx .media3 .common .C ;
9- import androidx .media3 .common .MediaItem ;
109import androidx .media3 .common .Player ;
10+ import androidx .media3 .common .Timeline ;
1111import androidx .media3 .exoplayer .DefaultLoadControl ;
1212import androidx .media3 .exoplayer .DefaultRenderersFactory ;
1313import androidx .media3 .exoplayer .ExoPlayer ;
14+ import androidx .media3 .exoplayer .source .ConcatenatingMediaSource ;
15+ import androidx .media3 .exoplayer .source .ConcatenatingMediaSource2 ;
1416import androidx .media3 .exoplayer .source .MediaSource ;
1517import androidx .media3 .exoplayer .trackselection .DefaultTrackSelector ;
1618
1719
1820import java .io .FileDescriptor ;
19- import java .util .ArrayList ;
2021import java .util .List ;
2122import java .util .Map ;
2223
2324import tv .danmaku .ijk .media .exo2 .IjkExo2MediaPlayer ;
2425import tv .danmaku .ijk .media .exo2 .demo .EventLogger ;
25- import tv .danmaku .ijk .media .player .IMediaPlayer ;
2626
2727/**
2828 * 自定义exo player,实现不同于库的exo 无缝切换效果
@@ -31,14 +31,14 @@ public class GSYExo2MediaPlayer extends IjkExo2MediaPlayer {
3131
3232 private static final String TAG = "GSYExo2MediaPlayer" ;
3333
34- private static final long PLAYLIST_PRELOAD_DURATION_US = 3_000_000L ;
34+ private static final long MAX_POSITION_FOR_SEEK_TO_PREVIOUS = 3000 ;
35+
36+ private final Timeline .Window window = new Timeline .Window ();
3537
3638 public static final int POSITION_DISCONTINUITY = 899 ;
3739
3840 private int playIndex = 0 ;
3941
40- private final List <MediaSource > mediaSources = new ArrayList <>();
41-
4242 public GSYExo2MediaPlayer (Context context ) {
4343 super (context );
4444 }
@@ -70,33 +70,33 @@ public void setDataSource(FileDescriptor fd) {
7070 @ Override
7171 public void onPositionDiscontinuity (Player .PositionInfo oldPosition , Player .PositionInfo newPosition , @ Player .DiscontinuityReason int reason ) {
7272 super .onPositionDiscontinuity (oldPosition , newPosition , reason );
73- if (oldPosition .mediaItemIndex != newPosition .mediaItemIndex ) {
74- playIndex = newPosition .mediaItemIndex ;
75- notifyOnInfo (POSITION_DISCONTINUITY , reason );
76- }
77- }
78-
79- @ Override
80- public void onMediaItemTransition (MediaItem mediaItem , @ Player .MediaItemTransitionReason int reason ) {
81- if (mInternalPlayer != null ) {
82- playIndex = mInternalPlayer .getCurrentMediaItemIndex ();
83- notifyOnInfo (POSITION_DISCONTINUITY , reason );
84- }
73+ notifyOnInfo (POSITION_DISCONTINUITY , reason );
8574 }
8675
8776 public void setDataSource (List <String > uris , Map <String , String > headers , int index , boolean cache ) {
8877 mHeaders = headers ;
89- mediaSources .clear ();
90- mMediaSource = null ;
9178 if (uris == null ) {
9279 return ;
9380 }
81+ ConcatenatingMediaSource concatenatedSource = new ConcatenatingMediaSource ();
9482 for (String uri : uris ) {
9583 MediaSource mediaSource = mExoHelper .getMediaSource (uri , isPreview , cache , false , mCacheDir , getOverrideExtension ());
96- mediaSources . add (mediaSource );
84+ concatenatedSource . addMediaSource (mediaSource );
9785 }
9886 playIndex = index ;
99- mMediaSource = mediaSources .isEmpty () ? null : mediaSources .get (0 );
87+ mMediaSource = concatenatedSource ;
88+
89+
90+ /// ConcatenatingMediaSource2 是把多个视频拼成一个播放,时间轴只有一个
91+ // ConcatenatingMediaSource2.Builder mediaSourceBuilder =
92+ // new ConcatenatingMediaSource2.Builder().useDefaultMediaSourceFactory(mAppContext);
93+ //
94+ // for (String uri : uris) {
95+ // MediaSource mediaSource = mExoHelper.getMediaSource(uri, isPreview, cache, false, mCacheDir, getOverrideExtension());
96+ // mediaSourceBuilder.add(mediaSource, 0);
97+ // }
98+ // playIndex = index;
99+ // mMediaSource = mediaSourceBuilder.build();
100100 }
101101
102102
@@ -107,10 +107,20 @@ public void previous() {
107107 if (mInternalPlayer == null ) {
108108 return ;
109109 }
110- if (!mInternalPlayer .hasPreviousMediaItem ()) {
110+ Timeline timeline = mInternalPlayer .getCurrentTimeline ();
111+ if (timeline .isEmpty ()) {
111112 return ;
112113 }
113- mInternalPlayer .seekToPreviousMediaItem ();
114+ int windowIndex = mInternalPlayer .getCurrentMediaItemIndex ();
115+ timeline .getWindow (windowIndex , window );
116+ int previousWindowIndex = mInternalPlayer .getPreviousMediaItemIndex ();
117+ if (previousWindowIndex != C .INDEX_UNSET
118+ && (mInternalPlayer .getCurrentPosition () <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS
119+ || (window .isDynamic && !window .isSeekable ))) {
120+ mInternalPlayer .seekTo (previousWindowIndex , C .TIME_UNSET );
121+ } else {
122+ mInternalPlayer .seekTo (0 );
123+ }
114124 }
115125
116126 @ Override
@@ -140,8 +150,6 @@ public void run() {
140150 .setLooper (Looper .getMainLooper ())
141151 .setTrackSelector (mTrackSelector )
142152 .setLoadControl (mLoadControl ).build ();
143- mInternalPlayer .setPreloadConfiguration (
144- new ExoPlayer .PreloadConfiguration (PLAYLIST_PRELOAD_DURATION_US ));
145153
146154 mInternalPlayer .addListener (GSYExo2MediaPlayer .this );
147155 mInternalPlayer .addAnalyticsListener (GSYExo2MediaPlayer .this );
@@ -151,16 +159,11 @@ public void run() {
151159 }
152160 if (mSurface != null )
153161 mInternalPlayer .setVideoSurface (mSurface );
154- if (isLooping ) {
155- mInternalPlayer .setRepeatMode (Player .REPEAT_MODE_ALL );
156- }
157- if (mediaSources .isEmpty ()) {
158- notifyOnError (IMediaPlayer .MEDIA_ERROR_UNKNOWN , IMediaPlayer .MEDIA_ERROR_UNKNOWN );
159- release ();
160- return ;
162+ ///fix start index
163+ if (playIndex > 0 ) {
164+ mInternalPlayer .seekTo (playIndex , C .INDEX_UNSET );
161165 }
162- int startIndex = Math .min (Math .max (0 , playIndex ), mediaSources .size () - 1 );
163- mInternalPlayer .setMediaSources (mediaSources , startIndex , C .TIME_UNSET );
166+ mInternalPlayer .setMediaSource (mMediaSource , false );
164167 mInternalPlayer .prepare ();
165168 mInternalPlayer .setPlayWhenReady (false );
166169 }
@@ -175,18 +178,17 @@ public void next() {
175178 if (mInternalPlayer == null ) {
176179 return ;
177180 }
178- if (!mInternalPlayer .hasNextMediaItem ()) {
181+ Timeline timeline = mInternalPlayer .getCurrentTimeline ();
182+ if (timeline .isEmpty ()) {
179183 return ;
180184 }
181- mInternalPlayer .seekToNextMediaItem ();
182- }
183-
184- public boolean hasNext () {
185- return mInternalPlayer != null && mInternalPlayer .hasNextMediaItem ();
186- }
187-
188- public boolean hasPrevious () {
189- return mInternalPlayer != null && mInternalPlayer .hasPreviousMediaItem ();
185+ int windowIndex = mInternalPlayer .getCurrentMediaItemIndex ();
186+ int nextWindowIndex = mInternalPlayer .getNextMediaItemIndex ();
187+ if (nextWindowIndex != C .INDEX_UNSET ) {
188+ mInternalPlayer .seekTo (nextWindowIndex , C .TIME_UNSET );
189+ } else if (timeline .getWindow (windowIndex , window ).isDynamic ) {
190+ mInternalPlayer .seekTo (windowIndex , C .TIME_UNSET );
191+ }
190192 }
191193
192194 public int getCurrentWindowIndex () {
0 commit comments