Exoplayer: Video subtitles on chromecast

Created on 20 Apr 2019  路  17Comments  路  Source: google/ExoPlayer

I use exoplayerwith exoplayer-cast-extension in my android app. In the app its possible to play videos with subtitles (I have links on .srt files for each video source). And I want to cast these videos (on chromecast) with subtitles. For casting I use the following code:

 castPlayer?.loadItem(MediaQueueItem.Builder(buildMediaInfo(videoUrl ?: "")).build(), 0L)

    private fun buildMediaInfo(videoUrl: String): MediaInfo {
        val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
        movieMetadata.putString(MediaMetadata.KEY_TITLE, getString(R.string.app_name))
        return MediaInfo.Builder(videoUrl)
            .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
            .setContentType("video/m3u8")
            .setMetadata(movieMetadata)
            .setStreamDuration(UNKNOWN_DURATION)
            .build()
    }

It plays video with chromecast well, but without subtitles. And I didnt find some method for adding subtitles for cast video. So, how to make them?

question

All 17 comments

@amjadmasri thanks. But when I set MediaTraks, there is no subtitles in cast video, unfortunately:

private fun buildMediaInfo(): MediaInfo {
        val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
        movieMetadata.putString(MediaMetadata.KEY_TITLE, getString(R.string.app_name))
        val englishSubtitle = MediaTrack.Builder(1, MediaTrack.TYPE_TEXT)
            .setName("English Subtitle")
            .setSubtype(MediaTrack.SUBTYPE_SUBTITLES)
            .setContentId("http://www.storiesinflight.com/js_videosub/jellies.srt")
            .setLanguage("en-US")
            .build()
        return MediaInfo.Builder("https://clvod.itworkscdn.net/itwvod/smil:itwfcdn/admin/515002-R204MDrB22W6kG8.smil/playlist.m3u8")
            .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
            .setContentType("video/m3u8")
            .setMetadata(movieMetadata)
            .setMediaTracks(listOf(englishSubtitle))
            .setStreamDuration(UNKNOWN_DURATION)
            .build()
    }

The video plays well, but without subtitles. Is there a way to show subtitles successfully? I use Styled Media Receiver.

So, no one knows how to solve the problem?

I have the same problem any help?

Any update on this, I have the same issue.

Having the same issue. How could we add srt files to a stream?

I am facing the same issue. anyone, resolves this issue?

@amjadmasri , I have followed as per your posted link.

MediaTrack englishSubtitle = new MediaTrack.Builder(1 /* ID */,
MediaTrack.TYPE_TEXT)
  .setName("English Subtitle")
  .setSubtype(MediaTrack.SUBTYPE_SUBTITLES)
  .setContentId("https://some-url/caption_en.vtt")
  .setLanguage("en-US")
  .build();
// the ID for the English Subtitle '1'
mRemoteMediaClient.setActiveMediaTracks(new long[]{1})
  .setResultCallback(new ResultCallback() {
    @Override
    public void onResult(MediaChannelResult mediaChannelResult) {
      if (!mediaChannelResult.getStatus().isSuccess()) {
        Log.e(TAG, "Failed with status code:" +
          mediaChannelResult.getStatus().getStatusCode());
      }else{
         Log.d("TAG", "Success with status code:" +
           mediaChannelResult.getStatus().getStatusCode());
      }
    }
  });

D/TAG: Success with status code:0

But the subtitle is not working on the cast player.
@AquilesCanta , @ojw28

Same problem!!

Hey @mjmancuso can you provide advise here?

By the way @drayan85, can you share the media you are using:

  • Link to the main content (video + audio)
  • Link to sideloaded subtitles
    ?
    You can send them to dev.[email protected] if you don't want to make them public.

@AquilesCanta , Sorry I have forgot to update here. The subtitle is working fine with below code;

