How to add Subtitles(.SRT files) to video in Exoplayer android?

12,613

Solution 1

I know it's too late to answer this question, but if someone else falls for it, try this :

public class MainActivity extends AppCompatActivity {
SimpleExoPlayerView exoPlayerView;
SimpleExoPlayer exoPlayer;
String videoURL = "http://blueappsoftware.in/layout_design_android_blog.mp4";
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    exoPlayerView = (SimpleExoPlayerView) findViewById(R.id.exo_player_view);
    try {


        BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        TrackSelector trackSelector = new DefaultTrackSelector(new AdaptiveTrackSelection.Factory(bandwidthMeter));
        exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector);

        Uri videoURI = Uri.parse(videoURL);
        Uri subtitleUri=Uri.parse("https://firebasestorage.googleapis.com/v0/b/findandfix-2f4a9.appspot.com/o/Despacito%20Remix%20Luis%20Fonsi%20ft.Daddy%20Yankee%20Justin%20Bieber%20Lyrics%20%5BSpanish%5D.srt?alt=media&token=63344d04-af1c-4e2c-9d15-381bf7159308");
        DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory("exoplayer_video");

        ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
        MediaSource mediaSource = new ExtractorMediaSource(videoURI, dataSourceFactory, extractorsFactory, null, null);

        // Build the subtitle MediaSource.
        Format subtitleFormat = Format.createTextSampleFormat(
                null, // An identifier for the track. May be null.
                MimeTypes.APPLICATION_SUBRIP, // The mime type. Must be set correctly.
                null,
                Format.NO_VALUE,
                Format.NO_VALUE,
                "en",
                null); // The subtitle language. May be null.

        MediaSource subtitleSource =new SingleSampleMediaSource(subtitleUri, dataSourceFactory, subtitleFormat, C.TIME_UNSET);

        MergingMediaSource mergedSource =
                new MergingMediaSource(mediaSource, subtitleSource);

        exoPlayerView.setPlayer(exoPlayer);
        exoPlayer.prepare(mergedSource);
        exoPlayer.setPlayWhenReady(true);
    }catch (Exception e){
        Log.e("MainAcvtivity"," exoplayer error "+ e.toString());
    }

}

}

Solution 2

SubtitleView subtitleView=(SubtitleView)findViewById(com.google.android.exoplayer2.R.id.exo_subtitles); 
player.setTextOutput(new ComponentListener());

public class ComponentListener implements TextRenderer.Output{
  @Override
  public void onCues(List<Cue> cues) {
    if (subtitleView != null) {
        subtitleView.onCues(cues);
    }
  }

}

To show/hide the subtitleView:

subtitleView.setVisiblity(Visible/Gone);

Solution 3

I just edit exoplayer example in there Player activity such like... and its working for me...

 private void initializePlayer() {
        Intent intent = getIntent();
        if (player == null) {
            boolean preferExtensionDecoders = intent.getBooleanExtra(PREFER_EXTENSION_DECODERS, false);
            UUID drmSchemeUuid = intent.hasExtra(DRM_SCHEME_UUID_EXTRA)
                    ? UUID.fromString(intent.getStringExtra(DRM_SCHEME_UUID_EXTRA)) : null;
            DrmSessionManager<FrameworkMediaCrypto> drmSessionManager = null;
            if (drmSchemeUuid != null) {
                String drmLicenseUrl = intent.getStringExtra(DRM_LICENSE_URL);
                String[] keyRequestPropertiesArray = intent.getStringArrayExtra(DRM_KEY_REQUEST_PROPERTIES);
                Map<String, String> keyRequestProperties;
                if (keyRequestPropertiesArray == null || keyRequestPropertiesArray.length < 2) {
                    keyRequestProperties = null;
                } else {
                    keyRequestProperties = new HashMap<>();
                    for (int i = 0; i < keyRequestPropertiesArray.length - 1; i += 2) {
                        keyRequestProperties.put(keyRequestPropertiesArray[i],
                                keyRequestPropertiesArray[i + 1]);
                    }
                }
                try {
                    drmSessionManager = buildDrmSessionManager(drmSchemeUuid, drmLicenseUrl,
                            keyRequestProperties);
                } catch (UnsupportedDrmException e) {
                    int errorStringId = Util.SDK_INT < 18 ? R.string.error_drm_not_supported
                            : (e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME
                            ? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown);
                    showToast(errorStringId);
                    return;
                }
            }

            @SimpleExoPlayer.ExtensionRendererMode int extensionRendererMode =
                    ((AppController) getApplication()).useExtensionRenderers()
                            ? (preferExtensionDecoders ? SimpleExoPlayer.EXTENSION_RENDERER_MODE_PREFER
                            : SimpleExoPlayer.EXTENSION_RENDERER_MODE_ON)
                            : SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF;
            TrackSelection.Factory videoTrackSelectionFactory =
                    new AdaptiveVideoTrackSelection.Factory(BANDWIDTH_METER);
            trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
            trackSelectionHelper = new TrackSelectionHelper(trackSelector, videoTrackSelectionFactory);
            player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, new DefaultLoadControl(),
                    drmSessionManager, extensionRendererMode);
            player.addListener(this);

            eventLogger = new EventLogger(trackSelector);
            player.addListener(eventLogger);
            player.setAudioDebugListener(eventLogger);
            player.setVideoDebugListener(eventLogger);
            player.setMetadataOutput(eventLogger);

            simpleExoPlayerView.setPlayer(player);
            player.setPlayWhenReady(shouldAutoPlay);
            debugViewHelper = new DebugTextViewHelper(player, debugTextView);
            debugViewHelper.start();
            playerNeedsSource = true;


        }
        if (playerNeedsSource) {
            String action = intent.getAction();
            Log.d("URL action: ", action);
            Uri[] uris;
            String[] extensions;
            if (ACTION_VIEW.equals(action)) {
                uris = new Uri[] {intent.getData()};
                extensions = new String[] {intent.getStringExtra(EXTENSION_EXTRA)};
            } else if (ACTION_VIEW_LIST.equals(action)) {
                String[] uriStrings = intent.getStringArrayExtra(URI_LIST_EXTRA);
                uris = new Uri[uriStrings.length];
                for (int i = 0; i < uriStrings.length; i++) {
                    uris[i] = Uri.parse(uriStrings[i]);
                    Log.d("URL action2: ", String.valueOf(uris[i])+" ");
                }
                extensions = intent.getStringArrayExtra(EXTENSION_LIST_EXTRA);
                if (extensions == null) {
                    extensions = new String[uriStrings.length];
                }
            } else {
                showToast(getString(R.string.unexpected_intent_action, action));
                return;
            }
            if (Util.maybeRequestReadExternalStoragePermission(this, uris)) {
                // The player will be reinitialized if the permission is granted.
                return;
            }
            MediaSource[] mediaSources = new MediaSource[uris.length];
            for (int i = 0; i < uris.length; i++) {
                mediaSources[i] = buildMediaSource(uris[i], extensions[i]);
                Log.d("URL action extensions: ", String.valueOf( extensions[i]));
            }
            MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0]
                    : new ConcatenatingMediaSource(mediaSources);
            boolean haveResumePosition = resumeWindow != C.INDEX_UNSET;
            if (haveResumePosition) {
                player.seekTo(resumeWindow, resumePosition);
            }
            // edit for subtitle
           // player.prepare(mediaSource, !haveResumePosition, false);
         //   playerNeedsSource = false;
          // player.seekTo(0);
            //updateButtonVisibilities();

           /* MediaSource mediaSource = new HlsMediaSource(Uri.parse("https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8"),
                    mediaDataSourceFactory, mainHandler, null);*/

            Format textFormat = Format.createTextSampleFormat(null, MimeTypes.APPLICATION_SUBRIP,
                    null, Format.NO_VALUE, Format.NO_VALUE, "en", null);

            Uri uri = Uri.parse("http://www.storiesinflight.com/js_videosub/jellies.srt");


            MediaSource subtitleSource = new SingleSampleMediaSource(uri, mediaDataSourceFactory, textFormat, C.TIME_UNSET);
// Plays the video with the sideloaded subtitle.
            MergingMediaSource mergedSource =
                    new MergingMediaSource(mediaSource, subtitleSource);

            player.prepare(mergedSource,!haveResumePosition, false);
            playerNeedsSource = false;
            //player.seekTo(0);
        }


    }

Solution 4

I have given a lots of efforts for this and finally concluded to the solution...
Sharing here for the reference

Srt file format ref link - http://www.storiesinflight.com/js_videosub/jellies.srt

Solution which finds a way for me - https://github.com/google/ExoPlayer/issues/3869#issuecomment-367067013

Adding Exoplayer code here

// initialize exoplayer
private void initializeExoPlayer() {
    if (player == null) {
        video_view = (PlayerView) findViewById(R.id.video_view);

        // 1. Create a default TrackSelector
        LoadControl loadControl = new DefaultLoadControl(
                new DefaultAllocator(true, 16),
                VideoPlayerConfig.MIN_BUFFER_DURATION,
                VideoPlayerConfig.MAX_BUFFER_DURATION,
                VideoPlayerConfig.MIN_PLAYBACK_START_BUFFER,
                VideoPlayerConfig.MIN_PLAYBACK_RESUME_BUFFER, -1, true);

        BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        TrackSelection.Factory videoTrackSelectionFactory =
                new AdaptiveTrackSelection.Factory(bandwidthMeter);
        TrackSelector trackSelector =
                new DefaultTrackSelector(videoTrackSelectionFactory);
        // 2. Create the player
        player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(mContext), trackSelector, loadControl);
        video_view.setPlayer(player);

    }
}


public void buildMediaSource(String videoUrl, final String questionVideoThumbnail) {


    Uri mUri = Uri.parse(videoUrl);
    Uri srtUri = Uri.parse("http://www.storiesinflight.com/js_videosub/jellies.srt");

    // Measures bandwidth during playback. Can be null if not required.
    DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
    // Produces DataSource instances through which media data is loaded.
    DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mContext,
            Util.getUserAgent(mContext, getString(R.string.app_name)), bandwidthMeter);
    // This is the MediaSource representing the media to be played.
    MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory)
            .createMediaSource(mUri);
    // Prepare the player with the source.

    Format textFormat = Format.createTextSampleFormat(null, MimeTypes.APPLICATION_SUBRIP,
            null, Format.NO_VALUE, Format.NO_VALUE, "en", null, Format.OFFSET_SAMPLE_RELATIVE);
    MediaSource textMediaSource = new SingleSampleMediaSource.Factory(dataSourceFactory)
            .createMediaSource(srtUri, textFormat, C.TIME_UNSET);
    MergingMediaSource mediaSource = new MergingMediaSource(videoSource, textMediaSource);

    player.prepare(mediaSource);
    player.setPlayWhenReady(true);
    player.addListener(this);


}

Solution 5

Aside from the merged media source I created a Listener for the Text Rendered as an Interface as in the Demo

    private final class ComponentListener implements TextRenderer.Output{

        @Override
        public void onCues(List<Cue> cues) {
            if (subtitleView != null) {
                subtitleView.onCues(cues);
            }
        }
    }

player.setTextOutput(componentListener);

I created an object and set the TextOutput as this

Share:
12,613

Related videos on Youtube

Kanagalingam
Author by

Kanagalingam

Updated on September 16, 2022

Comments

  • Kanagalingam
    Kanagalingam over 1 year

    i am working on a project where i should play .srt files along with video in android. I was working through the samples of Exoplayer but cant able to play .srt files with video.

    The code i used is,

    MediaSource mediaSource = new HlsMediaSource(Uri.parse("https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8"),
                    mediaDataSourceFactory, mainHandler, null);
    
             Format textFormat = Format.createTextSampleFormat(null, MimeTypes.APPLICATION_SUBRIP,
                    null, Format.NO_VALUE, Format.NO_VALUE, "en", null);
    
            Uri uri = Uri.parse("http://www.storiesinflight.com/js_videosub/jellies.srt");
    
    
            MediaSource subtitleSource = new SingleSampleMediaSource(uri, mediaDataSourceFactory, textFormat, C.TIME_UNSET);
    // Plays the video with the sideloaded subtitle.
            MergingMediaSource mergedSource =
                    new MergingMediaSource(mediaSource, subtitleSource);
    
            player.prepare(mergedSource);
    

    Can anyone please suggest me solution for this or any tutorial links for the same. Your help is very much appreciated !

  • solidfox
    solidfox over 5 years
    it says , can not resolve method createTextSampleFormat()
  • Pemba Tamang
    Pemba Tamang over 4 years
    SingleSampleMediaSource is deprecated what do I use
  • Nasib
    Nasib over 4 years
    i like your answer, but how to do i add an external .srt subtitle for the player to sync with the playback.
  • Lloyd Dcosta
    Lloyd Dcosta almost 4 years
    @PembaTamang You can use SingleSampleMediaSource.Factory methods
  • Vikas Acharya
    Vikas Acharya over 3 years
    no explanation at all and didn't find mediaDataSourceFactory in this answer
  • Vikas Acharya
    Vikas Acharya over 3 years
    can anyone explain where is the subtitle path here ?
  • 6rchid
    6rchid about 3 years
    The subtitle is embedded within the m3u8 or mpd file.
  • JPM
    JPM over 2 years
    Can we update this for kotlin and latest library, this does not work