mirror of
https://github.com/samsonjs/media.git
synced 2026-03-26 09:35:47 +00:00
Add support for KEYFORMAT and SAMPLE-AES (only parsing, not decryption)
Also add sample streams that use METHOD=SAMPLE-AES. Note that some of the streams provide alternative EXT-X-KEY's. Support for alternative decryption methods will be added in a later CL. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=166048858
This commit is contained in:
parent
c1d7e5bf9d
commit
52ec70dd80
4 changed files with 45 additions and 20 deletions
|
|
@ -306,7 +306,8 @@ import java.util.List;
|
|||
out.chunk = new HlsMediaChunk(mediaDataSource, dataSpec, initDataSpec, selectedUrl,
|
||||
muxedCaptionFormats, trackSelection.getSelectionReason(), trackSelection.getSelectionData(),
|
||||
startTimeUs, startTimeUs + segment.durationUs, chunkMediaSequence, discontinuitySequence,
|
||||
isTimestampMaster, timestampAdjuster, previous, encryptionKey, encryptionIv);
|
||||
isTimestampMaster, timestampAdjuster, previous, segment.keyFormat, encryptionKey,
|
||||
encryptionIv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
|
|||
import com.google.android.exoplayer2.metadata.id3.PrivFrame;
|
||||
import com.google.android.exoplayer2.source.chunk.MediaChunk;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
|
|
@ -116,16 +117,19 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
* @param isMasterTimestampSource True if the chunk can initialize the timestamp adjuster.
|
||||
* @param timestampAdjuster Adjuster corresponding to the provided discontinuity sequence number.
|
||||
* @param previousChunk The {@link HlsMediaChunk} that preceded this one. May be null.
|
||||
* @param encryptionKey For AES encryption chunks, the encryption key.
|
||||
* @param encryptionIv For AES encryption chunks, the encryption initialization vector.
|
||||
* @param keyFormat A string describing the format for {@code keyData}, or null if the chunk is
|
||||
* not encrypted.
|
||||
* @param keyData Data specifying how to obtain the keys to decrypt the chunk, or null if the
|
||||
* chunk is not encrypted.
|
||||
* @param encryptionIv The AES initialization vector, or null if the chunk is not encrypted.
|
||||
*/
|
||||
public HlsMediaChunk(DataSource dataSource, DataSpec dataSpec, DataSpec initDataSpec,
|
||||
HlsUrl hlsUrl, List<Format> muxedCaptionFormats, int trackSelectionReason,
|
||||
Object trackSelectionData, long startTimeUs, long endTimeUs, int chunkIndex,
|
||||
int discontinuitySequenceNumber, boolean isMasterTimestampSource,
|
||||
TimestampAdjuster timestampAdjuster, HlsMediaChunk previousChunk, byte[] encryptionKey,
|
||||
byte[] encryptionIv) {
|
||||
super(buildDataSource(dataSource, encryptionKey, encryptionIv), dataSpec, hlsUrl.format,
|
||||
TimestampAdjuster timestampAdjuster, HlsMediaChunk previousChunk, String keyFormat,
|
||||
byte[] keyData, byte[] encryptionIv) {
|
||||
super(buildDataSource(dataSource, keyFormat, keyData, encryptionIv), dataSpec, hlsUrl.format,
|
||||
trackSelectionReason, trackSelectionData, startTimeUs, endTimeUs, chunkIndex);
|
||||
this.discontinuitySequenceNumber = discontinuitySequenceNumber;
|
||||
this.initDataSpec = initDataSpec;
|
||||
|
|
@ -327,15 +331,16 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
// Internal factory methods.
|
||||
|
||||
/**
|
||||
* If the content is encrypted, returns an {@link Aes128DataSource} that wraps the original in
|
||||
* order to decrypt the loaded data. Else returns the original.
|
||||
* If the content is encrypted using the "identity" key format, returns an
|
||||
* {@link Aes128DataSource} that wraps the original in order to decrypt the loaded data. Else
|
||||
* returns the original.
|
||||
*/
|
||||
private static DataSource buildDataSource(DataSource dataSource, byte[] encryptionKey,
|
||||
private static DataSource buildDataSource(DataSource dataSource, String keyFormat, byte[] keyData,
|
||||
byte[] encryptionIv) {
|
||||
if (encryptionKey == null || encryptionIv == null) {
|
||||
return dataSource;
|
||||
if (HlsMediaPlaylist.KEYFORMAT_IDENTITY.equals(keyFormat)) {
|
||||
return new Aes128DataSource(dataSource, keyData, encryptionIv);
|
||||
}
|
||||
return new Aes128DataSource(dataSource, encryptionKey, encryptionIv);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private Extractor createExtractor() {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,10 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||
* Whether the segment is encrypted, as defined by #EXT-X-KEY.
|
||||
*/
|
||||
public final boolean isEncrypted;
|
||||
/**
|
||||
* The key format as defined by #EXT-X-KEY, or null if the segment is not encrypted.
|
||||
*/
|
||||
public final String keyFormat;
|
||||
/**
|
||||
* The encryption key uri as defined by #EXT-X-KEY, or null if the segment is not encrypted.
|
||||
*/
|
||||
|
|
@ -73,7 +77,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||
public final long byterangeLength;
|
||||
|
||||
public Segment(String uri, long byterangeOffset, long byterangeLength) {
|
||||
this(uri, 0, -1, C.TIME_UNSET, false, null, null, byterangeOffset, byterangeLength);
|
||||
this(uri, 0, -1, C.TIME_UNSET, false, null, null, null, byterangeOffset, byterangeLength);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -82,19 +86,21 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||
* @param relativeDiscontinuitySequence See {@link #relativeDiscontinuitySequence}.
|
||||
* @param relativeStartTimeUs See {@link #relativeStartTimeUs}.
|
||||
* @param isEncrypted See {@link #isEncrypted}.
|
||||
* @param keyFormat See {@link #keyFormat}.
|
||||
* @param encryptionKeyUri See {@link #encryptionKeyUri}.
|
||||
* @param encryptionIV See {@link #encryptionIV}.
|
||||
* @param byterangeOffset See {@link #byterangeOffset}.
|
||||
* @param byterangeLength See {@link #byterangeLength}.
|
||||
*/
|
||||
public Segment(String url, long durationUs, int relativeDiscontinuitySequence,
|
||||
long relativeStartTimeUs, boolean isEncrypted, String encryptionKeyUri, String encryptionIV,
|
||||
long byterangeOffset, long byterangeLength) {
|
||||
long relativeStartTimeUs, boolean isEncrypted, String keyFormat, String encryptionKeyUri,
|
||||
String encryptionIV, long byterangeOffset, long byterangeLength) {
|
||||
this.url = url;
|
||||
this.durationUs = durationUs;
|
||||
this.relativeDiscontinuitySequence = relativeDiscontinuitySequence;
|
||||
this.relativeStartTimeUs = relativeStartTimeUs;
|
||||
this.isEncrypted = isEncrypted;
|
||||
this.keyFormat = keyFormat;
|
||||
this.encryptionKeyUri = encryptionKeyUri;
|
||||
this.encryptionIV = encryptionIV;
|
||||
this.byterangeOffset = byterangeOffset;
|
||||
|
|
@ -110,7 +116,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||
}
|
||||
|
||||
/**
|
||||
* Type of the playlist as defined by #EXT-X-PLAYLIST-TYPE.
|
||||
* The identity key format, as defined by #EXT-X-KEY.
|
||||
*/
|
||||
public static final String KEYFORMAT_IDENTITY = "identity";
|
||||
|
||||
/**
|
||||
* Type of the playlist, as defined by #EXT-X-PLAYLIST-TYPE.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({PLAYLIST_TYPE_UNKNOWN, PLAYLIST_TYPE_VOD, PLAYLIST_TYPE_EVENT})
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
private static final String TYPE_CLOSED_CAPTIONS = "CLOSED-CAPTIONS";
|
||||
|
||||
private static final String METHOD_NONE = "NONE";
|
||||
private static final String METHOD_AES128 = "AES-128";
|
||||
private static final String METHOD_AES_128 = "AES-128";
|
||||
private static final String METHOD_SAMPLE_AES = "SAMPLE-AES";
|
||||
|
||||
private static final String BOOLEAN_TRUE = "YES";
|
||||
private static final String BOOLEAN_FALSE = "NO";
|
||||
|
|
@ -97,7 +98,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
private static final Pattern REGEX_ATTR_BYTERANGE =
|
||||
Pattern.compile("BYTERANGE=\"(\\d+(?:@\\d+)?)\\b\"");
|
||||
private static final Pattern REGEX_METHOD = Pattern.compile("METHOD=(" + METHOD_NONE + "|"
|
||||
+ METHOD_AES128 + ")");
|
||||
+ METHOD_AES_128 + "|" + METHOD_SAMPLE_AES + ")");
|
||||
private static final Pattern REGEX_KEYFORMAT = Pattern.compile("KEYFORMAT=\"(.+?)\"");
|
||||
private static final Pattern REGEX_URI = Pattern.compile("URI=\"(.+?)\"");
|
||||
private static final Pattern REGEX_IV = Pattern.compile("IV=([^,.*]+)");
|
||||
private static final Pattern REGEX_TYPE = Pattern.compile("TYPE=(" + TYPE_AUDIO + "|" + TYPE_VIDEO
|
||||
|
|
@ -314,6 +316,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
int segmentMediaSequence = 0;
|
||||
|
||||
boolean isEncrypted = false;
|
||||
String keyFormat = null;
|
||||
String encryptionKeyUri = null;
|
||||
String encryptionIV = null;
|
||||
|
||||
|
|
@ -360,11 +363,16 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
(long) (parseDoubleAttr(line, REGEX_MEDIA_DURATION) * C.MICROS_PER_SECOND);
|
||||
} else if (line.startsWith(TAG_KEY)) {
|
||||
String method = parseStringAttr(line, REGEX_METHOD);
|
||||
isEncrypted = METHOD_AES128.equals(method);
|
||||
isEncrypted = METHOD_AES_128.equals(method) || METHOD_SAMPLE_AES.equals(method);
|
||||
if (isEncrypted) {
|
||||
keyFormat = parseOptionalStringAttr(line, REGEX_KEYFORMAT);
|
||||
if (keyFormat == null) {
|
||||
keyFormat = HlsMediaPlaylist.KEYFORMAT_IDENTITY;
|
||||
}
|
||||
encryptionKeyUri = parseStringAttr(line, REGEX_URI);
|
||||
encryptionIV = parseOptionalStringAttr(line, REGEX_IV);
|
||||
} else {
|
||||
keyFormat = null;
|
||||
encryptionKeyUri = null;
|
||||
encryptionIV = null;
|
||||
}
|
||||
|
|
@ -400,7 +408,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
segmentByteRangeOffset = 0;
|
||||
}
|
||||
segments.add(new Segment(line, segmentDurationUs, relativeDiscontinuitySequence,
|
||||
segmentStartTimeUs, isEncrypted, encryptionKeyUri, segmentEncryptionIV,
|
||||
segmentStartTimeUs, isEncrypted, keyFormat, encryptionKeyUri, segmentEncryptionIV,
|
||||
segmentByteRangeOffset, segmentByteRangeLength));
|
||||
segmentStartTimeUs += segmentDurationUs;
|
||||
segmentDurationUs = 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue