mirror of
https://github.com/samsonjs/media.git
synced 2026-04-05 11:15:46 +00:00
Add DownloadHelper.createMediaSource utility method
PiperOrigin-RevId: 245243488
This commit is contained in:
parent
21b2a471bb
commit
708cad6b28
4 changed files with 98 additions and 75 deletions
|
|
@ -30,15 +30,12 @@ import com.google.android.exoplayer2.offline.DownloadIndex;
|
|||
import com.google.android.exoplayer2.offline.DownloadManager;
|
||||
import com.google.android.exoplayer2.offline.DownloadRequest;
|
||||
import com.google.android.exoplayer2.offline.DownloadService;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/** Tracks media that has been downloaded. */
|
||||
|
|
@ -86,11 +83,9 @@ public class DownloadTracker {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<StreamKey> getOfflineStreamKeys(Uri uri) {
|
||||
public DownloadRequest getDownloadRequest(Uri uri) {
|
||||
Download download = downloads.get(uri);
|
||||
return download != null && download.state != Download.STATE_FAILED
|
||||
? download.request.streamKeys
|
||||
: Collections.emptyList();
|
||||
return download != null && download.state != Download.STATE_FAILED ? download.request : null;
|
||||
}
|
||||
|
||||
public void toggleDownload(
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
|
|||
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.offline.DownloadHelper;
|
||||
import com.google.android.exoplayer2.offline.DownloadRequest;
|
||||
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
|
|
@ -75,7 +76,6 @@ import java.lang.reflect.Constructor;
|
|||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/** An activity that plays media using {@link SimpleExoPlayer}. */
|
||||
|
|
@ -457,33 +457,26 @@ public class PlayerActivity extends AppCompatActivity
|
|||
}
|
||||
|
||||
private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) {
|
||||
DownloadRequest downloadRequest =
|
||||
((DemoApplication) getApplication()).getDownloadTracker().getDownloadRequest(uri);
|
||||
if (downloadRequest != null) {
|
||||
return DownloadHelper.createMediaSource(downloadRequest, dataSourceFactory);
|
||||
}
|
||||
@ContentType int type = Util.inferContentType(uri, overrideExtension);
|
||||
List<StreamKey> offlineStreamKeys = getOfflineStreamKeys(uri);
|
||||
switch (type) {
|
||||
case C.TYPE_DASH:
|
||||
return new DashMediaSource.Factory(dataSourceFactory)
|
||||
.setStreamKeys(offlineStreamKeys)
|
||||
.createMediaSource(uri);
|
||||
return new DashMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
case C.TYPE_SS:
|
||||
return new SsMediaSource.Factory(dataSourceFactory)
|
||||
.setStreamKeys(offlineStreamKeys)
|
||||
.createMediaSource(uri);
|
||||
return new SsMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
case C.TYPE_HLS:
|
||||
return new HlsMediaSource.Factory(dataSourceFactory)
|
||||
.setStreamKeys(offlineStreamKeys)
|
||||
.createMediaSource(uri);
|
||||
return new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
case C.TYPE_OTHER:
|
||||
return new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
|
||||
default: {
|
||||
default:
|
||||
throw new IllegalStateException("Unsupported type: " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<StreamKey> getOfflineStreamKeys(Uri uri) {
|
||||
return ((DemoApplication) getApplication()).getDownloadTracker().getOfflineStreamKeys(uri);
|
||||
}
|
||||
|
||||
private DefaultDrmSessionManager<FrameworkMediaCrypto> buildDrmSessionManagerV18(
|
||||
UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray, boolean multiSession)
|
||||
throws UnsupportedDrmException {
|
||||
|
|
|
|||
|
|
@ -46,18 +46,21 @@
|
|||
|
||||
# Constructors accessed via reflection in DownloadHelper
|
||||
-dontnote com.google.android.exoplayer2.source.dash.DashMediaSource$Factory
|
||||
-keepclassmembers class com.google.android.exoplayer2.source.dash.DashMediaSource$Factory {
|
||||
-keepclasseswithmembers class com.google.android.exoplayer2.source.dash.DashMediaSource$Factory {
|
||||
<init>(com.google.android.exoplayer2.upstream.DataSource$Factory);
|
||||
** setStreamKeys(java.util.List);
|
||||
com.google.android.exoplayer2.source.dash.DashMediaSource createMediaSource(android.net.Uri);
|
||||
}
|
||||
-dontnote com.google.android.exoplayer2.source.hls.HlsMediaSource$Factory
|
||||
-keepclassmembers class com.google.android.exoplayer2.source.hls.HlsMediaSource$Factory {
|
||||
-keepclasseswithmembers class com.google.android.exoplayer2.source.hls.HlsMediaSource$Factory {
|
||||
<init>(com.google.android.exoplayer2.upstream.DataSource$Factory);
|
||||
** setStreamKeys(java.util.List);
|
||||
com.google.android.exoplayer2.source.hls.HlsMediaSource createMediaSource(android.net.Uri);
|
||||
}
|
||||
-dontnote com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource$Factory
|
||||
-keepclassmembers class com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource$Factory {
|
||||
-keepclasseswithmembers class com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource$Factory {
|
||||
<init>(com.google.android.exoplayer2.upstream.DataSource$Factory);
|
||||
** setStreamKeys(java.util.List);
|
||||
com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource createMediaSource(android.net.Uri);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import android.os.Handler;
|
|||
import android.os.HandlerThread;
|
||||
import android.os.Message;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseIntArray;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
|
|
@ -32,6 +31,7 @@ import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
|||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.BaseTrackSelection;
|
||||
|
|
@ -44,6 +44,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
|
|||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSource.Factory;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
|
@ -106,30 +107,13 @@ public final class DownloadHelper {
|
|||
void onPrepareError(DownloadHelper helper, IOException e);
|
||||
}
|
||||
|
||||
@Nullable private static final Constructor<?> DASH_FACTORY_CONSTRUCTOR;
|
||||
@Nullable private static final Constructor<?> HLS_FACTORY_CONSTRUCTOR;
|
||||
@Nullable private static final Constructor<?> SS_FACTORY_CONSTRUCTOR;
|
||||
@Nullable private static final Method DASH_FACTORY_CREATE_METHOD;
|
||||
@Nullable private static final Method HLS_FACTORY_CREATE_METHOD;
|
||||
@Nullable private static final Method SS_FACTORY_CREATE_METHOD;
|
||||
|
||||
static {
|
||||
Pair<@NullableType Constructor<?>, @NullableType Method> dashFactoryMethods =
|
||||
getMediaSourceFactoryMethods(
|
||||
"com.google.android.exoplayer2.source.dash.DashMediaSource$Factory");
|
||||
DASH_FACTORY_CONSTRUCTOR = dashFactoryMethods.first;
|
||||
DASH_FACTORY_CREATE_METHOD = dashFactoryMethods.second;
|
||||
Pair<@NullableType Constructor<?>, @NullableType Method> hlsFactoryMethods =
|
||||
getMediaSourceFactoryMethods(
|
||||
"com.google.android.exoplayer2.source.hls.HlsMediaSource$Factory");
|
||||
HLS_FACTORY_CONSTRUCTOR = hlsFactoryMethods.first;
|
||||
HLS_FACTORY_CREATE_METHOD = hlsFactoryMethods.second;
|
||||
Pair<@NullableType Constructor<?>, @NullableType Method> ssFactoryMethods =
|
||||
getMediaSourceFactoryMethods(
|
||||
"com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource$Factory");
|
||||
SS_FACTORY_CONSTRUCTOR = ssFactoryMethods.first;
|
||||
SS_FACTORY_CREATE_METHOD = ssFactoryMethods.second;
|
||||
}
|
||||
private static final MediaSourceFactory DASH_FACTORY =
|
||||
getMediaSourceFactory("com.google.android.exoplayer2.source.dash.DashMediaSource$Factory");
|
||||
private static final MediaSourceFactory SS_FACTORY =
|
||||
getMediaSourceFactory(
|
||||
"com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource$Factory");
|
||||
private static final MediaSourceFactory HLS_FACTORY =
|
||||
getMediaSourceFactory("com.google.android.exoplayer2.source.hls.HlsMediaSource$Factory");
|
||||
|
||||
/**
|
||||
* Creates a {@link DownloadHelper} for progressive streams.
|
||||
|
|
@ -202,8 +186,7 @@ public final class DownloadHelper {
|
|||
DownloadRequest.TYPE_DASH,
|
||||
uri,
|
||||
/* cacheKey= */ null,
|
||||
createMediaSource(
|
||||
uri, dataSourceFactory, DASH_FACTORY_CONSTRUCTOR, DASH_FACTORY_CREATE_METHOD),
|
||||
DASH_FACTORY.createMediaSource(uri, dataSourceFactory, /* streamKeys= */ null),
|
||||
trackSelectorParameters,
|
||||
Util.getRendererCapabilities(renderersFactory, drmSessionManager));
|
||||
}
|
||||
|
|
@ -252,8 +235,7 @@ public final class DownloadHelper {
|
|||
DownloadRequest.TYPE_HLS,
|
||||
uri,
|
||||
/* cacheKey= */ null,
|
||||
createMediaSource(
|
||||
uri, dataSourceFactory, HLS_FACTORY_CONSTRUCTOR, HLS_FACTORY_CREATE_METHOD),
|
||||
HLS_FACTORY.createMediaSource(uri, dataSourceFactory, /* streamKeys= */ null),
|
||||
trackSelectorParameters,
|
||||
Util.getRendererCapabilities(renderersFactory, drmSessionManager));
|
||||
}
|
||||
|
|
@ -302,11 +284,42 @@ public final class DownloadHelper {
|
|||
DownloadRequest.TYPE_SS,
|
||||
uri,
|
||||
/* cacheKey= */ null,
|
||||
createMediaSource(uri, dataSourceFactory, SS_FACTORY_CONSTRUCTOR, SS_FACTORY_CREATE_METHOD),
|
||||
SS_FACTORY.createMediaSource(uri, dataSourceFactory, /* streamKeys= */ null),
|
||||
trackSelectorParameters,
|
||||
Util.getRendererCapabilities(renderersFactory, drmSessionManager));
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to create a MediaSource which only contains the tracks defined in {@code
|
||||
* downloadRequest}.
|
||||
*
|
||||
* @param downloadRequest A {@link DownloadRequest}.
|
||||
* @param dataSourceFactory A factory for {@link DataSource}s to read the media.
|
||||
* @return A MediaSource which only contains the tracks defined in {@code downloadRequest}.
|
||||
*/
|
||||
public static MediaSource createMediaSource(
|
||||
DownloadRequest downloadRequest, DataSource.Factory dataSourceFactory) {
|
||||
MediaSourceFactory factory;
|
||||
switch (downloadRequest.type) {
|
||||
case DownloadRequest.TYPE_DASH:
|
||||
factory = DASH_FACTORY;
|
||||
break;
|
||||
case DownloadRequest.TYPE_SS:
|
||||
factory = SS_FACTORY;
|
||||
break;
|
||||
case DownloadRequest.TYPE_HLS:
|
||||
factory = HLS_FACTORY;
|
||||
break;
|
||||
case DownloadRequest.TYPE_PROGRESSIVE:
|
||||
return new ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||
.createMediaSource(downloadRequest.uri);
|
||||
default:
|
||||
throw new IllegalStateException("Unsupported type: " + downloadRequest.type);
|
||||
}
|
||||
return factory.createMediaSource(
|
||||
downloadRequest.uri, dataSourceFactory, downloadRequest.streamKeys);
|
||||
}
|
||||
|
||||
private final String downloadType;
|
||||
private final Uri uri;
|
||||
@Nullable private final String cacheKey;
|
||||
|
|
@ -728,35 +741,54 @@ public final class DownloadHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private static Pair<@NullableType Constructor<?>, @NullableType Method>
|
||||
getMediaSourceFactoryMethods(String className) {
|
||||
private static MediaSourceFactory getMediaSourceFactory(String className) {
|
||||
Constructor<?> constructor = null;
|
||||
Method setStreamKeysMethod = null;
|
||||
Method createMethod = null;
|
||||
try {
|
||||
// LINT.IfChange
|
||||
Class<?> factoryClazz = Class.forName(className);
|
||||
constructor = factoryClazz.getConstructor(DataSource.Factory.class);
|
||||
constructor = factoryClazz.getConstructor(Factory.class);
|
||||
setStreamKeysMethod = factoryClazz.getMethod("setStreamKeys", List.class);
|
||||
createMethod = factoryClazz.getMethod("createMediaSource", Uri.class);
|
||||
// LINT.ThenChange(../../../../../../../../proguard-rules.txt)
|
||||
} catch (Exception e) {
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Expected if the app was built without the respective module.
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
// Something is wrong with the library or the proguard configuration.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return Pair.create(constructor, createMethod);
|
||||
return new MediaSourceFactory(constructor, setStreamKeysMethod, createMethod);
|
||||
}
|
||||
|
||||
private static MediaSource createMediaSource(
|
||||
Uri uri,
|
||||
DataSource.Factory dataSourceFactory,
|
||||
@Nullable Constructor<?> factoryConstructor,
|
||||
@Nullable Method createMediaSourceMethod) {
|
||||
if (factoryConstructor == null || createMediaSourceMethod == null) {
|
||||
throw new IllegalStateException("Module missing to create media source.");
|
||||
private static final class MediaSourceFactory {
|
||||
@Nullable private final Constructor<?> constructor;
|
||||
@Nullable private final Method setStreamKeysMethod;
|
||||
@Nullable private final Method createMethod;
|
||||
|
||||
public MediaSourceFactory(
|
||||
@Nullable Constructor<?> constructor,
|
||||
@Nullable Method setStreamKeysMethod,
|
||||
@Nullable Method createMethod) {
|
||||
this.constructor = constructor;
|
||||
this.setStreamKeysMethod = setStreamKeysMethod;
|
||||
this.createMethod = createMethod;
|
||||
}
|
||||
try {
|
||||
Object factory = factoryConstructor.newInstance(dataSourceFactory);
|
||||
return (MediaSource) Assertions.checkNotNull(createMediaSourceMethod.invoke(factory, uri));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to instantiate media source.", e);
|
||||
|
||||
private MediaSource createMediaSource(
|
||||
Uri uri, Factory dataSourceFactory, @Nullable List<StreamKey> streamKeys) {
|
||||
if (constructor == null || setStreamKeysMethod == null || createMethod == null) {
|
||||
throw new IllegalStateException("Module missing to create media source.");
|
||||
}
|
||||
try {
|
||||
Object factory = constructor.newInstance(dataSourceFactory);
|
||||
if (streamKeys != null) {
|
||||
setStreamKeysMethod.invoke(factory, streamKeys);
|
||||
}
|
||||
return (MediaSource) Assertions.checkNotNull(createMethod.invoke(factory, uri));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to instantiate media source.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue