forked from recloudstream/cloudstream
		
	Improved video loading speed by fixing regression caused by ProgressiveMediaSource
This commit is contained in:
		
							parent
							
								
									ff63d54412
								
							
						
					
					
						commit
						e04e6e686e
					
				
					 2 changed files with 68 additions and 76 deletions
				
			
		|  | @ -7,12 +7,10 @@ import android.util.Log | ||||||
| import android.widget.FrameLayout | import android.widget.FrameLayout | ||||||
| import com.google.android.exoplayer2.* | import com.google.android.exoplayer2.* | ||||||
| import com.google.android.exoplayer2.database.StandaloneDatabaseProvider | import com.google.android.exoplayer2.database.StandaloneDatabaseProvider | ||||||
| import com.google.android.exoplayer2.extractor.ExtractorsFactory |  | ||||||
| import com.google.android.exoplayer2.source.DefaultMediaSourceFactory | import com.google.android.exoplayer2.source.DefaultMediaSourceFactory | ||||||
| import com.google.android.exoplayer2.source.MergingMediaSource | import com.google.android.exoplayer2.source.MergingMediaSource | ||||||
| import com.google.android.exoplayer2.source.ProgressiveMediaSource | import com.google.android.exoplayer2.source.SingleSampleMediaSource | ||||||
| import com.google.android.exoplayer2.text.SubtitleDecoderFactory | import com.google.android.exoplayer2.text.TextRenderer | ||||||
| import com.google.android.exoplayer2.text.SubtitleExtractor |  | ||||||
| import com.google.android.exoplayer2.trackselection.DefaultTrackSelector | import com.google.android.exoplayer2.trackselection.DefaultTrackSelector | ||||||
| import com.google.android.exoplayer2.trackselection.TrackSelector | import com.google.android.exoplayer2.trackselection.TrackSelector | ||||||
| import com.google.android.exoplayer2.ui.SubtitleView | import com.google.android.exoplayer2.ui.SubtitleView | ||||||
|  | @ -37,7 +35,7 @@ const val TAG = "CS3ExoPlayer" | ||||||
| 
 | 
 | ||||||
| /** Cache */ | /** Cache */ | ||||||
| 
 | 
 | ||||||
