@@ -402,9 +402,9 @@ public interface OutputConsumer {
402402 * onSampleDataFound(int, MediaParser.InputReader)} for the specified track, since the
403403 * last byte belonging to the sample whose metadata is being passed.
404404 * @param cryptoInfo Encryption data required to decrypt the sample. May be null for
405- * unencrypted samples. MediaParser may reuse {@link CryptoInfo} instances to avoid
406- * allocations, so implementations of this method must not write to or keep reference to
407- * the fields of this parameter .
405+ * unencrypted samples. Implementors should treat any output {@link CryptoInfo}
406+ * instances as immutable. MediaParser will not modify any output {@code cryptoInfos}
407+ * and implementors should not modify them either .
408408 */
409409 void onSampleCompleted (
410410 int trackIndex ,
@@ -1409,23 +1409,28 @@ public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSee
14091409 private class TrackOutputAdapter implements TrackOutput {
14101410
14111411 private final int mTrackIndex ;
1412- private final CryptoInfo mCryptoInfo ;
1412+
1413+ private CryptoInfo mLastOutputCryptoInfo ;
1414+ private CryptoInfo .Pattern mLastOutputEncryptionPattern ;
1415+ private CryptoData mLastReceivedCryptoData ;
14131416
14141417 @ EncryptionDataReadState private int mEncryptionDataReadState ;
14151418 private int mEncryptionDataSizeToSubtractFromSampleDataSize ;
14161419 private int mEncryptionVectorSize ;
1420+ private byte [] mScratchIvSpace ;
1421+ private int mSubsampleEncryptionDataSize ;
1422+ private int [] mScratchSubsampleEncryptedBytesCount ;
1423+ private int [] mScratchSubsampleClearBytesCount ;
14171424 private boolean mHasSubsampleEncryptionData ;
1418- private CryptoInfo .Pattern mEncryptionPattern ;
14191425 private int mSkippedSupplementalDataBytes ;
14201426
14211427 private TrackOutputAdapter (int trackIndex ) {
14221428 mTrackIndex = trackIndex ;
1423- mCryptoInfo = new CryptoInfo ();
1424- mCryptoInfo .iv = new byte [16 ]; // Size documented in CryptoInfo.
1425- mCryptoInfo .numBytesOfClearData = new int [0 ];
1426- mCryptoInfo .numBytesOfEncryptedData = new int [0 ];
1429+ mScratchIvSpace = new byte [16 ]; // Size documented in CryptoInfo.
1430+ mScratchSubsampleEncryptedBytesCount = new int [32 ];
1431+ mScratchSubsampleClearBytesCount = new int [32 ];
14271432 mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE ;
1428- mEncryptionPattern =
1433+ mLastOutputEncryptionPattern =
14291434 new CryptoInfo .Pattern (/* blocksToEncrypt= */ 0 , /* blocksToSkip= */ 0 );
14301435 }
14311436
@@ -1466,35 +1471,39 @@ public void sampleData(
14661471 mEncryptionDataReadState = STATE_READING_INIT_VECTOR ;
14671472 break ;
14681473 case STATE_READING_INIT_VECTOR :
1469- Arrays .fill (mCryptoInfo . iv , (byte ) 0 ); // Ensure 0-padding.
1470- data .readBytes (mCryptoInfo . iv , /* offset= */ 0 , mEncryptionVectorSize );
1474+ Arrays .fill (mScratchIvSpace , (byte ) 0 ); // Ensure 0-padding.
1475+ data .readBytes (mScratchIvSpace , /* offset= */ 0 , mEncryptionVectorSize );
14711476 length -= mEncryptionVectorSize ;
14721477 if (mHasSubsampleEncryptionData ) {
14731478 mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE ;
14741479 } else {
1475- mCryptoInfo . numSubSamples = 0 ;
1480+ mSubsampleEncryptionDataSize = 0 ;
14761481 mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE ;
14771482 }
14781483 break ;
14791484 case STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE :
1480- int numSubSamples = data .readUnsignedShort ();
1481- mCryptoInfo .numSubSamples = numSubSamples ;
1482- if (mCryptoInfo .numBytesOfClearData .length < numSubSamples ) {
1483- mCryptoInfo .numBytesOfClearData = new int [numSubSamples ];
1484- mCryptoInfo .numBytesOfEncryptedData = new int [numSubSamples ];
1485+ mSubsampleEncryptionDataSize = data .readUnsignedShort ();
1486+ if (mScratchSubsampleClearBytesCount .length
1487+ < mSubsampleEncryptionDataSize ) {
1488+ mScratchSubsampleClearBytesCount =
1489+ new int [mSubsampleEncryptionDataSize ];
1490+ mScratchSubsampleEncryptedBytesCount =
1491+ new int [mSubsampleEncryptionDataSize ];
14851492 }
14861493 length -= 2 ;
14871494 mEncryptionDataSizeToSubtractFromSampleDataSize +=
1488- 2 + numSubSamples * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY ;
1495+ 2
1496+ + mSubsampleEncryptionDataSize
1497+ * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY ;
14891498 mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_DATA ;
14901499 break ;
14911500 case STATE_READING_SUBSAMPLE_ENCRYPTION_DATA :
1492- for (int i = 0 ; i < mCryptoInfo . numSubSamples ; i ++) {
1493- mCryptoInfo . numBytesOfClearData [i ] = data .readUnsignedShort ();
1494- mCryptoInfo . numBytesOfEncryptedData [i ] = data .readInt ();
1501+ for (int i = 0 ; i < mSubsampleEncryptionDataSize ; i ++) {
1502+ mScratchSubsampleClearBytesCount [i ] = data .readUnsignedShort ();
1503+ mScratchSubsampleEncryptedBytesCount [i ] = data .readInt ();
14951504 }
14961505 length -=
1497- mCryptoInfo . numSubSamples
1506+ mSubsampleEncryptionDataSize
14981507 * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY ;
14991508 mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE ;
15001509 if (length != 0 ) {
@@ -1536,24 +1545,71 @@ private CryptoInfo getPopulatedCryptoInfo(@Nullable CryptoData cryptoData) {
15361545 if (cryptoData == null ) {
15371546 // The sample is not encrypted.
15381547 return null ;
1548+ } else if (mInBandCryptoInfo ) {
1549+ if (cryptoData != mLastReceivedCryptoData ) {
1550+ mLastOutputCryptoInfo =
1551+ createNewCryptoInfoAndPopulateWithCryptoData (cryptoData );
1552+ }
1553+ } else /* We must populate the full CryptoInfo. */ {
1554+ // CryptoInfo.pattern is not accessible to the user, so the user needs to feed
1555+ // this CryptoInfo directly to MediaCodec. We need to create a new CryptoInfo per
1556+ // sample because of per-sample initialization vector changes.
1557+ CryptoInfo newCryptoInfo = createNewCryptoInfoAndPopulateWithCryptoData (cryptoData );
1558+ newCryptoInfo .iv = Arrays .copyOf (mScratchIvSpace , mScratchIvSpace .length );
1559+ boolean canReuseSubsampleInfo =
1560+ mLastOutputCryptoInfo != null
1561+ && mLastOutputCryptoInfo .numSubSamples
1562+ == mSubsampleEncryptionDataSize ;
1563+ for (int i = 0 ; i < mSubsampleEncryptionDataSize && canReuseSubsampleInfo ; i ++) {
1564+ canReuseSubsampleInfo =
1565+ mLastOutputCryptoInfo .numBytesOfClearData [i ]
1566+ == mScratchSubsampleClearBytesCount [i ]
1567+ && mLastOutputCryptoInfo .numBytesOfEncryptedData [i ]
1568+ == mScratchSubsampleEncryptedBytesCount [i ];
1569+ }
1570+ newCryptoInfo .numSubSamples = mSubsampleEncryptionDataSize ;
1571+ if (canReuseSubsampleInfo ) {
1572+ newCryptoInfo .numBytesOfClearData = mLastOutputCryptoInfo .numBytesOfClearData ;
1573+ newCryptoInfo .numBytesOfEncryptedData =
1574+ mLastOutputCryptoInfo .numBytesOfEncryptedData ;
1575+ } else {
1576+ newCryptoInfo .numBytesOfClearData =
1577+ Arrays .copyOf (
1578+ mScratchSubsampleClearBytesCount , mSubsampleEncryptionDataSize );
1579+ newCryptoInfo .numBytesOfEncryptedData =
1580+ Arrays .copyOf (
1581+ mScratchSubsampleEncryptedBytesCount ,
1582+ mSubsampleEncryptionDataSize );
1583+ }
1584+ mLastOutputCryptoInfo = newCryptoInfo ;
15391585 }
1540- mCryptoInfo .key = cryptoData .encryptionKey ;
1541- // ExoPlayer modes match MediaCodec modes.
1542- mCryptoInfo .mode = cryptoData .cryptoMode ;
1543- if (cryptoData .clearBlocks != 0 ) {
1544- // Content is pattern-encrypted.
1545- mCryptoInfo .setPattern (mEncryptionPattern );
1546- mEncryptionPattern .set (cryptoData .encryptedBlocks , cryptoData .clearBlocks );
1547- } else {
1548- mCryptoInfo .setPattern (null );
1586+ mLastReceivedCryptoData = cryptoData ;
1587+ return mLastOutputCryptoInfo ;
1588+ }
1589+
1590+ private CryptoInfo createNewCryptoInfoAndPopulateWithCryptoData (CryptoData cryptoData ) {
1591+ CryptoInfo cryptoInfo = new CryptoInfo ();
1592+ cryptoInfo .key = cryptoData .encryptionKey ;
1593+ cryptoInfo .mode = cryptoData .cryptoMode ;
1594+ if (cryptoData .clearBlocks != mLastOutputEncryptionPattern .getSkipBlocks ()
1595+ || cryptoData .encryptedBlocks
1596+ != mLastOutputEncryptionPattern .getEncryptBlocks ()) {
1597+ mLastOutputEncryptionPattern =
1598+ new CryptoInfo .Pattern (cryptoData .encryptedBlocks , cryptoData .clearBlocks );
15491599 }
1550- return mCryptoInfo ;
1600+ cryptoInfo .setPattern (mLastOutputEncryptionPattern );
1601+ return cryptoInfo ;
15511602 }
15521603
15531604 private void outputSampleData (ParsableByteArray data , int length ) {
15541605 mScratchParsableByteArrayAdapter .resetWithByteArray (data , length );
15551606 try {
1556- mOutputConsumer .onSampleDataFound (mTrackIndex , mScratchParsableByteArrayAdapter );
1607+ // Read all bytes from data. ExoPlayer extractors expect all sample data to be
1608+ // consumed by TrackOutput implementations when passing a ParsableByteArray.
1609+ while (mScratchParsableByteArrayAdapter .getLength () > 0 ) {
1610+ mOutputConsumer .onSampleDataFound (
1611+ mTrackIndex , mScratchParsableByteArrayAdapter );
1612+ }
15571613 } catch (IOException e ) {
15581614 // Unexpected.
15591615 throw new RuntimeException (e );
0 commit comments