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

Have DrmInitData classes implement hashCode/equals.

This will be required for key rotation to work, since
we'll need a way to determine whether or not the init
data has changed.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=121018211
上级 9b574878
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer.drm;
import static com.google.android.exoplayer.drm.StreamingDrmSessionManager.PLAYREADY_UUID;
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.testutil.TestUtil;
import android.test.MoreAsserts;
import junit.framework.TestCase;
/**
* Unit test for {@link DrmInitData}.
*/
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 */));
public void testMappedEquals() {
DrmInitData.Mapped drmInitData = new DrmInitData.Mapped(
new UuidSchemeInitDataTuple(WIDEVINE_UUID, DATA_1),
new UuidSchemeInitDataTuple(PLAYREADY_UUID, 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));
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));
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));
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));
MoreAsserts.assertNotEqual(drmInitData, testInitData);
}
public void testUniversalEquals() {
DrmInitData.Universal drmInitData = new DrmInitData.Universal(DATA_1);
// Basic non-referential equality test.
DrmInitData.Universal testInitData = new DrmInitData.Universal(DATA_1);
assertEquals(drmInitData, testInitData);
assertEquals(drmInitData.hashCode(), testInitData.hashCode());
// Different data should affect equality.
testInitData = new DrmInitData.Universal(DATA_2);
MoreAsserts.assertNotEqual(drmInitData, testInitData);
}
}
......@@ -17,6 +17,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.extractor.ExtractorSampleSource;
import com.google.android.exoplayer.extractor.mp4.PsshAtomUtil;
import com.google.android.exoplayer.util.Assertions;
......@@ -286,12 +287,15 @@ public final class FrameworkSampleSource implements SampleSource {
if (psshInfo == null || psshInfo.isEmpty()) {
return null;
}
DrmInitData.Mapped drmInitData = new DrmInitData.Mapped();
UuidSchemeInitDataTuple[] uuidSchemeInitDataTuples =
new UuidSchemeInitDataTuple[psshInfo.size()];
int count = 0;
for (UUID uuid : psshInfo.keySet()) {
byte[] psshAtom = PsshAtomUtil.buildPsshAtom(uuid, psshInfo.get(uuid));
drmInitData.put(uuid, new SchemeInitData(MimeTypes.VIDEO_MP4, psshAtom));
SchemeInitData schemeData = new SchemeInitData(MimeTypes.VIDEO_MP4, psshAtom);
uuidSchemeInitDataTuples[count++] = new UuidSchemeInitDataTuple(uuid, schemeData);
}
return drmInitData;
return new DrmInitData.Mapped(uuidSchemeInitDataTuples);
}
private void seekToUsInternal(long positionUs, boolean force) {
......
......@@ -37,6 +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.extractor.ChunkIndex;
import com.google.android.exoplayer.extractor.SeekMap;
import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor;
......@@ -49,6 +50,7 @@ import com.google.android.exoplayer.util.Util;
import android.os.SystemClock;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
......@@ -342,17 +344,19 @@ public class DashChunkSource implements ChunkSource {
}
private static DrmInitData getDrmInitData(AdaptationSet adaptationSet) {
DrmInitData.Mapped drmInitData = null;
ArrayList<UuidSchemeInitDataTuple> uuidSchemeInitDataTuples = null;
for (int i = 0; i < adaptationSet.contentProtections.size(); i++) {
ContentProtection contentProtection = adaptationSet.contentProtections.get(i);
if (contentProtection.uuid != null && contentProtection.data != null) {
if (drmInitData == null) {
drmInitData = new DrmInitData.Mapped();
if (uuidSchemeInitDataTuples == null) {
uuidSchemeInitDataTuples = new ArrayList<UuidSchemeInitDataTuple>();
}
drmInitData.put(contentProtection.uuid, contentProtection.data);
uuidSchemeInitDataTuples.add(
new UuidSchemeInitDataTuple(contentProtection.uuid, contentProtection.data));
}
}
return drmInitData;
return uuidSchemeInitDataTuples == null ? null
: new DrmInitData.Mapped(uuidSchemeInitDataTuples);
}
private static long getPeriodDurationUs(MediaPresentationDescription manifest, int index) {
......
......@@ -16,16 +16,14 @@
package com.google.android.exoplayer.drm;
import com.google.android.exoplayer.util.Assertions;
import android.media.MediaDrm;
import com.google.android.exoplayer.util.Util;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.UUID;
/**
* Encapsulates initialization data required by a {@link MediaDrm} instances.
* Encapsulates DRM initialization data for possibly multiple DRM schemes.
*/
public interface DrmInitData {
......@@ -42,31 +40,54 @@ public interface DrmInitData {
*/
final class Mapped implements DrmInitData {
private final Map<UUID, SchemeInitData> schemeData;
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() {
schemeData = new HashMap<>();
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) {
return schemeData.get(schemeUuid);
for (UuidSchemeInitDataTuple schemeData : schemeDatas) {
if (schemeUuid.equals(schemeData.uuid)) {
return schemeData.data;
}
}
return null;
}
/**
* Inserts scheme specific initialization data.
*
* @param schemeUuid The scheme UUID.
* @param schemeInitData The corresponding initialization data.
*/
public void put(UUID schemeUuid, SchemeInitData schemeInitData) {
schemeData.put(schemeUuid, schemeInitData);
@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);
}
}
/**
* A {@link DrmInitData} implementation that returns the same initialization data for all schemes.
* A {@link DrmInitData} implementation that returns the same data for all schemes.
*/
final class Universal implements DrmInitData {
......@@ -81,6 +102,22 @@ public interface DrmInitData {
return data;
}
@Override
public int hashCode() {
return data == null ? 0 : data.hashCode();
}
@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);
}
}
/**
......@@ -88,6 +125,9 @@ public interface DrmInitData {
*/
final class SchemeInitData {
// Lazily initialized hashcode.
private int hashCode;
/**
* The mimeType of {@link #data}.
*/
......@@ -114,14 +154,55 @@ public interface DrmInitData {
if (obj == this) {
return true;
}
SchemeInitData other = (SchemeInitData) obj;
return mimeType.equals(other.mimeType) && Arrays.equals(data, other.data);
}
@Override
public int hashCode() {
return mimeType.hashCode() + 31 * Arrays.hashCode(data);
if (hashCode == 0) {
hashCode = mimeType.hashCode() + 31 * Arrays.hashCode(data);
}
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);
}
}
......
......@@ -19,6 +19,7 @@ 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.extractor.ChunkIndex;
import com.google.android.exoplayer.extractor.Extractor;
import com.google.android.exoplayer.extractor.ExtractorInput;
......@@ -39,6 +40,7 @@ import android.util.Pair;
import android.util.SparseArray;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
......@@ -318,25 +320,25 @@ public final class FragmentedMp4Extractor implements Extractor {
List<Atom.LeafAtom> moovLeafChildren = moov.leafChildren;
int moovLeafChildrenSize = moovLeafChildren.size();
DrmInitData.Mapped drmInitData = null;
ArrayList<UuidSchemeInitDataTuple> uuidSchemeInitDataTuples = null;
for (int i = 0; i < moovLeafChildrenSize; i++) {
LeafAtom child = moovLeafChildren.get(i);
if (child.type == Atom.TYPE_pssh) {
if (drmInitData == null) {
drmInitData = new DrmInitData.Mapped();
if (uuidSchemeInitDataTuples == null) {
uuidSchemeInitDataTuples = new ArrayList<UuidSchemeInitDataTuple>();
}
byte[] psshData = child.data.data;
UUID uuid = PsshAtomUtil.parseUuid(psshData);
if (uuid == null) {
Log.w(TAG, "Skipped pssh atom (failed to extract uuid)");
} else {
drmInitData.put(PsshAtomUtil.parseUuid(psshData),
new SchemeInitData(MimeTypes.VIDEO_MP4, psshData));
uuidSchemeInitDataTuples.add(new UuidSchemeInitDataTuple(uuid,
new SchemeInitData(MimeTypes.VIDEO_MP4, psshData)));
}
}
}
if (drmInitData != null) {
extractorOutput.drmInitData(drmInitData);
if (uuidSchemeInitDataTuples != null) {
extractorOutput.drmInitData(new DrmInitData.Mapped(uuidSchemeInitDataTuples));
}
// Read declaration of track fragments in the Moov box.
......
......@@ -30,6 +30,7 @@ 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.extractor.mp4.TrackEncryptionBox;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.ProtectionElement;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
......@@ -119,9 +120,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();
drmInitData.put(protectionElement.uuid,
new SchemeInitData(MimeTypes.VIDEO_MP4, protectionElement.data));
drmInitData = new DrmInitData.Mapped(new UuidSchemeInitDataTuple(protectionElement.uuid,
new SchemeInitData(MimeTypes.VIDEO_MP4, protectionElement.data)));
}
return true;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册