82
82
import androidx .annotation .Nullable ;
83
83
import androidx .core .os .EnvironmentCompat ;
84
84
import androidx .exifinterface .media .ExifInterface ;
85
+ import androidx .media3 .common .C ;
86
+ import androidx .media3 .common .Format ;
87
+ import androidx .media3 .common .MimeTypes ;
85
88
import androidx .media3 .common .PlaybackException ;
89
+ import androidx .media3 .common .util .TimestampAdjuster ;
90
+ import androidx .media3 .datasource .ByteArrayDataSource ;
91
+ import androidx .media3 .datasource .DataSource ;
86
92
import androidx .media3 .datasource .FileDataSource ;
87
93
import androidx .media3 .exoplayer .DefaultLoadControl ;
88
94
import androidx .media3 .exoplayer .DefaultRenderersFactory ;
89
95
import androidx .media3 .exoplayer .ExoPlaybackException ;
90
96
import androidx .media3 .exoplayer .ExoPlayer ;
91
97
import androidx .media3 .exoplayer .RenderersFactory ;
98
+ import androidx .media3 .exoplayer .analytics .PlayerId ;
99
+ import androidx .media3 .exoplayer .hls .BundledHlsMediaChunkExtractor ;
100
+ import androidx .media3 .exoplayer .hls .DefaultHlsExtractorFactory ;
101
+ import androidx .media3 .exoplayer .hls .HlsExtractorFactory ;
102
+ import androidx .media3 .exoplayer .hls .HlsMediaChunkExtractor ;
103
+ import androidx .media3 .exoplayer .hls .HlsMediaSource ;
104
+ import androidx .media3 .exoplayer .hls .playlist .DefaultHlsPlaylistParserFactory ;
92
105
import androidx .media3 .exoplayer .source .DefaultMediaSourceFactory ;
93
106
import androidx .media3 .exoplayer .source .MediaSource ;
94
- import androidx .media3 .exoplayer .source .MediaSourceFactory ;
95
107
import androidx .media3 .exoplayer .source .ProgressiveMediaSource ;
96
108
import androidx .media3 .exoplayer .source .UnrecognizedInputFormatException ;
97
109
import androidx .media3 .exoplayer .trackselection .DefaultTrackSelector ;
98
110
import androidx .media3 .extractor .DefaultExtractorsFactory ;
111
+ import androidx .media3 .extractor .ExtractorInput ;
99
112
import androidx .recyclerview .widget .RecyclerView ;
100
113
101
114
import com .google .android .gms .common .ConnectionResult ;
161
174
import java .util .TreeSet ;
162
175
import java .util .concurrent .CountDownLatch ;
163
176
import java .util .concurrent .TimeUnit ;
177
+ import java .util .concurrent .TimeoutException ;
164
178
import java .util .zip .GZIPInputStream ;
165
179
166
180
import javax .microedition .khronos .egl .EGL10 ;
185
199
import okio .Sink ;
186
200
import okio .Source ;
187
201
import tgx .td .Td ;
202
+ import tgx .td .data .HlsPath ;
203
+ import tgx .td .data .HlsVideo ;
188
204
189
205
@ SuppressWarnings ("JniMissingFunction" )
190
206
public class U {
@@ -726,7 +742,7 @@ public static ExoPlayer newExoPlayer (Context context, boolean preferExtensions)
726
742
// DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON
727
743
final int extensionMode = preferExtensions || org .thunderdog .challegram .unsorted .Settings .instance ().getNewSetting (org .thunderdog .challegram .unsorted .Settings .SETTING_FLAG_FORCE_EXO_PLAYER_EXTENSIONS ) ? DefaultRenderersFactory .EXTENSION_RENDERER_MODE_PREFER : DefaultRenderersFactory .EXTENSION_RENDERER_MODE_ON ;
728
744
final RenderersFactory renderersFactory = new DefaultRenderersFactory (context ).setExtensionRendererMode (extensionMode );
729
- final MediaSourceFactory mediaSourceFactory = new DefaultMediaSourceFactory (context , new DefaultExtractorsFactory ().setConstantBitrateSeekingEnabled (true ));
745
+ final MediaSource . Factory mediaSourceFactory = new DefaultMediaSourceFactory (context , new DefaultExtractorsFactory ().setConstantBitrateSeekingEnabled (true ));
730
746
return new ExoPlayer .Builder (context , renderersFactory , mediaSourceFactory )
731
747
.setTrackSelector (new DefaultTrackSelector (context ))
732
748
.setLoadControl (new DefaultLoadControl ())
@@ -746,29 +762,109 @@ public static MediaSource newMediaSource (File file) {
746
762
}
747
763
748
764
public static androidx .media3 .common .MediaItem newMediaItem (Uri uri ) {
749
- return new androidx .media3 .common .MediaItem .Builder (). setUri ( uri ). build ( );
765
+ return androidx .media3 .common .MediaItem .fromUri ( uri );
750
766
}
751
767
752
768
public static MediaSource newMediaSource (int accountId , TdApi .Message message ) {
753
769
return newMediaSource (accountId , TD .getFile (message ));
754
770
}
755
771
772
+ public static MediaSource newMediaSource (int accountId , @ Nullable HlsVideo hlsVideo ) {
773
+ if (hlsVideo == null ) {
774
+ throw new IllegalArgumentException ();
775
+ }
776
+
777
+ Uri manifestUri = TdlibDataSource .UriFactory .create (accountId , -1 );
778
+
779
+ TdlibDataSource .Factory factory = new TdlibDataSource .Factory (accountId , new TdlibDataSource .RequestModifier () {
780
+ @ Override
781
+ public Uri modifyUri (Uri sourceUri ) {
782
+ String scheme = sourceUri .getScheme ();
783
+ if (scheme == null ) {
784
+ throw new IllegalArgumentException (sourceUri .toString ());
785
+ }
786
+ switch (scheme ) {
787
+ case HlsVideo .MTPROTO_SCHEME : {
788
+ long streamId = HlsVideo .extractStreamId (sourceUri );
789
+ int videoFileId = hlsVideo .findVideoFileIdByStreamId (streamId );
790
+ return TdlibDataSource .UriFactory .create (accountId , videoFileId );
791
+ }
792
+ case HlsVideo .SCHEME : {
793
+ HlsPath hlsPath = HlsPath .fromUri (sourceUri );
794
+ return TdlibDataSource .UriFactory .create (accountId , hlsPath .hlsFileId );
795
+ }
796
+ default : {
797
+ return sourceUri ;
798
+ }
799
+ }
800
+ }
801
+
802
+ @ Nullable
803
+ @ Override
804
+ public DataSource redirectDataSource (Uri uri ) {
805
+ if (uri .equals (manifestUri )) {
806
+ String playlistData = hlsVideo .multivariantPlaylistData ();
807
+ return new ByteArrayDataSource (playlistData .getBytes ());
808
+ }
809
+ return null ;
810
+ }
811
+ });
812
+
813
+ return new HlsMediaSource .Factory (factory )
814
+ .setAllowChunklessPreparation (false )
815
+ .setExtractorFactory (newHlsExtractorFactory (hlsVideo ))
816
+ .createMediaSource (newMediaItem (manifestUri ));
817
+ }
818
+
819
+ @ NonNull private static HlsExtractorFactory newHlsExtractorFactory (@ NonNull HlsVideo hlsVideo ) {
820
+ DefaultHlsExtractorFactory defaultHlsExtractorFactory = new DefaultHlsExtractorFactory ();
821
+ return new HlsExtractorFactory () {
822
+ @ Override
823
+ @ NonNull
824
+ public HlsMediaChunkExtractor createExtractor (@ NonNull Uri uri , @ NonNull Format format , @ Nullable List <Format > muxedCaptionFormats , @ NonNull TimestampAdjuster timestampAdjuster , @ NonNull Map <String , List <String >> responseHeaders , @ NonNull ExtractorInput sniffingExtractorInput , @ NonNull PlayerId playerId ) throws IOException {
825
+ if (HlsVideo .MTPROTO_SCHEME .equals (uri .getScheme ())) {
826
+ long streamId = HlsVideo .extractStreamId (uri );
827
+ TdApi .AlternativeVideo alternativeVideo = hlsVideo .findVideoByStreamId (streamId );
828
+ format = format .buildUpon ()
829
+ .setCodecs (alternativeVideo .codec )
830
+ .setWidth (alternativeVideo .width )
831
+ .setHeight (alternativeVideo .height )
832
+ .setContainerMimeType (MimeTypes .VIDEO_MP4 )
833
+ .setCryptoType (C .CRYPTO_TYPE_UNSUPPORTED )
834
+ .build ();
835
+ if (!timestampAdjuster .isInitialized ()) {
836
+ try {
837
+ timestampAdjuster .sharedInitializeOrWait (true , 0 , 0 );
838
+ } catch (TimeoutException | InterruptedException ignored ) { }
839
+ }
840
+ }
841
+ return defaultHlsExtractorFactory .createExtractor (uri , format , muxedCaptionFormats , timestampAdjuster , responseHeaders , sniffingExtractorInput , playerId );
842
+ }
843
+ };
844
+ }
845
+
756
846
public static MediaSource newMediaSource (int accountId , @ Nullable TdApi .File file ) {
757
847
if (file == null )
758
848
throw new IllegalArgumentException ();
849
+ Uri uri ;
850
+ DataSource .Factory factory ;
759
851
if (file .id == -1 && !StringUtils .isEmpty (file .local .path )) {
760
- return newMediaSource (new File (file .local .path ));
852
+ uri = Uri .fromFile (new File (file .local .path ));
853
+ factory = new FileDataSource .Factory ();
761
854
} else {
762
- return new ProgressiveMediaSource .Factory (new TdlibDataSource .Factory ()).createMediaSource (newMediaItem (TdlibDataSource .UriFactory .create (accountId , file )));
855
+ uri = TdlibDataSource .UriFactory .create (accountId , file );
856
+ factory = new TdlibDataSource .Factory ();
763
857
}
858
+ androidx .media3 .common .MediaItem media = newMediaItem (uri );
859
+ return new ProgressiveMediaSource .Factory (factory ).createMediaSource (media );
764
860
}
765
861
766
862
public static MediaSource newMediaSource (RandomAccessFile file ) {
767
863
return new ProgressiveMediaSource .Factory (new RandomAccessDataSource .Factory (file )).createMediaSource (newMediaItem (Uri .EMPTY ));
768
864
}
769
865
770
866
public static MediaSource newMediaSource (int accountId , int fileId ) {
771
- return new ProgressiveMediaSource .Factory (new TdlibDataSource .Factory ()).createMediaSource (newMediaItem (TdlibDataSource .UriFactory .create (accountId , fileId )));
867
+ return new ProgressiveMediaSource .Factory (new TdlibDataSource .Factory (accountId )).createMediaSource (newMediaItem (TdlibDataSource .UriFactory .create (accountId , fileId )));
772
868
}
773
869
774
870
public static boolean isGooglePlayServicesAvailable (Context context ) {
@@ -1204,11 +1300,12 @@ public static float getAnimationScale (Context context) {
1204
1300
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ) {
1205
1301
return ValueAnimator .getDurationScale ();
1206
1302
}
1207
- try {
1208
- return Settings . Global . getFloat ( context . getContentResolver (), Settings . Global . ANIMATOR_DURATION_SCALE , 1.0f );
1209
- } catch ( Throwable ignored ) {
1210
- return 1.0f ;
1303
+ if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . JELLY_BEAN_MR1 ) {
1304
+ try {
1305
+ return Settings . Global . getFloat ( context . getContentResolver (), Settings . Global . ANIMATOR_DURATION_SCALE , 1.0f );
1306
+ } catch ( Throwable ignored ) { }
1211
1307
}
1308
+ return 1.0f ;
1212
1309
}
1213
1310
public static String getDataColumn (Context context , Uri uri , String selection , String [] selectionArgs ) {
1214
1311
final String column = "_data" ;
0 commit comments