public void setSelectedSubTitle(final String selectedSubTitleLang, final Resources resources) {
     List<MediaTrack> tracks = new ArrayList<>();
    MediaTrack englishSubtitle = new MediaTrack.Builder(1 /* ID */,
   MediaTrack.TYPE_TEXT)
     .setName("English(US)")
     .setSubtype(MediaTrack.SUBTYPE_SUBTITLES)
     .setContentId("https://some-url/us_english.srt")
     .setLanguage("en-US")
     .build();
  tracks.clear();
  tracks.add(mediaTrack);
}

The problem was calling the place, we have to call after the player got initialised

    //PlayerManager.Listener
    @Override
    public void onTracksChanged(final TrackGroupArray trackGroups, final TrackSelectionArray trackSelections) {
        updatePlayerButtonVisibilities();
        TrackSelection trackSelection = trackSelections.get(2);
        if (trackSelection != null) {
            selectedSubtitleLang = trackSelection.getFormat(0).language;
            playerManager.setSelectedSubTitle(selectedSubtitleLang, resource);

        if (playerManager != null && trackGroups != lastSeenTrackGroupArray) {
            MappedTrackInfo mappedTrackInfo = playerManager.getTrackSelector().getCurrentMappedTrackInfo();
            if (mappedTrackInfo != null) {
                if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO)
                        == MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
                    showToast(R.string.error_unsupported_video);
                }
                if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_AUDIO)
                        == MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
                    showToast(R.string.error_unsupported_audio);
                }
            }
            lastSeenTrackGroupArray = trackGroups;
        }
    }

I'll try experimenting this and figuring out what the final API should look like from the Cast extension perspective.

any news

@msxenon
Have you tried my solution as mentioned above
https://github.com/google/ExoPlayer/issues/5786#issuecomment-551622165

In the PlayerManager after Track Change got changed,

    //PlayerManager.Listener
    @Override
    public void onTracksChanged(final TrackGroupArray trackGroups, final TrackSelectionArray trackSelections) {
        updatePlayerButtonVisibilities();
        TrackSelection trackSelection = trackSelections.get(2);
        if (trackSelection != null) {
            selectedSubtitleLang = trackSelection.getFormat(0).language;
            playerManager.setSelectedSubTitle(selectedSubtitleLang, resource);

        if (playerManager != null && trackGroups != lastSeenTrackGroupArray) {
            MappedTrackInfo mappedTrackInfo = playerManager.getTrackSelector().getCurrentMappedTrackInfo();
            if (mappedTrackInfo != null) {
                if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO)
                        == MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
                    showToast(R.string.error_unsupported_video);
                }
                if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_AUDIO)
                        == MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
                    showToast(R.string.error_unsupported_audio);
                }
            }
            lastSeenTrackGroupArray = trackGroups;
        }
    }

Hi @drayan85 I'm interested with your suggest solution, can you provide full example code in add MediaItem before setMediaItems to load media by using CastPlayer?

@BayuWijayaPermanaPutra, I hope this will help you make it work.

List<MediaTrack> tracks;
MediaTrack mediaTrack = new MediaTrack.Builder(1 /* ID */,
                            MediaTrack.TYPE_TEXT)
                            .setName(new DefaultTrackNameProvider(resources).getTrackName(subtitleFormat))
                            .setSubtype(MediaTrack.SUBTYPE_SUBTITLES)
                            .setContentId(url)
                            /* language is required for subtitle type but optional otherwise */
                            .setLanguage(language)
                            .build();
                    tracks.clear();
                    tracks.add(mediaTrack);



md5-ad5f362fa25cb4ccebc834962843198c



JSONObject jsonObj = new JSONObject();
jsonObj.put("description", "Video Description");
MediaInfo mediaInfo =
                    new MediaInfo.Builder(item.uri.toString())
                            .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
                            .setContentType(item.mimeType)
                            .setMetadata(movieMetadata)
                            .setMediaTracks(tracks) /*Selected SubTitle*/
                            .setCustomData(jsonObj)
                            .build();



md5-ad5f362fa25cb4ccebc834962843198c



new MediaQueueItem.Builder(mediaInfo).build()
Was this page helpful?
0 / 5 - 0 ratings