提交 6e5ae4ed 编写于 作者: O olly 提交者: Oliver Woodman

Simplify DrmInitData.

- This moves to a single DrmInitData implementation that supports
  both specific and universal UUID matching. You can also do a
  combination of the two, which was not previously possible.
- The object model is simplified as a result. This is a precursor
  to a change where DrmInitData will be included directly in the
  Format to enable key rotation.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=121472592
上级 686816a6
......@@ -19,8 +19,8 @@ import static com.google.android.exoplayer.drm.StreamingDrmSessionManager.PLAYRE
import static com.google.android.exoplayer.drm.StreamingDrmSessionManager.WIDEVINE_UUID;
import static com.google.android.exoplayer.util.MimeTypes.VIDEO_MP4;
import com.google.android.exoplayer.drm.DrmInitData.SchemeInitData;
import com.google.android.exoplayer.drm.DrmInitData.UuidSchemeInitDataTuple;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.testutil.TestUtil;
import android.test.MoreAsserts;
......@@ -32,53 +32,110 @@ import junit.framework.TestCase;
*/
public class DrmInitDataTest extends TestCase {
private static final SchemeInitData DATA_1 =
new SchemeInitData(VIDEO_MP4, TestUtil.buildTestData(128, 1 /* data seed */));
private static final SchemeInitData DATA_2 =
new SchemeInitData(VIDEO_MP4, TestUtil.buildTestData(128, 2 /* data seed */));
private static final SchemeData DATA_1 =
new SchemeData(WIDEVINE_UUID, VIDEO_MP4, TestUtil.buildTestData(128, 1 /* data seed */));
private static final SchemeData DATA_2 =
new SchemeData(PLAYREADY_UUID, VIDEO_MP4, TestUtil.buildTestData(128, 2 /* data seed */));
private static final SchemeData DATA_1B =
new SchemeData(WIDEVINE_UUID, VIDEO_MP4, TestUtil.buildTestData(128, 1 /* data seed */));
private static final SchemeData DATA_2B =
new SchemeData(PLAYREADY_UUID, VIDEO_MP4, TestUtil.buildTestData(128, 2 /* data seed */));
private static final SchemeData DATA_UNIVERSAL =
new SchemeData(C.UUID_NIL, VIDEO_MP4, TestUtil.buildTestData(128, 3 /* data seed */));
public void testMappedEquals() {
DrmInitData.Mapped drmInitData = new DrmInitData.Mapped(
new UuidSchemeInitDataTuple(WIDEVINE_UUID, DATA_1),
new UuidSchemeInitDataTuple(PLAYREADY_UUID, DATA_2));
public void testEquals() {
DrmInitData drmInitData = new DrmInitData(DATA_1, DATA_2);
// Basic non-referential equality test.
DrmInitData.Mapped testInitData = new DrmInitData.Mapped(
new UuidSchemeInitDataTuple(WIDEVINE_UUID, DATA_1),
new UuidSchemeInitDataTuple(PLAYREADY_UUID, DATA_2));
DrmInitData testInitData = new DrmInitData(DATA_1, DATA_2);
assertEquals(drmInitData, testInitData);
assertEquals(drmInitData.hashCode(), testInitData.hashCode());
// Passing the tuples in reverse order shouldn't affect equality.
testInitData = new DrmInitData.Mapped(
new UuidSchemeInitDataTuple(PLAYREADY_UUID, DATA_2),
new UuidSchemeInitDataTuple(WIDEVINE_UUID, DATA_1));
// Basic non-referential equality test with non-referential scheme data.
testInitData = new DrmInitData(DATA_1B, DATA_2B);
assertEquals(drmInitData, testInitData);
assertEquals(drmInitData.hashCode(), testInitData.hashCode());
// Passing the scheme data in reverse order shouldn't affect equality.
testInitData = new DrmInitData(DATA_2, DATA_1);
assertEquals(drmInitData, testInitData);
assertEquals(drmInitData.hashCode(), testInitData.hashCode());
// Ditto.
testInitData = new DrmInitData(DATA_2B, DATA_1B);
assertEquals(drmInitData, testInitData);
assertEquals(drmInitData.hashCode(), testInitData.hashCode());
// Different number of tuples should affect equality.
testInitData = new DrmInitData.Mapped(
new UuidSchemeInitDataTuple(WIDEVINE_UUID, DATA_1));
testInitData = new DrmInitData(DATA_1);
MoreAsserts.assertNotEqual(drmInitData, testInitData);
// Different data in one of the tuples should affect equality.
testInitData = new DrmInitData.Mapped(
new UuidSchemeInitDataTuple(WIDEVINE_UUID, DATA_1),
new UuidSchemeInitDataTuple(PLAYREADY_UUID, DATA_1));
testInitData = new DrmInitData(DATA_1, DATA_1);
MoreAsserts.assertNotEqual(drmInitData, testInitData);
}
public void testUniversalEquals() {
DrmInitData.Universal drmInitData = new DrmInitData.Universal(DATA_1);
public void testGet() {
// Basic matching.
DrmInitData testInitData = new DrmInitData(DATA_1, DATA_2);
assertEquals(DATA_1, testInitData.get(WIDEVINE_UUID));
assertEquals(DATA_2, testInitData.get(PLAYREADY_UUID));
assertNull(testInitData.get(C.UUID_NIL));
// Basic non-referential equality test.
DrmInitData.Universal testInitData = new DrmInitData.Universal(DATA_1);
assertEquals(drmInitData, testInitData);
assertEquals(drmInitData.hashCode(), testInitData.hashCode());
// Basic matching including universal data.
testInitData = new DrmInitData(DATA_1, DATA_2, DATA_UNIVERSAL);
assertEquals(DATA_1, testInitData.get(WIDEVINE_UUID));
assertEquals(DATA_2, testInitData.get(PLAYREADY_UUID));
assertEquals(DATA_UNIVERSAL, testInitData.get(C.UUID_NIL));
// Different data should affect equality.
testInitData = new DrmInitData.Universal(DATA_2);
MoreAsserts.assertNotEqual(drmInitData, testInitData);
// Passing the scheme data in reverse order shouldn't affect equality.
testInitData = new DrmInitData(DATA_UNIVERSAL, DATA_2, DATA_1);
assertEquals(DATA_1, testInitData.get(WIDEVINE_UUID));
assertEquals(DATA_2, testInitData.get(PLAYREADY_UUID));
assertEquals(DATA_UNIVERSAL, testInitData.get(C.UUID_NIL));
// Universal data should be returned in the absence of a specific match.
testInitData = new DrmInitData(DATA_1, DATA_UNIVERSAL);
assertEquals(DATA_1, testInitData.get(WIDEVINE_UUID));
assertEquals(DATA_UNIVERSAL, testInitData.get(PLAYREADY_UUID));
assertEquals(DATA_UNIVERSAL, testInitData.get(C.UUID_NIL));
}
public void testDuplicateSchemeDataRejected() {
try {
new DrmInitData(DATA_1, DATA_1);
fail();
} catch (IllegalArgumentException e) {
// Expected.
}
try {
new DrmInitData(DATA_1, DATA_1B);
fail();
} catch (IllegalArgumentException e) {
// Expected.
}
try {
new DrmInitData(DATA_1, DATA_2, DATA_1B);
fail();
} catch (IllegalArgumentException e) {
// Expected.
}
}
public void testSchemeDataMatches() {
assertTrue(DATA_1.matches(WIDEVINE_UUID));
assertFalse(DATA_1.matches(PLAYREADY_UUID));
assertFalse(DATA_2.matches(C.UUID_NIL));
assertFalse(DATA_2.matches(WIDEVINE_UUID));
assertTrue(DATA_2.matches(PLAYREADY_UUID));
assertFalse(DATA_2.matches(C.UUID_NIL));
assertTrue(DATA_UNIVERSAL.matches(WIDEVINE_UUID));
assertTrue(DATA_UNIVERSAL.matches(PLAYREADY_UUID));
assertTrue(DATA_UNIVERSAL.matches(C.UUID_NIL));
}
}
......@@ -21,7 +21,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.mkv.StreamBuilder.ContentEncodingSettings;
import com.google.android.exoplayer.testutil.FakeExtractorOutput;
......@@ -237,10 +237,10 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase {
assertSeekMap(DEFAULT_TIMECODE_SCALE, 1);
DrmInitData drmInitData = extractorOutput.drmInitData;
assertNotNull(drmInitData);
SchemeInitData widevineInitData = drmInitData.get(WIDEVINE_UUID);
SchemeData widevineInitData = drmInitData.get(WIDEVINE_UUID);
assertEquals(MimeTypes.VIDEO_WEBM, widevineInitData.mimeType);
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, widevineInitData.data);
SchemeInitData zeroInitData = drmInitData.get(ZERO_UUID);
SchemeData zeroInitData = drmInitData.get(ZERO_UUID);
assertEquals(MimeTypes.VIDEO_WEBM, zeroInitData.mimeType);
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, zeroInitData.data);
}
......
......@@ -20,6 +20,8 @@ import com.google.android.exoplayer.util.Util;
import android.media.AudioFormat;
import android.media.MediaCodec;
import java.util.UUID;
/**
* Defines constants that are generally useful throughout the library.
*/
......@@ -175,6 +177,12 @@ public final class C {
public static final int DEFAULT_MUXED_BUFFER_SIZE = DEFAULT_VIDEO_BUFFER_SIZE
+ DEFAULT_AUDIO_BUFFER_SIZE + DEFAULT_TEXT_BUFFER_SIZE;
/**
* The Nil UUID as defined by
* <a href="https://tools.ietf.org/html/rfc4122#section-4.1.7">RFC4122</a>.
*/
public static final UUID UUID_NIL = new UUID(0L, 0L);
private C() {}
}
......@@ -16,8 +16,7 @@
package com.google.android.exoplayer;
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.ExtractorSampleSource;
import com.google.android.exoplayer.extractor.mp4.PsshAtomUtil;
import com.google.android.exoplayer.util.Assertions;
......@@ -287,15 +286,13 @@ public final class FrameworkSampleSource implements SampleSource {
if (psshInfo == null || psshInfo.isEmpty()) {
return null;
}
UuidSchemeInitDataTuple[] uuidSchemeInitDataTuples =
new UuidSchemeInitDataTuple[psshInfo.size()];
SchemeData[] schemeDatas = new SchemeData[psshInfo.size()];
int count = 0;
for (UUID uuid : psshInfo.keySet()) {
byte[] psshAtom = PsshAtomUtil.buildPsshAtom(uuid, psshInfo.get(uuid));
SchemeInitData schemeData = new SchemeInitData(MimeTypes.VIDEO_MP4, psshAtom);
uuidSchemeInitDataTuples[count++] = new UuidSchemeInitDataTuple(uuid, schemeData);
schemeDatas[count++] = new SchemeData(uuid, MimeTypes.VIDEO_MP4, psshAtom);
}
return new DrmInitData.Mapped(uuidSchemeInitDataTuples);
return new DrmInitData(schemeDatas);
}
private void seekToUsInternal(long positionUs, boolean force) {
......
......@@ -37,7 +37,7 @@ import com.google.android.exoplayer.dash.mpd.Period;
import com.google.android.exoplayer.dash.mpd.RangedUri;
import com.google.android.exoplayer.dash.mpd.Representation;
import com.google.android.exoplayer.drm.DrmInitData;
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.SeekMap;
import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor;
......@@ -344,19 +344,17 @@ public class DashChunkSource implements ChunkSource {
}
private static DrmInitData getDrmInitData(AdaptationSet adaptationSet) {
ArrayList<UuidSchemeInitDataTuple> uuidSchemeInitDataTuples = null;
ArrayList<SchemeData> schemeDatas = null;
for (int i = 0; i < adaptationSet.contentProtections.size(); i++) {
ContentProtection contentProtection = adaptationSet.contentProtections.get(i);
if (contentProtection.uuid != null && contentProtection.data != null) {
if (uuidSchemeInitDataTuples == null) {
uuidSchemeInitDataTuples = new ArrayList<UuidSchemeInitDataTuple>();
if (contentProtection.schemeData != null) {
if (schemeDatas == null) {
schemeDatas = new ArrayList<SchemeData>();
}
uuidSchemeInitDataTuples.add(
new UuidSchemeInitDataTuple(contentProtection.uuid, contentProtection.data));
schemeDatas.add(contentProtection.schemeData);
}
}
return uuidSchemeInitDataTuples == null ? null
: new DrmInitData.Mapped(uuidSchemeInitDataTuples);
return schemeDatas == null ? null : new DrmInitData(schemeDatas);
}
private static long getPeriodDurationUs(MediaPresentationDescription manifest, int index) {
......
......@@ -15,12 +15,10 @@
*/
package com.google.android.exoplayer.dash.mpd;
import com.google.android.exoplayer.drm.DrmInitData.SchemeInitData;
import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util;
import java.util.UUID;
/**
* Represents a ContentProtection tag in an AdaptationSet.
*/
......@@ -31,25 +29,18 @@ public class ContentProtection {
*/
public final String schemeUriId;
/**
* The UUID of the protection scheme. May be null.
*/
public final UUID uuid;
/**
* Protection scheme specific initialization data. May be null.
*/
public final SchemeInitData data;
public final SchemeData schemeData;
/**
* @param schemeUriId Identifies the content protection scheme.
* @param uuid The UUID of the protection scheme, if known. May be null.
* @param data Protection scheme specific initialization data. May be null.
* @param schemeData Protection scheme specific initialization data. May be null.
*/
public ContentProtection(String schemeUriId, UUID uuid, SchemeInitData data) {
public ContentProtection(String schemeUriId, SchemeData schemeData) {
this.schemeUriId = Assertions.checkNotNull(schemeUriId);
this.uuid = uuid;
this.data = data;
this.schemeData = schemeData;
}
@Override
......@@ -62,17 +53,12 @@ public class ContentProtection {
}
ContentProtection other = (ContentProtection) obj;
return schemeUriId.equals(other.schemeUriId)
&& Util.areEqual(uuid, other.uuid)
&& Util.areEqual(data, other.data);
return schemeUriId.equals(other.schemeUriId) && Util.areEqual(schemeData, other.schemeData);
}
@Override
public int hashCode() {
int hashCode = schemeUriId.hashCode();
hashCode = (31 * hashCode) + (uuid != null ? uuid.hashCode() : 0);
hashCode = (31 * hashCode) + (data != null ? data.hashCode() : 0);
return hashCode;
return (31 * schemeUriId.hashCode()) + (schemeData != null ? schemeData.hashCode() : 0);
}
}
......@@ -22,7 +22,7 @@ import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentList;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentTemplate;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SegmentTimelineElement;
import com.google.android.exoplayer.dash.mpd.SegmentBase.SingleSegmentBase;
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.upstream.UriLoadable;
import com.google.android.exoplayer.util.Assertions;
......@@ -314,29 +314,29 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
protected ContentProtection parseContentProtection(XmlPullParser xpp)
throws XmlPullParserException, IOException {
String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri");
UUID uuid = null;
SchemeInitData data = null;
SchemeData schemeData = null;
boolean seenPsshElement = false;
do {
xpp.next();
// The cenc:pssh element is defined in 23001-7:2015.
if (ParserUtil.isStartTag(xpp, "cenc:pssh") && xpp.next() == XmlPullParser.TEXT) {
seenPsshElement = true;
data = new SchemeInitData(MimeTypes.VIDEO_MP4,
Base64.decode(xpp.getText(), Base64.DEFAULT));
uuid = PsshAtomUtil.parseUuid(data.data);
byte[] data = Base64.decode(xpp.getText(), Base64.DEFAULT);
UUID uuid = PsshAtomUtil.parseUuid(data);
if (uuid != null) {
schemeData = new SchemeData(uuid, MimeTypes.VIDEO_MP4, data);
}
}
} while (!ParserUtil.isEndTag(xpp, "ContentProtection"));
if (seenPsshElement && uuid == null) {
if (seenPsshElement && schemeData == null) {
Log.w(TAG, "Skipped unsupported ContentProtection element");
return null;
}
return buildContentProtection(schemeIdUri, uuid, data);
return buildContentProtection(schemeIdUri, schemeData);
}
protected ContentProtection buildContentProtection(String schemeIdUri, UUID uuid,
SchemeInitData data) {
return new ContentProtection(schemeIdUri, uuid, data);
protected ContentProtection buildContentProtection(String schemeIdUri, SchemeData schemeData) {
return new ContentProtection(schemeIdUri, schemeData);
}
/**
......
......@@ -15,119 +15,103 @@
*/
package com.google.android.exoplayer.drm;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
/**
* Encapsulates DRM initialization data for possibly multiple DRM schemes.
*/
public interface DrmInitData {
public final class DrmInitData implements Comparator<SchemeData> {
/**
* Retrieves initialization data for a given DRM scheme, specified by its UUID.
*
* @param schemeUuid The DRM scheme's UUID.
* @return The initialization data for the scheme, or null if the scheme is not supported.
*/
SchemeInitData get(UUID schemeUuid);
private final SchemeData[] schemeDatas;
/**
* A {@link DrmInitData} implementation that maps UUID onto scheme specific data.
*/
final class Mapped implements DrmInitData {
// Lazily initialized hashcode.
private int hashCode;
private final UuidSchemeInitDataTuple[] schemeDatas;
// Lazily initialized hashcode.
private int hashCode;
public Mapped(UuidSchemeInitDataTuple... schemeDatas) {
this.schemeDatas = schemeDatas.clone();
Arrays.sort(this.schemeDatas); // Required for correct equals and hashcode implementations.
}
public Mapped(List<UuidSchemeInitDataTuple> 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;
}
}
return null;
}
public DrmInitData(List<SchemeData> schemeDatas) {
this(false, schemeDatas.toArray(new SchemeData[schemeDatas.size()]));
}
@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = Arrays.hashCode(schemeDatas);
}
return hashCode;
}
public DrmInitData(SchemeData... schemeDatas) {
this(true, schemeDatas);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
private DrmInitData(boolean cloneSchemeDatas, SchemeData... schemeDatas) {
if (cloneSchemeDatas) {
schemeDatas = schemeDatas.clone();
}
// 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);
}
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;
public SchemeData get(UUID uuid) {
for (SchemeData schemeData : schemeDatas) {
if (schemeData.matches(uuid)) {
return schemeData;
}
}
return null;
}
@Override
public SchemeInitData get(UUID schemeUuid) {
return data;
@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = Arrays.hashCode(schemeDatas);
}
return hashCode;
}
@Override
public int hashCode() {
return data == null ? 0 : data.hashCode();
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return Util.areEqual(data, ((Universal) obj).data);
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}.
* <p>
* Implements {@link Comparable} based on {@link UUID} ordering.
*/
final class UuidSchemeInitDataTuple implements Comparable<UuidSchemeInitDataTuple> {
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);
}
}
}
......@@ -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) {
......
......@@ -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;
}
}
......
......@@ -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<Atom.LeafAtom> moovLeafChildren = moov.leafChildren;
int moovLeafChildrenSize = moovLeafChildren.size();
ArrayList<UuidSchemeInitDataTuple> uuidSchemeInitDataTuples = null;
ArrayList<SchemeData> 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<UuidSchemeInitDataTuple>();
if (schemeDatas == null) {
schemeDatas = new ArrayList<SchemeData>();
}
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.
......
......@@ -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;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册