| class CS3IPlayer : IPlayer { | class CS3IPlayer() : IPlayer { | ||||||
|     private var isPlaying = false |     private var isPlaying = false | ||||||
|     private var exoPlayer: ExoPlayer? = null |     private var exoPlayer: ExoPlayer? = null | ||||||
|     var cacheSize = 300L * 1024L * 1024L // 300 mb |     var cacheSize = 300L * 1024L * 1024L // 300 mb | ||||||
|  | @ -373,7 +371,7 @@ class CS3IPlayer : IPlayer { | ||||||
|         private fun buildExoPlayer( |         private fun buildExoPlayer( | ||||||
|             context: Context, |             context: Context, | ||||||
|             mediaItem: MediaItem, |             mediaItem: MediaItem, | ||||||
|             subSources: List<ProgressiveMediaSource>, |             subSources: List<SingleSampleMediaSource>, | ||||||
|             currentWindow: Int, |             currentWindow: Int, | ||||||
|             playbackPosition: Long, |             playbackPosition: Long, | ||||||
|             playBackSpeed: Float, |             playBackSpeed: Float, | ||||||
|  | @ -383,6 +381,21 @@ class CS3IPlayer : IPlayer { | ||||||
|         ): ExoPlayer { |         ): ExoPlayer { | ||||||
|             val exoPlayerBuilder = |             val exoPlayerBuilder = | ||||||
|                 ExoPlayer.Builder(context) |                 ExoPlayer.Builder(context) | ||||||
|  |                     .setRenderersFactory { eventHandler, videoRendererEventListener, audioRendererEventListener, textRendererOutput, metadataRendererOutput -> | ||||||
|  |                         DefaultRenderersFactory(context).createRenderers( | ||||||
|  |                             eventHandler, | ||||||
|  |                             videoRendererEventListener, | ||||||
|  |                             audioRendererEventListener, | ||||||
|  |                             textRendererOutput, | ||||||
|  |                             metadataRendererOutput | ||||||
|  |                         ).map { | ||||||
|  |                             if (it is TextRenderer) TextRenderer( | ||||||
|  |                                 textRendererOutput, | ||||||
|  |                                 eventHandler.looper, | ||||||
|  |                                 CustomSubtitleDecoderFactory() | ||||||
|  |                             ) else it | ||||||
|  |                         }.toTypedArray() | ||||||
|  |                     } | ||||||
|                     .setTrackSelector(trackSelector ?: getTrackSelector(context)) |                     .setTrackSelector(trackSelector ?: getTrackSelector(context)) | ||||||
| 
 | 
 | ||||||
|             val videoMediaSource = |             val videoMediaSource = | ||||||
|  | @ -472,7 +485,7 @@ class CS3IPlayer : IPlayer { | ||||||
|     private fun loadExo( |     private fun loadExo( | ||||||
|         context: Context, |         context: Context, | ||||||
|         mediaItem: MediaItem, |         mediaItem: MediaItem, | ||||||
|         subSources: List<ProgressiveMediaSource>, |         subSources: List<SingleSampleMediaSource>, | ||||||
|         cacheFactory: CacheDataSource.Factory? = null |         cacheFactory: CacheDataSource.Factory? = null | ||||||
|     ) { |     ) { | ||||||
|         Log.i(TAG, "loadExo") |         Log.i(TAG, "loadExo") | ||||||
|  | @ -595,68 +608,6 @@ class CS3IPlayer : IPlayer { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * https://github.com/google/ExoPlayer/blob/029a2b27cbdc27cf9d51d4a73ebeb503968849f6/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java |  | ||||||
|      * */ |  | ||||||
|     private fun createProgressiveMediaSources( |  | ||||||
|         subHelper: PlayerSubtitleHelper, |  | ||||||
|         offlineSourceFactory: DataSource.Factory?, |  | ||||||
|         onlineSourceFactory: DataSource.Factory?, |  | ||||||
|     ): Pair<List<SubtitleData>, List<ProgressiveMediaSource>> { |  | ||||||
|         val activeSubtitles = ArrayList<SubtitleData>() |  | ||||||
| 
 |  | ||||||
|         return Pair(activeSubtitles, subHelper.getAllSubtitles().mapNotNull { sub -> |  | ||||||
|             val format = Format.Builder() |  | ||||||
|                 .setSampleMimeType(sub.mimeType) |  | ||||||
|                 .setLanguage("_${sub.name}") |  | ||||||
|                 .setSelectionFlags(C.SELECTION_FLAG_DEFAULT) |  | ||||||
|                 .build() |  | ||||||
| 
 |  | ||||||
|             val ownFactory = CustomSubtitleDecoderFactory() |  | ||||||
|             val extractorFactory = ExtractorsFactory { |  | ||||||
|                 arrayOf( |  | ||||||
|                     if (ownFactory.supportsFormat(format)) { |  | ||||||
|                         SubtitleExtractor( |  | ||||||
|                             ownFactory.createDecoder(format), format |  | ||||||
|                         ) |  | ||||||
|                     } else { |  | ||||||
|                         if (SubtitleDecoderFactory.DEFAULT.supportsFormat(format)) { |  | ||||||
|                             SubtitleExtractor( |  | ||||||
|                                 SubtitleDecoderFactory.DEFAULT.createDecoder(format), format |  | ||||||
|                             ) |  | ||||||
|                         } else { |  | ||||||
|                             // ye we guess if not found instead of using UnknownSubtitlesExtractor, |  | ||||||
|                             // this way you can hopefully load a .txt file that is an srt and it will work |  | ||||||
|                             SubtitleExtractor( |  | ||||||
|                                 ownFactory.createDecoder(format), format |  | ||||||
|                             ) |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             val factory = when (sub.origin) { |  | ||||||
|                 SubtitleOrigin.DOWNLOADED_FILE -> { |  | ||||||
|                     activeSubtitles.add(sub) |  | ||||||
|                     offlineSourceFactory |  | ||||||
|                 } |  | ||||||
|                 SubtitleOrigin.URL -> { |  | ||||||
|                     activeSubtitles.add(sub) |  | ||||||
|                     onlineSourceFactory |  | ||||||
|                 } |  | ||||||
|                 SubtitleOrigin.OPEN_SUBTITLES -> { |  | ||||||
|                     null |  | ||||||
|                 } |  | ||||||
|             } ?: return@mapNotNull null |  | ||||||
| 
 |  | ||||||
|             return@mapNotNull ProgressiveMediaSource.Factory(factory, extractorFactory) |  | ||||||
|                 .createMediaSource( |  | ||||||
|                     MediaItem.fromUri(sub.url) |  | ||||||
|                 ) |  | ||||||
|         }) |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private fun loadOfflinePlayer(context: Context, data: ExtractorUri) { |     private fun loadOfflinePlayer(context: Context, data: ExtractorUri) { | ||||||
|         Log.i(TAG, "loadOfflinePlayer") |         Log.i(TAG, "loadOfflinePlayer") | ||||||
|         try { |         try { | ||||||
|  | @ -665,20 +616,60 @@ class CS3IPlayer : IPlayer { | ||||||
|             val mediaItem = getMediaItem(MimeTypes.VIDEO_MP4, data.uri) |             val mediaItem = getMediaItem(MimeTypes.VIDEO_MP4, data.uri) | ||||||
|             val offlineSourceFactory = context.createOfflineSource() |             val offlineSourceFactory = context.createOfflineSource() | ||||||
| 
 | 
 | ||||||
|             val (activeSubtitles, progressiveMediaSources) = createProgressiveMediaSources( |             val (subSources, activeSubtitles) = getSubSources( | ||||||
|  |                 offlineSourceFactory, | ||||||
|  |                 offlineSourceFactory, | ||||||
|                 subtitleHelper, |                 subtitleHelper, | ||||||
|                 offlineSourceFactory, |  | ||||||
|                 offlineSourceFactory, |  | ||||||
|             ) |             ) | ||||||
| 
 | 
 | ||||||
|             subtitleHelper.setActiveSubtitles(activeSubtitles.toSet()) |             subtitleHelper.setActiveSubtitles(activeSubtitles.toSet()) | ||||||
|             loadExo(context, mediaItem, progressiveMediaSources) |             loadExo(context, mediaItem, subSources) | ||||||
|         } catch (e: Exception) { |         } catch (e: Exception) { | ||||||
|             Log.e(TAG, "loadOfflinePlayer error", e) |             Log.e(TAG, "loadOfflinePlayer error", e) | ||||||
|             playerError?.invoke(e) |             playerError?.invoke(e) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private fun getSubSources( | ||||||
|  |         onlineSourceFactory: DataSource.Factory?, | ||||||
|  |         offlineSourceFactory: DataSource.Factory?, | ||||||
|  |         subHelper: PlayerSubtitleHelper, | ||||||
|  |     ): Pair<List<SingleSampleMediaSource>, List<SubtitleData>> { | ||||||
|  |         val activeSubtitles = ArrayList<SubtitleData>() | ||||||
|  |         val subSources = subHelper.getAllSubtitles().mapNotNull { sub -> | ||||||
|  |             val subConfig = MediaItem.SubtitleConfiguration.Builder(Uri.parse(sub.url)) | ||||||
|  |                 .setMimeType(sub.mimeType) | ||||||
|  |                 .setLanguage("_${sub.name}") | ||||||
|  |                 .setSelectionFlags(C.SELECTION_FLAG_DEFAULT) | ||||||
|  |                 .build() | ||||||
|  |             when (sub.origin) { | ||||||
|  |                 SubtitleOrigin.DOWNLOADED_FILE -> { | ||||||
|  |                     if (offlineSourceFactory != null) { | ||||||
|  |                         activeSubtitles.add(sub) | ||||||
|  |                         SingleSampleMediaSource.Factory(offlineSourceFactory) | ||||||
|  |                             .createMediaSource(subConfig, C.TIME_UNSET) | ||||||
|  |                     } else { | ||||||
|  |                         null | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 SubtitleOrigin.URL -> { | ||||||
|  |                     if (onlineSourceFactory != null) { | ||||||
|  |                         activeSubtitles.add(sub) | ||||||
|  |                         SingleSampleMediaSource.Factory(onlineSourceFactory) | ||||||
|  |                             .createMediaSource(subConfig, C.TIME_UNSET) | ||||||
|  |                     } else { | ||||||
|  |                         null | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 SubtitleOrigin.OPEN_SUBTITLES -> { | ||||||
|  |                     // TODO | ||||||
|  |                     throw NotImplementedError() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return Pair(subSources, activeSubtitles) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private fun loadOnlinePlayer(context: Context, link: ExtractorLink) { |     private fun loadOnlinePlayer(context: Context, link: ExtractorLink) { | ||||||
|         Log.i(TAG, "loadOnlinePlayer") |         Log.i(TAG, "loadOnlinePlayer") | ||||||
|         try { |         try { | ||||||
|  | @ -705,10 +696,10 @@ class CS3IPlayer : IPlayer { | ||||||
|             val onlineSourceFactory = createOnlineSource(link) |             val onlineSourceFactory = createOnlineSource(link) | ||||||
|             val offlineSourceFactory = context.createOfflineSource() |             val offlineSourceFactory = context.createOfflineSource() | ||||||
| 
 | 
 | ||||||
|             val (activeSubtitles, progressiveMediaSources) = createProgressiveMediaSources( |             val (subSources, activeSubtitles) = getSubSources( | ||||||
|                 subtitleHelper, |  | ||||||
|                 offlineSourceFactory, |                 offlineSourceFactory, | ||||||
|                 onlineSourceFactory, |                 onlineSourceFactory, | ||||||
|  |                 subtitleHelper | ||||||
|             ) |             ) | ||||||
| 
 | 
 | ||||||
|             subtitleHelper.setActiveSubtitles(activeSubtitles.toSet()) |             subtitleHelper.setActiveSubtitles(activeSubtitles.toSet()) | ||||||
|  | @ -721,7 +712,7 @@ class CS3IPlayer : IPlayer { | ||||||
|                 setUpstreamDataSourceFactory(onlineSourceFactory) |                 setUpstreamDataSourceFactory(onlineSourceFactory) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             loadExo(context, mediaItem, progressiveMediaSources, cacheFactory) |             loadExo(context, mediaItem, subSources, cacheFactory) | ||||||
|         } catch (e: Exception) { |         } catch (e: Exception) { | ||||||
|             Log.e(TAG, "loadOnlinePlayer error", e) |             Log.e(TAG, "loadOnlinePlayer error", e) | ||||||
|             playerError?.invoke(e) |             playerError?.invoke(e) | ||||||
|  |  | ||||||
|  | @ -126,6 +126,7 @@ class RepoLinkGenerator( | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             { link -> |             { link -> | ||||||
|  |                 Log.d(TAG, "Loaded ExtractorLink: $link") | ||||||
|                 if (!currentLinks.contains(link.url)) { |                 if (!currentLinks.contains(link.url)) { | ||||||
|                     if (!currentLinkCache.contains(link)) { |                     if (!currentLinkCache.contains(link)) { | ||||||
|                         currentLinks.add(link.url) |                         currentLinks.add(link.url) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue