mirror of
https://github.com/samsonjs/media.git
synced 2026-04-04 11:05:47 +00:00
add clearTrackTypes and playClearContentWithoutKey to DrmConfiguration
With these additional properties, we can declare the behaviour for clear tracks and clear content on a media item level. PiperOrigin-RevId: 304351716
This commit is contained in:
parent
dbea614cca
commit
dc4118da7b
6 changed files with 139 additions and 48 deletions
|
|
@ -454,7 +454,6 @@ public class PlayerActivity extends AppCompatActivity
|
|||
private MediaSource createLeafMediaSource(UriSample parameters) {
|
||||
MediaItem.Builder builder = new MediaItem.Builder().setSourceUri(parameters.uri);
|
||||
builder.setMimeType(Sample.inferAdaptiveStreamMimeType(parameters.uri, parameters.extension));
|
||||
int[] drmSessionForClearTypes = new int[0];
|
||||
HttpDataSource.Factory drmDataSourceFactory = null;
|
||||
if (parameters.drmInfo != null) {
|
||||
if (Util.SDK_INT < 18) {
|
||||
|
|
@ -471,8 +470,8 @@ public class PlayerActivity extends AppCompatActivity
|
|||
.setDrmLicenseRequestHeaders(
|
||||
createLicenseHeaders(parameters.drmInfo.drmKeyRequestProperties))
|
||||
.setDrmUuid(parameters.drmInfo.drmScheme)
|
||||
.setDrmMultiSession(parameters.drmInfo.drmMultiSession);
|
||||
drmSessionForClearTypes = parameters.drmInfo.drmSessionForClearTypes;
|
||||
.setDrmMultiSession(parameters.drmInfo.drmMultiSession)
|
||||
.setDrmSessionForClearTypes(Util.toList(parameters.drmInfo.drmSessionForClearTypes));
|
||||
drmDataSourceFactory = ((DemoApplication) getApplication()).buildHttpDataSourceFactory();
|
||||
}
|
||||
if (parameters.subtitleInfo != null) {
|
||||
|
|
@ -494,7 +493,6 @@ public class PlayerActivity extends AppCompatActivity
|
|||
}
|
||||
return mediaSourceFactory
|
||||
.setDrmHttpDataSourceFactory(drmDataSourceFactory)
|
||||
.setUseDrmSessionForClearContent(drmSessionForClearTypes)
|
||||
.createMediaSource(builder.build());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ import java.io.InputStream;
|
|||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
|
|
@ -1199,6 +1200,23 @@ public final class Util {
|
|||
return intArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of primitive ints to a list of integers.
|
||||
*
|
||||
* @param ints The ints.
|
||||
* @return The input array in list form.
|
||||
*/
|
||||
public static List<Integer> toList(int... ints) {
|
||||
if (ints == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<Integer> integers = new ArrayList<>();
|
||||
for (int anInt : ints) {
|
||||
integers.add(anInt);
|
||||
}
|
||||
return integers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer equal to the big-endian concatenation of the characters in {@code string}
|
||||
* as bytes. The string must be no more than four characters long.
|
||||
|
|
|
|||
|
|
@ -934,6 +934,21 @@ public class UtilTest {
|
|||
assertThat(Util.normalizeLanguageCode("hsn")).isEqualTo("zh-hsn");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toList() {
|
||||
assertThat(Util.toList(0, 3, 4)).containsExactly(0, 3, 4).inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toList_nullPassed_returnsEmptyList() {
|
||||
assertThat(Util.toList(null)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toList_emptyArrayPassed_returnsEmptyList() {
|
||||
assertThat(Util.toList(new int[0])).isEmpty();
|
||||
}
|
||||
|
||||
private static void assertEscapeUnescapeFileName(String fileName, String escapedFileName) {
|
||||
assertThat(escapeFileName(fileName)).isEqualTo(escapedFileName);
|
||||
assertThat(unescapeFileName(escapedFileName)).isEqualTo(fileName);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.google.android.exoplayer2.offline.StreamKey;
|
|||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
|
@ -60,6 +61,8 @@ public final class MediaItem {
|
|||
private Map<String, String> drmLicenseRequestHeaders;
|
||||
@Nullable private UUID drmUuid;
|
||||
private boolean drmMultiSession;
|
||||
private boolean drmPlayClearContentWithoutKey;
|
||||
private List<Integer> drmSessionForClearTypes;
|
||||
private List<StreamKey> streamKeys;
|
||||
private List<Subtitle> subtitles;
|
||||
@Nullable private Object tag;
|
||||
|
|
@ -69,6 +72,7 @@ public final class MediaItem {
|
|||
public Builder() {
|
||||
streamKeys = Collections.emptyList();
|
||||
subtitles = Collections.emptyList();
|
||||
drmSessionForClearTypes = Collections.emptyList();
|
||||
drmLicenseRequestHeaders = Collections.emptyMap();
|
||||
}
|
||||
|
||||
|
|
@ -145,10 +149,10 @@ public final class MediaItem {
|
|||
* <p>If no valid drm configuration is specified, the drm license request headers are ignored.
|
||||
*/
|
||||
public Builder setDrmLicenseRequestHeaders(
|
||||
@Nullable Map<String, String> drmLicenseRequestHeaders) {
|
||||
@Nullable Map<String, String> licenseRequestHeaders) {
|
||||
this.drmLicenseRequestHeaders =
|
||||
drmLicenseRequestHeaders != null && !drmLicenseRequestHeaders.isEmpty()
|
||||
? drmLicenseRequestHeaders
|
||||
licenseRequestHeaders != null && !licenseRequestHeaders.isEmpty()
|
||||
? licenseRequestHeaders
|
||||
: Collections.emptyMap();
|
||||
return this;
|
||||
}
|
||||
|
|
@ -176,6 +180,50 @@ public final class MediaItem {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether clear samples within protected content should be played when keys for the
|
||||
* encrypted part of the content have yet to be loaded.
|
||||
*/
|
||||
public Builder setDrmPlayClearContentWithoutKey(boolean playClearContentWithoutKey) {
|
||||
this.drmPlayClearContentWithoutKey = playClearContentWithoutKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a drm session should be used for clear tracks of type {@link C#TRACK_TYPE_VIDEO}
|
||||
* and {@link C#TRACK_TYPE_AUDIO}.
|
||||
*
|
||||
* <p>This method overrides what has been set by previously calling {@link
|
||||
* #setDrmSessionForClearTypes(List)}.
|
||||
*/
|
||||
public Builder setDrmSessionForClearPeriods(boolean sessionForClearPeriods) {
|
||||
this.setDrmSessionForClearTypes(
|
||||
sessionForClearPeriods
|
||||
? Arrays.asList(C.TRACK_TYPE_VIDEO, C.TRACK_TYPE_AUDIO)
|
||||
: Collections.emptyList());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a list of {@link C}{@code .TRACK_TYPE_*} constants for which to use a drm session even
|
||||
* when the tracks are in the clear.
|
||||
*
|
||||
* <p>For the common case of using a drm session for {@link C#TRACK_TYPE_VIDEO} and {@link
|
||||
* C#TRACK_TYPE_AUDIO} the {@link #setDrmSessionForClearPeriods(boolean)} can be used.
|
||||
*
|
||||
* <p>This method overrides what has been set by previously calling {@link
|
||||
* #setDrmSessionForClearPeriods(boolean)}.
|
||||
*
|
||||
* <p>{@code null} or an empty {@link List} can be used for a reset.
|
||||
*/
|
||||
public Builder setDrmSessionForClearTypes(@Nullable List<Integer> sessionForClearTypes) {
|
||||
this.drmSessionForClearTypes =
|
||||
sessionForClearTypes != null && !sessionForClearTypes.isEmpty()
|
||||
? Collections.unmodifiableList(new ArrayList<>(sessionForClearTypes))
|
||||
: Collections.emptyList();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional stream keys by which the manifest is filtered (only used for adaptive
|
||||
* streams).
|
||||
|
|
@ -241,7 +289,12 @@ public final class MediaItem {
|
|||
mimeType,
|
||||
drmUuid != null
|
||||
? new DrmConfiguration(
|
||||
drmUuid, drmLicenseUri, drmLicenseRequestHeaders, drmMultiSession)
|
||||
drmUuid,
|
||||
drmLicenseUri,
|
||||
drmLicenseRequestHeaders,
|
||||
drmMultiSession,
|
||||
drmPlayClearContentWithoutKey,
|
||||
drmSessionForClearTypes)
|
||||
: null,
|
||||
streamKeys,
|
||||
subtitles,
|
||||
|
|
@ -273,15 +326,28 @@ public final class MediaItem {
|
|||
/** Whether the drm configuration is multi session enabled. */
|
||||
public final boolean multiSession;
|
||||
|
||||
/**
|
||||
* Whether clear samples within protected content should be played when keys for the encrypted
|
||||
* part of the content have yet to be loaded.
|
||||
*/
|
||||
public final boolean playClearContentWithoutKey;
|
||||
|
||||
/** The types of clear tracks for which to use a drm session. */
|
||||
public final List<Integer> sessionForClearTypes;
|
||||
|
||||
private DrmConfiguration(
|
||||
UUID uuid,
|
||||
@Nullable Uri licenseUri,
|
||||
Map<String, String> requestHeaders,
|
||||
boolean multiSession) {
|
||||
boolean multiSession,
|
||||
boolean playClearContentWithoutKey,
|
||||
List<Integer> drmSessionForClearTypes) {
|
||||
this.uuid = uuid;
|
||||
this.licenseUri = licenseUri;
|
||||
this.requestHeaders = Collections.unmodifiableMap(new HashMap<>(requestHeaders));
|
||||
this.multiSession = multiSession;
|
||||
this.playClearContentWithoutKey = playClearContentWithoutKey;
|
||||
this.sessionForClearTypes = drmSessionForClearTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -297,7 +363,9 @@ public final class MediaItem {
|
|||
return uuid.equals(other.uuid)
|
||||
&& Util.areEqual(licenseUri, other.licenseUri)
|
||||
&& Util.areEqual(requestHeaders, other.requestHeaders)
|
||||
&& multiSession == other.multiSession;
|
||||
&& multiSession == other.multiSession
|
||||
&& playClearContentWithoutKey == other.playClearContentWithoutKey
|
||||
&& sessionForClearTypes.equals(other.sessionForClearTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -306,6 +374,8 @@ public final class MediaItem {
|
|||
result = 31 * result + (licenseUri != null ? licenseUri.hashCode() : 0);
|
||||
result = 31 * result + requestHeaders.hashCode();
|
||||
result = 31 * result + (multiSession ? 1 : 0);
|
||||
result = 31 * result + (playClearContentWithoutKey ? 1 : 0);
|
||||
result = 31 * result + sessionForClearTypes.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,14 +77,9 @@ import java.util.Map;
|
|||
*
|
||||
* <p>For a media item with a valid {@link
|
||||
* com.google.android.exoplayer2.MediaItem.DrmConfiguration}, a {@link DefaultDrmSessionManager} is
|
||||
* created. The following setters can be used to optionally configure the creation:
|
||||
* created. The following setter can be used to optionally configure the creation:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #setPlayClearContentWithoutKey(boolean)}: See {@link
|
||||
* DefaultDrmSessionManager.Builder#setPlayClearSamplesWithoutKeys(boolean)} (default: {@code
|
||||
* false}).
|
||||
* <li>{@link #setUseDrmSessionForClearContent(int...)}: See {@link
|
||||
* DefaultDrmSessionManager.Builder#setUseDrmSessionsForClearContent(int...)} (default: none).
|
||||
* <li>{@link #setDrmHttpDataSourceFactory(HttpDataSource.Factory)}: Sets the data source factory
|
||||
* to be used by the {@link HttpMediaDrmCallback} for network requests (default: {@link
|
||||
* DefaultHttpDataSourceFactory}).
|
||||
|
|
@ -130,8 +125,6 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
|||
|
||||
private DrmSessionManager drmSessionManager;
|
||||
private HttpDataSource.Factory drmHttpDataSourceFactory;
|
||||
private boolean playClearContentWithoutKey;
|
||||
private int[] useDrmSessionsForClearContentTrackTypes;
|
||||
@Nullable private List<StreamKey> streamKeys;
|
||||
|
||||
private DefaultMediaSourceFactory(Context context, DataSource.Factory dataSourceFactory) {
|
||||
|
|
@ -139,7 +132,6 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
|||
drmSessionManager = DrmSessionManager.getDummyDrmSessionManager();
|
||||
userAgent = Util.getUserAgent(context, ExoPlayerLibraryInfo.VERSION_SLASHY);
|
||||
drmHttpDataSourceFactory = new DefaultHttpDataSourceFactory(userAgent);
|
||||
useDrmSessionsForClearContentTrackTypes = new int[0];
|
||||
mediaSourceFactories = loadDelegates(dataSourceFactory);
|
||||
supportedTypes = new int[mediaSourceFactories.size()];
|
||||
for (int i = 0; i < mediaSourceFactories.size(); i++) {
|
||||
|
|
@ -165,33 +157,6 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create {@link DrmSessionManager DrmSessionManagers}. See {@link
|
||||
* DefaultDrmSessionManager.Builder#setPlayClearSamplesWithoutKeys(boolean)}.
|
||||
*
|
||||
* @return This factory, for convenience.
|
||||
*/
|
||||
public DefaultMediaSourceFactory setPlayClearContentWithoutKey(
|
||||
boolean playClearContentWithoutKey) {
|
||||
this.playClearContentWithoutKey = playClearContentWithoutKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create {@link DrmSessionManager DrmSessionManagers}. See {@link
|
||||
* DefaultDrmSessionManager.Builder#setUseDrmSessionsForClearContent(int...)}.
|
||||
*
|
||||
* @return This factory, for convenience.
|
||||
*/
|
||||
public DefaultMediaSourceFactory setUseDrmSessionForClearContent(
|
||||
int... useDrmSessionsForClearContentTrackTypes) {
|
||||
for (int trackType : useDrmSessionsForClearContentTrackTypes) {
|
||||
Assertions.checkArgument(trackType == C.TRACK_TYPE_VIDEO || trackType == C.TRACK_TYPE_AUDIO);
|
||||
}
|
||||
this.useDrmSessionsForClearContentTrackTypes = useDrmSessionsForClearContentTrackTypes.clone();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultMediaSourceFactory setDrmSessionManager(
|
||||
@Nullable DrmSessionManager drmSessionManager) {
|
||||
|
|
@ -202,6 +167,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultMediaSourceFactory setLoadErrorHandlingPolicy(
|
||||
@Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
LoadErrorHandlingPolicy newLoadErrorHandlingPolicy =
|
||||
|
|
@ -286,8 +252,10 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
|||
.setUuidAndExoMediaDrmProvider(
|
||||
mediaItem.playbackProperties.drmConfiguration.uuid, FrameworkMediaDrm.DEFAULT_PROVIDER)
|
||||
.setMultiSession(mediaItem.playbackProperties.drmConfiguration.multiSession)
|
||||
.setPlayClearSamplesWithoutKeys(playClearContentWithoutKey)
|
||||
.setUseDrmSessionsForClearContent(useDrmSessionsForClearContentTrackTypes)
|
||||
.setPlayClearSamplesWithoutKeys(
|
||||
mediaItem.playbackProperties.drmConfiguration.playClearContentWithoutKey)
|
||||
.setUseDrmSessionsForClearContent(
|
||||
Util.toArray(mediaItem.playbackProperties.drmConfiguration.sessionForClearTypes))
|
||||
.build(createHttpMediaDrmCallback(mediaItem.playbackProperties.drmConfiguration));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.google.android.exoplayer2.offline.StreamKey;
|
|||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -97,6 +98,8 @@ public class MediaItemTest {
|
|||
.setDrmLicenseUri(licenseUri)
|
||||
.setDrmLicenseRequestHeaders(requestHeaders)
|
||||
.setDrmMultiSession(/* multiSession= */ true)
|
||||
.setDrmPlayClearContentWithoutKey(true)
|
||||
.setDrmSessionForClearTypes(Collections.singletonList(C.TRACK_TYPE_AUDIO))
|
||||
.build();
|
||||
|
||||
assertThat(mediaItem.playbackProperties.drmConfiguration).isNotNull();
|
||||
|
|
@ -105,6 +108,25 @@ public class MediaItemTest {
|
|||
assertThat(mediaItem.playbackProperties.drmConfiguration.requestHeaders)
|
||||
.isEqualTo(requestHeaders);
|
||||
assertThat(mediaItem.playbackProperties.drmConfiguration.multiSession).isTrue();
|
||||
assertThat(mediaItem.playbackProperties.drmConfiguration.playClearContentWithoutKey).isTrue();
|
||||
assertThat(mediaItem.playbackProperties.drmConfiguration.sessionForClearTypes)
|
||||
.containsExactly(C.TRACK_TYPE_AUDIO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderSetDrmSessionForClearPeriods_setsAudioAndVideoTracks() {
|
||||
Uri licenseUri = Uri.parse(URI_STRING);
|
||||
MediaItem mediaItem =
|
||||
new MediaItem.Builder()
|
||||
.setSourceUri(URI_STRING)
|
||||
.setDrmUuid(C.WIDEVINE_UUID)
|
||||
.setDrmLicenseUri(licenseUri)
|
||||
.setDrmSessionForClearTypes(Arrays.asList(C.TRACK_TYPE_AUDIO))
|
||||
.setDrmSessionForClearPeriods(true)
|
||||
.build();
|
||||
|
||||
assertThat(mediaItem.playbackProperties.drmConfiguration.sessionForClearTypes)
|
||||
.containsExactly(C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_VIDEO);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Reference in a new issue