In my application I want use exoplayer to play video and for this I added this dependency:
implementation 'com.google.android.exoplayer:exoplayer:2.18.0'
with simple way I can play video with this code:
player = ExoPlayer.Builder(this).build()
binding.player.player = player
// Build the media item.
val mediaItem: MediaItem = MediaItem.fromUri(url)
// Set the media item to be played.
player.setMediaItem(mediaItem)
// Prepare the player.
player.prepare()
// Start the playback.
player.play()
But I want add Header for video and for this I write below codes:
val dataSourceFactory: DataSource.Factory = DataSource.Factory {
val dataSource: HttpDataSource = httpDataSourceFactory.createDataSource()
// Set a custom authentication request header.
dataSource.setRequestProperty("Header", "Value")
dataSource
}
But in my code not found httpDataSourceFactory.
I used this link tutorial : https://exoplayer.dev/customization.html#customizing-server-interactions
How can I add header for exoplayer?
val dataSourceFactory = DefaultHttpDataSource.Factory()
.setDefaultRequestProperties(hashMapOf("Header" to "Value"))
val audioSource: MediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
Use the "DefaultHttpDataSource"
It only happens to specific audio. All other audio are working fine as expected. I'm using the following to create an exo player object
fun playAudio(id: Int, url: String) {
if (currentPlayingId == null || currentPlayingId != id) {
if (currentPlayingId != null) {
calculatePlayTimeAndUpdateServer(getCurrentItem()?.id)
}
val extractorsFactory = DefaultExtractorsFactory()
.setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING)
val mediaSource = ProgressiveMediaSource
.Factory(
DefaultDataSourceFactory(applicationContext, userAgent),
extractorsFactory
).setCustomCacheKey("exampleaudio$id")
.createMediaSource(MediaItem.fromUri(Uri.parse(url)))
val attr = AudioAttributes.Builder().setUsage(C.USAGE_MEDIA)
.setContentType(C.CONTENT_TYPE_MUSIC)
.build()
exoPlayer?.setAudioAttributes(attr, true)
exoPlayer?.setMediaSource(mediaSource)
exoPlayer?.prepare()
userSetPlayWhenReadyValue = true
exoPlayer?.playWhenReady = true
} else {
val oppositeValue = !isCurrentlyPlaying()
userSetPlayWhenReadyValue = oppositeValue
exoPlayer?.playWhenReady = oppositeValue
}
currentPlayingId = id
currentlyPlayingUrl = url
bottomListener?.onStatusChanged(exoPlayer?.playWhenReady ?: false)
}
When it plays it gives me the following exception.
2022-02-10 12:54:15.545 31333-9748/com.example.app E/ExoPlayerImplInternal: Playback error
com.google.android.exoplayer2.ExoPlaybackException: Source error
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleIoException(ExoPlayerImplInternal.java:628)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:598)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:246)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: com.google.android.exoplayer2.ParserException: Searched too many bytes.
at com.google.android.exoplayer2.extractor.mp3.Mp3Extractor.synchronize(Mp3Extractor.java:381)
at com.google.android.exoplayer2.extractor.mp3.Mp3Extractor.readInternal(Mp3Extractor.java:256)
at com.google.android.exoplayer2.extractor.mp3.Mp3Extractor.read(Mp3Extractor.java:229)
at com.google.android.exoplayer2.source.BundledExtractorsAdapter.read(BundledExtractorsAdapter.java:127)
at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:1046)
at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:409)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
I'm using the latest exoplayer of today which is 2.16.1. I'm using this mp3 AUDIO https://drive.google.com/file/d/1E3Xs_jS896po3AR0x1cBH_Com8b0N7Si/view?usp=sharing It perfectly works with my team who has the iOS device. I've already tried with all the different MP3Extractor formats
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING,
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING_ALWAYS,
FLAG_ENABLE_INDEX_SEEKING,
FLAG_DISABLE_ID3_METADATA
But still The issue still persists. Do I need to do something else when initializing the file or anything else? How to increase the size for the mp3Extractor when playing the audio file? Is there any way to do this in android? it only happens when running on Android 11 and above.
I am using ConcatenatingMediaSource to make hls urls playlist for my ExoPlayer.
when playing media sources by local files, it works fine without gap.
However, when playing media sources by hls urls, It noticeably shows gap while transition (first video to second one)
I want my media source transit smoothly in ConcatenatingMediaSource.
How can I achieve this?
Guide me please.
This below is my init code.
val playerView = findViewById<PlayerView>(R.id.playerView)
val concatenatedSource = ConcatenatingMediaSource()
val trackSelector = DefaultTrackSelector(mContext!!)
trackSelector.parameters = trackSelector.buildUponParameters().build()
val dataSourceFactory = DefaultHttpDataSource.Factory()
val hlsMediaSource: HlsMediaSource = HlsMediaSource.Factory(dataSourceFactory)
.setAllowChunklessPreparation(true)
.createMediaSource(MediaItem.fromUri("https://multiplatform-f.akamaihd.net/i/multi/april11/sintel/sintel-hd_,512x288_450_b,640x360_700_b,768x432_1000_b,1024x576_1400_m,.mp4.csmil/master.m3u8"))
concatenatedSource.addMediaSource(hlsMediaSource)
val player = ExoPlayer.Builder(mContext)
.setTrackSelector(trackSelector)
.build()
player.setMediaSource(concatenatedSource)
player.addAnalyticsListener(EventLogger(trackSelector))
player.addListener(object : Player.Listener {
override fun onPlayerError(error: PlaybackException) {
super.onPlayerError(error)
}
})
playerView?.player = player
playerView?.player?.prepare()
playerView?.player?.playWhenReady = true
For those who have this kind of issues, you should try CacheDataSource while building MediaItem objects. This resolved my issues. Thanks
I am using ExoPlayer to stream videos in a RecyclerView.
I am implementing the ExoPlayer inside my RecyclerView Adapter's bind method inside my ViewHolder.
The video format I am using is m3u8 and the URL I am using works in a browser.
So I know that the video link is valid. I've also testing a youtube link in there.
Here is the code from the Recyclerview adapter's ViewHolder ->
class ViewHolder private constructor(val binding: FeedRowBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(context: Activity){
if (entity.content.videolink != null) {
setupVideoPlayer(entity.content.videolink, context)
}
}
}
private fun setupVideoPlayer(url: String, context: Activity) {
val videoExoPlayer = SimpleExoPlayer.Builder(binding.videoView.context).build()
videoExoPlayer.prepare(createUrlMediaSource(url, context))
binding.play.setOnClickListener {
videoExoPlayer.playWhenReady = true
}
binding.pause.setOnClickListener {
videoExoPlayer.playWhenReady = false
}
}
private fun createUrlMediaSource(url: String, context: Activity): MediaSource {
val userAgent = Util.getUserAgent(context, context.getString(R.string.about))
return ProgressiveMediaSource
.Factory(DefaultDataSourceFactory(context, userAgent), DefaultExtractorsFactory())
.createMediaSource(Uri.parse(url))
}
When loading my recyclerview and get to the row with the video I get the following error:
ExoPlayerImplInternal: Source error.
com.google.android.exoplayer2.source.UnrecognizedInputFormatException:
None of the available extractors (MatroskaExtractor,
FragmentedMp4Extractor, Mp4Extractor, Mp3Extractor, AdtsExtractor,
Ac3Extractor, TsExtractor, FlvExtractor, OggExtractor, PsExtractor,
WavExtractor, AmrExtractor, Ac4Extractor, FlacExtractor) could read
the stream.
at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractorHolder.selectExtractor(ProgressiveMediaPeriod.java:1090)
at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:969)
at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:391)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
I'm not sure what am I doing wrong, any ideas on how to fix this issue?
You need to modify your createUrlMediaSource
private fun createUrlMediaSource(url: String, context: Activity): MediaSource {
val userAgent = Util.getUserAgent(context, context.getString(R.string.about))
return ProgressiveMediaSource
.Factory(DefaultDataSourceFactory(context, userAgent), DefaultExtractorsFactory())
.createMediaSource(Uri.parse(url))
}
as stated in https://exoplayer.dev
DashMediaSource for DASH.
SsMediaSource for SmoothStreaming.
HlsMediaSource for HLS (this is your format => .m3u8).
ProgressiveMediaSource for regular media files.
So you need to replace your function to this:
private fun createUrlMediaSource(url: String, context: Activity): MediaSource {
val userAgent = Util.getUserAgent(context, context.getString(R.string.about))
return HlsMediaSource
.Factory(DefaultDataSourceFactory(context, userAgent), DefaultExtractorsFactory())
.createMediaSource(Uri.parse(url))
}
I don't think m3u8 is a video format but rather a playlist format. I think Exoplayer is lower level than handling playlists; probably you need to read the m3u8 file yourself and then pass in the links in the playlist yourself.
Luckily the file format isn't complicated and it shouldn't be too difficult to parse. It seems it's pretty well documented. There's even some examples on Wikipedia: https://en.wikipedia.org/wiki/M3U
On Android 4.1+, you can use this library https://github.com/brianwernick/ExoMedia/ . The example mentioned on the Read-me page should be sufficient to get you started. I have reproduced that code snippet with a few additions/modifications.
private void setupVideoView() {
EMVideoView emVideoView = (EMVideoView)findViewById(R.id.video_play_activity_video_view);
emVideoView.setOnPreparedListener(this);
//Enter your m3u8 URL below
emVideoView.setVideoURI(Uri.parse("http://SOMESERVER/playlist.m3u8"));
}
#Override
public void onPrepared(MediaPlayer mp) {
//Starts the video playback as soon as it is ready
emVideoView.start();
}
#Override
public void onPause() {
super.onPause();
//Pause Video Playback
emVideoView.pause();
}
For streaming .m3u8 file use below code while initializing Exoplayer:-
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
videoPlayer = ExoPlayerFactory.newSimpleInstance(context,trackSelector);
Handler mHandler = new Handler();
String userAgent = Util.getUserAgent(context, "Exo Player");
DataSource.Factory dataSourceFactory = new DefaultHttpDataSourceFactory(
userAgent, null,
DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
1800000,
true);
HlsMediaSource mediaSource = new HlsMediaSource(Uri.parse(mediaUrl),dataSourceFactory, 1800000,mHandler, null);
if (mediaUrl != null) {
videoPlayer.prepare(mediaSource);
videoPlayer.setPlayWhenReady(true);
}
I am trying to play a video with exoplayer but it's taking too long to play.
How do I fix this issue?
PS - internet speed is not (so no speed issue)
private fun exoPlayerSetupVideo() {
var trackSelector = DefaultTrackSelector()
//var loadControl = DefaultLoadControl()
var exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector)
simpleExoPlayerView.player = exoPlayer
var dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, "VideoPlayer"))
var videoSource = ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(url1))
exoPlayer.prepare(videoSource)
exoPlayer.playWhenReady = true
}
Have you tried some video urls inside the assets folder that the exoplayer demo project provide? If they play normally means that exoplayer is not the problem.