Skip to content

Commit

Permalink
Allow out-of-band pssh data for DASH playbacks.
Browse files Browse the repository at this point in the history
This fixes the referenced issue, except that the MPD parser
needs to actually parse out UUID and binary data for schemes
that we wish to support. Alternatively, it's easy to applications
to do this themselves by extending the parser and overriding
the parseContentProtection and buildContentProtection methods.

Github Issue: google#119
  • Loading branch information
ojw28 committed Dec 8, 2014
1 parent 2f0a177 commit c4b2a01
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.google.android.exoplayer.chunk.Mp4MediaChunk;
import com.google.android.exoplayer.chunk.SingleSampleMediaChunk;
import com.google.android.exoplayer.dash.mpd.AdaptationSet;
import com.google.android.exoplayer.dash.mpd.ContentProtection;
import com.google.android.exoplayer.dash.mpd.MediaPresentationDescription;
import com.google.android.exoplayer.dash.mpd.Period;
import com.google.android.exoplayer.dash.mpd.RangedUri;
Expand All @@ -53,6 +54,8 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
* An {@link ChunkSource} for DASH streams.
Expand Down Expand Up @@ -92,6 +95,7 @@ public NoAdaptationSetException(String message) {
private final ManifestFetcher<MediaPresentationDescription> manifestFetcher;
private final int adaptationSetIndex;
private final int[] representationIndices;
private final Map<UUID, byte[]> psshInfo;

private MediaPresentationDescription currentManifest;
private boolean finishedCurrentManifest;
Expand Down Expand Up @@ -180,6 +184,7 @@ private DashChunkSource(ManifestFetcher<MediaPresentationDescription> manifestFe
this.evaluation = new Evaluation();
this.headerBuilder = new StringBuilder();

psshInfo = getPsshInfo(currentManifest, adaptationSetIndex);
Representation[] representations = getFilteredRepresentations(currentManifest,
adaptationSetIndex, representationIndices);
long periodDurationUs = (representations[0].periodDurationMs == TrackRenderer.UNKNOWN_TIME_US)
Expand Down Expand Up @@ -438,7 +443,7 @@ private Chunk newMediaChunk(RepresentationHolder representationHolder, DataSourc
startTimeUs, endTimeUs, nextAbsoluteSegmentNum, null, representationHolder.vttHeader);
} else {
return new Mp4MediaChunk(dataSource, dataSpec, representation.format, trigger, startTimeUs,
endTimeUs, nextAbsoluteSegmentNum, representationHolder.extractor, null, false,
endTimeUs, nextAbsoluteSegmentNum, representationHolder.extractor, psshInfo, false,
presentationTimeOffsetUs);
}
}
Expand All @@ -463,8 +468,8 @@ private long getLiveSeekPosition() {

private static Representation[] getFilteredRepresentations(MediaPresentationDescription manifest,
int adaptationSetIndex, int[] representationIndices) {
List<Representation> representations =
manifest.periods.get(0).adaptationSets.get(adaptationSetIndex).representations;
AdaptationSet adaptationSet = manifest.periods.get(0).adaptationSets.get(adaptationSetIndex);
List<Representation> representations = adaptationSet.representations;
if (representationIndices == null) {
Representation[] filteredRepresentations = new Representation[representations.size()];
representations.toArray(filteredRepresentations);
Expand All @@ -478,6 +483,22 @@ private static Representation[] getFilteredRepresentations(MediaPresentationDesc
}
}

private static Map<UUID, byte[]> getPsshInfo(MediaPresentationDescription manifest,
int adaptationSetIndex) {
AdaptationSet adaptationSet = manifest.periods.get(0).adaptationSets.get(adaptationSetIndex);
if (adaptationSet.contentProtections.isEmpty()) {
return null;
} else {
Map<UUID, byte[]> psshInfo = new HashMap<UUID, byte[]>();
for (ContentProtection contentProtection : adaptationSet.contentProtections) {
if (contentProtection.uuid != null && contentProtection.data != null) {
psshInfo.put(contentProtection.uuid, contentProtection.data);
}
}
return psshInfo.isEmpty() ? null : psshInfo;
}
}

private static MediaPresentationDescription buildManifest(List<Representation> representations) {
Representation firstRepresentation = representations.get(0);
AdaptationSet adaptationSet = new AdaptationSet(0, AdaptationSet.TYPE_UNKNOWN, representations);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer.dash.mpd;

import java.util.UUID;

/**
* Represents a ContentProtection tag in an AdaptationSet.
*/
Expand All @@ -25,11 +27,25 @@ public class ContentProtection {
*/
public final String schemeUriId;

/**
* The UUID of the protection scheme. May be null.
*/
public final UUID uuid;

/**
* Protection scheme specific data. May be null.
*/
public final byte[] data;

/**
* @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.
*/
public ContentProtection(String schemeUriId) {
public ContentProtection(String schemeUriId, UUID uuid, byte[] data) {
this.schemeUriId = schemeUriId;
this.uuid = uuid;
this.data = data;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ protected ContentProtection parseContentProtection(XmlPullParser xpp)
}

protected ContentProtection buildContentProtection(String schemeIdUri) {
return new ContentProtection(schemeIdUri);
return new ContentProtection(schemeIdUri, null, null);
}

/**
Expand Down

0 comments on commit c4b2a01

Please sign in to comment.