Add allowOnlyClearBuffers to SampleQueue#read
Removes the need for duplicate calls to SampleQueue#read when implementing DecryptionResources acquisition in the MediaSources. PiperOrigin-RevId: 250298175
This commit is contained in:
parent
c495a3f55e
commit
04f3888550
@ -447,7 +447,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
maybeNotifyDownstreamFormat(track);
|
||||
int result =
|
||||
sampleQueues[track].read(
|
||||
formatHolder, buffer, formatRequired, loadingFinished, lastSeekPositionUs);
|
||||
formatHolder,
|
||||
buffer,
|
||||
formatRequired,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
loadingFinished,
|
||||
lastSeekPositionUs);
|
||||
if (result == C.RESULT_NOTHING_READ) {
|
||||
maybeStartDeferredRetry(track);
|
||||
}
|
||||
|
@ -230,6 +230,8 @@ import com.google.android.exoplayer2.util.Util;
|
||||
* @param formatRequired Whether the caller requires that the format of the stream be read even if
|
||||
* it's not changing. A sample will never be read if set to true, however it is still possible
|
||||
* for the end of stream or nothing to be read.
|
||||
* @param allowOnlyClearBuffers If set to true, this method will not return encrypted buffers,
|
||||
* returning {@link C#RESULT_NOTHING_READ} (without advancing the read position) instead.
|
||||
* @param loadingFinished True if an empty queue should be considered the end of the stream.
|
||||
* @param downstreamFormat The current downstream {@link Format}. If the format of the next sample
|
||||
* is different to the current downstream format then a format will be read.
|
||||
@ -242,6 +244,7 @@ import com.google.android.exoplayer2.util.Util;
|
||||
FormatHolder formatHolder,
|
||||
DecoderInputBuffer buffer,
|
||||
boolean formatRequired,
|
||||
boolean allowOnlyClearBuffers,
|
||||
boolean loadingFinished,
|
||||
Format downstreamFormat,
|
||||
SampleExtrasHolder extrasHolder) {
|
||||
@ -264,6 +267,10 @@ import com.google.android.exoplayer2.util.Util;
|
||||
return C.RESULT_FORMAT_READ;
|
||||
}
|
||||
|
||||
if (allowOnlyClearBuffers && (flags[relativeReadIndex] & C.BUFFER_FLAG_ENCRYPTED) != 0) {
|
||||
return C.RESULT_NOTHING_READ;
|
||||
}
|
||||
|
||||
buffer.setFlags(flags[relativeReadIndex]);
|
||||
buffer.timeUs = timesUs[relativeReadIndex];
|
||||
if (buffer.isFlagsOnly()) {
|
||||
|
@ -324,6 +324,8 @@ public class SampleQueue implements TrackOutput {
|
||||
* @param formatRequired Whether the caller requires that the format of the stream be read even if
|
||||
* it's not changing. A sample will never be read if set to true, however it is still possible
|
||||
* for the end of stream or nothing to be read.
|
||||
* @param allowOnlyClearBuffers If set to true, this method will not return encrypted buffers,
|
||||
* returning {@link C#RESULT_NOTHING_READ} (without advancing the read position) instead.
|
||||
* @param loadingFinished True if an empty queue should be considered the end of the stream.
|
||||
* @param decodeOnlyUntilUs If a buffer is read, the {@link C#BUFFER_FLAG_DECODE_ONLY} flag will
|
||||
* be set if the buffer's timestamp is less than this value.
|
||||
@ -334,10 +336,18 @@ public class SampleQueue implements TrackOutput {
|
||||
FormatHolder formatHolder,
|
||||
DecoderInputBuffer buffer,
|
||||
boolean formatRequired,
|
||||
boolean allowOnlyClearBuffers,
|
||||
boolean loadingFinished,
|
||||
long decodeOnlyUntilUs) {
|
||||
int result = metadataQueue.read(formatHolder, buffer, formatRequired, loadingFinished,
|
||||
downstreamFormat, extrasHolder);
|
||||
int result =
|
||||
metadataQueue.read(
|
||||
formatHolder,
|
||||
buffer,
|
||||
formatRequired,
|
||||
allowOnlyClearBuffers,
|
||||
loadingFinished,
|
||||
downstreamFormat,
|
||||
extrasHolder);
|
||||
switch (result) {
|
||||
case C.RESULT_FORMAT_READ:
|
||||
downstreamFormat = formatHolder.format;
|
||||
|
@ -409,7 +409,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
||||
}
|
||||
maybeNotifyPrimaryTrackFormatChanged();
|
||||
return primarySampleQueue.read(
|
||||
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilPositionUs);
|
||||
formatHolder,
|
||||
buffer,
|
||||
formatRequired,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
loadingFinished,
|
||||
decodeOnlyUntilPositionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -801,7 +806,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
||||
}
|
||||
maybeNotifyDownstreamFormat();
|
||||
return sampleQueue.read(
|
||||
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilPositionUs);
|
||||
formatHolder,
|
||||
buffer,
|
||||
formatRequired,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
loadingFinished,
|
||||
decodeOnlyUntilPositionUs);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
|
@ -29,10 +29,12 @@ import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import java.util.Arrays;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -89,6 +91,8 @@ public final class SampleQueueTest {
|
||||
private static final Format[] SAMPLE_FORMATS =
|
||||
new Format[] {FORMAT_1, FORMAT_1, FORMAT_1, FORMAT_1, FORMAT_2, FORMAT_2, FORMAT_2, FORMAT_2};
|
||||
private static final int DATA_SECOND_KEYFRAME_INDEX = 4;
|
||||
private static final TrackOutput.CryptoData DUMMY_CRYPTO_DATA =
|
||||
new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, new byte[16], 0, 0);
|
||||
|
||||
private Allocator allocator;
|
||||
private SampleQueue sampleQueue;
|
||||
@ -511,6 +515,49 @@ public final class SampleQueueTest {
|
||||
assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(MIN_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowOnlyClearBuffers() {
|
||||
int[] flags =
|
||||
new int[] {
|
||||
C.BUFFER_FLAG_KEY_FRAME,
|
||||
C.BUFFER_FLAG_ENCRYPTED,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
C.BUFFER_FLAG_KEY_FRAME | C.BUFFER_FLAG_ENCRYPTED,
|
||||
0,
|
||||
0
|
||||
};
|
||||
int[] sampleSizes = new int[flags.length];
|
||||
Arrays.fill(sampleSizes, /* val= */ 1);
|
||||
|
||||
// Two encryption preamble bytes per encrypted sample in the sample queue.
|
||||
byte[] sampleData = new byte[flags.length + 2 + 2];
|
||||
Arrays.fill(sampleData, /* val= */ (byte) 1);
|
||||
|
||||
writeTestData(
|
||||
sampleData, sampleSizes, new int[flags.length], SAMPLE_TIMESTAMPS, SAMPLE_FORMATS, flags);
|
||||
assertReadFormat(/* formatRequired= */ false, FORMAT_1);
|
||||
assertResult(RESULT_BUFFER_READ, /* allowOnlyClearBuffers= */ true);
|
||||
assertResult(RESULT_NOTHING_READ, /* allowOnlyClearBuffers= */ true);
|
||||
|
||||
assertResult(RESULT_BUFFER_READ, /* allowOnlyClearBuffers= */ false);
|
||||
|
||||
assertResult(RESULT_BUFFER_READ, /* allowOnlyClearBuffers= */ true);
|
||||
assertResult(RESULT_BUFFER_READ, /* allowOnlyClearBuffers= */ true);
|
||||
assertResult(RESULT_FORMAT_READ, /* allowOnlyClearBuffers= */ true);
|
||||
assertResult(RESULT_BUFFER_READ, /* allowOnlyClearBuffers= */ true);
|
||||
assertResult(RESULT_NOTHING_READ, /* allowOnlyClearBuffers= */ true);
|
||||
|
||||
assertResult(RESULT_BUFFER_READ, /* allowOnlyClearBuffers= */ false);
|
||||
|
||||
assertResult(RESULT_BUFFER_READ, /* allowOnlyClearBuffers= */ true);
|
||||
assertResult(RESULT_BUFFER_READ, /* allowOnlyClearBuffers= */ true);
|
||||
assertResult(RESULT_NOTHING_READ, /* allowOnlyClearBuffers= */ true);
|
||||
|
||||
assertResult(RESULT_NOTHING_READ, /* allowOnlyClearBuffers= */ false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLargestQueuedTimestampWithRead() {
|
||||
writeTestData();
|
||||
@ -602,8 +649,12 @@ public final class SampleQueueTest {
|
||||
sampleQueue.format(sampleFormats[i]);
|
||||
format = sampleFormats[i];
|
||||
}
|
||||
sampleQueue.sampleMetadata(sampleTimestamps[i], sampleFlags[i], sampleSizes[i],
|
||||
sampleOffsets[i], null);
|
||||
sampleQueue.sampleMetadata(
|
||||
sampleTimestamps[i],
|
||||
sampleFlags[i],
|
||||
sampleSizes[i],
|
||||
sampleOffsets[i],
|
||||
(sampleFlags[i] & C.BUFFER_FLAG_ENCRYPTED) != 0 ? DUMMY_CRYPTO_DATA : null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -714,11 +765,18 @@ public final class SampleQueueTest {
|
||||
/**
|
||||
* Asserts {@link SampleQueue#read} returns {@link C#RESULT_NOTHING_READ}.
|
||||
*
|
||||
* @param formatRequired The value of {@code formatRequired} passed to readData.
|
||||
* @param formatRequired The value of {@code formatRequired} passed to {@link SampleQueue#read}.
|
||||
*/
|
||||
private void assertReadNothing(boolean formatRequired) {
|
||||
clearFormatHolderAndInputBuffer();
|
||||
int result = sampleQueue.read(formatHolder, inputBuffer, formatRequired, false, 0);
|
||||
int result =
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
inputBuffer,
|
||||
formatRequired,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
/* loadingFinished= */ false,
|
||||
/* decodeOnlyUntilUs= */ 0);
|
||||
assertThat(result).isEqualTo(RESULT_NOTHING_READ);
|
||||
// formatHolder should not be populated.
|
||||
assertThat(formatHolder.format).isNull();
|
||||
@ -728,14 +786,21 @@ public final class SampleQueueTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts {@link SampleQueue#read} returns {@link C#RESULT_BUFFER_READ} and that the
|
||||
* {@link DecoderInputBuffer#isEndOfStream()} is set.
|
||||
* Asserts {@link SampleQueue#read} returns {@link C#RESULT_BUFFER_READ} and that the {@link
|
||||
* DecoderInputBuffer#isEndOfStream()} is set.
|
||||
*
|
||||
* @param formatRequired The value of {@code formatRequired} passed to readData.
|
||||
* @param formatRequired The value of {@code formatRequired} passed to {@link SampleQueue#read}.
|
||||
*/
|
||||
private void assertReadEndOfStream(boolean formatRequired) {
|
||||
clearFormatHolderAndInputBuffer();
|
||||
int result = sampleQueue.read(formatHolder, inputBuffer, formatRequired, true, 0);
|
||||
int result =
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
inputBuffer,
|
||||
formatRequired,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
/* loadingFinished= */ true,
|
||||
/* decodeOnlyUntilUs= */ 0);
|
||||
assertThat(result).isEqualTo(RESULT_BUFFER_READ);
|
||||
// formatHolder should not be populated.
|
||||
assertThat(formatHolder.format).isNull();
|
||||
@ -750,12 +815,19 @@ public final class SampleQueueTest {
|
||||
* Asserts {@link SampleQueue#read} returns {@link C#RESULT_FORMAT_READ} and that the format
|
||||
* holder is filled with a {@link Format} that equals {@code format}.
|
||||
*
|
||||
* @param formatRequired The value of {@code formatRequired} passed to readData.
|
||||
* @param formatRequired The value of {@code formatRequired} passed to {@link SampleQueue#read}.
|
||||
* @param format The expected format.
|
||||
*/
|
||||
private void assertReadFormat(boolean formatRequired, Format format) {
|
||||
clearFormatHolderAndInputBuffer();
|
||||
int result = sampleQueue.read(formatHolder, inputBuffer, formatRequired, false, 0);
|
||||
int result =
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
inputBuffer,
|
||||
formatRequired,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
/* loadingFinished= */ false,
|
||||
/* decodeOnlyUntilUs= */ 0);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
// formatHolder should be populated.
|
||||
assertThat(formatHolder.format).isEqualTo(format);
|
||||
@ -777,7 +849,14 @@ public final class SampleQueueTest {
|
||||
private void assertReadSample(
|
||||
long timeUs, boolean isKeyframe, byte[] sampleData, int offset, int length) {
|
||||
clearFormatHolderAndInputBuffer();
|
||||
int result = sampleQueue.read(formatHolder, inputBuffer, false, false, 0);
|
||||
int result =
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
inputBuffer,
|
||||
/* formatRequired= */ false,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
/* loadingFinished= */ false,
|
||||
/* decodeOnlyUntilUs= */ 0);
|
||||
assertThat(result).isEqualTo(RESULT_BUFFER_READ);
|
||||
// formatHolder should not be populated.
|
||||
assertThat(formatHolder.format).isNull();
|
||||
@ -793,6 +872,19 @@ public final class SampleQueueTest {
|
||||
assertThat(readData).isEqualTo(copyOfRange(sampleData, offset, offset + length));
|
||||
}
|
||||
|
||||
/** Asserts {@link SampleQueue#read} returns the given result. */
|
||||
private void assertResult(int expectedResult, boolean allowOnlyClearBuffers) {
|
||||
int obtainedResult =
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
inputBuffer,
|
||||
/* formatRequired= */ false,
|
||||
allowOnlyClearBuffers,
|
||||
/* loadingFinished= */ false,
|
||||
/* decodeOnlyUntilUs= */ 0);
|
||||
assertThat(obtainedResult).isEqualTo(expectedResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the number of allocations currently in use by {@code sampleQueue}.
|
||||
*
|
||||
|
@ -371,7 +371,14 @@ public final class PlayerEmsgHandler implements Handler.Callback {
|
||||
@Nullable
|
||||
private MetadataInputBuffer dequeueSample() {
|
||||
buffer.clear();
|
||||
int result = sampleQueue.read(formatHolder, buffer, false, false, 0);
|
||||
int result =
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
buffer,
|
||||
/* formatRequired= */ false,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
/* loadingFinished= */ false,
|
||||
/* decodeOnlyUntilUs= */ 0);
|
||||
if (result == C.RESULT_BUFFER_READ) {
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
|
@ -491,7 +491,12 @@ import java.util.Map;
|
||||
|
||||
int result =
|
||||
sampleQueues[sampleQueueIndex].read(
|
||||
formatHolder, buffer, requireFormat, loadingFinished, lastSeekPositionUs);
|
||||
formatHolder,
|
||||
buffer,
|
||||
requireFormat,
|
||||
/* allowOnlyClearBuffers= */ false,
|
||||
loadingFinished,
|
||||
lastSeekPositionUs);
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
Format format = formatHolder.format;
|
||||
if (sampleQueueIndex == primarySampleQueueIndex) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user