From c4b2a0121230cb533a658fd6c55b4c01199a3000 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Mon, 8 Dec 2014 20:15:06 +0000 Subject: [PATCH] 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 --- .../exoplayer/dash/DashChunkSource.java | 27 ++++++++++++++++--- .../exoplayer/dash/mpd/ContentProtection.java | 20 ++++++++++++-- .../MediaPresentationDescriptionParser.java | 2 +- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java index d0c123bdc9..932a8ea598 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java @@ -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 manifestFetcher; private final int adaptationSetIndex; private final int[] representationIndices; + private final Map 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 representations = - manifest.periods.get(0).adaptationSets.get(adaptationSetIndex).representations; + AdaptationSet adaptationSet = manifest.periods.get(0).adaptationSets.get(adaptationSetIndex); + List 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 getPsshInfo(MediaPresentationDescription manifest, + int adaptationSetIndex) { + AdaptationSet adaptationSet = manifest.periods.get(0).adaptationSets.get(adaptationSetIndex); + if (adaptationSet.contentProtections.isEmpty()) { + return null; + } else { + Map psshInfo = new HashMap(); + 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 representations) { Representation firstRepresentation = representations.get(0); AdaptationSet adaptationSet = new AdaptationSet(0, AdaptationSet.TYPE_UNKNOWN, representations); diff --git a/library/src/main/java/com/google/android/exoplayer/dash/mpd/ContentProtection.java b/library/src/main/java/com/google/android/exoplayer/dash/mpd/ContentProtection.java index bd6acca9af..c8f7cfb501 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/mpd/ContentProtection.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/mpd/ContentProtection.java @@ -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; } } diff --git a/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java b/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java index bf1ba532b7..a8ed7c03f2 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java @@ -257,7 +257,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler } protected ContentProtection buildContentProtection(String schemeIdUri) { - return new ContentProtection(schemeIdUri); + return new ContentProtection(schemeIdUri, null, null); } /**