schemeDatas) {
- this.schemeDatas = schemeDatas.toArray(new UuidSchemeInitDataTuple[schemeDatas.size()]);
- Arrays.sort(this.schemeDatas); // Required for correct equals and hashcode implementations.
- }
-
- @Override
- public SchemeInitData get(UUID schemeUuid) {
- for (UuidSchemeInitDataTuple schemeData : schemeDatas) {
- if (schemeUuid.equals(schemeData.uuid)) {
- return schemeData.data;
- }
+ // Sorting ensures that universal scheme data(i.e. data that applies to all schemes) is matched
+ // last. It's also required by the equals and hashcode implementations.
+ Arrays.sort(schemeDatas, this);
+ // Check for no duplicates.
+ for (int i = 1; i < schemeDatas.length; i++) {
+ if (schemeDatas[i - 1].uuid.equals(schemeDatas[i].uuid)) {
+ throw new IllegalArgumentException("Duplicate data for uuid: " + schemeDatas[i].uuid);
}
- return null;
}
-
- @Override
- public int hashCode() {
- if (hashCode == 0) {
- hashCode = Arrays.hashCode(schemeDatas);
- }
- return hashCode;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- return Arrays.equals(schemeDatas, ((Mapped) obj).schemeDatas);
- }
-
+ this.schemeDatas = schemeDatas;
}
/**
- * A {@link DrmInitData} implementation that returns the same data for all schemes.
+ * Retrieves data for a given DRM scheme, specified by its UUID.
+ *
+ * @param uuid The DRM scheme's UUID.
+ * @return The initialization data for the scheme, or null if the scheme is not supported.
*/
- final class Universal implements DrmInitData {
-
- private final SchemeInitData data;
-
- public Universal(SchemeInitData data) {
- this.data = data;
- }
-
- @Override
- public SchemeInitData get(UUID schemeUuid) {
- return data;
- }
-
- @Override
- public int hashCode() {
- return data == null ? 0 : data.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
+ public SchemeData get(UUID uuid) {
+ for (SchemeData schemeData : schemeDatas) {
+ if (schemeData.matches(uuid)) {
+ return schemeData;
}
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- return Util.areEqual(data, ((Universal) obj).data);
}
+ return null;
+ }
+ @Override
+ public int hashCode() {
+ if (hashCode == 0) {
+ hashCode = Arrays.hashCode(schemeDatas);
+ }
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ return Arrays.equals(schemeDatas, ((DrmInitData) obj).schemeDatas);
+ }
+
+ @Override
+ public int compare(SchemeData first, SchemeData second) {
+ return C.UUID_NIL.equals(first.uuid) ? (C.UUID_NIL.equals(second.uuid) ? 0 : 1)
+ : first.uuid.compareTo(second.uuid);
}
/**
* Scheme initialization data.
*/
- final class SchemeInitData {
+ public static final class SchemeData {
// Lazily initialized hashcode.
private int hashCode;
+ /**
+ * The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is universal (i.e.
+ * applies to all schemes).
+ */
+ private final UUID uuid;
/**
* The mimeType of {@link #data}.
*/
@@ -138,73 +122,51 @@ public interface DrmInitData {
public final byte[] data;
/**
+ * @param uuid The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is
+ * universal (i.e. applies to all schemes).
* @param mimeType The mimeType of the initialization data.
* @param data The initialization data.
*/
- public SchemeInitData(String mimeType, byte[] data) {
+ public SchemeData(UUID uuid, String mimeType, byte[] data) {
+ this.uuid = Assertions.checkNotNull(uuid);
this.mimeType = Assertions.checkNotNull(mimeType);
this.data = Assertions.checkNotNull(data);
}
+ /**
+ * Returns whether this initialization data applies to the specified scheme.
+ *
+ * @param schemeUuid The scheme {@link UUID}.
+ * @return True if this initialization data applies to the specified scheme. False otherwise.
+ */
+ public boolean matches(UUID schemeUuid) {
+ return C.UUID_NIL.equals(uuid) || schemeUuid.equals(uuid);
+ }
+
@Override
public boolean equals(Object obj) {
- if (!(obj instanceof SchemeInitData)) {
+ if (!(obj instanceof SchemeData)) {
return false;
}
if (obj == this) {
return true;
}
- SchemeInitData other = (SchemeInitData) obj;
- return mimeType.equals(other.mimeType) && Arrays.equals(data, other.data);
+ SchemeData other = (SchemeData) obj;
+ return mimeType.equals(other.mimeType) && Util.areEqual(uuid, other.uuid)
+ && Arrays.equals(data, other.data);
}
@Override
public int hashCode() {
if (hashCode == 0) {
- hashCode = mimeType.hashCode() + 31 * Arrays.hashCode(data);
+ int result = ((uuid == null) ? 0 : uuid.hashCode());
+ result = 31 * result + mimeType.hashCode();
+ result = 31 * result + Arrays.hashCode(data);
+ hashCode = result;
}
return hashCode;
}
}
- /**
- * A tuple consisting of a {@link UUID} and a {@link SchemeInitData}.
- *
- * Implements {@link Comparable} based on {@link UUID} ordering.
- */
- final class UuidSchemeInitDataTuple implements Comparable {
-
- public final UUID uuid;
- public final SchemeInitData data;
-
- public UuidSchemeInitDataTuple(UUID uuid, SchemeInitData data) {
- this.uuid = Assertions.checkNotNull(uuid);
- this.data = Assertions.checkNotNull(data);
- }
-
- @Override
- public int compareTo(UuidSchemeInitDataTuple another) {
- return uuid.compareTo(another.uuid);
- }
-
- @Override
- public int hashCode() {
- return uuid.hashCode() + 31 * data.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- UuidSchemeInitDataTuple other = (UuidSchemeInitDataTuple) obj;
- return Util.areEqual(uuid, other.uuid) && Util.areEqual(data, other.data);
- }
-
- }
-
}
diff --git a/library/src/main/java/com/google/android/exoplayer/drm/StreamingDrmSessionManager.java b/library/src/main/java/com/google/android/exoplayer/drm/StreamingDrmSessionManager.java
index be22d4c6c8..59539ee67c 100644
--- a/library/src/main/java/com/google/android/exoplayer/drm/StreamingDrmSessionManager.java
+++ b/library/src/main/java/com/google/android/exoplayer/drm/StreamingDrmSessionManager.java
@@ -15,7 +15,7 @@
*/
package com.google.android.exoplayer.drm;
-import com.google.android.exoplayer.drm.DrmInitData.SchemeInitData;
+import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.extractor.mp4.PsshAtomUtil;
import com.google.android.exoplayer.util.Util;
@@ -104,7 +104,7 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
private int state;
private MediaCrypto mediaCrypto;
private Exception lastException;
- private SchemeInitData schemeInitData;
+ private SchemeData schemeData;
private byte[] sessionId;
/**
@@ -273,19 +273,19 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
requestHandlerThread.start();
postRequestHandler = new PostRequestHandler(requestHandlerThread.getLooper());
}
- if (schemeInitData == null) {
- schemeInitData = drmInitData.get(uuid);
- if (schemeInitData == null) {
+ if (schemeData == null) {
+ schemeData = drmInitData.get(uuid);
+ if (schemeData == null) {
onError(new IllegalStateException("Media does not support uuid: " + uuid));
return;
}
if (Util.SDK_INT < 21) {
// Prior to L the Widevine CDM required data to be extracted from the PSSH atom.
- byte[] psshData = PsshAtomUtil.parseSchemeSpecificData(schemeInitData.data, WIDEVINE_UUID);
+ byte[] psshData = PsshAtomUtil.parseSchemeSpecificData(schemeData.data, WIDEVINE_UUID);
if (psshData == null) {
// Extraction failed. schemeData isn't a Widevine PSSH atom, so leave it unchanged.
} else {
- schemeInitData = new SchemeInitData(schemeInitData.mimeType, psshData);
+ schemeData = new SchemeData(WIDEVINE_UUID, schemeData.mimeType, psshData);
}
}
}
@@ -306,7 +306,7 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
postRequestHandler = null;
requestHandlerThread.quit();
requestHandlerThread = null;
- schemeInitData = null;
+ schemeData = null;
mediaCrypto = null;
lastException = null;
if (sessionId != null) {
@@ -368,7 +368,7 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
private void postKeyRequest() {
KeyRequest keyRequest;
try {
- keyRequest = mediaDrm.getKeyRequest(sessionId, schemeInitData.data, schemeInitData.mimeType,
+ keyRequest = mediaDrm.getKeyRequest(sessionId, schemeData.data, schemeData.mimeType,
MediaDrm.KEY_TYPE_STREAMING, optionalKeyRequestParameters);
postRequestHandler.obtainMessage(MSG_KEYS, keyRequest).sendToTarget();
} catch (NotProvisionedException e) {
diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/mkv/MatroskaExtractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/mkv/MatroskaExtractor.java
index a13927969d..4851acd749 100644
--- a/library/src/main/java/com/google/android/exoplayer/extractor/mkv/MatroskaExtractor.java
+++ b/library/src/main/java/com/google/android/exoplayer/extractor/mkv/MatroskaExtractor.java
@@ -19,7 +19,7 @@ import com.google.android.exoplayer.C;
import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.drm.DrmInitData;
-import com.google.android.exoplayer.drm.DrmInitData.SchemeInitData;
+import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.extractor.ChunkIndex;
import com.google.android.exoplayer.extractor.Extractor;
import com.google.android.exoplayer.extractor.ExtractorInput;
@@ -484,8 +484,8 @@ public final class MatroskaExtractor implements Extractor {
throw new ParserException("Encrypted Track found but ContentEncKeyID was not found");
}
if (!sentDrmInitData) {
- extractorOutput.drmInitData(new DrmInitData.Universal(
- new SchemeInitData(MimeTypes.VIDEO_WEBM, currentTrack.encryptionKeyId)));
+ extractorOutput.drmInitData(new DrmInitData(
+ new SchemeData(C.UUID_NIL, MimeTypes.VIDEO_WEBM, currentTrack.encryptionKeyId)));
sentDrmInitData = true;
}
}
diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/mp4/FragmentedMp4Extractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/mp4/FragmentedMp4Extractor.java
index 7e32adcef4..9af79a015a 100644
--- a/library/src/main/java/com/google/android/exoplayer/extractor/mp4/FragmentedMp4Extractor.java
+++ b/library/src/main/java/com/google/android/exoplayer/extractor/mp4/FragmentedMp4Extractor.java
@@ -18,8 +18,7 @@ package com.google.android.exoplayer.extractor.mp4;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.drm.DrmInitData;
-import com.google.android.exoplayer.drm.DrmInitData.SchemeInitData;
-import com.google.android.exoplayer.drm.DrmInitData.UuidSchemeInitDataTuple;
+import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.extractor.ChunkIndex;
import com.google.android.exoplayer.extractor.Extractor;
import com.google.android.exoplayer.extractor.ExtractorInput;
@@ -320,25 +319,24 @@ public final class FragmentedMp4Extractor implements Extractor {
List moovLeafChildren = moov.leafChildren;
int moovLeafChildrenSize = moovLeafChildren.size();
- ArrayList uuidSchemeInitDataTuples = null;
+ ArrayList schemeDatas = null;
for (int i = 0; i < moovLeafChildrenSize; i++) {
LeafAtom child = moovLeafChildren.get(i);
if (child.type == Atom.TYPE_pssh) {
- if (uuidSchemeInitDataTuples == null) {
- uuidSchemeInitDataTuples = new ArrayList();
+ if (schemeDatas == null) {
+ schemeDatas = new ArrayList();
}
byte[] psshData = child.data.data;
UUID uuid = PsshAtomUtil.parseUuid(psshData);
if (uuid == null) {
Log.w(TAG, "Skipped pssh atom (failed to extract uuid)");
} else {
- uuidSchemeInitDataTuples.add(new UuidSchemeInitDataTuple(uuid,
- new SchemeInitData(MimeTypes.VIDEO_MP4, psshData)));
+ schemeDatas.add(new SchemeData(uuid, MimeTypes.VIDEO_MP4, psshData));
}
}
}
- if (uuidSchemeInitDataTuples != null) {
- extractorOutput.drmInitData(new DrmInitData.Mapped(uuidSchemeInitDataTuples));
+ if (schemeDatas != null) {
+ extractorOutput.drmInitData(new DrmInitData(schemeDatas));
}
// Read declaration of track fragments in the Moov box.
diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingSampleSource.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingSampleSource.java
index 2669489b72..1a4ac05773 100644
--- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingSampleSource.java
+++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingSampleSource.java
@@ -29,8 +29,7 @@ import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener;
import com.google.android.exoplayer.chunk.FormatEvaluator;
import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator;
import com.google.android.exoplayer.drm.DrmInitData;
-import com.google.android.exoplayer.drm.DrmInitData.SchemeInitData;
-import com.google.android.exoplayer.drm.DrmInitData.UuidSchemeInitDataTuple;
+import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.extractor.mp4.TrackEncryptionBox;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.ProtectionElement;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
@@ -70,7 +69,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
private long durationUs;
private SmoothStreamingManifest currentManifest;
private TrackEncryptionBox[] trackEncryptionBoxes;
- private DrmInitData.Mapped drmInitData;
+ private DrmInitData drmInitData;
private TrackGroupArray trackGroups;
private int[] trackGroupElementIndices;
private boolean pendingReset;
@@ -120,8 +119,8 @@ public final class SmoothStreamingSampleSource implements SampleSource {
byte[] keyId = getProtectionElementKeyId(protectionElement.data);
trackEncryptionBoxes = new TrackEncryptionBox[1];
trackEncryptionBoxes[0] = new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId);
- drmInitData = new DrmInitData.Mapped(new UuidSchemeInitDataTuple(protectionElement.uuid,
- new SchemeInitData(MimeTypes.VIDEO_MP4, protectionElement.data)));
+ drmInitData = new DrmInitData(
+ new SchemeData(protectionElement.uuid, MimeTypes.VIDEO_MP4, protectionElement.data));
}
return true;
}