mirror of
https://github.com/androidx/media.git
synced 2025-05-16 12:09:50 +08:00
Enable ContentProtect elements at the Representation level
This commit is contained in:
parent
5a5935cb72
commit
acd1b9acff
@ -15,6 +15,10 @@
|
||||
*/
|
||||
package com.google.android.exoplayer.dash.mpd;
|
||||
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@ -43,9 +47,38 @@ public class ContentProtection {
|
||||
* @param data Protection scheme specific initialization data. May be null.
|
||||
*/
|
||||
public ContentProtection(String schemeUriId, UUID uuid, byte[] data) {
|
||||
this.schemeUriId = schemeUriId;
|
||||
this.schemeUriId = Assertions.checkNotNull(schemeUriId);
|
||||
this.uuid = uuid;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ContentProtection)) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ContentProtection other = (ContentProtection) obj;
|
||||
return schemeUriId.equals(other.schemeUriId)
|
||||
&& Util.areEqual(uuid, other.uuid)
|
||||
&& Arrays.equals(data, other.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 1;
|
||||
|
||||
hashCode = hashCode * 37 + schemeUriId.hashCode();
|
||||
if (uuid != null) {
|
||||
hashCode = hashCode * 37 + uuid.hashCode();
|
||||
}
|
||||
if (data != null) {
|
||||
hashCode = hashCode * 37 + Arrays.hashCode(data);
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -178,24 +180,22 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
||||
int contentType = parseAdaptationSetTypeFromMimeType(mimeType);
|
||||
|
||||
int id = -1;
|
||||
List<ContentProtection> contentProtections = null;
|
||||
ContentProtectionsBuilder contentProtectionsBuilder = new ContentProtectionsBuilder();
|
||||
List<Representation> representations = new ArrayList<Representation>();
|
||||
do {
|
||||
xpp.next();
|
||||
if (isStartTag(xpp, "BaseURL")) {
|
||||
baseUrl = parseBaseUrl(xpp, baseUrl);
|
||||
} else if (isStartTag(xpp, "ContentProtection")) {
|
||||
if (contentProtections == null) {
|
||||
contentProtections = new ArrayList<ContentProtection>();
|
||||
}
|
||||
contentProtections.add(parseContentProtection(xpp));
|
||||
contentProtectionsBuilder.addAdaptationSetProtection(parseContentProtection(xpp));
|
||||
} else if (isStartTag(xpp, "ContentComponent")) {
|
||||
id = Integer.parseInt(xpp.getAttributeValue(null, "id"));
|
||||
contentType = checkAdaptationSetTypeConsistency(contentType,
|
||||
parseAdaptationSetType(xpp.getAttributeValue(null, "contentType")));
|
||||
} else if (isStartTag(xpp, "Representation")) {
|
||||
Representation representation = parseRepresentation(xpp, baseUrl, periodStartMs,
|
||||
periodDurationMs, mimeType, language, segmentBase);
|
||||
periodDurationMs, mimeType, language, segmentBase, contentProtectionsBuilder);
|
||||
contentProtectionsBuilder.endRepresentation();
|
||||
contentType = checkAdaptationSetTypeConsistency(contentType,
|
||||
parseAdaptationSetTypeFromMimeType(representation.format.mimeType));
|
||||
representations.add(representation);
|
||||
@ -211,7 +211,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
||||
}
|
||||
} while (!isEndTag(xpp, "AdaptationSet"));
|
||||
|
||||
return buildAdaptationSet(id, contentType, representations, contentProtections);
|
||||
return buildAdaptationSet(id, contentType, representations, contentProtectionsBuilder.build());
|
||||
}
|
||||
|
||||
protected AdaptationSet buildAdaptationSet(int id, int contentType,
|
||||
@ -289,7 +289,8 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
||||
|
||||
protected Representation parseRepresentation(XmlPullParser xpp, String baseUrl,
|
||||
long periodStartMs, long periodDurationMs, String mimeType, String language,
|
||||
SegmentBase segmentBase) throws XmlPullParserException, IOException {
|
||||
SegmentBase segmentBase, ContentProtectionsBuilder contentProtectionsBuilder)
|
||||
throws XmlPullParserException, IOException {
|
||||
String id = xpp.getAttributeValue(null, "id");
|
||||
int bandwidth = parseInt(xpp, "bandwidth");
|
||||
int audioSamplingRate = parseInt(xpp, "audioSamplingRate");
|
||||
@ -312,6 +313,8 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
||||
} else if (isStartTag(xpp, "SegmentTemplate")) {
|
||||
segmentBase = parseSegmentTemplate(xpp, baseUrl, (SegmentTemplate) segmentBase,
|
||||
periodDurationMs);
|
||||
} else if (isStartTag(xpp, "ContentProtection")) {
|
||||
contentProtectionsBuilder.addRepresentationProtection(parseContentProtection(xpp));
|
||||
}
|
||||
} while (!isEndTag(xpp, "Representation"));
|
||||
|
||||
@ -577,4 +580,120 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a list of {@link ContentProtection} elements for an {@link AdaptationSet}.
|
||||
* <p>
|
||||
* If child Representation elements contain ContentProtection elements, then it is required that
|
||||
* they all define the same ones. If they do, the ContentProtection elements are bubbled up to the
|
||||
* AdaptationSet. Child Representation elements defining different ContentProtection elements is
|
||||
* considered an error.
|
||||
*/
|
||||
protected static final class ContentProtectionsBuilder implements Comparator<ContentProtection> {
|
||||
|
||||
private ArrayList<ContentProtection> adaptationSetProtections;
|
||||
private ArrayList<ContentProtection> representationProtections;
|
||||
private ArrayList<ContentProtection> currentRepresentationProtections;
|
||||
|
||||
private boolean representationProtectionsSet;
|
||||
|
||||
/**
|
||||
* Adds a {@link ContentProtection} found in the AdaptationSet element.
|
||||
*
|
||||
* @param contentProtection The {@link ContentProtection} to add.
|
||||
*/
|
||||
public void addAdaptationSetProtection(ContentProtection contentProtection) {
|
||||
if (adaptationSetProtections == null) {
|
||||
adaptationSetProtections = new ArrayList<ContentProtection>();
|
||||
}
|
||||
maybeAddContentProtection(adaptationSetProtections, contentProtection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link ContentProtection} found in a child Representation element.
|
||||
*
|
||||
* @param contentProtection The {@link ContentProtection} to add.
|
||||
*/
|
||||
public void addRepresentationProtection(ContentProtection contentProtection) {
|
||||
if (currentRepresentationProtections == null) {
|
||||
currentRepresentationProtections = new ArrayList<ContentProtection>();
|
||||
}
|
||||
maybeAddContentProtection(currentRepresentationProtections, contentProtection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be invoked after processing each child Representation element, in order to apply
|
||||
* consistency checks.
|
||||
*/
|
||||
public void endRepresentation() {
|
||||
if (!representationProtectionsSet) {
|
||||
if (currentRepresentationProtections != null) {
|
||||
Collections.sort(currentRepresentationProtections, this);
|
||||
}
|
||||
representationProtections = currentRepresentationProtections;
|
||||
representationProtectionsSet = true;
|
||||
} else {
|
||||
// Assert that each Representation element defines the same ContentProtection elements.
|
||||
if (currentRepresentationProtections == null) {
|
||||
Assertions.checkState(representationProtections == null);
|
||||
} else {
|
||||
Collections.sort(currentRepresentationProtections, this);
|
||||
Assertions.checkState(currentRepresentationProtections.equals(representationProtections));
|
||||
}
|
||||
}
|
||||
currentRepresentationProtections = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the final list of consistent {@link ContentProtection} elements.
|
||||
*/
|
||||
public ArrayList<ContentProtection> build() {
|
||||
if (adaptationSetProtections == null) {
|
||||
return representationProtections;
|
||||
} else if (representationProtections == null) {
|
||||
return adaptationSetProtections;
|
||||
} else {
|
||||
// Bubble up ContentProtection elements found in the child Representation elements.
|
||||
for (int i = 0; i < representationProtections.size(); i++) {
|
||||
maybeAddContentProtection(adaptationSetProtections, representationProtections.get(i));
|
||||
}
|
||||
return adaptationSetProtections;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a ContentProtection for consistency with the given list, adding it if necessary.
|
||||
* <ul>
|
||||
* <li>If the new ContentProtection matches another in the list, it's consistent and is not
|
||||
* added to the list.
|
||||
* <li>If the new ContentProtection has the same schemeUriId as another ContentProtection in the
|
||||
* list, but its other attributes do not match, then it's inconsistent and an
|
||||
* {@link IllegalStateException} is thrown.
|
||||
* <li>Else the new ContentProtection has a unique schemeUriId, it's consistent and is added.
|
||||
* </ul>
|
||||
*
|
||||
* @param contentProtections The list of ContentProtection elements currently known.
|
||||
* @param contentProtection The ContentProtection to add.
|
||||
*/
|
||||
private void maybeAddContentProtection(List<ContentProtection> contentProtections,
|
||||
ContentProtection contentProtection) {
|
||||
if (!contentProtections.contains(contentProtection)) {
|
||||
for (int i = 0; i < contentProtections.size(); i++) {
|
||||
// If contains returned false (no complete match), but find a matching schemeUriId, then
|
||||
// the MPD contains inconsistent ContentProtection data.
|
||||
Assertions.checkState(
|
||||
!contentProtections.get(i).schemeUriId.equals(contentProtection.schemeUriId));
|
||||
}
|
||||
contentProtections.add(contentProtection);
|
||||
}
|
||||
}
|
||||
|
||||
// Comparator implementation.
|
||||
|
||||
@Override
|
||||
public int compare(ContentProtection first, ContentProtection second) {
|
||||
return first.schemeUriId.compareTo(second.schemeUriId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user