Improved video loading speed by fixing regression caused by ProgressiveMediaSource

This commit is contained in:
Blatzar 2022-02-08 16:15:57 +01:00
parent ff63d54412
commit e04e6e686e
2 changed files with 68 additions and 76 deletions

View file

@ -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)

View file

@ -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)