Merge "Align CryptoInfo value and identity equality" into rvc-dev am: 9a2fdad064
Change-Id: I7569c8c944045303955547a71d57ab51c470ab41
This commit is contained in:
@@ -402,9 +402,9 @@ public final class MediaParser {
|
|||||||
* onSampleDataFound(int, MediaParser.InputReader)} for the specified track, since the
|
* onSampleDataFound(int, MediaParser.InputReader)} for the specified track, since the
|
||||||
* last byte belonging to the sample whose metadata is being passed.
|
* last byte belonging to the sample whose metadata is being passed.
|
||||||
* @param cryptoInfo Encryption data required to decrypt the sample. May be null for
|
* @param cryptoInfo Encryption data required to decrypt the sample. May be null for
|
||||||
* unencrypted samples. MediaParser may reuse {@link CryptoInfo} instances to avoid
|
* unencrypted samples. Implementors should treat any output {@link CryptoInfo}
|
||||||
* allocations, so implementations of this method must not write to or keep reference to
|
* instances as immutable. MediaParser will not modify any output {@code cryptoInfos}
|
||||||
* the fields of this parameter.
|
* and implementors should not modify them either.
|
||||||
*/
|
*/
|
||||||
void onSampleCompleted(
|
void onSampleCompleted(
|
||||||
int trackIndex,
|
int trackIndex,
|
||||||
@@ -1409,23 +1409,28 @@ public final class MediaParser {
|
|||||||
private class TrackOutputAdapter implements TrackOutput {
|
private class TrackOutputAdapter implements TrackOutput {
|
||||||
|
|
||||||
private final int mTrackIndex;
|
private final int mTrackIndex;
|
||||||
private final CryptoInfo mCryptoInfo;
|
|
||||||
|
private CryptoInfo mLastOutputCryptoInfo;
|
||||||
|
private CryptoInfo.Pattern mLastOutputEncryptionPattern;
|
||||||
|
private CryptoData mLastReceivedCryptoData;
|
||||||
|
|
||||||
@EncryptionDataReadState private int mEncryptionDataReadState;
|
@EncryptionDataReadState private int mEncryptionDataReadState;
|
||||||
private int mEncryptionDataSizeToSubtractFromSampleDataSize;
|
private int mEncryptionDataSizeToSubtractFromSampleDataSize;
|
||||||
private int mEncryptionVectorSize;
|
private int mEncryptionVectorSize;
|
||||||
|
private byte[] mScratchIvSpace;
|
||||||
|
private int mSubsampleEncryptionDataSize;
|
||||||
|
private int[] mScratchSubsampleEncryptedBytesCount;
|
||||||
|
private int[] mScratchSubsampleClearBytesCount;
|
||||||
private boolean mHasSubsampleEncryptionData;
|
private boolean mHasSubsampleEncryptionData;
|
||||||
private CryptoInfo.Pattern mEncryptionPattern;
|
|
||||||
private int mSkippedSupplementalDataBytes;
|
private int mSkippedSupplementalDataBytes;
|
||||||
|
|
||||||
private TrackOutputAdapter(int trackIndex) {
|
private TrackOutputAdapter(int trackIndex) {
|
||||||
mTrackIndex = trackIndex;
|
mTrackIndex = trackIndex;
|
||||||
mCryptoInfo = new CryptoInfo();
|
mScratchIvSpace = new byte[16]; // Size documented in CryptoInfo.
|
||||||
mCryptoInfo.iv = new byte[16]; // Size documented in CryptoInfo.
|
mScratchSubsampleEncryptedBytesCount = new int[32];
|
||||||
mCryptoInfo.numBytesOfClearData = new int[0];
|
mScratchSubsampleClearBytesCount = new int[32];
|
||||||
mCryptoInfo.numBytesOfEncryptedData = new int[0];
|
|
||||||
mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
|
mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
|
||||||
mEncryptionPattern =
|
mLastOutputEncryptionPattern =
|
||||||
new CryptoInfo.Pattern(/* blocksToEncrypt= */ 0, /* blocksToSkip= */ 0);
|
new CryptoInfo.Pattern(/* blocksToEncrypt= */ 0, /* blocksToSkip= */ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1466,35 +1471,39 @@ public final class MediaParser {
|
|||||||
mEncryptionDataReadState = STATE_READING_INIT_VECTOR;
|
mEncryptionDataReadState = STATE_READING_INIT_VECTOR;
|
||||||
break;
|
break;
|
||||||
case STATE_READING_INIT_VECTOR:
|
case STATE_READING_INIT_VECTOR:
|
||||||
Arrays.fill(mCryptoInfo.iv, (byte) 0); // Ensure 0-padding.
|
Arrays.fill(mScratchIvSpace, (byte) 0); // Ensure 0-padding.
|
||||||
data.readBytes(mCryptoInfo.iv, /* offset= */ 0, mEncryptionVectorSize);
|
data.readBytes(mScratchIvSpace, /* offset= */ 0, mEncryptionVectorSize);
|
||||||
length -= mEncryptionVectorSize;
|
length -= mEncryptionVectorSize;
|
||||||
if (mHasSubsampleEncryptionData) {
|
if (mHasSubsampleEncryptionData) {
|
||||||
mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE;
|
mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE;
|
||||||
} else {
|
} else {
|
||||||
mCryptoInfo.numSubSamples = 0;
|
mSubsampleEncryptionDataSize = 0;
|
||||||
mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
|
mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE:
|
case STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE:
|
||||||
int numSubSamples = data.readUnsignedShort();
|
mSubsampleEncryptionDataSize = data.readUnsignedShort();
|
||||||
mCryptoInfo.numSubSamples = numSubSamples;
|
if (mScratchSubsampleClearBytesCount.length
|
||||||
if (mCryptoInfo.numBytesOfClearData.length < numSubSamples) {
|
< mSubsampleEncryptionDataSize) {
|
||||||
mCryptoInfo.numBytesOfClearData = new int[numSubSamples];
|
mScratchSubsampleClearBytesCount =
|
||||||
mCryptoInfo.numBytesOfEncryptedData = new int[numSubSamples];
|
new int[mSubsampleEncryptionDataSize];
|
||||||
|
mScratchSubsampleEncryptedBytesCount =
|
||||||
|
new int[mSubsampleEncryptionDataSize];
|
||||||
}
|
}
|
||||||
length -= 2;
|
length -= 2;
|
||||||
mEncryptionDataSizeToSubtractFromSampleDataSize +=
|
mEncryptionDataSizeToSubtractFromSampleDataSize +=
|
||||||
2 + numSubSamples * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY;
|
2
|
||||||
|
+ mSubsampleEncryptionDataSize
|
||||||
|
* BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY;
|
||||||
mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_DATA;
|
mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_DATA;
|
||||||
break;
|
break;
|
||||||
case STATE_READING_SUBSAMPLE_ENCRYPTION_DATA:
|
case STATE_READING_SUBSAMPLE_ENCRYPTION_DATA:
|
||||||
for (int i = 0; i < mCryptoInfo.numSubSamples; i++) {
|
for (int i = 0; i < mSubsampleEncryptionDataSize; i++) {
|
||||||
mCryptoInfo.numBytesOfClearData[i] = data.readUnsignedShort();
|
mScratchSubsampleClearBytesCount[i] = data.readUnsignedShort();
|
||||||
mCryptoInfo.numBytesOfEncryptedData[i] = data.readInt();
|
mScratchSubsampleEncryptedBytesCount[i] = data.readInt();
|
||||||
}
|
}
|
||||||
length -=
|
length -=
|
||||||
mCryptoInfo.numSubSamples
|
mSubsampleEncryptionDataSize
|
||||||
* BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY;
|
* BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY;
|
||||||
mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
|
mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
|
||||||
if (length != 0) {
|
if (length != 0) {
|
||||||
@@ -1536,24 +1545,71 @@ public final class MediaParser {
|
|||||||
if (cryptoData == null) {
|
if (cryptoData == null) {
|
||||||
// The sample is not encrypted.
|
// The sample is not encrypted.
|
||||||
return null;
|
return null;
|
||||||
|
} else if (mInBandCryptoInfo) {
|
||||||
|
if (cryptoData != mLastReceivedCryptoData) {
|
||||||
|
mLastOutputCryptoInfo =
|
||||||
|
createNewCryptoInfoAndPopulateWithCryptoData(cryptoData);
|
||||||
|
}
|
||||||
|
} else /* We must populate the full CryptoInfo. */ {
|
||||||
|
// CryptoInfo.pattern is not accessible to the user, so the user needs to feed
|
||||||
|
// this CryptoInfo directly to MediaCodec. We need to create a new CryptoInfo per
|
||||||
|
// sample because of per-sample initialization vector changes.
|
||||||
|
CryptoInfo newCryptoInfo = createNewCryptoInfoAndPopulateWithCryptoData(cryptoData);
|
||||||
|
newCryptoInfo.iv = Arrays.copyOf(mScratchIvSpace, mScratchIvSpace.length);
|
||||||
|
boolean canReuseSubsampleInfo =
|
||||||
|
mLastOutputCryptoInfo != null
|
||||||
|
&& mLastOutputCryptoInfo.numSubSamples
|
||||||
|
== mSubsampleEncryptionDataSize;
|
||||||
|
for (int i = 0; i < mSubsampleEncryptionDataSize && canReuseSubsampleInfo; i++) {
|
||||||
|
canReuseSubsampleInfo =
|
||||||
|
mLastOutputCryptoInfo.numBytesOfClearData[i]
|
||||||
|
== mScratchSubsampleClearBytesCount[i]
|
||||||
|
&& mLastOutputCryptoInfo.numBytesOfEncryptedData[i]
|
||||||
|
== mScratchSubsampleEncryptedBytesCount[i];
|
||||||
|
}
|
||||||
|
newCryptoInfo.numSubSamples = mSubsampleEncryptionDataSize;
|
||||||
|
if (canReuseSubsampleInfo) {
|
||||||
|
newCryptoInfo.numBytesOfClearData = mLastOutputCryptoInfo.numBytesOfClearData;
|
||||||
|
newCryptoInfo.numBytesOfEncryptedData =
|
||||||
|
mLastOutputCryptoInfo.numBytesOfEncryptedData;
|
||||||
|
} else {
|
||||||
|
newCryptoInfo.numBytesOfClearData =
|
||||||
|
Arrays.copyOf(
|
||||||
|
mScratchSubsampleClearBytesCount, mSubsampleEncryptionDataSize);
|
||||||
|
newCryptoInfo.numBytesOfEncryptedData =
|
||||||
|
Arrays.copyOf(
|
||||||
|
mScratchSubsampleEncryptedBytesCount,
|
||||||
|
mSubsampleEncryptionDataSize);
|
||||||
|
}
|
||||||
|
mLastOutputCryptoInfo = newCryptoInfo;
|
||||||
}
|
}
|
||||||
mCryptoInfo.key = cryptoData.encryptionKey;
|
mLastReceivedCryptoData = cryptoData;
|
||||||
// ExoPlayer modes match MediaCodec modes.
|
return mLastOutputCryptoInfo;
|
||||||
mCryptoInfo.mode = cryptoData.cryptoMode;
|
}
|
||||||
if (cryptoData.clearBlocks != 0) {
|
|
||||||
// Content is pattern-encrypted.
|
private CryptoInfo createNewCryptoInfoAndPopulateWithCryptoData(CryptoData cryptoData) {
|
||||||
mCryptoInfo.setPattern(mEncryptionPattern);
|
CryptoInfo cryptoInfo = new CryptoInfo();
|
||||||
mEncryptionPattern.set(cryptoData.encryptedBlocks, cryptoData.clearBlocks);
|
cryptoInfo.key = cryptoData.encryptionKey;
|
||||||
} else {
|
cryptoInfo.mode = cryptoData.cryptoMode;
|
||||||
mCryptoInfo.setPattern(null);
|
if (cryptoData.clearBlocks != mLastOutputEncryptionPattern.getSkipBlocks()
|
||||||
|
|| cryptoData.encryptedBlocks
|
||||||
|
!= mLastOutputEncryptionPattern.getEncryptBlocks()) {
|
||||||
|
mLastOutputEncryptionPattern =
|
||||||
|
new CryptoInfo.Pattern(cryptoData.encryptedBlocks, cryptoData.clearBlocks);
|
||||||
}
|
}
|
||||||
return mCryptoInfo;
|
cryptoInfo.setPattern(mLastOutputEncryptionPattern);
|
||||||
|
return cryptoInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void outputSampleData(ParsableByteArray data, int length) {
|
private void outputSampleData(ParsableByteArray data, int length) {
|
||||||
mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
|
mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
|
||||||
try {
|
try {
|
||||||
mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchParsableByteArrayAdapter);
|
// Read all bytes from data. ExoPlayer extractors expect all sample data to be
|
||||||
|
// consumed by TrackOutput implementations when passing a ParsableByteArray.
|
||||||
|
while (mScratchParsableByteArrayAdapter.getLength() > 0) {
|
||||||
|
mOutputConsumer.onSampleDataFound(
|
||||||
|
mTrackIndex, mScratchParsableByteArrayAdapter);
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Unexpected.
|
// Unexpected.
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|||||||
Reference in New Issue
Block a user