Commit aca80b83 by aquilescanta Committed by Oliver Woodman

Add support for pattern encryption and default initialization vectors

This will extend our CENC modes support to cbcs and cens. The change was
not split into two different CLs due to lack of test content for
default initialization vectors, aside from AES-CBCS encrypted ones.

Issue:#1661
Issue:#1989
Issue:#2089

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=159810371
parent 73b17a7e
...@@ -184,6 +184,30 @@ ...@@ -184,6 +184,30 @@
"uri": "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1_uhd.mpd", "uri": "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1_uhd.mpd",
"drm_scheme": "widevine", "drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure SD & HD (cbcs,MP4,H264)",
"uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure SD (cbcs,MP4,H264)",
"uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs_sd.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure HD (cbcs,MP4,H264)",
"uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs_hd.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure UHD (cbcs,MP4,H264)",
"uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs_uhd.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
} }
] ]
}, },
......
...@@ -52,11 +52,11 @@ public final class CryptoInfo { ...@@ -52,11 +52,11 @@ public final class CryptoInfo {
/** /**
* @see android.media.MediaCodec.CryptoInfo.Pattern * @see android.media.MediaCodec.CryptoInfo.Pattern
*/ */
public int patternBlocksToEncrypt; public int encryptedBlocks;
/** /**
* @see android.media.MediaCodec.CryptoInfo.Pattern * @see android.media.MediaCodec.CryptoInfo.Pattern
*/ */
public int patternBlocksToSkip; public int clearBlocks;
private final android.media.MediaCodec.CryptoInfo frameworkCryptoInfo; private final android.media.MediaCodec.CryptoInfo frameworkCryptoInfo;
private final PatternHolderV24 patternHolder; private final PatternHolderV24 patternHolder;
...@@ -70,28 +70,20 @@ public final class CryptoInfo { ...@@ -70,28 +70,20 @@ public final class CryptoInfo {
* @see android.media.MediaCodec.CryptoInfo#set(int, int[], int[], byte[], byte[], int) * @see android.media.MediaCodec.CryptoInfo#set(int, int[], int[], byte[], byte[], int)
*/ */
public void set(int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData, public void set(int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
byte[] key, byte[] iv, @C.CryptoMode int mode) { byte[] key, byte[] iv, @C.CryptoMode int mode, int encryptedBlocks, int clearBlocks) {
this.numSubSamples = numSubSamples; this.numSubSamples = numSubSamples;
this.numBytesOfClearData = numBytesOfClearData; this.numBytesOfClearData = numBytesOfClearData;
this.numBytesOfEncryptedData = numBytesOfEncryptedData; this.numBytesOfEncryptedData = numBytesOfEncryptedData;
this.key = key; this.key = key;
this.iv = iv; this.iv = iv;
this.mode = mode; this.mode = mode;
patternBlocksToEncrypt = 0; this.encryptedBlocks = encryptedBlocks;
patternBlocksToSkip = 0; this.clearBlocks = clearBlocks;
if (Util.SDK_INT >= 16) { if (Util.SDK_INT >= 16) {
updateFrameworkCryptoInfoV16(); updateFrameworkCryptoInfoV16();
} }
} }
public void setPattern(int patternBlocksToEncrypt, int patternBlocksToSkip) {
this.patternBlocksToEncrypt = patternBlocksToEncrypt;
this.patternBlocksToSkip = patternBlocksToSkip;
if (Util.SDK_INT >= 24) {
patternHolder.set(patternBlocksToEncrypt, patternBlocksToSkip);
}
}
/** /**
* Returns an equivalent {@link android.media.MediaCodec.CryptoInfo} instance. * Returns an equivalent {@link android.media.MediaCodec.CryptoInfo} instance.
* <p> * <p>
...@@ -122,7 +114,7 @@ public final class CryptoInfo { ...@@ -122,7 +114,7 @@ public final class CryptoInfo {
frameworkCryptoInfo.iv = iv; frameworkCryptoInfo.iv = iv;
frameworkCryptoInfo.mode = mode; frameworkCryptoInfo.mode = mode;
if (Util.SDK_INT >= 24) { if (Util.SDK_INT >= 24) {
patternHolder.set(patternBlocksToEncrypt, patternBlocksToSkip); patternHolder.set(encryptedBlocks, clearBlocks);
} }
} }
...@@ -137,8 +129,8 @@ public final class CryptoInfo { ...@@ -137,8 +129,8 @@ public final class CryptoInfo {
pattern = new android.media.MediaCodec.CryptoInfo.Pattern(0, 0); pattern = new android.media.MediaCodec.CryptoInfo.Pattern(0, 0);
} }
private void set(int blocksToEncrypt, int blocksToSkip) { private void set(int encryptedBlocks, int clearBlocks) {
pattern.set(blocksToEncrypt, blocksToSkip); pattern.set(encryptedBlocks, clearBlocks);
frameworkCryptoInfo.setPattern(pattern); frameworkCryptoInfo.setPattern(pattern);
} }
......
...@@ -42,9 +42,30 @@ public interface TrackOutput { ...@@ -42,9 +42,30 @@ public interface TrackOutput {
*/ */
public final byte[] encryptionKey; public final byte[] encryptionKey;
public CryptoData(@C.CryptoMode int cryptoMode, byte[] encryptionKey) { /**
* The number of encrypted blocks in the encryption pattern, 0 if pattern encryption does not
* apply.
*/
public final int encryptedBlocks;
/**
* The number of clear blocks in the encryption pattern, 0 if pattern encryption does not
* apply.
*/
public final int clearBlocks;
/**
* @param cryptoMode See {@link #cryptoMode}.
* @param encryptionKey See {@link #encryptionKey}.
* @param encryptedBlocks See {@link #encryptedBlocks}.
* @param clearBlocks See {@link #clearBlocks}.
*/
public CryptoData(@C.CryptoMode int cryptoMode, byte[] encryptionKey, int encryptedBlocks,
int clearBlocks) {
this.cryptoMode = cryptoMode; this.cryptoMode = cryptoMode;
this.encryptionKey = encryptionKey; this.encryptionKey = encryptionKey;
this.encryptedBlocks = encryptedBlocks;
this.clearBlocks = clearBlocks;
} }
@Override @Override
...@@ -56,13 +77,16 @@ public interface TrackOutput { ...@@ -56,13 +77,16 @@ public interface TrackOutput {
return false; return false;
} }
CryptoData other = (CryptoData) obj; CryptoData other = (CryptoData) obj;
return cryptoMode == other.cryptoMode && Arrays.equals(encryptionKey, other.encryptionKey); return cryptoMode == other.cryptoMode && encryptedBlocks == other.encryptedBlocks
&& clearBlocks == other.clearBlocks && Arrays.equals(encryptionKey, other.encryptionKey);
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = cryptoMode; int result = cryptoMode;
result = 31 * result + Arrays.hashCode(encryptionKey); result = 31 * result + Arrays.hashCode(encryptionKey);
result = 31 * result + encryptedBlocks;
result = 31 * result + clearBlocks;
return result; return result;
} }
......
...@@ -893,7 +893,8 @@ public final class MatroskaExtractor implements Extractor { ...@@ -893,7 +893,8 @@ public final class MatroskaExtractor implements Extractor {
case ID_CONTENT_ENCRYPTION_KEY_ID: case ID_CONTENT_ENCRYPTION_KEY_ID:
byte[] encryptionKey = new byte[contentSize]; byte[] encryptionKey = new byte[contentSize];
input.readFully(encryptionKey, 0, contentSize); input.readFully(encryptionKey, 0, contentSize);
currentTrack.cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionKey); currentTrack.cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionKey,
0, 0); // We assume patternless AES-CTR.
break; break;
case ID_SIMPLE_BLOCK: case ID_SIMPLE_BLOCK:
case ID_BLOCK: case ID_BLOCK:
......
...@@ -1105,13 +1105,30 @@ import java.util.List; ...@@ -1105,13 +1105,30 @@ import java.util.List;
int childAtomSize = parent.readInt(); int childAtomSize = parent.readInt();
int childAtomType = parent.readInt(); int childAtomType = parent.readInt();
if (childAtomType == Atom.TYPE_tenc) { if (childAtomType == Atom.TYPE_tenc) {
parent.skipBytes(6); int fullAtom = parent.readInt();
boolean defaultIsEncrypted = parent.readUnsignedByte() == 1; int version = Atom.parseFullAtomVersion(fullAtom);
int defaultInitVectorSize = parent.readUnsignedByte(); parent.skipBytes(1); // reserved = 0.
int defaultCryptByteBlock = 0;
int defaultSkipByteBlock = 0;
if (version == 0) {
parent.skipBytes(1); // reserved = 0.
} else /* version 1 or greater */ {
int patternByte = parent.readUnsignedByte();
defaultCryptByteBlock = (patternByte & 0xF0) >> 4;
defaultSkipByteBlock = patternByte & 0x0F;
}
boolean defaultIsProtected = parent.readUnsignedByte() == 1;
int defaultPerSampleIvSize = parent.readUnsignedByte();
byte[] defaultKeyId = new byte[16]; byte[] defaultKeyId = new byte[16];
parent.readBytes(defaultKeyId, 0, defaultKeyId.length); parent.readBytes(defaultKeyId, 0, defaultKeyId.length);
return new TrackEncryptionBox(defaultIsEncrypted, schemeType, defaultInitVectorSize, byte[] constantIv = null;
defaultKeyId); if (defaultIsProtected && defaultPerSampleIvSize == 0) {
int constantIvSize = parent.readUnsignedByte();
constantIv = new byte[constantIvSize];
parent.readBytes(constantIv, 0, constantIvSize);
}
return new TrackEncryptionBox(defaultIsProtected, schemeType, defaultPerSampleIvSize,
defaultKeyId, defaultCryptByteBlock, defaultSkipByteBlock, constantIv);
} }
childPosition += childAtomSize; childPosition += childAtomSize;
} }
......
...@@ -128,6 +128,7 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -128,6 +128,7 @@ public final class FragmentedMp4Extractor implements Extractor {
private final ParsableByteArray nalPrefix; private final ParsableByteArray nalPrefix;
private final ParsableByteArray nalBuffer; private final ParsableByteArray nalBuffer;
private final ParsableByteArray encryptionSignalByte; private final ParsableByteArray encryptionSignalByte;
private final ParsableByteArray defaultInitializationVector;
// Adjusts sample timestamps. // Adjusts sample timestamps.
private final TimestampAdjuster timestampAdjuster; private final TimestampAdjuster timestampAdjuster;
...@@ -197,6 +198,7 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -197,6 +198,7 @@ public final class FragmentedMp4Extractor implements Extractor {
nalPrefix = new ParsableByteArray(5); nalPrefix = new ParsableByteArray(5);
nalBuffer = new ParsableByteArray(); nalBuffer = new ParsableByteArray();
encryptionSignalByte = new ParsableByteArray(1); encryptionSignalByte = new ParsableByteArray(1);
defaultInitializationVector = new ParsableByteArray();
extendedTypeScratch = new byte[16]; extendedTypeScratch = new byte[16];
containerAtoms = new Stack<>(); containerAtoms = new Stack<>();
pendingMetadataSampleInfos = new LinkedList<>(); pendingMetadataSampleInfos = new LinkedList<>();
...@@ -879,9 +881,9 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -879,9 +881,9 @@ public final class FragmentedMp4Extractor implements Extractor {
return; return;
} }
if (Atom.parseFullAtomVersion(sbgpFullAtom) == 1) { if (Atom.parseFullAtomVersion(sbgpFullAtom) == 1) {
sbgp.skipBytes(4); sbgp.skipBytes(4); // default_length.
} }
if (sbgp.readInt() != 1) { if (sbgp.readInt() != 1) { // entry_count.
throw new ParserException("Entry count in sbgp != 1 (unsupported)."); throw new ParserException("Entry count in sbgp != 1 (unsupported).");
} }
...@@ -894,25 +896,35 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -894,25 +896,35 @@ public final class FragmentedMp4Extractor implements Extractor {
int sgpdVersion = Atom.parseFullAtomVersion(sgpdFullAtom); int sgpdVersion = Atom.parseFullAtomVersion(sgpdFullAtom);
if (sgpdVersion == 1) { if (sgpdVersion == 1) {
if (sgpd.readUnsignedInt() == 0) { if (sgpd.readUnsignedInt() == 0) {
throw new ParserException("Variable length decription in sgpd found (unsupported)"); throw new ParserException("Variable length description in sgpd found (unsupported)");
} }
} else if (sgpdVersion >= 2) { } else if (sgpdVersion >= 2) {
sgpd.skipBytes(4); sgpd.skipBytes(4); // default_sample_description_index.
} }
if (sgpd.readUnsignedInt() != 1) { if (sgpd.readUnsignedInt() != 1) { // entry_count.
throw new ParserException("Entry count in sgpd != 1 (unsupported)."); throw new ParserException("Entry count in sgpd != 1 (unsupported).");
} }
// CencSampleEncryptionInformationGroupEntry // CencSampleEncryptionInformationGroupEntry
sgpd.skipBytes(2); sgpd.skipBytes(1); // reserved = 0.
int patternByte = sgpd.readUnsignedByte();
int cryptByteBlock = (patternByte & 0xF0) >> 4;
int skipByteBlock = patternByte & 0x0F;
boolean isProtected = sgpd.readUnsignedByte() == 1; boolean isProtected = sgpd.readUnsignedByte() == 1;
if (!isProtected) { if (!isProtected) {
return; return;
} }
int initVectorSize = sgpd.readUnsignedByte(); int perSampleIvSize = sgpd.readUnsignedByte();
byte[] keyId = new byte[16]; byte[] keyId = new byte[16];
sgpd.readBytes(keyId, 0, keyId.length); sgpd.readBytes(keyId, 0, keyId.length);
byte[] constantIv = null;
if (isProtected && perSampleIvSize == 0) {
int constantIvSize = sgpd.readUnsignedByte();
constantIv = new byte[constantIvSize];
sgpd.readBytes(constantIv, 0, constantIvSize);
}
out.definesEncryptionData = true; out.definesEncryptionData = true;
out.trackEncryptionBox = new TrackEncryptionBox(isProtected, schemeType, initVectorSize, keyId); out.trackEncryptionBox = new TrackEncryptionBox(isProtected, schemeType, perSampleIvSize, keyId,
cryptByteBlock, skipByteBlock, constantIv);
} }
/** /**
...@@ -1197,12 +1209,24 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -1197,12 +1209,24 @@ public final class FragmentedMp4Extractor implements Extractor {
*/ */
private int appendSampleEncryptionData(TrackBundle trackBundle) { private int appendSampleEncryptionData(TrackBundle trackBundle) {
TrackFragment trackFragment = trackBundle.fragment; TrackFragment trackFragment = trackBundle.fragment;
ParsableByteArray sampleEncryptionData = trackFragment.sampleEncryptionData;
int sampleDescriptionIndex = trackFragment.header.sampleDescriptionIndex; int sampleDescriptionIndex = trackFragment.header.sampleDescriptionIndex;
TrackEncryptionBox encryptionBox = trackFragment.trackEncryptionBox != null TrackEncryptionBox encryptionBox = trackFragment.trackEncryptionBox != null
? trackFragment.trackEncryptionBox ? trackFragment.trackEncryptionBox
: trackBundle.track.getSampleDescriptionEncryptionBox(sampleDescriptionIndex); : trackBundle.track.getSampleDescriptionEncryptionBox(sampleDescriptionIndex);
int vectorSize = encryptionBox.initializationVectorSize;
ParsableByteArray initializationVectorData;
int vectorSize;
if (encryptionBox.initializationVectorSize != 0) {
initializationVectorData = trackFragment.sampleEncryptionData;
vectorSize = encryptionBox.initializationVectorSize;
} else {
// The default initialization vector should be used.
byte[] initVectorData = encryptionBox.defaultInitializationVector;
defaultInitializationVector.reset(initVectorData, initVectorData.length);
initializationVectorData = defaultInitializationVector;
vectorSize = initVectorData.length;
}
boolean subsampleEncryption = trackFragment boolean subsampleEncryption = trackFragment
.sampleHasSubsampleEncryptionTable[trackBundle.currentSampleIndex]; .sampleHasSubsampleEncryptionTable[trackBundle.currentSampleIndex];
...@@ -1212,20 +1236,20 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -1212,20 +1236,20 @@ public final class FragmentedMp4Extractor implements Extractor {
TrackOutput output = trackBundle.output; TrackOutput output = trackBundle.output;
output.sampleData(encryptionSignalByte, 1); output.sampleData(encryptionSignalByte, 1);
// Write the vector. // Write the vector.
output.sampleData(sampleEncryptionData, vectorSize); output.sampleData(initializationVectorData, vectorSize);
// If we don't have subsample encryption data, we're done. // If we don't have subsample encryption data, we're done.
if (!subsampleEncryption) { if (!subsampleEncryption) {
return 1 + vectorSize; return 1 + vectorSize;
} }
// Write the subsample encryption data. // Write the subsample encryption data.
int subsampleCount = sampleEncryptionData.readUnsignedShort(); ParsableByteArray subsampleEncryptionData = trackFragment.sampleEncryptionData;
sampleEncryptionData.skipBytes(-2); int subsampleCount = subsampleEncryptionData.readUnsignedShort();
subsampleEncryptionData.skipBytes(-2);
int subsampleDataLength = 2 + 6 * subsampleCount; int subsampleDataLength = 2 + 6 * subsampleCount;
output.sampleData(sampleEncryptionData, subsampleDataLength); output.sampleData(subsampleEncryptionData, subsampleDataLength);
return 1 + vectorSize + subsampleDataLength; return 1 + vectorSize + subsampleDataLength;
} }
/** Returns DrmInitData from leaf atoms. */ /** Returns DrmInitData from leaf atoms. */
private static DrmInitData getDrmInitDataFromAtoms(List<Atom.LeafAtom> leafChildren) { private static DrmInitData getDrmInitDataFromAtoms(List<Atom.LeafAtom> leafChildren) {
ArrayList<SchemeData> schemeDatas = null; ArrayList<SchemeData> schemeDatas = null;
......
...@@ -19,6 +19,7 @@ import android.support.annotation.Nullable; ...@@ -19,6 +19,7 @@ import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.util.Assertions;
/** /**
* Encapsulates information parsed from a track encryption (tenc) box or sample group description * Encapsulates information parsed from a track encryption (tenc) box or sample group description
...@@ -49,19 +50,31 @@ public final class TrackEncryptionBox { ...@@ -49,19 +50,31 @@ public final class TrackEncryptionBox {
*/ */
public final int initializationVectorSize; public final int initializationVectorSize;
/**
* If {@link #initializationVectorSize} is 0, holds the default initialization vector as defined
* in the track encryption box or sample group description box. Null otherwise.
*/
public final byte[] defaultInitializationVector;
/** /**
* @param isEncrypted See {@link #isEncrypted}. * @param isEncrypted See {@link #isEncrypted}.
* @param schemeType See {@link #schemeType}. * @param schemeType See {@link #schemeType}.
* @param initializationVectorSize See {@link #initializationVectorSize}. * @param initializationVectorSize See {@link #initializationVectorSize}.
* @param keyId See {@link TrackOutput.CryptoData#encryptionKey}. * @param keyId See {@link TrackOutput.CryptoData#encryptionKey}.
* @param defaultEncryptedBlocks See {@link TrackOutput.CryptoData#encryptedBlocks}.
* @param defaultClearBlocks See {@link TrackOutput.CryptoData#clearBlocks}.
* @param defaultInitializationVector See {@link #defaultInitializationVector}.
*/ */
public TrackEncryptionBox(boolean isEncrypted, @Nullable String schemeType, public TrackEncryptionBox(boolean isEncrypted, @Nullable String schemeType,
int initializationVectorSize, byte[] keyId) { int initializationVectorSize, byte[] keyId, int defaultEncryptedBlocks,
int defaultClearBlocks, @Nullable byte[] defaultInitializationVector) {
Assertions.checkArgument(initializationVectorSize == 0 ^ defaultInitializationVector == null);
this.isEncrypted = isEncrypted; this.isEncrypted = isEncrypted;
this.schemeType = schemeType; this.schemeType = schemeType;
this.initializationVectorSize = initializationVectorSize; this.initializationVectorSize = initializationVectorSize;
cryptoData = new TrackOutput.CryptoData(schemeToCryptoMode(schemeType), keyId); this.defaultInitializationVector = defaultInitializationVector;
cryptoData = new TrackOutput.CryptoData(schemeToCryptoMode(schemeType), keyId,
defaultEncryptedBlocks, defaultClearBlocks);
} }
@C.CryptoMode @C.CryptoMode
...@@ -72,8 +85,10 @@ public final class TrackEncryptionBox { ...@@ -72,8 +85,10 @@ public final class TrackEncryptionBox {
} }
switch (schemeType) { switch (schemeType) {
case "cenc": case "cenc":
case "cens":
return C.CRYPTO_MODE_AES_CTR; return C.CRYPTO_MODE_AES_CTR;
case "cbc1": case "cbc1":
case "cbcs":
return C.CRYPTO_MODE_AES_CBC; return C.CRYPTO_MODE_AES_CBC;
default: default:
Log.w(TAG, "Unsupported protection scheme type '" + schemeType + "'. Assuming AES-CTR " Log.w(TAG, "Unsupported protection scheme type '" + schemeType + "'. Assuming AES-CTR "
......
...@@ -426,7 +426,8 @@ public final class SampleQueue implements TrackOutput { ...@@ -426,7 +426,8 @@ public final class SampleQueue implements TrackOutput {
// Populate the cryptoInfo. // Populate the cryptoInfo.
CryptoData cryptoData = extrasHolder.cryptoData; CryptoData cryptoData = extrasHolder.cryptoData;
buffer.cryptoInfo.set(subsampleCount, clearDataSizes, encryptedDataSizes, buffer.cryptoInfo.set(subsampleCount, clearDataSizes, encryptedDataSizes,
cryptoData.encryptionKey, buffer.cryptoInfo.iv, cryptoData.cryptoMode); cryptoData.encryptionKey, buffer.cryptoInfo.iv, cryptoData.cryptoMode,
cryptoData.encryptedBlocks, cryptoData.clearBlocks);
// Adjust the offset and size to take into account the bytes read. // Adjust the offset and size to take into account the bytes read.
int bytesRead = (int) (offset - extrasHolder.offset); int bytesRead = (int) (offset - extrasHolder.offset);
......
...@@ -68,8 +68,9 @@ import java.util.ArrayList; ...@@ -68,8 +68,9 @@ import java.util.ArrayList;
ProtectionElement protectionElement = manifest.protectionElement; ProtectionElement protectionElement = manifest.protectionElement;
if (protectionElement != null) { if (protectionElement != null) {
byte[] keyId = getProtectionElementKeyId(protectionElement.data); byte[] keyId = getProtectionElementKeyId(protectionElement.data);
// We assume pattern encryption does not apply.
trackEncryptionBoxes = new TrackEncryptionBox[] { trackEncryptionBoxes = new TrackEncryptionBox[] {
new TrackEncryptionBox(true, null, INITIALIZATION_VECTOR_SIZE, keyId)}; new TrackEncryptionBox(true, null, INITIALIZATION_VECTOR_SIZE, keyId, 0, 0, null)};
} else { } else {
trackEncryptionBoxes = null; trackEncryptionBoxes = null;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment