Commit 04f38885 by aquilescanta Committed by Toni

Add allowOnlyClearBuffers to SampleQueue#read

Removes the need for duplicate calls to SampleQueue#read when
implementing DecryptionResources acquisition in the MediaSources.

PiperOrigin-RevId: 250298175
parent c495a3f5
...@@ -447,7 +447,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; ...@@ -447,7 +447,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
maybeNotifyDownstreamFormat(track); maybeNotifyDownstreamFormat(track);
int result = int result =
sampleQueues[track].read( sampleQueues[track].read(
formatHolder, buffer, formatRequired, loadingFinished, lastSeekPositionUs); formatHolder,
buffer,
formatRequired,
/* allowOnlyClearBuffers= */ false,
loadingFinished,
lastSeekPositionUs);
if (result == C.RESULT_NOTHING_READ) { if (result == C.RESULT_NOTHING_READ) {
maybeStartDeferredRetry(track); maybeStartDeferredRetry(track);
} }
......
...@@ -230,6 +230,8 @@ import com.google.android.exoplayer2.util.Util; ...@@ -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 * @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 * 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. * 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 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 * @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. * is different to the current downstream format then a format will be read.
...@@ -242,6 +244,7 @@ import com.google.android.exoplayer2.util.Util; ...@@ -242,6 +244,7 @@ import com.google.android.exoplayer2.util.Util;
FormatHolder formatHolder, FormatHolder formatHolder,
DecoderInputBuffer buffer, DecoderInputBuffer buffer,
boolean formatRequired, boolean formatRequired,
boolean allowOnlyClearBuffers,
boolean loadingFinished, boolean loadingFinished,
Format downstreamFormat, Format downstreamFormat,
SampleExtrasHolder extrasHolder) { SampleExtrasHolder extrasHolder) {
...@@ -264,6 +267,10 @@ import com.google.android.exoplayer2.util.Util; ...@@ -264,6 +267,10 @@ import com.google.android.exoplayer2.util.Util;
return C.RESULT_FORMAT_READ; return C.RESULT_FORMAT_READ;
} }
if (allowOnlyClearBuffers && (flags[relativeReadIndex] & C.BUFFER_FLAG_ENCRYPTED) != 0) {
return C.RESULT_NOTHING_READ;
}
buffer.setFlags(flags[relativeReadIndex]); buffer.setFlags(flags[relativeReadIndex]);
buffer.timeUs = timesUs[relativeReadIndex]; buffer.timeUs = timesUs[relativeReadIndex];
if (buffer.isFlagsOnly()) { if (buffer.isFlagsOnly()) {
......
...@@ -324,6 +324,8 @@ public class SampleQueue implements TrackOutput { ...@@ -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 * @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 * 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. * 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 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 * @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. * be set if the buffer's timestamp is less than this value.
...@@ -334,10 +336,18 @@ public class SampleQueue implements TrackOutput { ...@@ -334,10 +336,18 @@ public class SampleQueue implements TrackOutput {
FormatHolder formatHolder, FormatHolder formatHolder,
DecoderInputBuffer buffer, DecoderInputBuffer buffer,
boolean formatRequired, boolean formatRequired,
boolean allowOnlyClearBuffers,
boolean loadingFinished, boolean loadingFinished,
long decodeOnlyUntilUs) { long decodeOnlyUntilUs) {
int result = metadataQueue.read(formatHolder, buffer, formatRequired, loadingFinished, int result =
downstreamFormat, extrasHolder); metadataQueue.read(
formatHolder,
buffer,
formatRequired,
allowOnlyClearBuffers,
loadingFinished,
downstreamFormat,
extrasHolder);
switch (result) { switch (result) {
case C.RESULT_FORMAT_READ: case C.RESULT_FORMAT_READ:
downstreamFormat = formatHolder.format; downstreamFormat = formatHolder.format;
......
...@@ -409,7 +409,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -409,7 +409,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
} }
maybeNotifyPrimaryTrackFormatChanged(); maybeNotifyPrimaryTrackFormatChanged();
return primarySampleQueue.read( return primarySampleQueue.read(
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilPositionUs); formatHolder,
buffer,
formatRequired,
/* allowOnlyClearBuffers= */ false,
loadingFinished,
decodeOnlyUntilPositionUs);
} }
@Override @Override
...@@ -801,7 +806,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -801,7 +806,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
} }
maybeNotifyDownstreamFormat(); maybeNotifyDownstreamFormat();
return sampleQueue.read( return sampleQueue.read(
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilPositionUs); formatHolder,
buffer,
formatRequired,
/* allowOnlyClearBuffers= */ false,
loadingFinished,
decodeOnlyUntilPositionUs);
} }
public void release() { public void release() {
......
...@@ -29,10 +29,12 @@ import com.google.android.exoplayer2.C; ...@@ -29,10 +29,12 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; 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.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DefaultAllocator; import com.google.android.exoplayer2.upstream.DefaultAllocator;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.util.Arrays;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
...@@ -89,6 +91,8 @@ public final class SampleQueueTest { ...@@ -89,6 +91,8 @@ public final class SampleQueueTest {
private static final Format[] SAMPLE_FORMATS = private static final Format[] SAMPLE_FORMATS =
new Format[] {FORMAT_1, FORMAT_1, FORMAT_1, FORMAT_1, FORMAT_2, FORMAT_2, FORMAT_2, FORMAT_2}; 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 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 Allocator allocator;
private SampleQueue sampleQueue; private SampleQueue sampleQueue;
...@@ -512,6 +516,49 @@ public final class SampleQueueTest { ...@@ -512,6 +516,49 @@ public final class SampleQueueTest {
} }
@Test @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() { public void testLargestQueuedTimestampWithRead() {
writeTestData(); writeTestData();
assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(LAST_SAMPLE_TIMESTAMP); assertThat(sampleQueue.getLargestQueuedTimestampUs()).isEqualTo(LAST_SAMPLE_TIMESTAMP);
...@@ -602,8 +649,12 @@ public final class SampleQueueTest { ...@@ -602,8 +649,12 @@ public final class SampleQueueTest {
sampleQueue.format(sampleFormats[i]); sampleQueue.format(sampleFormats[i]);
format = sampleFormats[i]; format = sampleFormats[i];
} }
sampleQueue.sampleMetadata(sampleTimestamps[i], sampleFlags[i], sampleSizes[i], sampleQueue.sampleMetadata(
sampleOffsets[i], null); 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 { ...@@ -714,11 +765,18 @@ public final class SampleQueueTest {
/** /**
* Asserts {@link SampleQueue#read} returns {@link C#RESULT_NOTHING_READ}. * 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) { private void assertReadNothing(boolean formatRequired) {
clearFormatHolderAndInputBuffer(); 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); assertThat(result).isEqualTo(RESULT_NOTHING_READ);
// formatHolder should not be populated. // formatHolder should not be populated.
assertThat(formatHolder.format).isNull(); assertThat(formatHolder.format).isNull();
...@@ -728,14 +786,21 @@ public final class SampleQueueTest { ...@@ -728,14 +786,21 @@ public final class SampleQueueTest {
} }
/** /**
* Asserts {@link SampleQueue#read} returns {@link C#RESULT_BUFFER_READ} and that the * Asserts {@link SampleQueue#read} returns {@link C#RESULT_BUFFER_READ} and that the {@link
* {@link DecoderInputBuffer#isEndOfStream()} is set. * 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) { private void assertReadEndOfStream(boolean formatRequired) {
clearFormatHolderAndInputBuffer(); 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); assertThat(result).isEqualTo(RESULT_BUFFER_READ);
// formatHolder should not be populated. // formatHolder should not be populated.
assertThat(formatHolder.format).isNull(); assertThat(formatHolder.format).isNull();
...@@ -750,12 +815,19 @@ public final class SampleQueueTest { ...@@ -750,12 +815,19 @@ public final class SampleQueueTest {
* Asserts {@link SampleQueue#read} returns {@link C#RESULT_FORMAT_READ} and that the format * 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}. * 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. * @param format The expected format.
*/ */
private void assertReadFormat(boolean formatRequired, Format format) { private void assertReadFormat(boolean formatRequired, Format format) {
clearFormatHolderAndInputBuffer(); 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); assertThat(result).isEqualTo(RESULT_FORMAT_READ);
// formatHolder should be populated. // formatHolder should be populated.
assertThat(formatHolder.format).isEqualTo(format); assertThat(formatHolder.format).isEqualTo(format);
...@@ -777,7 +849,14 @@ public final class SampleQueueTest { ...@@ -777,7 +849,14 @@ public final class SampleQueueTest {
private void assertReadSample( private void assertReadSample(
long timeUs, boolean isKeyframe, byte[] sampleData, int offset, int length) { long timeUs, boolean isKeyframe, byte[] sampleData, int offset, int length) {
clearFormatHolderAndInputBuffer(); 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); assertThat(result).isEqualTo(RESULT_BUFFER_READ);
// formatHolder should not be populated. // formatHolder should not be populated.
assertThat(formatHolder.format).isNull(); assertThat(formatHolder.format).isNull();
...@@ -793,6 +872,19 @@ public final class SampleQueueTest { ...@@ -793,6 +872,19 @@ public final class SampleQueueTest {
assertThat(readData).isEqualTo(copyOfRange(sampleData, offset, offset + length)); 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}. * Asserts the number of allocations currently in use by {@code sampleQueue}.
* *
......
...@@ -371,7 +371,14 @@ public final class PlayerEmsgHandler implements Handler.Callback { ...@@ -371,7 +371,14 @@ public final class PlayerEmsgHandler implements Handler.Callback {
@Nullable @Nullable
private MetadataInputBuffer dequeueSample() { private MetadataInputBuffer dequeueSample() {
buffer.clear(); 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) { if (result == C.RESULT_BUFFER_READ) {
buffer.flip(); buffer.flip();
return buffer; return buffer;
......
...@@ -491,7 +491,12 @@ import java.util.Map; ...@@ -491,7 +491,12 @@ import java.util.Map;
int result = int result =
sampleQueues[sampleQueueIndex].read( sampleQueues[sampleQueueIndex].read(
formatHolder, buffer, requireFormat, loadingFinished, lastSeekPositionUs); formatHolder,
buffer,
requireFormat,
/* allowOnlyClearBuffers= */ false,
loadingFinished,
lastSeekPositionUs);
if (result == C.RESULT_FORMAT_READ) { if (result == C.RESULT_FORMAT_READ) {
Format format = formatHolder.format; Format format = formatHolder.format;
if (sampleQueueIndex == primarySampleQueueIndex) { if (sampleQueueIndex == primarySampleQueueIndex) {
......
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