mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
commit
1344b36da9
@ -279,8 +279,8 @@ public class DashRendererBuilder implements RendererBuilder,
|
|||||||
public static Pair<DrmSessionManager, Boolean> getDrmSessionManagerData(DemoPlayer player,
|
public static Pair<DrmSessionManager, Boolean> getDrmSessionManagerData(DemoPlayer player,
|
||||||
MediaDrmCallback drmCallback) throws UnsupportedSchemeException {
|
MediaDrmCallback drmCallback) throws UnsupportedSchemeException {
|
||||||
StreamingDrmSessionManager streamingDrmSessionManager = new StreamingDrmSessionManager(
|
StreamingDrmSessionManager streamingDrmSessionManager = new StreamingDrmSessionManager(
|
||||||
DemoUtil.WIDEVINE_UUID, player.getPlaybackLooper(), drmCallback, player.getMainHandler(),
|
DemoUtil.WIDEVINE_UUID, player.getPlaybackLooper(), drmCallback, null,
|
||||||
player);
|
player.getMainHandler(), player);
|
||||||
return Pair.create((DrmSessionManager) streamingDrmSessionManager,
|
return Pair.create((DrmSessionManager) streamingDrmSessionManager,
|
||||||
getWidevineSecurityLevel(streamingDrmSessionManager) == SECURITY_LEVEL_1);
|
getWidevineSecurityLevel(streamingDrmSessionManager) == SECURITY_LEVEL_1);
|
||||||
}
|
}
|
||||||
|
@ -252,7 +252,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
|
|||||||
|
|
||||||
public static DrmSessionManager getDrmSessionManager(UUID uuid, DemoPlayer player,
|
public static DrmSessionManager getDrmSessionManager(UUID uuid, DemoPlayer player,
|
||||||
MediaDrmCallback drmCallback) throws UnsupportedSchemeException {
|
MediaDrmCallback drmCallback) throws UnsupportedSchemeException {
|
||||||
return new StreamingDrmSessionManager(uuid, player.getPlaybackLooper(), drmCallback,
|
return new StreamingDrmSessionManager(uuid, player.getPlaybackLooper(), drmCallback, null,
|
||||||
player.getMainHandler(), player);
|
player.getMainHandler(), player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,17 @@ public final class Mp4MediaChunk extends MediaChunk {
|
|||||||
private MediaFormat mediaFormat;
|
private MediaFormat mediaFormat;
|
||||||
private Map<UUID, byte[]> psshInfo;
|
private Map<UUID, byte[]> psshInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use the other constructor, passing null as {@code psshInfo}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public Mp4MediaChunk(DataSource dataSource, DataSpec dataSpec, Format format,
|
||||||
|
int trigger, long startTimeUs, long endTimeUs, int nextChunkIndex,
|
||||||
|
Extractor extractor, boolean maybeSelfContained, long sampleOffsetUs) {
|
||||||
|
this(dataSource, dataSpec, format, trigger, startTimeUs, endTimeUs, nextChunkIndex,
|
||||||
|
extractor, null, maybeSelfContained, sampleOffsetUs);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dataSource A {@link DataSource} for loading the data.
|
* @param dataSource A {@link DataSource} for loading the data.
|
||||||
* @param dataSpec Defines the data to be loaded.
|
* @param dataSpec Defines the data to be loaded.
|
||||||
@ -49,6 +60,8 @@ public final class Mp4MediaChunk extends MediaChunk {
|
|||||||
* @param endTimeUs The end time of the media contained by the chunk, in microseconds.
|
* @param endTimeUs The end time of the media contained by the chunk, in microseconds.
|
||||||
* @param nextChunkIndex The index of the next chunk, or -1 if this is the last chunk.
|
* @param nextChunkIndex The index of the next chunk, or -1 if this is the last chunk.
|
||||||
* @param extractor The extractor that will be used to extract the samples.
|
* @param extractor The extractor that will be used to extract the samples.
|
||||||
|
* @param psshInfo Pssh data. May be null if pssh data is present within the stream, meaning it
|
||||||
|
* can be obtained directly from {@code extractor}, or if no pssh data is required.
|
||||||
* @param maybeSelfContained Set to true if this chunk might be self contained, meaning it might
|
* @param maybeSelfContained Set to true if this chunk might be self contained, meaning it might
|
||||||
* contain a moov atom defining the media format of the chunk. This parameter can always be
|
* contain a moov atom defining the media format of the chunk. This parameter can always be
|
||||||
* safely set to true. Setting to false where the chunk is known to not be self contained may
|
* safely set to true. Setting to false where the chunk is known to not be self contained may
|
||||||
@ -56,12 +69,13 @@ public final class Mp4MediaChunk extends MediaChunk {
|
|||||||
* @param sampleOffsetUs An offset to subtract from the sample timestamps parsed by the extractor.
|
* @param sampleOffsetUs An offset to subtract from the sample timestamps parsed by the extractor.
|
||||||
*/
|
*/
|
||||||
public Mp4MediaChunk(DataSource dataSource, DataSpec dataSpec, Format format,
|
public Mp4MediaChunk(DataSource dataSource, DataSpec dataSpec, Format format,
|
||||||
int trigger, long startTimeUs, long endTimeUs, int nextChunkIndex,
|
int trigger, long startTimeUs, long endTimeUs, int nextChunkIndex, Extractor extractor,
|
||||||
Extractor extractor, boolean maybeSelfContained, long sampleOffsetUs) {
|
Map<UUID, byte[]> psshInfo, boolean maybeSelfContained, long sampleOffsetUs) {
|
||||||
super(dataSource, dataSpec, format, trigger, startTimeUs, endTimeUs, nextChunkIndex);
|
super(dataSource, dataSpec, format, trigger, startTimeUs, endTimeUs, nextChunkIndex);
|
||||||
this.extractor = extractor;
|
this.extractor = extractor;
|
||||||
this.maybeSelfContained = maybeSelfContained;
|
this.maybeSelfContained = maybeSelfContained;
|
||||||
this.sampleOffsetUs = sampleOffsetUs;
|
this.sampleOffsetUs = sampleOffsetUs;
|
||||||
|
this.psshInfo = psshInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -97,7 +111,10 @@ public final class Mp4MediaChunk extends MediaChunk {
|
|||||||
}
|
}
|
||||||
if (prepared) {
|
if (prepared) {
|
||||||
mediaFormat = extractor.getFormat();
|
mediaFormat = extractor.getFormat();
|
||||||
psshInfo = extractor.getPsshInfo();
|
Map<UUID, byte[]> extractorPsshInfo = extractor.getPsshInfo();
|
||||||
|
if (extractorPsshInfo != null) {
|
||||||
|
psshInfo = extractorPsshInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return prepared;
|
return prepared;
|
||||||
|
@ -31,6 +31,7 @@ import com.google.android.exoplayer.chunk.MediaChunk;
|
|||||||
import com.google.android.exoplayer.chunk.Mp4MediaChunk;
|
import com.google.android.exoplayer.chunk.Mp4MediaChunk;
|
||||||
import com.google.android.exoplayer.chunk.SingleSampleMediaChunk;
|
import com.google.android.exoplayer.chunk.SingleSampleMediaChunk;
|
||||||
import com.google.android.exoplayer.dash.mpd.AdaptationSet;
|
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.MediaPresentationDescription;
|
||||||
import com.google.android.exoplayer.dash.mpd.Period;
|
import com.google.android.exoplayer.dash.mpd.Period;
|
||||||
import com.google.android.exoplayer.dash.mpd.RangedUri;
|
import com.google.android.exoplayer.dash.mpd.RangedUri;
|
||||||
@ -53,6 +54,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link ChunkSource} for DASH streams.
|
* An {@link ChunkSource} for DASH streams.
|
||||||
@ -92,6 +95,7 @@ public class DashChunkSource implements ChunkSource {
|
|||||||
private final ManifestFetcher<MediaPresentationDescription> manifestFetcher;
|
private final ManifestFetcher<MediaPresentationDescription> manifestFetcher;
|
||||||
private final int adaptationSetIndex;
|
private final int adaptationSetIndex;
|
||||||
private final int[] representationIndices;
|
private final int[] representationIndices;
|
||||||
|
private final Map<UUID, byte[]> psshInfo;
|
||||||
|
|
||||||
private MediaPresentationDescription currentManifest;
|
private MediaPresentationDescription currentManifest;
|
||||||
private boolean finishedCurrentManifest;
|
private boolean finishedCurrentManifest;
|
||||||
@ -180,6 +184,7 @@ public class DashChunkSource implements ChunkSource {
|
|||||||
this.evaluation = new Evaluation();
|
this.evaluation = new Evaluation();
|
||||||
this.headerBuilder = new StringBuilder();
|
this.headerBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
psshInfo = getPsshInfo(currentManifest, adaptationSetIndex);
|
||||||
Representation[] representations = getFilteredRepresentations(currentManifest,
|
Representation[] representations = getFilteredRepresentations(currentManifest,
|
||||||
adaptationSetIndex, representationIndices);
|
adaptationSetIndex, representationIndices);
|
||||||
long periodDurationUs = (representations[0].periodDurationMs == TrackRenderer.UNKNOWN_TIME_US)
|
long periodDurationUs = (representations[0].periodDurationMs == TrackRenderer.UNKNOWN_TIME_US)
|
||||||
@ -438,7 +443,7 @@ public class DashChunkSource implements ChunkSource {
|
|||||||
startTimeUs, endTimeUs, nextAbsoluteSegmentNum, null, representationHolder.vttHeader);
|
startTimeUs, endTimeUs, nextAbsoluteSegmentNum, null, representationHolder.vttHeader);
|
||||||
} else {
|
} else {
|
||||||
return new Mp4MediaChunk(dataSource, dataSpec, representation.format, trigger, startTimeUs,
|
return new Mp4MediaChunk(dataSource, dataSpec, representation.format, trigger, startTimeUs,
|
||||||
endTimeUs, nextAbsoluteSegmentNum, representationHolder.extractor, false,
|
endTimeUs, nextAbsoluteSegmentNum, representationHolder.extractor, psshInfo, false,
|
||||||
presentationTimeOffsetUs);
|
presentationTimeOffsetUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -463,8 +468,8 @@ public class DashChunkSource implements ChunkSource {
|
|||||||
|
|
||||||
private static Representation[] getFilteredRepresentations(MediaPresentationDescription manifest,
|
private static Representation[] getFilteredRepresentations(MediaPresentationDescription manifest,
|
||||||
int adaptationSetIndex, int[] representationIndices) {
|
int adaptationSetIndex, int[] representationIndices) {
|
||||||
List<Representation> representations =
|
AdaptationSet adaptationSet = manifest.periods.get(0).adaptationSets.get(adaptationSetIndex);
|
||||||
manifest.periods.get(0).adaptationSets.get(adaptationSetIndex).representations;
|
List<Representation> representations = adaptationSet.representations;
|
||||||
if (representationIndices == null) {
|
if (representationIndices == null) {
|
||||||
Representation[] filteredRepresentations = new Representation[representations.size()];
|
Representation[] filteredRepresentations = new Representation[representations.size()];
|
||||||
representations.toArray(filteredRepresentations);
|
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) {
|
private static MediaPresentationDescription buildManifest(List<Representation> representations) {
|
||||||
Representation firstRepresentation = representations.get(0);
|
Representation firstRepresentation = representations.get(0);
|
||||||
AdaptationSet adaptationSet = new AdaptationSet(0, AdaptationSet.TYPE_UNKNOWN, representations);
|
AdaptationSet adaptationSet = new AdaptationSet(0, AdaptationSet.TYPE_UNKNOWN, representations);
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.dash.mpd;
|
package com.google.android.exoplayer.dash.mpd;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a ContentProtection tag in an AdaptationSet.
|
* Represents a ContentProtection tag in an AdaptationSet.
|
||||||
*/
|
*/
|
||||||
@ -26,10 +28,24 @@ public class ContentProtection {
|
|||||||
public final String schemeUriId;
|
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.schemeUriId = schemeUriId;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected ContentProtection buildContentProtection(String schemeIdUri) {
|
protected ContentProtection buildContentProtection(String schemeIdUri) {
|
||||||
return new ContentProtection(schemeIdUri);
|
return new ContentProtection(schemeIdUri, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +30,7 @@ import android.os.HandlerThread;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -61,6 +62,7 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
|||||||
private final Handler eventHandler;
|
private final Handler eventHandler;
|
||||||
private final EventListener eventListener;
|
private final EventListener eventListener;
|
||||||
private final MediaDrm mediaDrm;
|
private final MediaDrm mediaDrm;
|
||||||
|
private final HashMap<String, String> optionalKeyRequestParameters;
|
||||||
|
|
||||||
/* package */ final MediaDrmHandler mediaDrmHandler;
|
/* package */ final MediaDrmHandler mediaDrmHandler;
|
||||||
/* package */ final MediaDrmCallback callback;
|
/* package */ final MediaDrmCallback callback;
|
||||||
@ -79,20 +81,33 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
|||||||
private byte[] schemePsshData;
|
private byte[] schemePsshData;
|
||||||
private byte[] sessionId;
|
private byte[] sessionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use the other constructor, passing null as {@code optionalKeyRequestParameters}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public StreamingDrmSessionManager(UUID uuid, Looper playbackLooper, MediaDrmCallback callback,
|
||||||
|
Handler eventHandler, EventListener eventListener) throws UnsupportedSchemeException {
|
||||||
|
this(uuid, playbackLooper, callback, null, eventHandler, eventListener);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param uuid The UUID of the drm scheme.
|
* @param uuid The UUID of the drm scheme.
|
||||||
* @param playbackLooper The looper associated with the media playback thread. Should usually be
|
* @param playbackLooper The looper associated with the media playback thread. Should usually be
|
||||||
* obtained using {@link com.google.android.exoplayer.ExoPlayer#getPlaybackLooper()}.
|
* obtained using {@link com.google.android.exoplayer.ExoPlayer#getPlaybackLooper()}.
|
||||||
* @param callback Performs key and provisioning requests.
|
* @param callback Performs key and provisioning requests.
|
||||||
|
* @param optionalKeyRequestParameters An optional map of parameters to pass as the last argument
|
||||||
|
* to {@link MediaDrm#getKeyRequest(byte[], byte[], String, int, HashMap)}. May be null.
|
||||||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
||||||
* null if delivery of events is not required.
|
* null if delivery of events is not required.
|
||||||
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||||
* @throws UnsupportedSchemeException If the specified DRM scheme is not supported.
|
* @throws UnsupportedSchemeException If the specified DRM scheme is not supported.
|
||||||
*/
|
*/
|
||||||
public StreamingDrmSessionManager(UUID uuid, Looper playbackLooper, MediaDrmCallback callback,
|
public StreamingDrmSessionManager(UUID uuid, Looper playbackLooper, MediaDrmCallback callback,
|
||||||
Handler eventHandler, EventListener eventListener) throws UnsupportedSchemeException {
|
HashMap<String, String> optionalKeyRequestParameters, Handler eventHandler,
|
||||||
|
EventListener eventListener) throws UnsupportedSchemeException {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
this.optionalKeyRequestParameters = optionalKeyRequestParameters;
|
||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
mediaDrm = new MediaDrm(uuid);
|
mediaDrm = new MediaDrm(uuid);
|
||||||
@ -250,7 +265,7 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
|||||||
KeyRequest keyRequest;
|
KeyRequest keyRequest;
|
||||||
try {
|
try {
|
||||||
keyRequest = mediaDrm.getKeyRequest(sessionId, schemePsshData, mimeType,
|
keyRequest = mediaDrm.getKeyRequest(sessionId, schemePsshData, mimeType,
|
||||||
MediaDrm.KEY_TYPE_STREAMING, null);
|
MediaDrm.KEY_TYPE_STREAMING, optionalKeyRequestParameters);
|
||||||
postRequestHandler.obtainMessage(MSG_KEYS, keyRequest).sendToTarget();
|
postRequestHandler.obtainMessage(MSG_KEYS, keyRequest).sendToTarget();
|
||||||
} catch (NotProvisionedException e) {
|
} catch (NotProvisionedException e) {
|
||||||
onKeysError(e);
|
onKeysError(e);
|
||||||
|
@ -189,20 +189,6 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||||||
this.track = track;
|
this.track = track;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sideloads pssh information into the extractor, so that it can be read through
|
|
||||||
* {@link #getPsshInfo()}.
|
|
||||||
*
|
|
||||||
* @param uuid The UUID of the scheme for which information is being sideloaded.
|
|
||||||
* @param data The corresponding data.
|
|
||||||
*/
|
|
||||||
public void putPsshInfo(UUID uuid, byte[] data) {
|
|
||||||
// TODO: This is for SmoothStreaming. Consider using something other than
|
|
||||||
// FragmentedMp4Extractor.getPsshInfo to obtain the pssh data for that use case, so that we can
|
|
||||||
// remove this method.
|
|
||||||
psshData.put(uuid, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<UUID, byte[]> getPsshInfo() {
|
public Map<UUID, byte[]> getPsshInfo() {
|
||||||
return psshData.isEmpty() ? null : psshData;
|
return psshData.isEmpty() ? null : psshData;
|
||||||
|
@ -48,6 +48,8 @@ import java.io.IOException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link ChunkSource} for SmoothStreaming.
|
* An {@link ChunkSource} for SmoothStreaming.
|
||||||
@ -69,6 +71,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
|||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
|
|
||||||
private final SparseArray<FragmentedMp4Extractor> extractors;
|
private final SparseArray<FragmentedMp4Extractor> extractors;
|
||||||
|
private final Map<UUID, byte[]> psshInfo;
|
||||||
private final SmoothStreamingFormat[] formats;
|
private final SmoothStreamingFormat[] formats;
|
||||||
|
|
||||||
private SmoothStreamingManifest currentManifest;
|
private SmoothStreamingManifest currentManifest;
|
||||||
@ -140,6 +143,9 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
|||||||
byte[] keyId = getKeyId(protectionElement.data);
|
byte[] keyId = getKeyId(protectionElement.data);
|
||||||
trackEncryptionBoxes = new TrackEncryptionBox[1];
|
trackEncryptionBoxes = new TrackEncryptionBox[1];
|
||||||
trackEncryptionBoxes[0] = new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId);
|
trackEncryptionBoxes[0] = new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId);
|
||||||
|
psshInfo = Collections.singletonMap(protectionElement.uuid, protectionElement.data);
|
||||||
|
} else {
|
||||||
|
psshInfo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int trackCount = trackIndices != null ? trackIndices.length : streamElement.tracks.length;
|
int trackCount = trackIndices != null ? trackIndices.length : streamElement.tracks.length;
|
||||||
@ -163,9 +169,6 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
|||||||
FragmentedMp4Extractor.WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME);
|
FragmentedMp4Extractor.WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME);
|
||||||
extractor.setTrack(new Track(trackIndex, trackType, streamElement.timescale, mediaFormat,
|
extractor.setTrack(new Track(trackIndex, trackType, streamElement.timescale, mediaFormat,
|
||||||
trackEncryptionBoxes));
|
trackEncryptionBoxes));
|
||||||
if (protectionElement != null) {
|
|
||||||
extractor.putPsshInfo(protectionElement.uuid, protectionElement.data);
|
|
||||||
}
|
|
||||||
extractors.put(trackIndex, extractor);
|
extractors.put(trackIndex, extractor);
|
||||||
}
|
}
|
||||||
this.maxHeight = maxHeight;
|
this.maxHeight = maxHeight;
|
||||||
@ -296,8 +299,8 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
|||||||
|
|
||||||
Uri uri = streamElement.buildRequestUri(selectedFormat.trackIndex, chunkIndex);
|
Uri uri = streamElement.buildRequestUri(selectedFormat.trackIndex, chunkIndex);
|
||||||
Chunk mediaChunk = newMediaChunk(selectedFormat, uri, null,
|
Chunk mediaChunk = newMediaChunk(selectedFormat, uri, null,
|
||||||
extractors.get(Integer.parseInt(selectedFormat.id)), dataSource, currentAbsoluteChunkIndex,
|
extractors.get(Integer.parseInt(selectedFormat.id)), psshInfo, dataSource,
|
||||||
isLastChunk, chunkStartTimeUs, nextChunkStartTimeUs, 0);
|
currentAbsoluteChunkIndex, isLastChunk, chunkStartTimeUs, nextChunkStartTimeUs, 0);
|
||||||
out.chunk = mediaChunk;
|
out.chunk = mediaChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +364,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static MediaChunk newMediaChunk(Format formatInfo, Uri uri, String cacheKey,
|
private static MediaChunk newMediaChunk(Format formatInfo, Uri uri, String cacheKey,
|
||||||
Extractor extractor, DataSource dataSource, int chunkIndex,
|
Extractor extractor, Map<UUID, byte[]> psshInfo, DataSource dataSource, int chunkIndex,
|
||||||
boolean isLast, long chunkStartTimeUs, long nextChunkStartTimeUs, int trigger) {
|
boolean isLast, long chunkStartTimeUs, long nextChunkStartTimeUs, int trigger) {
|
||||||
int nextChunkIndex = isLast ? -1 : chunkIndex + 1;
|
int nextChunkIndex = isLast ? -1 : chunkIndex + 1;
|
||||||
long nextStartTimeUs = isLast ? -1 : nextChunkStartTimeUs;
|
long nextStartTimeUs = isLast ? -1 : nextChunkStartTimeUs;
|
||||||
@ -370,7 +373,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
|||||||
// In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk.
|
// In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk.
|
||||||
// To convert them the absolute timestamps, we need to set sampleOffsetUs to -chunkStartTimeUs.
|
// To convert them the absolute timestamps, we need to set sampleOffsetUs to -chunkStartTimeUs.
|
||||||
return new Mp4MediaChunk(dataSource, dataSpec, formatInfo, trigger, chunkStartTimeUs,
|
return new Mp4MediaChunk(dataSource, dataSpec, formatInfo, trigger, chunkStartTimeUs,
|
||||||
nextStartTimeUs, nextChunkIndex, extractor, false, -chunkStartTimeUs);
|
nextStartTimeUs, nextChunkIndex, extractor, psshInfo, false, -chunkStartTimeUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] getKeyId(byte[] initData) {
|
private static byte[] getKeyId(byte[] initData) {
|
||||||
|
@ -274,7 +274,7 @@ public class SmoothStreamingManifest {
|
|||||||
String chunkUrl = chunkTemplate
|
String chunkUrl = chunkTemplate
|
||||||
.replace(URL_PLACEHOLDER_BITRATE, Integer.toString(tracks[track].bitrate))
|
.replace(URL_PLACEHOLDER_BITRATE, Integer.toString(tracks[track].bitrate))
|
||||||
.replace(URL_PLACEHOLDER_START_TIME, Long.toString(chunkStartTimes.get(chunkIndex)));
|
.replace(URL_PLACEHOLDER_START_TIME, Long.toString(chunkStartTimes.get(chunkIndex)));
|
||||||
return baseUri.buildUpon().appendEncodedPath(chunkUrl).build();
|
return Util.getMergedUri(baseUri, chunkUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user