Commit 1f43fb19 by aquilescanta Committed by Oliver Woodman

Introduce CryptoData parameter object

This will allow supporting more encryption schemes. Including some
that require more encryption data, like the encryption pattern.

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

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=155481889
parent 0302fd6b
......@@ -30,5 +30,6 @@ track 1:
time = 0
flags = 1073741824
data = length 39, hash B7FE77F4
crypto mode = 1
encryption key = length 16, hash 4CE944CF
tracksEnded = true
......@@ -30,5 +30,6 @@ track 1:
time = 0
flags = 1073741824
data = length 24, hash E58668B1
crypto mode = 1
encryption key = length 16, hash 4CE944CF
tracksEnded = true
......@@ -83,12 +83,12 @@ public final class C {
public static final String UTF16_NAME = "UTF-16";
/**
* * The name of the serif font family.
* The name of the serif font family.
*/
public static final String SERIF_NAME = "serif";
/**
* * The name of the sans-serif font family.
* The name of the sans-serif font family.
*/
public static final String SANS_SERIF_NAME = "sans-serif";
......
......@@ -366,8 +366,9 @@ public final class DefaultTrackOutput implements TrackOutput {
}
// Populate the cryptoInfo.
CryptoData cryptoData = extrasHolder.cryptoData;
buffer.cryptoInfo.set(subsampleCount, clearDataSizes, encryptedDataSizes,
extrasHolder.encryptionKeyId, buffer.cryptoInfo.iv, C.CRYPTO_MODE_AES_CTR);
cryptoData.encryptionKey, buffer.cryptoInfo.iv, cryptoData.cryptoMode);
// Adjust the offset and size to take into account the bytes read.
int bytesRead = (int) (offset - extrasHolder.offset);
......@@ -516,7 +517,7 @@ public final class DefaultTrackOutput implements TrackOutput {
@Override
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
byte[] encryptionKey) {
CryptoData cryptoData) {
if (pendingFormatAdjustment) {
format(lastUnadjustedFormat);
}
......@@ -533,7 +534,7 @@ public final class DefaultTrackOutput implements TrackOutput {
}
timeUs += sampleOffsetUs;
long absoluteOffset = totalBytesWritten - size - offset;
infoQueue.commitSample(timeUs, flags, absoluteOffset, size, encryptionKey);
infoQueue.commitSample(timeUs, flags, absoluteOffset, size, cryptoData);
} finally {
endWriteOperation();
}
......@@ -606,7 +607,7 @@ public final class DefaultTrackOutput implements TrackOutput {
private int[] sizes;
private int[] flags;
private long[] timesUs;
private byte[][] encryptionKeys;
private CryptoData[] cryptoDatas;
private Format[] formats;
private int queueSize;
......@@ -628,7 +629,7 @@ public final class DefaultTrackOutput implements TrackOutput {
timesUs = new long[capacity];
flags = new int[capacity];
sizes = new int[capacity];
encryptionKeys = new byte[capacity][];
cryptoDatas = new CryptoData[capacity];
formats = new Format[capacity];
largestDequeuedTimestampUs = Long.MIN_VALUE;
largestQueuedTimestampUs = Long.MIN_VALUE;
......@@ -792,7 +793,7 @@ public final class DefaultTrackOutput implements TrackOutput {
buffer.setFlags(flags[relativeReadIndex]);
extrasHolder.size = sizes[relativeReadIndex];
extrasHolder.offset = offsets[relativeReadIndex];
extrasHolder.encryptionKeyId = encryptionKeys[relativeReadIndex];
extrasHolder.cryptoData = cryptoDatas[relativeReadIndex];
largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs);
queueSize--;
......@@ -892,7 +893,7 @@ public final class DefaultTrackOutput implements TrackOutput {
}
public synchronized void commitSample(long timeUs, @C.BufferFlags int sampleFlags, long offset,
int size, byte[] encryptionKey) {
int size, CryptoData cryptoData) {
if (upstreamKeyframeRequired) {
if ((sampleFlags & C.BUFFER_FLAG_KEY_FRAME) == 0) {
return;
......@@ -905,7 +906,7 @@ public final class DefaultTrackOutput implements TrackOutput {
offsets[relativeWriteIndex] = offset;
sizes[relativeWriteIndex] = size;
flags[relativeWriteIndex] = sampleFlags;
encryptionKeys[relativeWriteIndex] = encryptionKey;
cryptoDatas[relativeWriteIndex] = cryptoData;
formats[relativeWriteIndex] = upstreamFormat;
sourceIds[relativeWriteIndex] = upstreamSourceId;
// Increment the write index.
......@@ -918,14 +919,14 @@ public final class DefaultTrackOutput implements TrackOutput {
long[] newTimesUs = new long[newCapacity];
int[] newFlags = new int[newCapacity];
int[] newSizes = new int[newCapacity];
byte[][] newEncryptionKeys = new byte[newCapacity][];
CryptoData[] newCryptoDatas = new CryptoData[newCapacity];
Format[] newFormats = new Format[newCapacity];
int beforeWrap = capacity - relativeReadIndex;
System.arraycopy(offsets, relativeReadIndex, newOffsets, 0, beforeWrap);
System.arraycopy(timesUs, relativeReadIndex, newTimesUs, 0, beforeWrap);
System.arraycopy(flags, relativeReadIndex, newFlags, 0, beforeWrap);
System.arraycopy(sizes, relativeReadIndex, newSizes, 0, beforeWrap);
System.arraycopy(encryptionKeys, relativeReadIndex, newEncryptionKeys, 0, beforeWrap);
System.arraycopy(cryptoDatas, relativeReadIndex, newCryptoDatas, 0, beforeWrap);
System.arraycopy(formats, relativeReadIndex, newFormats, 0, beforeWrap);
System.arraycopy(sourceIds, relativeReadIndex, newSourceIds, 0, beforeWrap);
int afterWrap = relativeReadIndex;
......@@ -933,14 +934,14 @@ public final class DefaultTrackOutput implements TrackOutput {
System.arraycopy(timesUs, 0, newTimesUs, beforeWrap, afterWrap);
System.arraycopy(flags, 0, newFlags, beforeWrap, afterWrap);
System.arraycopy(sizes, 0, newSizes, beforeWrap, afterWrap);
System.arraycopy(encryptionKeys, 0, newEncryptionKeys, beforeWrap, afterWrap);
System.arraycopy(cryptoDatas, 0, newCryptoDatas, beforeWrap, afterWrap);
System.arraycopy(formats, 0, newFormats, beforeWrap, afterWrap);
System.arraycopy(sourceIds, 0, newSourceIds, beforeWrap, afterWrap);
offsets = newOffsets;
timesUs = newTimesUs;
flags = newFlags;
sizes = newSizes;
encryptionKeys = newEncryptionKeys;
cryptoDatas = newCryptoDatas;
formats = newFormats;
sourceIds = newSourceIds;
relativeReadIndex = 0;
......@@ -990,7 +991,7 @@ public final class DefaultTrackOutput implements TrackOutput {
public int size;
public long offset;
public long nextOffset;
public byte[] encryptionKeyId;
public CryptoData cryptoData;
}
......
......@@ -51,7 +51,7 @@ public final class DummyTrackOutput implements TrackOutput {
@Override
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
byte[] encryptionKey) {
CryptoData cryptoData) {
// Do nothing.
}
......
......@@ -20,6 +20,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.EOFException;
import java.io.IOException;
import java.util.Arrays;
/**
* Receives track level data extracted by an {@link Extractor}.
......@@ -27,6 +28,47 @@ import java.io.IOException;
public interface TrackOutput {
/**
* Holds data required to decrypt a sample.
*/
final class CryptoData {
/**
* The encryption mode used for the sample.
*/
@C.CryptoMode public final int cryptoMode;
/**
* The encryption key associated with the sample. Its contents must not be modified.
*/
public final byte[] encryptionKey;
public CryptoData(@C.CryptoMode int cryptoMode, byte[] encryptionKey) {
this.cryptoMode = cryptoMode;
this.encryptionKey = encryptionKey;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
CryptoData other = (CryptoData) obj;
return cryptoMode == other.cryptoMode && Arrays.equals(encryptionKey, other.encryptionKey);
}
@Override
public int hashCode() {
int result = cryptoMode;
result = 31 * result + Arrays.hashCode(encryptionKey);
return result;
}
}
/**
* Called when the {@link Format} of the track has been extracted from the stream.
*
* @param format The extracted {@link Format}.
......@@ -70,9 +112,9 @@ public interface TrackOutput {
* {@link #sampleData(ExtractorInput, int, boolean)} or
* {@link #sampleData(ParsableByteArray, int)} since the last byte belonging to the sample
* whose metadata is being passed.
* @param encryptionKey The encryption key associated with the sample. May be null.
* @param encryptionData The encryption data required to decrypt the sample. May be null.
*/
void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
byte[] encryptionKey);
CryptoData encryptionData);
}
......@@ -580,11 +580,11 @@ public final class MatroskaExtractor implements Extractor {
break;
case ID_CONTENT_ENCODING:
if (currentTrack.hasContentEncryption) {
if (currentTrack.encryptionKeyId == null) {
if (currentTrack.cryptoData == null) {
throw new ParserException("Encrypted Track found but ContentEncKeyID was not found");
}
currentTrack.drmInitData = new DrmInitData(
new SchemeData(C.UUID_NIL, MimeTypes.VIDEO_WEBM, currentTrack.encryptionKeyId));
currentTrack.drmInitData = new DrmInitData(new SchemeData(C.UUID_NIL,
MimeTypes.VIDEO_WEBM, currentTrack.cryptoData.encryptionKey));
}
break;
case ID_CONTENT_ENCODINGS:
......@@ -888,8 +888,9 @@ public final class MatroskaExtractor implements Extractor {
input.readFully(currentTrack.sampleStrippedBytes, 0, contentSize);
break;
case ID_CONTENT_ENCRYPTION_KEY_ID:
currentTrack.encryptionKeyId = new byte[contentSize];
input.readFully(currentTrack.encryptionKeyId, 0, contentSize);
byte[] encryptionKey = new byte[contentSize];
input.readFully(encryptionKey, 0, contentSize);
currentTrack.cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionKey);
break;
case ID_SIMPLE_BLOCK:
case ID_BLOCK:
......@@ -1033,7 +1034,7 @@ public final class MatroskaExtractor implements Extractor {
if (CODEC_ID_SUBRIP.equals(track.codecId)) {
writeSubripSample(track);
}
track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.encryptionKeyId);
track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.cryptoData);
sampleRead = true;
resetSample();
}
......@@ -1470,7 +1471,7 @@ public final class MatroskaExtractor implements Extractor {
public int defaultSampleDurationNs;
public boolean hasContentEncryption;
public byte[] sampleStrippedBytes;
public byte[] encryptionKeyId;
public TrackOutput.CryptoData cryptoData;
public byte[] codecPrivate;
public DrmInitData drmInitData;
......
......@@ -1122,19 +1122,30 @@ public final class FragmentedMp4Extractor implements Extractor {
}
long sampleTimeUs = fragment.getSamplePresentationTime(sampleIndex) * 1000L;
if (timestampAdjuster != null) {
sampleTimeUs = timestampAdjuster.adjustSampleTimestamp(sampleTimeUs);
}
@C.BufferFlags int sampleFlags = (fragment.definesEncryptionData ? C.BUFFER_FLAG_ENCRYPTED : 0)
| (fragment.sampleIsSyncFrameTable[sampleIndex] ? C.BUFFER_FLAG_KEY_FRAME : 0);
int sampleDescriptionIndex = fragment.header.sampleDescriptionIndex;
byte[] encryptionKey = null;
// Encryption data.
TrackOutput.CryptoData cryptoData = null;
TrackEncryptionBox encryptionBox = null;
if (fragment.definesEncryptionData) {
encryptionKey = fragment.trackEncryptionBox != null
? fragment.trackEncryptionBox.keyId
: track.sampleDescriptionEncryptionBoxes[sampleDescriptionIndex].keyId;
}
if (timestampAdjuster != null) {
sampleTimeUs = timestampAdjuster.adjustSampleTimestamp(sampleTimeUs);
encryptionBox = fragment.trackEncryptionBox != null
? fragment.trackEncryptionBox
: track.sampleDescriptionEncryptionBoxes[fragment.header.sampleDescriptionIndex];
if (encryptionBox != currentTrackBundle.cachedEncryptionBox) {
cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionBox.keyId);
} else {
cryptoData = currentTrackBundle.cachedCryptoData;
}
}
output.sampleMetadata(sampleTimeUs, sampleFlags, sampleSize, 0, encryptionKey);
currentTrackBundle.cachedCryptoData = cryptoData;
currentTrackBundle.cachedEncryptionBox = encryptionBox;
output.sampleMetadata(sampleTimeUs, sampleFlags, sampleSize, 0, cryptoData);
while (!pendingMetadataSampleInfos.isEmpty()) {
MetadataSampleInfo sampleInfo = pendingMetadataSampleInfos.removeFirst();
......@@ -1288,6 +1299,10 @@ public final class FragmentedMp4Extractor implements Extractor {
public int currentSampleInTrackRun;
public int currentTrackRunIndex;
// Auxiliary references.
public TrackOutput.CryptoData cachedCryptoData;
public TrackEncryptionBox cachedEncryptionBox;
public TrackBundle(TrackOutput output) {
fragment = new TrackFragment();
this.output = output;
......@@ -1305,6 +1320,8 @@ public final class FragmentedMp4Extractor implements Extractor {
currentSampleIndex = 0;
currentTrackRunIndex = 0;
currentSampleInTrackRun = 0;
cachedCryptoData = null;
cachedEncryptionBox = null;
}
public void updateDrmInitData(DrmInitData drmInitData) {
......
......@@ -186,8 +186,8 @@ public final class ChunkExtractorWrapper implements ExtractorOutput {
@Override
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
byte[] encryptionKey) {
trackOutput.sampleMetadata(timeUs, flags, size, offset, encryptionKey);
CryptoData cryptoData) {
trackOutput.sampleMetadata(timeUs, flags, size, offset, cryptoData);
}
}
......
......@@ -36,7 +36,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
private final ArrayList<Integer> sampleFlags;
private final ArrayList<Integer> sampleStartOffsets;
private final ArrayList<Integer> sampleEndOffsets;
private final ArrayList<byte[]> sampleEncryptionKeys;
private final ArrayList<CryptoData> cryptoDatas;
private byte[] sampleData;
public Format format;
......@@ -47,7 +47,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
sampleFlags = new ArrayList<>();
sampleStartOffsets = new ArrayList<>();
sampleEndOffsets = new ArrayList<>();
sampleEncryptionKeys = new ArrayList<>();
cryptoDatas = new ArrayList<>();
}
public void clear() {
......@@ -56,7 +56,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
sampleFlags.clear();
sampleStartOffsets.clear();
sampleEndOffsets.clear();
sampleEncryptionKeys.clear();
cryptoDatas.clear();
}
@Override
......@@ -89,29 +89,24 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
@Override
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
byte[] encryptionKey) {
CryptoData cryptoData) {
sampleTimesUs.add(timeUs);
sampleFlags.add(flags);
sampleStartOffsets.add(sampleData.length - offset - size);
sampleEndOffsets.add(sampleData.length - offset);
sampleEncryptionKeys.add(encryptionKey);
cryptoDatas.add(cryptoData);
}
public void assertSampleCount(int count) {
Assert.assertEquals(count, sampleTimesUs.size());
}
public void assertSample(int index, byte[] data, long timeUs, int flags, byte[] encryptionKey) {
public void assertSample(int index, byte[] data, long timeUs, int flags, CryptoData cryptoData) {
byte[] actualData = getSampleData(index);
MoreAsserts.assertEquals(data, actualData);
Assert.assertEquals(timeUs, (long) sampleTimesUs.get(index));
Assert.assertEquals(flags, (int) sampleFlags.get(index));
byte[] sampleEncryptionKey = sampleEncryptionKeys.get(index);
if (encryptionKey == null) {
Assert.assertEquals(null, sampleEncryptionKey);
} else {
MoreAsserts.assertEquals(encryptionKey, sampleEncryptionKey);
}
Assert.assertEquals(cryptoData, cryptoDatas.get(index));
}
public byte[] getSampleData(int index) {
......@@ -128,10 +123,10 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
Assert.assertEquals(expected.sampleFlags.get(i), sampleFlags.get(i));
Assert.assertEquals(expected.sampleStartOffsets.get(i), sampleStartOffsets.get(i));
Assert.assertEquals(expected.sampleEndOffsets.get(i), sampleEndOffsets.get(i));
if (expected.sampleEncryptionKeys.get(i) == null) {
Assert.assertNull(sampleEncryptionKeys.get(i));
if (expected.cryptoDatas.get(i) == null) {
Assert.assertNull(cryptoDatas.get(i));
} else {
MoreAsserts.assertEquals(expected.sampleEncryptionKeys.get(i), sampleEncryptionKeys.get(i));
Assert.assertEquals(expected.cryptoDatas.get(i), cryptoDatas.get(i));
}
}
}
......@@ -172,9 +167,10 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
.add("time", sampleTimesUs.get(i))
.add("flags", sampleFlags.get(i))
.add("data", getSampleData(i));
byte[] key = sampleEncryptionKeys.get(i);
if (key != null) {
dumper.add("encryption key", key);
CryptoData cryptoData = cryptoDatas.get(i);
if (cryptoData != null) {
dumper.add("crypto mode", cryptoData.cryptoMode);
dumper.add("encryption key", cryptoData.encryptionKey);
}
dumper.endBlock();
}
......
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