Open MrBzik opened 1 year ago
I think you can inject your own MediaSource.Factory
that does this for you and in normal cases delegates to the default factory.
Something along these lines:
player =
ExoPlayer.Builder(this)
.setMediaSourceFactory(MyMediaSourceFactroy())
.build()
class MyMediaSourceFactory(context: Context, datasourceFactory: DataSource.Factory) : MediaSource.Factory {
private val defaultMediaSourceFactory: DefaultMediaSourceFactory
private val progressiveFactory : MediaSource.Factory
init {
defaultMediaSourceFactory = DefaultMediaSourceFactory(context)
progressiveFactory = ProgressiveMediaSource.Factory(datasourceFactory)
.setContinueLoadingCheckIntervalBytes(2028 * 2048)
}
override fun setDrmSessionManagerProvider(drmSessionManagerProvider: DrmSessionManagerProvider): MediaSource.Factory {
defaultMediaSourceFactory.setDrmSessionManagerProvider(drmSessionManagerProvider)
progressiveFactory.setDrmSessionManagerProvider(drmSessionManagerProvider)
return this;
}
override fun setLoadErrorHandlingPolicy(loadErrorHandlingPolicy: LoadErrorHandlingPolicy): MediaSource.Factory {
defaultMediaSourceFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
progressiveFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
return this
}
override fun getSupportedTypes(): IntArray {
return defaultMediaSourceFactory.supportedTypes
}
override fun createMediaSource(mediaItem: MediaItem): MediaSource {
if (mediaItem.localConfiguration?.uri?.path?.contains("m3u8") == true) {
return progressiveFactory.createMediaSource(mediaItem)
}
return defaultMediaSourceFactory.createMediaSource(mediaItem);
}
}
If you do this you can also take advantage of using player.setMediaItems(mediaItems)
instead of the MediaSource
version.
Hi. Thanks! This works perfectly Btw, m3u is not hls and should not necessarily handled by defaultMediaSourceFactory?
Ah, sorry. I have missed the m3u
extension. This is not supported by ExoPlayer (#Google/ExoPlayer/4066).
My example code was for HLS only.
How to custom http header for each mediaItem in MyMediaSourceFactory ?
@marcbaechinger You're doing great. but when url is m3u8 stream without m3u8 extensions,found err with "Source err",
i got format Util.inferContentType(uri)
is inter 4,means C.CONTENT_TYPE_OTHER, but it is hls, i can't change C.CONTENT_TYPE_OTHER -> ProgressiveMediaSource.Factory,because of some video is mp4,etc. here is my code
private fun buildMediaSource(
uri: Uri,
mediaDataSourceFactory: DataSource.Factory,
formatHint: String?,
cacheKey: String?,
context: Context
): MediaSource {
val type: Int = if (formatHint == null) {
Util.inferContentType(uri)
} else {
when (formatHint) {
FORMAT_SS -> C.CONTENT_TYPE_SS
FORMAT_DASH -> C.CONTENT_TYPE_DASH
FORMAT_HLS -> C.CONTENT_TYPE_HLS
FORMAT_OTHER -> C.CONTENT_TYPE_OTHER
FORMAT_RTSP -> C.CONTENT_TYPE_RTSP
else -> -1
}
}
val mediaItemBuilder = MediaItem.Builder()
mediaItemBuilder.setUri(uri)
if (!cacheKey.isNullOrEmpty()) {
mediaItemBuilder.setCustomCacheKey(cacheKey)
}
val mediaItem = mediaItemBuilder.build()
var drmSessionManagerProvider: DrmSessionManagerProvider? = null
drmSessionManager?.let { drmSessionManager ->
drmSessionManagerProvider = DrmSessionManagerProvider { drmSessionManager }
}
return when (type) {
C.CONTENT_TYPE_SS -> SsMediaSource.Factory(
DefaultSsChunkSource.Factory(mediaDataSourceFactory),
DefaultDataSource.Factory(context, mediaDataSourceFactory)
).apply {
if (drmSessionManagerProvider != null) {
setDrmSessionManagerProvider(drmSessionManagerProvider!!)
}
}
.createMediaSource(mediaItem)
C.CONTENT_TYPE_DASH -> DashMediaSource.Factory(
DefaultDashChunkSource.Factory(mediaDataSourceFactory),
DefaultDataSource.Factory(context, mediaDataSourceFactory)
).apply {
if (drmSessionManagerProvider != null) {
setDrmSessionManagerProvider(drmSessionManagerProvider!!)
}
}
.createMediaSource(mediaItem)
C.CONTENT_TYPE_HLS -> HlsMediaSource.Factory(mediaDataSourceFactory)
.apply {
if (drmSessionManagerProvider != null) {
setDrmSessionManagerProvider(drmSessionManagerProvider!!)
}
}
.createMediaSource(mediaItem)
C.CONTENT_TYPE_RTSP -> RtspMediaSource.Factory()
.apply {
if (drmSessionManagerProvider != null) {
setDrmSessionManagerProvider(drmSessionManagerProvider!!)
}
}
.createMediaSource(mediaItem)
C.CONTENT_TYPE_OTHER -> ProgressiveMediaSource.Factory(
mediaDataSourceFactory,
DefaultExtractorsFactory()
)
.apply {
if (drmSessionManagerProvider != null) {
setDrmSessionManagerProvider(drmSessionManagerProvider!!)
}
}
.createMediaSource(mediaItem)
else -> {
throw IllegalStateException("Unsupported type: $type")
}
}
}
any idea? when i use mpvplayer,work great! it's amazing ! sorry about my english is so bad! @MrBzik
The library can't help you with this I'm afraid. Yeah, you need to know the type of stream of an URI and then create the corresponding media source.
@marcbaechinger I fixed this! when i got err "Source err",
void debounceListen(Function? func, [int delay = 1000]) {
if (_debounceTimer != null) {
_debounceTimer?.cancel();
}
_debounceTimer = Timer(Duration(milliseconds: delay), () {
try {
tryHlsMethod() // try buildMediaSource with C.CONTENT_TYPE_HLS
} catch (e) {
log(e);
}
_debounceTimer = null;
});
}
Hi. I am getting lists of urls for audio streams, and some of them are hls. So I am using this logic, which is suitable for playing separate streams:
To play next/prev stream from notification/lock screen I need to pass list of mediaitems or concatenating mediasource to the player, and I don't see how I can switch between those two factories then. Maybe with DefaultMediaSourceFactory, but ideally I would like to keep setContinueLoadingCheckIntervalBytes setting. Is it possible, or should I look into custom actions of notification (i am using PlayerNotificationManager)?