From 8823856814c79c80e1533d99f38ad4270e8f1f5c Mon Sep 17 00:00:00 2001
From: "Warren R. Bank" <warren.r.bank@gmail.com>
Date: Sun, 1 Dec 2024 16:23:07 -0800
Subject: [PATCH] enable legacy decoding of text captions

issue:
  https://github.com/androidx/media/issues/1516
  https://github.com/androidx/media/issues/1644

references:
  https://github.com/androidx/media/blob/1.5.0/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java#L289
  https://github.com/androidx/media/blob/1.5.0/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MediaSource.java#L117
---
 .../exoplayer2/ExoPlayerUtils.java            |  1 +
 .../exoplayer2/PlayerManager.java             | 46 +++++++++++++------
 .../customizations/MyRenderersFactory.java    |  1 +
 3 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/ExoPlayerUtils.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/ExoPlayerUtils.java
index 7351967..d5a971e 100644
--- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/ExoPlayerUtils.java
+++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/ExoPlayerUtils.java
@@ -91,6 +91,7 @@ public static synchronized DefaultHttpDataSource.Factory getHttpDataSourceFactor
       cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
       CookieHandler.setDefault(cookieManager);
       httpDataSourceFactory = new DefaultHttpDataSource.Factory();
+      httpDataSourceFactory.setAllowCrossProtocolRedirects(true);
 
       if (USER_AGENT != null) {
         httpDataSourceFactory.setUserAgent(USER_AGENT);
diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/PlayerManager.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/PlayerManager.java
index 35c56dd..a0fd00d 100644
--- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/PlayerManager.java
+++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/PlayerManager.java
@@ -133,6 +133,8 @@ private PlayerManager(Context context) {
         : 0
     );
 
+    extractorsFactory.experimentalSetTextTrackTranscodingEnabled(true);
+
     trackSelector.setParameters(
       trackSelector.buildUponParameters()
         .setTunnelingEnabled(
@@ -156,10 +158,13 @@ private PlayerManager(Context context) {
     this.rtmpDataSourceFactory     = ExoPlayerUtils.getRtmpDataSourceFactory();
     this.downloadTracker           = ExoPlayerUtils.getDownloadTracker(context);
 
+    MediaSource.Factory msFactory  = new DefaultMediaSourceFactory(cacheDataSourceFactory, extractorsFactory);
+    msFactory.experimentalParseSubtitlesDuringExtraction(false);
+
     ExoPlayer.Builder builder = new ExoPlayer.Builder(
       context,
       (RenderersFactory) renderersFactory,
-      new DefaultMediaSourceFactory(cacheDataSourceFactory, extractorsFactory),
+      msFactory,
       trackSelector,
       loadControl,
       DefaultBandwidthMeter.getSingletonInstance(context),
@@ -1678,45 +1683,60 @@ private MediaSource buildMediaSource(VideoSource sample) {
   }
 
   private MediaSource buildUriMediaSource(VideoSource sample) {
-    DataSource.Factory factory = (ExternalStorageUtils.isFileUri(sample.uri) || ExternalStorageUtils.isContentUri(sample.uri))
+    DataSource.Factory dsFactory = (ExternalStorageUtils.isFileUri(sample.uri) || ExternalStorageUtils.isContentUri(sample.uri))
       ? defaultDataSourceFactory
       : cacheDataSourceFactory;
 
-    if (factory == null)
+    if (dsFactory == null)
       return null;
 
     MediaItem mediaItem = sample.getMediaItem();
 
+    MediaSource.Factory msFactory = null;
+
     switch (sample.uri_mimeType) {
       case "application/x-mpegURL":
       case "application/x-mpegurl":
-        return new HlsMediaSource.Factory(factory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy).createMediaSource(mediaItem);
+        msFactory = new HlsMediaSource.Factory(dsFactory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy);
+        break;
       case "application/dash+xml":
-        return new DashMediaSource.Factory(factory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy).createMediaSource(mediaItem);
+        msFactory = new DashMediaSource.Factory(dsFactory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy);
+        break;
       case "application/vnd.ms-sstr+xml":
-        return new SsMediaSource.Factory(factory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy).createMediaSource(mediaItem);
+        msFactory = new SsMediaSource.Factory(dsFactory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy);
+        break;
       case "application/x-rtsp":
-        return new RtspMediaSource.Factory().createMediaSource(mediaItem);
+        msFactory = new RtspMediaSource.Factory();
+        break;
       case "application/x-rtmp":
-        factory = rtmpDataSourceFactory;
-        return new ProgressiveMediaSource.Factory(factory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy).createMediaSource(mediaItem);
+        dsFactory = rtmpDataSourceFactory;
+        msFactory = new ProgressiveMediaSource.Factory(dsFactory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy);
+        break;
       default:
-        return new ProgressiveMediaSource.Factory(factory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy).createMediaSource(mediaItem);
+        msFactory = new ProgressiveMediaSource.Factory(dsFactory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy);
+        break;
     }
+
+    if (msFactory == null)
+      return null;
+
+    msFactory.experimentalParseSubtitlesDuringExtraction(false);
+
+    return msFactory.createMediaSource(mediaItem);
   }
 
   private ArrayList<MediaSource> buildCaptionMediaSources(MediaSource video) {
     ArrayList<MediaSource> captions = new ArrayList<MediaSource>();
-    DataSource.Factory factory;
+    DataSource.Factory dsFactory;
 
     try {
       for (MediaItem.SubtitleConfiguration subtitleConfiguration : video.getMediaItem().localConfiguration.subtitleConfigurations) {
-        factory = ExternalStorageUtils.isFileUri(subtitleConfiguration.uri.toString())
+        dsFactory = ExternalStorageUtils.isFileUri(subtitleConfiguration.uri.toString())
           ? defaultDataSourceFactory
           : httpDataSourceFactory;
 
         captions.add(
-          new SingleSampleMediaSource.Factory(factory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy).createMediaSource(subtitleConfiguration, C.TIME_UNSET)
+          new SingleSampleMediaSource.Factory(dsFactory).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy).createMediaSource(subtitleConfiguration, C.TIME_UNSET)
         );
       }
     }
diff --git a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/customizations/MyRenderersFactory.java b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/customizations/MyRenderersFactory.java
index 69f8c88..e769312 100644
--- a/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/customizations/MyRenderersFactory.java
+++ b/android-studio-project/ExoPlayer-AirPlay-Receiver/src/main/java/com/github/warren_bank/exoplayer_airplay_receiver/exoplayer2/customizations/MyRenderersFactory.java
@@ -33,6 +33,7 @@ protected void buildTextRenderers(
     ArrayList<Renderer> out
   ) {
     textRenderer = new MyTextRenderer(output, outputLooper);
+    textRenderer.experimentalSetLegacyDecodingEnabled(true);
     out.add(textRenderer);
   }