Merge "Align CryptoInfo value and identity equality" into rvc-dev

This commit is contained in:
Santiago Seifert
2020-06-01 16:38:16 +00:00
committed by Android (Google) Code Review

View File

@@ -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);