mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Update AC-4 DRM code based on comments
Update cleardatasize[0] in extractor rather than sampleDataQueue.
This commit is contained in:
parent
0ea49df901
commit
4ce72d9d6d
3 changed files with 70 additions and 25 deletions
|
|
@ -1265,10 +1265,17 @@ public class FragmentedMp4Extractor implements Extractor {
|
||||||
sampleSize -= Atom.HEADER_SIZE;
|
sampleSize -= Atom.HEADER_SIZE;
|
||||||
input.skipFully(Atom.HEADER_SIZE);
|
input.skipFully(Atom.HEADER_SIZE);
|
||||||
}
|
}
|
||||||
sampleBytesWritten = currentTrackBundle.outputSampleEncryptionData();
|
|
||||||
sampleSize += sampleBytesWritten;
|
boolean isAc4HeaderRequired =
|
||||||
if (MimeTypes.AUDIO_AC4.equals(currentTrackBundle.track.format.sampleMimeType)) {
|
MimeTypes.AUDIO_AC4.equals(currentTrackBundle.track.format.sampleMimeType);
|
||||||
Ac4Util.getAc4SampleHeader(sampleSize, scratch);
|
|
||||||
|
int encryptionDataBytesWritten = currentTrackBundle.outputSampleEncryptionData(
|
||||||
|
sampleSize, isAc4HeaderRequired ? Ac4Util.SAMPLE_HEADER_SIZE : 0);
|
||||||
|
sampleBytesWritten = encryptionDataBytesWritten;
|
||||||
|
sampleSize += encryptionDataBytesWritten;
|
||||||
|
|
||||||
|
if (isAc4HeaderRequired) {
|
||||||
|
Ac4Util.getAc4SampleHeader(sampleSize - encryptionDataBytesWritten, scratch);
|
||||||
currentTrackBundle.output.sampleData(scratch, Ac4Util.SAMPLE_HEADER_SIZE);
|
currentTrackBundle.output.sampleData(scratch, Ac4Util.SAMPLE_HEADER_SIZE);
|
||||||
sampleBytesWritten += Ac4Util.SAMPLE_HEADER_SIZE;
|
sampleBytesWritten += Ac4Util.SAMPLE_HEADER_SIZE;
|
||||||
sampleSize += Ac4Util.SAMPLE_HEADER_SIZE;
|
sampleSize += Ac4Util.SAMPLE_HEADER_SIZE;
|
||||||
|
|
@ -1555,9 +1562,13 @@ public class FragmentedMp4Extractor implements Extractor {
|
||||||
/**
|
/**
|
||||||
* Outputs the encryption data for the current sample.
|
* Outputs the encryption data for the current sample.
|
||||||
*
|
*
|
||||||
|
* @param sampleSize The size of the current sample in bytes, excluding any additional clear
|
||||||
|
* header that will be prefixed to the sample by the extractor.
|
||||||
|
* @param clearHeaderSize The size of a clear header that will be prefixed to the sample by the
|
||||||
|
* extractor, or 0.
|
||||||
* @return The number of written bytes.
|
* @return The number of written bytes.
|
||||||
*/
|
*/
|
||||||
public int outputSampleEncryptionData() {
|
public int outputSampleEncryptionData(int sampleSize, int clearHeaderSize) {
|
||||||
TrackEncryptionBox encryptionBox = getEncryptionBoxIfEncrypted();
|
TrackEncryptionBox encryptionBox = getEncryptionBoxIfEncrypted();
|
||||||
if (encryptionBox == null) {
|
if (encryptionBox == null) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1576,24 +1587,66 @@ public class FragmentedMp4Extractor implements Extractor {
|
||||||
vectorSize = initVectorData.length;
|
vectorSize = initVectorData.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean subsampleEncryption = fragment.sampleHasSubsampleEncryptionTable(currentSampleIndex);
|
boolean haveSubsampleEncryptionTable =
|
||||||
|
fragment.sampleHasSubsampleEncryptionTable(currentSampleIndex);
|
||||||
|
boolean writeSubsampleEncryptionData =
|
||||||
|
haveSubsampleEncryptionTable | clearHeaderSize != 0;
|
||||||
|
|
||||||
// Write the signal byte, containing the vector size and the subsample encryption flag.
|
// Write the signal byte, containing the vector size and the subsample encryption flag.
|
||||||
encryptionSignalByte.data[0] = (byte) (vectorSize | (subsampleEncryption ? 0x80 : 0));
|
encryptionSignalByte.data[0] =
|
||||||
|
(byte) (vectorSize | (writeSubsampleEncryptionData ? 0x80 : 0));
|
||||||
encryptionSignalByte.setPosition(0);
|
encryptionSignalByte.setPosition(0);
|
||||||
output.sampleData(encryptionSignalByte, 1);
|
output.sampleData(encryptionSignalByte, 1);
|
||||||
// Write the vector.
|
// Write the vector.
|
||||||
output.sampleData(initializationVectorData, vectorSize);
|
output.sampleData(initializationVectorData, vectorSize);
|
||||||
// If we don't have subsample encryption data, we're done.
|
|
||||||
if (!subsampleEncryption) {
|
if (!writeSubsampleEncryptionData) {
|
||||||
return 1 + vectorSize;
|
return 1 + vectorSize;
|
||||||
}
|
}
|
||||||
// Write the subsample encryption data.
|
|
||||||
|
if (!haveSubsampleEncryptionTable) {
|
||||||
|
// Need to synthesize subsample encryption data. The sample is fully encrypted except
|
||||||
|
// for the additional header that the extractor is going to prefix, so we need to write the
|
||||||
|
// following to output.sampleData:
|
||||||
|
// subsampleCount (unsigned short) = 1
|
||||||
|
// clearDataSizes[0] (unsigned short) = clearHeaderSize
|
||||||
|
// encryptedDataSizes[0] (unsigned int) = sampleSize
|
||||||
|
ParsableByteArray encryptionData = new ParsableByteArray(8);
|
||||||
|
encryptionData.data[0] = (byte)0;
|
||||||
|
encryptionData.data[1] = (byte)1;
|
||||||
|
encryptionData.data[2] = (byte)((clearHeaderSize & 0xFF00) >>> 8);
|
||||||
|
encryptionData.data[3] = (byte)( clearHeaderSize & 0x00FF);
|
||||||
|
encryptionData.data[4] = (byte)((sampleSize & 0xFF000000) >>> 24);
|
||||||
|
encryptionData.data[5] = (byte)((sampleSize & 0x00FF0000) >>> 16);
|
||||||
|
encryptionData.data[6] = (byte)((sampleSize & 0x0000FF00) >>> 8);
|
||||||
|
encryptionData.data[7] = (byte)( sampleSize & 0x000000FF);
|
||||||
|
encryptionData.setPosition(0);
|
||||||
|
output.sampleData(encryptionData, 8);
|
||||||
|
return 1 + vectorSize + 8;
|
||||||
|
}
|
||||||
|
|
||||||
ParsableByteArray subsampleEncryptionData = fragment.sampleEncryptionData;
|
ParsableByteArray subsampleEncryptionData = fragment.sampleEncryptionData;
|
||||||
int subsampleCount = subsampleEncryptionData.readUnsignedShort();
|
int subsampleCount = subsampleEncryptionData.readUnsignedShort();
|
||||||
subsampleEncryptionData.skipBytes(-2);
|
subsampleEncryptionData.skipBytes(-2);
|
||||||
int subsampleDataLength = 2 + 6 * subsampleCount;
|
int subsampleDataLength = 2 + 6 * subsampleCount;
|
||||||
output.sampleData(subsampleEncryptionData, subsampleDataLength);
|
|
||||||
|
if (clearHeaderSize > 0) {
|
||||||
|
// On the way through, we need to re-write the 3rd and 4th bytes, which hold
|
||||||
|
// clearDataSizes[0], so that clearHeaderSize is added into the value. This must be done
|
||||||
|
// without modifying subsampleEncryptionData itself.
|
||||||
|
ParsableByteArray subsampleEncryptionData2 = new ParsableByteArray(subsampleDataLength);
|
||||||
|
subsampleEncryptionData2.readBytes(subsampleEncryptionData.data,
|
||||||
|
subsampleEncryptionData.getPosition(), subsampleDataLength);
|
||||||
|
int clearDataSize = (subsampleEncryptionData2.data[2] & 0xFF) << 8
|
||||||
|
| (subsampleEncryptionData2.data[3] & 0xFF) + clearHeaderSize;
|
||||||
|
subsampleEncryptionData2.data[2] = (byte)((clearDataSize & 0xFF00) >>> 8);
|
||||||
|
subsampleEncryptionData2.data[3] = (byte)( clearDataSize & 0x00FF);
|
||||||
|
subsampleEncryptionData2.setPosition(0);
|
||||||
|
output.sampleData(subsampleEncryptionData2, subsampleDataLength);
|
||||||
|
subsampleEncryptionData.skipBytes(subsampleDataLength);
|
||||||
|
} else {
|
||||||
|
output.sampleData(subsampleEncryptionData, subsampleDataLength);
|
||||||
|
}
|
||||||
return 1 + vectorSize + subsampleDataLength;
|
return 1 + vectorSize + subsampleDataLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import com.google.android.exoplayer2.extractor.TrackOutput.CryptoData;
|
||||||
import com.google.android.exoplayer2.source.SampleQueue.SampleExtrasHolder;
|
import com.google.android.exoplayer2.source.SampleQueue.SampleExtrasHolder;
|
||||||
import com.google.android.exoplayer2.upstream.Allocation;
|
import com.google.android.exoplayer2.upstream.Allocation;
|
||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -115,13 +114,11 @@ import java.nio.ByteBuffer;
|
||||||
*
|
*
|
||||||
* @param buffer The buffer to populate.
|
* @param buffer The buffer to populate.
|
||||||
* @param extrasHolder The extras holder whose offset should be read and subsequently adjusted.
|
* @param extrasHolder The extras holder whose offset should be read and subsequently adjusted.
|
||||||
* @param mimeType The MIME type.
|
|
||||||
*/
|
*/
|
||||||
public void readToBuffer(DecoderInputBuffer buffer, SampleExtrasHolder extrasHolder,
|
public void readToBuffer(DecoderInputBuffer buffer, SampleExtrasHolder extrasHolder) {
|
||||||
String mimeType) {
|
|
||||||
// Read encryption data if the sample is encrypted.
|
// Read encryption data if the sample is encrypted.
|
||||||
if (buffer.isEncrypted()) {
|
if (buffer.isEncrypted()) {
|
||||||
readEncryptionData(buffer, extrasHolder, mimeType);
|
readEncryptionData(buffer, extrasHolder);
|
||||||
}
|
}
|
||||||
// Read sample data, extracting supplemental data into a separate buffer if needed.
|
// Read sample data, extracting supplemental data into a separate buffer if needed.
|
||||||
if (buffer.hasSupplementalData()) {
|
if (buffer.hasSupplementalData()) {
|
||||||
|
|
@ -218,10 +215,8 @@ import java.nio.ByteBuffer;
|
||||||
*
|
*
|
||||||
* @param buffer The buffer into which the encryption data should be written.
|
* @param buffer The buffer into which the encryption data should be written.
|
||||||
* @param extrasHolder The extras holder whose offset should be read and subsequently adjusted.
|
* @param extrasHolder The extras holder whose offset should be read and subsequently adjusted.
|
||||||
* @param mimeType The MIME type.
|
|
||||||
*/
|
*/
|
||||||
private void readEncryptionData(DecoderInputBuffer buffer, SampleExtrasHolder extrasHolder,
|
private void readEncryptionData(DecoderInputBuffer buffer, SampleExtrasHolder extrasHolder) {
|
||||||
String mimeType) {
|
|
||||||
long offset = extrasHolder.offset;
|
long offset = extrasHolder.offset;
|
||||||
|
|
||||||
// Read the signal byte.
|
// Read the signal byte.
|
||||||
|
|
@ -270,10 +265,8 @@ import java.nio.ByteBuffer;
|
||||||
encryptedDataSizes[i] = scratch.readUnsignedIntToInt();
|
encryptedDataSizes[i] = scratch.readUnsignedIntToInt();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int addedHeaderSize = MimeTypes.AUDIO_AC4.equals(mimeType) ? 7 : 0;
|
clearDataSizes[0] = 0;
|
||||||
clearDataSizes[0] = addedHeaderSize;
|
encryptedDataSizes[0] = extrasHolder.size - (int) (offset - extrasHolder.offset);
|
||||||
encryptedDataSizes[0] = extrasHolder.size - (int) (offset - extrasHolder.offset)
|
|
||||||
- addedHeaderSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the cryptoInfo.
|
// Populate the cryptoInfo.
|
||||||
|
|
|
||||||
|
|
@ -323,8 +323,7 @@ public class SampleQueue implements TrackOutput {
|
||||||
readSampleMetadata(
|
readSampleMetadata(
|
||||||
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilUs, extrasHolder);
|
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilUs, extrasHolder);
|
||||||
if (result == C.RESULT_BUFFER_READ && !buffer.isEndOfStream() && !buffer.isFlagsOnly()) {
|
if (result == C.RESULT_BUFFER_READ && !buffer.isEndOfStream() && !buffer.isFlagsOnly()) {
|
||||||
sampleDataQueue.readToBuffer(buffer, extrasHolder,
|
sampleDataQueue.readToBuffer(buffer, extrasHolder);
|
||||||
downstreamFormat == null ? null : downstreamFormat.sampleMimeType);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue