Allow out-of-band pssh data for DASH playbacks.

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: #119
This commit is contained in:
Oliver Woodman 2014-12-08 20:15:06 +00:00
parent 2f0a1779e2
commit c4b2a01212
3 changed files with 43 additions and 6 deletions

View File

@ -31,6 +31,7 @@ import com.google.android.exoplayer.chunk.MediaChunk;
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;
@ -53,6 +54,8 @@ import java.util.Arrays;
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.
@ -92,6 +95,7 @@ public class DashChunkSource implements ChunkSource {
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;
@ -180,6 +184,7 @@ public class DashChunkSource implements ChunkSource {
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)
@ -438,7 +443,7 @@ public class DashChunkSource implements ChunkSource {
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);
}
}
@ -463,8 +468,8 @@ public class DashChunkSource implements ChunkSource {
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);
@ -478,6 +483,22 @@ public class DashChunkSource implements ChunkSource {
}
}
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);

View File

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer.dash.mpd;
import java.util.UUID;
/**
* Represents a ContentProtection tag in an AdaptationSet.
*/
@ -26,10 +28,24 @@ public class ContentProtection {
public final String schemeUriId;
/**
* @param schemeUriId Identifies the content protection scheme.
* The UUID of the protection scheme. May be null.
*/
public ContentProtection(String schemeUriId) {
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, UUID uuid, byte[] data) {
this.schemeUriId = schemeUriId;
this.uuid = uuid;
this.data = data;
}
}

View File

@ -257,7 +257,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
}
protected ContentProtection buildContentProtection(String schemeIdUri) {
return new ContentProtection(schemeIdUri);
return new ContentProtection(schemeIdUri, null, null);
}
/**