Commit b626dd70 by eguven Committed by Oliver Woodman

Add DownloadHelper.createMediaSource utility method

PiperOrigin-RevId: 245243488
parent 7d430423
...@@ -30,15 +30,12 @@ import com.google.android.exoplayer2.offline.DownloadIndex; ...@@ -30,15 +30,12 @@ import com.google.android.exoplayer2.offline.DownloadIndex;
import com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadRequest; import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.DownloadService; 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.trackselection.MappingTrackSelector.MappedTrackInfo;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
/** Tracks media that has been downloaded. */ /** Tracks media that has been downloaded. */
...@@ -86,11 +83,9 @@ public class DownloadTracker { ...@@ -86,11 +83,9 @@ public class DownloadTracker {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<StreamKey> getOfflineStreamKeys(Uri uri) { public DownloadRequest getDownloadRequest(Uri uri) {
Download download = downloads.get(uri); Download download = downloads.get(uri);
return download != null && download.state != Download.STATE_FAILED return download != null && download.state != Download.STATE_FAILED ? download.request : null;
? download.request.streamKeys
: Collections.emptyList();
} }
public void toggleDownload( public void toggleDownload(
......
...@@ -45,7 +45,8 @@ import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; ...@@ -45,7 +45,8 @@ import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.UnsupportedDrmException; import com.google.android.exoplayer2.drm.UnsupportedDrmException;
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException; import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; 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.BehindLiveWindowException;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource; import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
...@@ -75,7 +76,6 @@ import java.lang.reflect.Constructor; ...@@ -75,7 +76,6 @@ import java.lang.reflect.Constructor;
import java.net.CookieHandler; import java.net.CookieHandler;
import java.net.CookieManager; import java.net.CookieManager;
import java.net.CookiePolicy; import java.net.CookiePolicy;
import java.util.List;
import java.util.UUID; import java.util.UUID;
/** An activity that plays media using {@link SimpleExoPlayer}. */ /** An activity that plays media using {@link SimpleExoPlayer}. */
...@@ -457,33 +457,26 @@ public class PlayerActivity extends AppCompatActivity ...@@ -457,33 +457,26 @@ public class PlayerActivity extends AppCompatActivity
} }
private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) { 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); @ContentType int type = Util.inferContentType(uri, overrideExtension);
List<StreamKey> offlineStreamKeys = getOfflineStreamKeys(uri);
switch (type) { switch (type) {
case C.TYPE_DASH: case C.TYPE_DASH:
return new DashMediaSource.Factory(dataSourceFactory) return new DashMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
.setStreamKeys(offlineStreamKeys)
.createMediaSource(uri);
case C.TYPE_SS: case C.TYPE_SS:
return new SsMediaSource.Factory(dataSourceFactory) return new SsMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
.setStreamKeys(offlineStreamKeys)
.createMediaSource(uri);
case C.TYPE_HLS: case C.TYPE_HLS:
return new HlsMediaSource.Factory(dataSourceFactory) return new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
.setStreamKeys(offlineStreamKeys)
.createMediaSource(uri);
case C.TYPE_OTHER: case C.TYPE_OTHER:
return new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(uri); return new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
default: { default:
throw new IllegalStateException("Unsupported type: " + type); throw new IllegalStateException("Unsupported type: " + type);
}
} }
} }
private List<StreamKey> getOfflineStreamKeys(Uri uri) {
return ((DemoApplication) getApplication()).getDownloadTracker().getOfflineStreamKeys(uri);
}
private DefaultDrmSessionManager<FrameworkMediaCrypto> buildDrmSessionManagerV18( private DefaultDrmSessionManager<FrameworkMediaCrypto> buildDrmSessionManagerV18(
UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray, boolean multiSession) UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray, boolean multiSession)
throws UnsupportedDrmException { throws UnsupportedDrmException {
......
...@@ -46,18 +46,21 @@ ...@@ -46,18 +46,21 @@
# Constructors accessed via reflection in DownloadHelper # Constructors accessed via reflection in DownloadHelper
-dontnote com.google.android.exoplayer2.source.dash.DashMediaSource$Factory -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); <init>(com.google.android.exoplayer2.upstream.DataSource$Factory);
** setStreamKeys(java.util.List);
com.google.android.exoplayer2.source.dash.DashMediaSource createMediaSource(android.net.Uri); com.google.android.exoplayer2.source.dash.DashMediaSource createMediaSource(android.net.Uri);
} }
-dontnote com.google.android.exoplayer2.source.hls.HlsMediaSource$Factory -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); <init>(com.google.android.exoplayer2.upstream.DataSource$Factory);
** setStreamKeys(java.util.List);
com.google.android.exoplayer2.source.hls.HlsMediaSource createMediaSource(android.net.Uri); com.google.android.exoplayer2.source.hls.HlsMediaSource createMediaSource(android.net.Uri);
} }
-dontnote com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource$Factory -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); <init>(com.google.android.exoplayer2.upstream.DataSource$Factory);
** setStreamKeys(java.util.List);
com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource createMediaSource(android.net.Uri); com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource createMediaSource(android.net.Uri);
} }
......
...@@ -20,7 +20,6 @@ import android.os.Handler; ...@@ -20,7 +20,6 @@ import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Message; import android.os.Message;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import android.util.Pair;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
...@@ -32,6 +31,7 @@ import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; ...@@ -32,6 +31,7 @@ import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; 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.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.BaseTrackSelection; import com.google.android.exoplayer2.trackselection.BaseTrackSelection;
...@@ -44,6 +44,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult; ...@@ -44,6 +44,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource; 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.DefaultAllocator;
import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
...@@ -106,30 +107,13 @@ public final class DownloadHelper { ...@@ -106,30 +107,13 @@ public final class DownloadHelper {
void onPrepareError(DownloadHelper helper, IOException e); void onPrepareError(DownloadHelper helper, IOException e);
} }
@Nullable private static final Constructor<?> DASH_FACTORY_CONSTRUCTOR; private static final MediaSourceFactory DASH_FACTORY =
@Nullable private static final Constructor<?> HLS_FACTORY_CONSTRUCTOR; getMediaSourceFactory("com.google.android.exoplayer2.source.dash.DashMediaSource$Factory");
@Nullable private static final Constructor<?> SS_FACTORY_CONSTRUCTOR; private static final MediaSourceFactory SS_FACTORY =
@Nullable private static final Method DASH_FACTORY_CREATE_METHOD; getMediaSourceFactory(
@Nullable private static final Method HLS_FACTORY_CREATE_METHOD; "com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource$Factory");
@Nullable private static final Method SS_FACTORY_CREATE_METHOD; private static final MediaSourceFactory HLS_FACTORY =
getMediaSourceFactory("com.google.android.exoplayer2.source.hls.HlsMediaSource$Factory");
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;
}
/** /**
* Creates a {@link DownloadHelper} for progressive streams. * Creates a {@link DownloadHelper} for progressive streams.
...@@ -202,8 +186,7 @@ public final class DownloadHelper { ...@@ -202,8 +186,7 @@ public final class DownloadHelper {
DownloadRequest.TYPE_DASH, DownloadRequest.TYPE_DASH,
uri, uri,
/* cacheKey= */ null, /* cacheKey= */ null,
createMediaSource( DASH_FACTORY.createMediaSource(uri, dataSourceFactory, /* streamKeys= */ null),
uri, dataSourceFactory, DASH_FACTORY_CONSTRUCTOR, DASH_FACTORY_CREATE_METHOD),
trackSelectorParameters, trackSelectorParameters,
Util.getRendererCapabilities(renderersFactory, drmSessionManager)); Util.getRendererCapabilities(renderersFactory, drmSessionManager));
} }
...@@ -252,8 +235,7 @@ public final class DownloadHelper { ...@@ -252,8 +235,7 @@ public final class DownloadHelper {
DownloadRequest.TYPE_HLS, DownloadRequest.TYPE_HLS,
uri, uri,
/* cacheKey= */ null, /* cacheKey= */ null,
createMediaSource( HLS_FACTORY.createMediaSource(uri, dataSourceFactory, /* streamKeys= */ null),
uri, dataSourceFactory, HLS_FACTORY_CONSTRUCTOR, HLS_FACTORY_CREATE_METHOD),
trackSelectorParameters, trackSelectorParameters,
Util.getRendererCapabilities(renderersFactory, drmSessionManager)); Util.getRendererCapabilities(renderersFactory, drmSessionManager));
} }
...@@ -302,11 +284,42 @@ public final class DownloadHelper { ...@@ -302,11 +284,42 @@ public final class DownloadHelper {
DownloadRequest.TYPE_SS, DownloadRequest.TYPE_SS,
uri, uri,
/* cacheKey= */ null, /* cacheKey= */ null,
createMediaSource(uri, dataSourceFactory, SS_FACTORY_CONSTRUCTOR, SS_FACTORY_CREATE_METHOD), SS_FACTORY.createMediaSource(uri, dataSourceFactory, /* streamKeys= */ null),
trackSelectorParameters, trackSelectorParameters,
Util.getRendererCapabilities(renderersFactory, drmSessionManager)); 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 String downloadType;
private final Uri uri; private final Uri uri;
@Nullable private final String cacheKey; @Nullable private final String cacheKey;
...@@ -739,35 +752,54 @@ public final class DownloadHelper { ...@@ -739,35 +752,54 @@ public final class DownloadHelper {
} }
} }
private static Pair<@NullableType Constructor<?>, @NullableType Method> private static MediaSourceFactory getMediaSourceFactory(String className) {
getMediaSourceFactoryMethods(String className) {
Constructor<?> constructor = null; Constructor<?> constructor = null;
Method setStreamKeysMethod = null;
Method createMethod = null; Method createMethod = null;
try { try {
// LINT.IfChange // LINT.IfChange
Class<?> factoryClazz = Class.forName(className); 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); createMethod = factoryClazz.getMethod("createMediaSource", Uri.class);
// LINT.ThenChange(../../../../../../../../proguard-rules.txt) // LINT.ThenChange(../../../../../../../../proguard-rules.txt)
} catch (Exception e) { } catch (ClassNotFoundException e) {
// Expected if the app was built without the respective module. // 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( private static final class MediaSourceFactory {
Uri uri, @Nullable private final Constructor<?> constructor;
DataSource.Factory dataSourceFactory, @Nullable private final Method setStreamKeysMethod;
@Nullable Constructor<?> factoryConstructor, @Nullable private final Method createMethod;
@Nullable Method createMediaSourceMethod) {
if (factoryConstructor == null || createMediaSourceMethod == null) { public MediaSourceFactory(
throw new IllegalStateException("Module missing to create media source."); @Nullable Constructor<?> constructor,
@Nullable Method setStreamKeysMethod,
@Nullable Method createMethod) {
this.constructor = constructor;
this.setStreamKeysMethod = setStreamKeysMethod;
this.createMethod = createMethod;
} }
try {
Object factory = factoryConstructor.newInstance(dataSourceFactory); private MediaSource createMediaSource(
return (MediaSource) Assertions.checkNotNull(createMediaSourceMethod.invoke(factory, uri)); Uri uri, Factory dataSourceFactory, @Nullable List<StreamKey> streamKeys) {
} catch (Exception e) { if (constructor == null || setStreamKeysMethod == null || createMethod == null) {
throw new IllegalStateException("Failed to instantiate media source.", e); 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);
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment