How to show VTT subtitles in ExoPlayer2? - android

How can I set and show subtitles from url with ExoPlayer2 in Android? Currently, I write in Kotlin, I'm using following code for setting up ExoPlayer with subtitles:
exoPlayer = SimpleExoPlayer.Builder(this).build()
val subtitle = MediaItem.Subtitle(Uri.parse(SUBTITLES_URL), MimeTypes.TEXT_VTT, "en")
val subtitles = arrayListOf(subtitle)
val mediaItem = MediaItem.Builder()
.setUri(movieSrc)
.setSubtitles(subtitles)
.build()
exoPlayer.setMediaItem(mediaItem)
exoPlayer.addListener(this)
exoPlayer.prepare()
And following code to display them in ExoPlayer SubtitleView:
exoPlayer.addTextOutput {
binding.exoSubtitles.onCues(it)
}
I don't get any exception, it just does not show anything idk...
Nothing really works... Really need some help, Thank You in Advance!

Here is the code I used (I got these from the Internet somewhere I forgot)
// create the simple cache
val leastRecentlyUsedCacheEvictor = LeastRecentlyUsedCacheEvictor(MAX_CACHE_SIZE)
val databaseProvider: DatabaseProvider = ExoDatabaseProvider(this)
val simpleCache = SimpleCache(cacheDir, leastRecentlyUsedCacheEvictor, databaseProvider)
// create http datasource
val defaultBandwidthMeter = DefaultBandwidthMeter.Builder(context).build()
val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(
context,
DefaultHttpDataSourceFactory(
System.getProperty("http.agent"),
defaultBandwidthMeter
)
)
// create the player
val simplePlayer = ExoPlayerFactory.newSimpleInstance(context)
simplePlayer.addListener(playerCallback)
cacheDataSourceFactory = CacheDataSourceFactory(
simpleCache,
DefaultHttpDataSourceFactory(
Util.getUserAgent(
context,
"exo"
)
)
)
// create subtitle text format
val textFormat = Format.createTextSampleFormat(
null,
MimeTypes.TEXT_VTT,
C.SELECTION_FLAG_DEFAULT,
null
)
// create the subtitle source
val subtitleSource = SingleSampleMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(it), textFormat, C.TIME_UNSET)
// create the media source based from video/audio url
val mediaSource = ProgressiveMediaSource.Factory(cacheDataSourceFactory).createMediaSource(uri)
// merge subtitle source and media source
val mediaSourceWithsubtitle = MergingMediaSource(mediaSource, subtitleSource)
// setup the player
simplePlayer.prepare(mediaSourceWithsubtitle, true, true)

Related

How to use ExoPlayer in Android

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"

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"

ExoPlayer initialize player deprecated

I'm currently working with the latest ExoPlayer update and I'm getting calls that it is deprecated, could someone help me?
private fun initializePlayer () {
if (simpleExoPlayer == null) {
val trackSelector = DefaultTrackSelector(this)
val loadControl = DefaultLoadControl()
simpleExoPlayer = E̶x̶o̶P̶l̶a̶y̶e̶r̶F̶a̶c̶t̶o̶r̶y̶.̶n̶e̶w̶S̶i̶m̶p̶l̶e̶I̶n̶s̶t̶a̶n̶c̶e̶(this, trackSelector, loadControl)
}
}
Setting Up Exoplayer version(2.11.8) :
Sep 2020 Update:
//Setting Up Exoplayer
private void SetupPlayer(){
SimpleExoPlayer simpleExoPlayer;
// Create a data source factory.
dataSourceFactory =
new DefaultHttpDataSourceFactory(Util.getUserAgent(this
, getApplicationInfo().loadLabel(getPackageManager()).toString()));
// Passing Load Control
loadControl = new DefaultLoadControl.Builder()
.setBufferDurationsMs(25000, 50000, 1500, 2000).createDefaultLoadControl();
#DefaultRenderersFactory.ExtensionRendererMode int extensionRendererMode = DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER;
renderersFactory = new DefaultRenderersFactory(this) .setExtensionRendererMode(extensionRendererMode);
// Create a progressive media source pointing to a stream uri.
mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(url_to_stream));
// Create a player instance.
simpleExoPlayer = new SimpleExoPlayer.Builder(this,renderersFactory).setLoadControl(loadControl).build();
// Prepare the player with the media source.
simpleExoPlayer.prepare(mediaSource, true, true);
}
It's worked. You should use this version:
implementation 'com.google.android.exoplayer:exoplayer:2.18.2'
exoPlayer = ExoPlayer.Builder(this).build()
exoPlayer?.playWhenReady = true
binding.playerView.player = exoPlayer
val defaultHttpDataSourceFactory = DefaultHttpDataSource.Factory()
val mediaItem =
MediaItem.fromUri(URL)
val mediaSource =
HlsMediaSource.Factory(defaultHttpDataSourceFactory).createMediaSource(mediaItem)
exoPlayer?.setMediaSource(mediaSource)
exoPlayer?.seekTo(playbackPosition)
exoPlayer?.playWhenReady = playWhenReady
exoPlayer?.prepare()

Exoplayer2 Streaming HLS Videos , Sometimes plays video with sound only(video not played)

I implement exoplayer2 in my app for playing HLS Videos, but sometimes it plays just sound, and doesn't work correctly. What am I supposed to do? I couldn't find why this happens sometimes.
this is the code for initializing player :
fun initPalyer(){
val mainHandler = Handler()
val bandwidthMeter: BandwidthMeter = DefaultBandwidthMeter.Builder(context).build()
bandwidthMeter.addEventListener(mainHandler!!, this)
val trackSelectionFactory: TrackSelection.Factory = AdaptiveTrackSelection.Factory()
trackSelector = DefaultTrackSelector(context, trackSelectionFactory)
val builder = ParametersBuilder(context)
trackSelectorParameters = builder.build()
trackSelector!!.parameters = trackSelectorParameters
var rendersFactory: RenderersFactory = app.buildRenderersFactory(false)
player = SimpleExoPlayer.Builder(
context, renderersFactory
)
.setTrackSelector(trackSelector!!)
.setBandwidthMeter(bandwidthMeter)
//.setLoadControl(loadControl)
.build()
player!!.addListener(this)
loadState()
playerView.player = player!!
}
the code for preparing player :
private fun preparePlayer(uri: Uri) {
val mediaSource = MediaSourceBuilder().build(uri)
durationSet = false
player?.prepare(mediaSource, true, false)
}
and the code for creating mediaSources :
class MediaSourceBuilder {
//Build various MediaSource depending upon the type of Media for a given video/audio uri
fun build(uri: Uri): MediaSource {
val userAgent = PlayerConstants.USER_AGENT
val lastPath = uri.lastPathSegment?:""
val defaultHttpDataSourceFactory = DefaultHttpDataSourceFactory(userAgent)
if(lastPath.contains(PlayerConstants.FORMAT_MP3) || lastPath.contains(PlayerConstants.FORMAT_MP4)){
return ExtractorMediaSource.Factory(defaultHttpDataSourceFactory)
.createMediaSource(uri)
}else if(lastPath.contains(PlayerConstants.FORMAT_M3U8)){
return HlsMediaSource.Factory(defaultHttpDataSourceFactory)
.setAllowChunklessPreparation(true)
.createMediaSource(uri)
}else{
val dashChunkSourceFactory = DefaultDashChunkSource.Factory(defaultHttpDataSourceFactory)
return DashMediaSource.Factory(dashChunkSourceFactory, defaultHttpDataSourceFactory)
.createMediaSource(uri)
}
}
You might wanna change your DataSourceFactory, in case your URL are in HTTPS you might end up with an error, try using DefaultDataSourceFactory instead of DefaultHttpDataSourceFactory

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