mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Separate encryption data into a new TrackOutput method
Allows media parser to populate crypto data. PiperOrigin-RevId: 307616083
This commit is contained in:
parent
1ab5923f27
commit
7839955f31
9 changed files with 104 additions and 23 deletions
|
|
@ -477,13 +477,15 @@ public class SampleQueue implements TrackOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int sampleData(DataReader input, int length, boolean allowEndOfInput)
|
public final int sampleData(
|
||||||
|
DataReader input, int length, boolean allowEndOfInput, @SampleDataPart int sampleDataPart)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return sampleDataQueue.sampleData(input, length, allowEndOfInput);
|
return sampleDataQueue.sampleData(input, length, allowEndOfInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void sampleData(ParsableByteArray buffer, int length) {
|
public final void sampleData(
|
||||||
|
ParsableByteArray buffer, int length, @SampleDataPart int sampleDataPart) {
|
||||||
sampleDataQueue.sampleData(buffer, length);
|
sampleDataQueue.sampleData(buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,13 +203,14 @@ public final class ChunkExtractorWrapper implements ExtractorOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int sampleData(DataReader input, int length, boolean allowEndOfInput)
|
public int sampleData(
|
||||||
|
DataReader input, int length, boolean allowEndOfInput, @SampleDataPart int sampleDataPart)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return castNonNull(trackOutput).sampleData(input, length, allowEndOfInput);
|
return castNonNull(trackOutput).sampleData(input, length, allowEndOfInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sampleData(ParsableByteArray data, int length) {
|
public void sampleData(ParsableByteArray data, int length, @SampleDataPart int sampleDataPart) {
|
||||||
castNonNull(trackOutput).sampleData(data, length);
|
castNonNull(trackOutput).sampleData(data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -300,13 +300,14 @@ public final class PlayerEmsgHandler implements Handler.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int sampleData(DataReader input, int length, boolean allowEndOfInput)
|
public int sampleData(
|
||||||
|
DataReader input, int length, boolean allowEndOfInput, @SampleDataPart int sampleDataPart)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return sampleQueue.sampleData(input, length, allowEndOfInput);
|
return sampleQueue.sampleData(input, length, allowEndOfInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sampleData(ParsableByteArray data, int length) {
|
public void sampleData(ParsableByteArray data, int length, @SampleDataPart int sampleDataPart) {
|
||||||
sampleQueue.sampleData(data, length);
|
sampleQueue.sampleData(data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,9 @@ public final class DummyTrackOutput implements TrackOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int sampleData(DataReader input, int length, boolean allowEndOfInput) throws IOException {
|
public int sampleData(
|
||||||
|
DataReader input, int length, boolean allowEndOfInput, @SampleDataPart int sampleDataPart)
|
||||||
|
throws IOException {
|
||||||
int bytesToSkipByReading = Math.min(readBuffer.length, length);
|
int bytesToSkipByReading = Math.min(readBuffer.length, length);
|
||||||
int bytesSkipped = input.read(readBuffer, /* offset= */ 0, bytesToSkipByReading);
|
int bytesSkipped = input.read(readBuffer, /* offset= */ 0, bytesToSkipByReading);
|
||||||
if (bytesSkipped == C.RESULT_END_OF_INPUT) {
|
if (bytesSkipped == C.RESULT_END_OF_INPUT) {
|
||||||
|
|
@ -56,7 +58,7 @@ public final class DummyTrackOutput implements TrackOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sampleData(ParsableByteArray data, int length) {
|
public void sampleData(ParsableByteArray data, int length, @SampleDataPart int sampleDataPart) {
|
||||||
data.skipBytes(length);
|
data.skipBytes(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.extractor;
|
package com.google.android.exoplayer2.extractor;
|
||||||
|
|
||||||
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
|
|
@ -22,6 +23,9 @@ import com.google.android.exoplayer2.upstream.DataReader;
|
||||||
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;
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -94,6 +98,41 @@ public interface TrackOutput {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Defines the part of the sample data to which a call to {@link #sampleData} corresponds. */
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({SAMPLE_DATA_PART_MAIN, SAMPLE_DATA_PART_ENCRYPTION, SAMPLE_DATA_PART_SUPPLEMENTAL})
|
||||||
|
@interface SampleDataPart {}
|
||||||
|
|
||||||
|
/** Main media sample data. */
|
||||||
|
int SAMPLE_DATA_PART_MAIN = 0;
|
||||||
|
/**
|
||||||
|
* Sample encryption data.
|
||||||
|
*
|
||||||
|
* <p>The format for encryption information is:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>(1 byte) {@code encryption_signal_byte}: Most significant bit signals whether the
|
||||||
|
* encryption data contains subsample encryption data. The remaining bits contain {@code
|
||||||
|
* initialization_vector_size}.
|
||||||
|
* <li>({@code initialization_vector_size} bytes) Initialization vector.
|
||||||
|
* <li>If subsample encryption data is present, as per {@code encryption_signal_byte}, the
|
||||||
|
* encryption data also contains:
|
||||||
|
* <ul>
|
||||||
|
* <li>(2 bytes) {@code subsample_encryption_data_length}.
|
||||||
|
* <li>({@code subsample_encryption_data_length} bytes) Subsample encryption data
|
||||||
|
* (repeated {@code subsample_encryption_data_length / 6} times:
|
||||||
|
* <ul>
|
||||||
|
* <li>(3 bytes) Size of a clear section in sample.
|
||||||
|
* <li>(3 bytes) Size of an encryption section in sample.
|
||||||
|
* </ul>
|
||||||
|
* </ul>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
int SAMPLE_DATA_PART_ENCRYPTION = 1;
|
||||||
|
/** Sample supplemental data. */
|
||||||
|
int SAMPLE_DATA_PART_SUPPLEMENTAL = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the {@link Format} of the track has been extracted from the stream.
|
* Called when the {@link Format} of the track has been extracted from the stream.
|
||||||
*
|
*
|
||||||
|
|
@ -101,6 +140,22 @@ public interface TrackOutput {
|
||||||
*/
|
*/
|
||||||
void format(Format format);
|
void format(Format format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to {@link #sampleData(DataReader, int, boolean, int) sampleData(input, length,
|
||||||
|
* allowEndOfInput, SAMPLE_DATA_PART_MAIN)}.
|
||||||
|
*/
|
||||||
|
default int sampleData(DataReader input, int length, boolean allowEndOfInput) throws IOException {
|
||||||
|
return sampleData(input, length, allowEndOfInput, SAMPLE_DATA_PART_MAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to {@link #sampleData(ParsableByteArray, int, int)} sampleData(data, length,
|
||||||
|
* SAMPLE_DATA_PART_MAIN)}.
|
||||||
|
*/
|
||||||
|
default void sampleData(ParsableByteArray data, int length) {
|
||||||
|
sampleData(data, length, SAMPLE_DATA_PART_MAIN);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to write sample data to the output.
|
* Called to write sample data to the output.
|
||||||
*
|
*
|
||||||
|
|
@ -109,18 +164,22 @@ public interface TrackOutput {
|
||||||
* @param allowEndOfInput True if encountering the end of the input having read no data is
|
* @param allowEndOfInput True if encountering the end of the input having read no data is
|
||||||
* allowed, and should result in {@link C#RESULT_END_OF_INPUT} being returned. False if it
|
* allowed, and should result in {@link C#RESULT_END_OF_INPUT} being returned. False if it
|
||||||
* should be considered an error, causing an {@link EOFException} to be thrown.
|
* should be considered an error, causing an {@link EOFException} to be thrown.
|
||||||
|
* @param sampleDataPart The part of the sample data to which this call corresponds.
|
||||||
* @return The number of bytes appended.
|
* @return The number of bytes appended.
|
||||||
* @throws IOException If an error occurred reading from the input.
|
* @throws IOException If an error occurred reading from the input.
|
||||||
*/
|
*/
|
||||||
int sampleData(DataReader input, int length, boolean allowEndOfInput) throws IOException;
|
int sampleData(
|
||||||
|
DataReader input, int length, boolean allowEndOfInput, @SampleDataPart int sampleDataPart)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to write sample data to the output.
|
* Called to write sample data to the output.
|
||||||
*
|
*
|
||||||
* @param data A {@link ParsableByteArray} from which to read the sample data.
|
* @param data A {@link ParsableByteArray} from which to read the sample data.
|
||||||
* @param length The number of bytes to read, starting from {@code data.getPosition()}.
|
* @param length The number of bytes to read, starting from {@code data.getPosition()}.
|
||||||
|
* @param sampleDataPart The part of the sample data to which this call corresponds.
|
||||||
*/
|
*/
|
||||||
void sampleData(ParsableByteArray data, int length);
|
void sampleData(ParsableByteArray data, int length, @SampleDataPart int sampleDataPart);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when metadata associated with a sample has been extracted from the stream.
|
* Called when metadata associated with a sample has been extracted from the stream.
|
||||||
|
|
|
||||||
|
|
@ -1281,7 +1281,8 @@ public class MatroskaExtractor implements Extractor {
|
||||||
} else {
|
} else {
|
||||||
// Append supplemental data.
|
// Append supplemental data.
|
||||||
int blockAdditionalSize = blockAdditionalData.limit();
|
int blockAdditionalSize = blockAdditionalData.limit();
|
||||||
track.output.sampleData(blockAdditionalData, blockAdditionalSize);
|
track.output.sampleData(
|
||||||
|
blockAdditionalData, blockAdditionalSize, TrackOutput.SAMPLE_DATA_PART_SUPPLEMENTAL);
|
||||||
size += blockAdditionalSize;
|
size += blockAdditionalSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1350,11 +1351,14 @@ public class MatroskaExtractor implements Extractor {
|
||||||
// Write the signal byte, containing the IV size and the subsample encryption flag.
|
// Write the signal byte, containing the IV size and the subsample encryption flag.
|
||||||
scratch.data[0] = (byte) (ENCRYPTION_IV_SIZE | (hasSubsampleEncryption ? 0x80 : 0x00));
|
scratch.data[0] = (byte) (ENCRYPTION_IV_SIZE | (hasSubsampleEncryption ? 0x80 : 0x00));
|
||||||
scratch.setPosition(0);
|
scratch.setPosition(0);
|
||||||
output.sampleData(scratch, 1);
|
output.sampleData(scratch, 1, TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
|
||||||
sampleBytesWritten++;
|
sampleBytesWritten++;
|
||||||
// Write the IV.
|
// Write the IV.
|
||||||
encryptionInitializationVector.setPosition(0);
|
encryptionInitializationVector.setPosition(0);
|
||||||
output.sampleData(encryptionInitializationVector, ENCRYPTION_IV_SIZE);
|
output.sampleData(
|
||||||
|
encryptionInitializationVector,
|
||||||
|
ENCRYPTION_IV_SIZE,
|
||||||
|
TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
|
||||||
sampleBytesWritten += ENCRYPTION_IV_SIZE;
|
sampleBytesWritten += ENCRYPTION_IV_SIZE;
|
||||||
}
|
}
|
||||||
if (hasSubsampleEncryption) {
|
if (hasSubsampleEncryption) {
|
||||||
|
|
@ -1402,7 +1406,10 @@ public class MatroskaExtractor implements Extractor {
|
||||||
encryptionSubsampleDataBuffer.putInt(0);
|
encryptionSubsampleDataBuffer.putInt(0);
|
||||||
}
|
}
|
||||||
encryptionSubsampleData.reset(encryptionSubsampleDataBuffer.array(), subsampleDataSize);
|
encryptionSubsampleData.reset(encryptionSubsampleDataBuffer.array(), subsampleDataSize);
|
||||||
output.sampleData(encryptionSubsampleData, subsampleDataSize);
|
output.sampleData(
|
||||||
|
encryptionSubsampleData,
|
||||||
|
subsampleDataSize,
|
||||||
|
TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
|
||||||
sampleBytesWritten += subsampleDataSize;
|
sampleBytesWritten += subsampleDataSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1421,7 +1428,7 @@ public class MatroskaExtractor implements Extractor {
|
||||||
scratch.data[1] = (byte) ((size >> 16) & 0xFF);
|
scratch.data[1] = (byte) ((size >> 16) & 0xFF);
|
||||||
scratch.data[2] = (byte) ((size >> 8) & 0xFF);
|
scratch.data[2] = (byte) ((size >> 8) & 0xFF);
|
||||||
scratch.data[3] = (byte) (size & 0xFF);
|
scratch.data[3] = (byte) (size & 0xFF);
|
||||||
output.sampleData(scratch, 4);
|
output.sampleData(scratch, 4, TrackOutput.SAMPLE_DATA_PART_SUPPLEMENTAL);
|
||||||
sampleBytesWritten += 4;
|
sampleBytesWritten += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1611,9 +1611,10 @@ public class FragmentedMp4Extractor implements Extractor {
|
||||||
encryptionSignalByte.data[0] =
|
encryptionSignalByte.data[0] =
|
||||||
(byte) (vectorSize | (writeSubsampleEncryptionData ? 0x80 : 0));
|
(byte) (vectorSize | (writeSubsampleEncryptionData ? 0x80 : 0));
|
||||||
encryptionSignalByte.setPosition(0);
|
encryptionSignalByte.setPosition(0);
|
||||||
output.sampleData(encryptionSignalByte, 1);
|
output.sampleData(encryptionSignalByte, 1, TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
|
||||||
// Write the vector.
|
// Write the vector.
|
||||||
output.sampleData(initializationVectorData, vectorSize);
|
output.sampleData(
|
||||||
|
initializationVectorData, vectorSize, TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
|
||||||
|
|
||||||
if (!writeSubsampleEncryptionData) {
|
if (!writeSubsampleEncryptionData) {
|
||||||
return 1 + vectorSize;
|
return 1 + vectorSize;
|
||||||
|
|
@ -1635,7 +1636,10 @@ public class FragmentedMp4Extractor implements Extractor {
|
||||||
scratch.data[5] = (byte) ((sampleSize >> 16) & 0xFF);
|
scratch.data[5] = (byte) ((sampleSize >> 16) & 0xFF);
|
||||||
scratch.data[6] = (byte) ((sampleSize >> 8) & 0xFF);
|
scratch.data[6] = (byte) ((sampleSize >> 8) & 0xFF);
|
||||||
scratch.data[7] = (byte) (sampleSize & 0xFF);
|
scratch.data[7] = (byte) (sampleSize & 0xFF);
|
||||||
output.sampleData(scratch, SINGLE_SUBSAMPLE_ENCRYPTION_DATA_LENGTH);
|
output.sampleData(
|
||||||
|
scratch,
|
||||||
|
SINGLE_SUBSAMPLE_ENCRYPTION_DATA_LENGTH,
|
||||||
|
TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
|
||||||
return 1 + vectorSize + SINGLE_SUBSAMPLE_ENCRYPTION_DATA_LENGTH;
|
return 1 + vectorSize + SINGLE_SUBSAMPLE_ENCRYPTION_DATA_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1658,7 +1662,8 @@ public class FragmentedMp4Extractor implements Extractor {
|
||||||
subsampleEncryptionData = scratch;
|
subsampleEncryptionData = scratch;
|
||||||
}
|
}
|
||||||
|
|
||||||
output.sampleData(subsampleEncryptionData, subsampleDataLength);
|
output.sampleData(
|
||||||
|
subsampleEncryptionData, subsampleDataLength, TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
|
||||||
return 1 + vectorSize + subsampleDataLength;
|
return 1 + vectorSize + subsampleDataLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1521,7 +1521,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int sampleData(DataReader input, int length, boolean allowEndOfInput)
|
public int sampleData(
|
||||||
|
DataReader input, int length, boolean allowEndOfInput, @SampleDataPart int sampleDataPart)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
ensureBufferCapacity(bufferPosition + length);
|
ensureBufferCapacity(bufferPosition + length);
|
||||||
int numBytesRead = input.read(buffer, bufferPosition, length);
|
int numBytesRead = input.read(buffer, bufferPosition, length);
|
||||||
|
|
@ -1537,7 +1538,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sampleData(ParsableByteArray buffer, int length) {
|
public void sampleData(
|
||||||
|
ParsableByteArray buffer, int length, @SampleDataPart int sampleDataPart) {
|
||||||
ensureBufferCapacity(bufferPosition + length);
|
ensureBufferCapacity(bufferPosition + length);
|
||||||
buffer.readBytes(this.buffer, bufferPosition, length);
|
buffer.readBytes(this.buffer, bufferPosition, length);
|
||||||
bufferPosition += length;
|
bufferPosition += length;
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,9 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int sampleData(DataReader input, int length, boolean allowEndOfInput) throws IOException {
|
public int sampleData(
|
||||||
|
DataReader input, int length, boolean allowEndOfInput, @SampleDataPart int sampleDataPart)
|
||||||
|
throws IOException {
|
||||||
byte[] newData = new byte[length];
|
byte[] newData = new byte[length];
|
||||||
int bytesAppended = input.read(newData, 0, length);
|
int bytesAppended = input.read(newData, 0, length);
|
||||||
if (bytesAppended == C.RESULT_END_OF_INPUT) {
|
if (bytesAppended == C.RESULT_END_OF_INPUT) {
|
||||||
|
|
@ -90,7 +92,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sampleData(ParsableByteArray data, int length) {
|
public void sampleData(ParsableByteArray data, int length, @SampleDataPart int sampleDataPart) {
|
||||||
byte[] newData = new byte[length];
|
byte[] newData = new byte[length];
|
||||||
data.readBytes(newData, 0, length);
|
data.readBytes(newData, 0, length);
|
||||||
sampleData = TestUtil.joinByteArrays(sampleData, newData);
|
sampleData = TestUtil.joinByteArrays(sampleData, newData);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue