Media3 ExoPlayer - DefaultTimeBar cannot be cast to TimeBar - android

Im migrating a Video screen from XML to Compose., I need to display Ads with the IMA plugin.
Right now, I'm using this dependencies:
implementation "androidx.media3:media3-ui:1.0.0-beta02"
implementation 'androidx.media3:media3-exoplayer:1.0.0-beta02'
implementation "androidx.media3:media3-exoplayer-ima:1.0.0-beta02"
And im implementing the player as follows:
#Composable
fun VideoPlayer(videoUri: String) {
val context = LocalContext.current
val exoPlayer = remember {
ExoPlayer.Builder(context)
.build()
.apply {
val defaultDataSourceFactory = DefaultDataSource.Factory(context)
val dataSourceFactory: DataSource.Factory = DefaultDataSource.Factory(
context,
defaultDataSourceFactory
)
val source = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(videoUri))
setMediaSource(source)
prepare()
}
}
DisposableEffect(
AndroidView(factory = {
PlayerView(context).apply {
hideController()
player = exoPlayer
}
})
) {
onDispose { exoPlayer.release() }
}
}
But, when I run my app and navigate to the ExoPlayer screen, I get this error:
java.lang.ClassCastException: com.google.android.exoplayer2.ui.DefaultTimeBar cannot be cast to androidx.media3.ui.TimeBar
I find this odd, but perhaps in ExoPlayer3 you can customize the TimeBar and choose what class to use. Has someone has faced this before?

Related

ExoPlayer HLS stream AD insertion

I have HLS stream. When I trying insert VAST tag into stream :
exoplayer not show AD with any errors and warnings in logcat
exoplayer throwing exception, and after re-init with HlsMediaSource.Factory(..) works well
How i build ExoPlayer instance:
private fun initPlayer() {
adsLoader = ImaAdsLoader.Builder(requireContext())
.setAdEventListener { adEvent ->
// SOME LISTENER
}
.build()
val httpDataSource = DefaultHttpDataSource.Factory().createDataSource().apply {
setRequestProperty("Referer", "*some referer*")
}
// Set up the factory for media sources, passing the ads loader and ad view providers.
val httpDataSourceFactory = DataSource.Factory { httpDataSource }
val mediaSourceFactory: MediaSource.Factory =
DefaultMediaSourceFactory(httpDataSourceFactory)
.setLocalAdInsertionComponents(
{ unusedAdTagUri: MediaItem.AdsConfiguration? -> adsLoader }
) { //some view for ad
binding.unsafe.adView
}
// some buffering settings
val loadControlBuilder = DefaultLoadControl.Builder()
loadControlBuilder.setBufferDurationsMs(
AppConstants.Player.PLAYER_BUFFER_DURATION,
AppConstants.Player.PLAYER_BUFFER_DURATION,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
)
// init player
playerInstance =
ExoPlayer.Builder(
requireContext(),
DefaultRenderersFactory(requireContext()),
mediaSourceFactory,
DefaultTrackSelector(requireContext()),
loadControlBuilder.build(),
DefaultBandwidthMeter.Builder(requireContext()).build(),
DefaultAnalyticsCollector(Clock.DEFAULT)
).setSeekBackIncrementMs(AppConstants.Player.PLAYER_SEEK_FORWARD)
.setSeekForwardIncrementMs(AppConstants.Player.PLAYER_SEEK_FORWARD)
.build()
}
How i setup my player for HLS stream:
private fun setupExoPlayer(source: String, adLink: String? = null) {
if (playerInstance == null) initPlayer()
binding {
player.playerView.player = playerInstance
adsLoader?.setPlayer(playerInstance)
player.playerView.subtitleView?.visibility = View.GONE
}
val adsConfig = adLink?.let { MediaItem.AdsConfiguration.Builder(Uri.parse(adLink)).build() }
val mediaItem = MediaItem.Builder()
.setUri(source)
.setAdsConfiguration(adsConfig)
.build()
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
val hlsMediaSource: HlsMediaSource = HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItem)
playerInstance?.apply {
setMediaSource(hlsMediaSource)
prepare()
addListener(playerErrorHandler) // adding some listeners here
playWhenReady = true
}
}
How i insert AD VAST tag after some playing time, difference in setMediaSource or setMediaItem of this source:
private fun injectAdIntoExoPlayer(adLink: String) {
val adsConfig = MediaItem.AdsConfiguration.Builder(Uri.parse(adLink)).build()
val mediaItemWithAd = playerInstance?.currentMediaItem?.buildUpon()?.setAdsConfiguration(
adsConfig
)?.build()
mediaItemWithAd?.let {
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
val hlsMediaSource: HlsMediaSource = HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItemWithAd)
// - first case behavior (not showing ad !!!)
playerInstance?.setMediaSource(hlsMediaSource)
// - second case behavior (showing ad !!!)
// playerInstance?.setMediaItem(hlsMediaSource.mediaItem)
}
}
In second case behaviour exoplayer throws this. Same exceptions I have when init player without HlsMediaSource factory:
E/LoadTask: Unexpected exception loading stream
java.lang.ArrayIndexOutOfBoundsException: size=9400 offset=0 byteCount=-940
at com.android.okhttp.okio.Util.checkOffsetAndCount(Util.java:30)
at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:368)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.readInternal(DefaultHttpDataSource.java:768)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.read(DefaultHttpDataSource.java:478)
at com.google.android.exoplayer2.upstream.StatsDataSource.read(StatsDataSource.java:92)
at com.google.android.exoplayer2.extractor.DefaultExtractorInput.readFromUpstream(DefaultExtractorInput.java:291)
at com.google.android.exoplayer2.extractor.DefaultExtractorInput.read(DefaultExtractorInput.java:68)
at com.google.android.exoplayer2.extractor.ts.TsExtractor.fillBufferWithAtLeastOnePacket(TsExtractor.java:433)
at com.google.android.exoplayer2.extractor.ts.TsExtractor.read(TsExtractor.java:323)
at com.google.android.exoplayer2.source.hls.BundledHlsMediaChunkExtractor.read(BundledHlsMediaChunkExtractor.java:67)
at com.google.android.exoplayer2.source.hls.HlsMediaChunk.feedDataToExtractor(HlsMediaChunk.java:473)
at com.google.android.exoplayer2.source.hls.HlsMediaChunk.loadMedia(HlsMediaChunk.java:437)
at com.google.android.exoplayer2.source.hls.HlsMediaChunk.load(HlsMediaChunk.java:394)
at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)
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:764)
E/LoadTask: Unexpected exception loading stream
java.lang.ArrayIndexOutOfBoundsException: size=8192 offset=0 byteCount=-33
at com.android.okhttp.okio.Util.checkOffsetAndCount(Util.java:30)
at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:368)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.readInternal(DefaultHttpDataSource.java:768)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.read(DefaultHttpDataSource.java:478)
at com.google.android.exoplayer2.upstream.StatsDataSource.read(StatsDataSource.java:92)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:80)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:288)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:351)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:172)
at java.io.BufferedReader.read(BufferedReader.java:193)
at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.checkPlaylistHeader(HlsPlaylistParser.java:296)
at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parse(HlsPlaylistParser.java:259)
at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parse(HlsPlaylistParser.java:68)
at com.google.android.exoplayer2.upstream.ParsingLoadable.load(ParsingLoadable.java:176)
at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)
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:764)
So i need inject my AD Vast tag with exoplayer:extension-ima dependency without handling player error and reiniting with setMediaSource method and without my AD link

Can I show a video from web player to android?

I want to ask, is it possible to display a video from a web player which is usually displayed using an iframe on the website?
my boss told me to make an application like that,
an example of a video using this
https://vanfem.com/v/8qqlyh8lmxgkn5y
is that possible? is it also possible to use that url in exoplayer?
Add gradle dependency in app/build.gradle
dependencies {
implementation project(":exoplayer-codelab-00")
}
Open the build.gradle file of the exoplayer-codelab-00 module.
Add the following lines to the dependencies section and sync the project.
def mediaVersion = "1.0.0-alpha03"
dependencies {
[...]
implementation "androidx.media3:media3-exoplayer:$mediaVersion"
implementation "androidx.media3:media3-ui:$mediaVersion"
implementation "androidx.media3:media3-exoplayer-dash:$mediaVersion"
}
Open the layout resource file activity_player.xml from the exoplayer-codelab-00 module.
<androidx.media3.ui.PlayerView
android:id="#+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
In PlayerActivity.kt
private var player: ExoPlayer? = null
private fun initializePlayer() {
player = ExoPlayer.Builder(this)
.build()
.also { exoPlayer ->
viewBinding.videoView.player = exoPlayer
val mediaItem = MediaItem.fromUri(Uri.parse("https://vanfem.com/v/8qqlyh8lmxgkn5y"))
exoPlayer.setMediaItem(mediaItem)
exoPlayer.playWhenReady = playWhenReady
exoPlayer.seekTo(currentItem, playbackPosition)
exoPlayer.prepare()
}
}
public override fun onStart() {
super.onStart()
if (Util.SDK_INT > 23) {
initializePlayer()
}
}
public override fun onStop() {
super.onStop()
if (Util.SDK_INT > 23) {
releasePlayer()
}
}
private fun releasePlayer() {
player?.let { exoPlayer ->
playbackPosition = exoPlayer.currentPosition
currentItem = exoPlayer.currentMediaItemIndex
playWhenReady = exoPlayer.playWhenReady
exoPlayer.release()
}
player = null
}
for more details you can study this codelab and github

ExoPlayer not loading subtitles from .srt file

So I am trying to show subtitles from my .srt file in exoplayer but it does not work.
Do I need to use a seperate SubtitleView to get my subtitles to show up?
Is the subtitleView in the PlayerView is not enough?
I use PlayerView btw.
The exoplayer version I use is 2.14.0.
The addTextOutput method.
simpleExoPlayer.addTextOutput(cues -> {
playerView.getSubtitleView().setCues(cues);
playerView.getSubtitleView().setVisibility(View.VISIBLE);
playerView.getSubtitleView().onCues(cues);
assert cues.get(0).text != null;
Log.d("subtitles", cues.get(0).text.toString());
});
I also tried to implement to TextOutput but that did not work too.
The contents of my sample.srt file:
1
00:00:00,000 --> 00:00:01,500
For www.forom.com
2
00:00:01,500 --> 00:00:02,500
<i>Tonight's the night.</i>
3
00:00:03,000 --> 00:00:15,000
<i>And it's going to happen
again and again --</i>
The function I use to load my subtitles:
public void buildMediaSourceV3(Uri uri){
String subtitlesUri = sharedPreferencesSubtitles.getString(videoName.getText().toString(), "");
DataSource.Factory factory = new DefaultDataSourceFactory(VideoPlayer.this, getPackageName(), new DefaultBandwidthMeter());
MediaItem mediaItem = MediaItem.fromUri(uri);
MediaSource videoSource = new ProgressiveMediaSource.Factory(factory).createMediaSource(mediaItem);
if(subtitlesUri.equals(""))
{
simpleExoPlayer.addMediaSource(videoSource);
}
else
{
MediaItem.Subtitle subtitle = new MediaItem.Subtitle(Uri.parse(subtitlesUri), MimeTypes.APPLICATION_SUBRIP, "en");
MediaSource textMediaSource = new SingleSampleMediaSource.Factory(factory).createMediaSource(subtitle, C.TIME_UNSET);
textMediaSource.getMediaItem().mediaMetadata.subtitle.toString();
MergingMediaSource mergingMediaSource = new MergingMediaSource(videoSource, textMediaSource);
simpleExoPlayer.addMediaSource(mergingMediaSource);
}
}
I know you've already implemented a workaround.
I've just encountered the same issue, and found a solution:
trackSelector.setPreferredTextLanguage
This helped me. Full context:
val trackSelector = DefaultTrackSelector(context)
trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en"))
Update:
I was wrong. That solution shows only video embedded captions, not the sideloading ones.
This works for me now:
val mediaItemBuilder = MediaItem.Builder()
.setUri(uri))
videoCaption?.vtt?.let {
val uriSubtitle = Uri.parse(it)
val mediaItemSubtitle = MediaItem.Subtitle(uriSubtitle,
MimeTypes.TEXT_VTT,
"en",
C.SELECTION_FLAG_DEFAULT)
mediaItemBuilder.setSubtitles(mutableListOf(mediaItemSubtitle))
}
val mediaItem = mediaItemBuilder.build()
val mediaSource = DefaultMediaSourceFactory(dataSourceFactory, extractoryFactory).createMediaSource(mediaItem)
Here is minimal example for video/mp4 with SRT subtitles. For XML layout is used com.google.android.exoplayer2.ui.StyledPlayerView and there is no need for additional subtitle layout. Files are located in assets directory inside the project.
val playerView = view.findViewById<StyledPlayerView>(R.id.video_pv)
val exoPlayer = ExoPlayer.Builder(requireActivity()).build()
playerView.player = exoPlayer
val assetSrtUri = Uri.parse(("file:///android_asset/subtitle.srt"))
val subtitle = SubtitleConfiguration.Builder(assetSrtUri)
.setMimeType(MimeTypes.APPLICATION_SUBRIP)
.setLanguage("en")
.setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
.build()
val assetVideoUri = Uri.parse(("file:///android_asset/video.mp4"))
val mediaItem = MediaItem.Builder()
.setUri(assetVideoUri)
.setSubtitleConfigurations(ImmutableList.of(subtitle))
.build()
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.play()
Gradle dependencies:
implementation "com.google.android.exoplayer:exoplayer:2.17.1"
implementation "com.google.android.exoplayer:exoplayer-core:2.17.1"
implementation "com.google.android.exoplayer:exoplayer-ui:2.17.1"

Small laggy when prepare exoplayer

In my application, I had an infinite animation. Actually, it's a TextSwitcher animation running from left to right. However, whenever I tried to prepare the player, I got a jitter issue with the text's animation. Although it's just a few milliseconds, it caused my texts was like jumping from left to right. Here's the prepare video method:
private fun prepareVideo(uri: Uri): SimpleExoPlayer? {
val simpleExoPlayer = SimpleExoPlayer
.Builder(this) // .setLoadControl(defaultLoadControl)
.build()
val mediaItem = MediaItem.fromUri(uri)
simpleExoPlayer.setMediaItem(mediaItem)
val eventListener: Player.EventListener = object : Player.EventListener {
override fun onPlaybackStateChanged(state: Int) {
if (state == ExoPlayer.STATE_READY) {
playVideo(simpleExoPlayer)
}
}
}
simpleExoPlayer.addListener(eventListener)
simpleExoPlayer.playWhenReady = false
simpleExoPlayer.prepare()
showToast("Prepare video")
return simpleExoPlayer
}
Do you guys have any idea to fix it?
If you thinks problem in this part of code i can recommend you to try initialize your SimpleExoPlayer object in application class and use it's instance all across application.
Try with this code
var exoPlayer: SimpleExoPlayer? = null
private fun setupVideo(uriString: String) {
val appName = R.string.app_name
val trackSelector: TrackSelector = DefaultTrackSelector()
val userAgent = context.let { Util.getUserAgent(it, it.getString(appName)) }
val sourceFactory = DefaultDataSourceFactory(requireContext(), userAgent)
val uri = Uri.parse(uriString)
val mediaSource = ProgressiveMediaSource.Factory(sourceFactory).createMediaSource(uri)
exoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector)
exoPlayer?.prepare(mediaSource)
exoPlayer?.playWhenReady = false
pvPlayer.player = exoPlayer
}
After quite some time investigating, I found the issue is creating an ExoPlayer instance.
val simpleExoPlayer = SimpleExoPlayer
.Builder(this) // .setLoadControl(defaultLoadControl)
.build()
Just this simple blook took about 0.1 seconds to finish. As a result, it froze the animation for a short period of time. I decided to create it on splash screen and reused it whenever possible.

How to implement ExoPlayer with Databinding?

I have a class activity_player layout in which I have exoplayer2.ui.PlayerView and I created exo_player_control_view so that it overrides default controls in ExoPlayer. So I wanted to use Databinding in newly created custom control view but don't know how to do it. Any advice?
It is actually an open issue over here, but yet to be solved. So is there anyone who had a workaround to make exo_player_control_view Databinding friendly?
Use Like this >>>>>
private val binding by lazy {
ActivityPipVideoPlayerBinding.inflate(layoutInflater)}
private val exoPLayerBinding by lazy {
VdoExoControlViewBinding.inflate(LayoutInflater.from(this), binding.root, true)
}
You can use binding variable inside fragment/activity to access the playerView inside fragment/activity and
val uri: Uri? = if (url is String) Uri.parse(url as String?) else url as Uri?
val trackSelector =
DefaultTrackSelector(AdaptiveTrackSelection.Factory(DefaultBandwidthMeter()))
val player: SimpleExoPlayer = ExoPlayerFactory.newSimpleInstance(view.context, trackSelector)
val dataSourceFactory = DefaultDataSourceFactory(view.context, "ua")
val mediaSource =
ExtractorMediaSource(uri, dataSourceFactory, DefaultExtractorsFactory(), null, null)
player.prepare(mediaSource)
player.apply {
volume = 0f
repeatMode = Player.REPEAT_MODE_ONE
playWhenReady = true
videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT
}
binding.playerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL)
binding.playerView.player = player

Categories

Resources