Commit 918963c2 by krocard Committed by Oliver Woodman

Do not use MediaCodec in passthrough mode.

Now that MediaCodec is not use in passthrough, no
MediaCodec should be created in this mode.

Additionally, do not instantiate a MediaCodec in passthrough

#exo-offload

PiperOrigin-RevId: 309916131
parent fa7d26dd
...@@ -55,9 +55,6 @@ ...@@ -55,9 +55,6 @@
* Add `DataSpec.Builder` and deprecate most `DataSpec` constructors. * Add `DataSpec.Builder` and deprecate most `DataSpec` constructors.
* Add `DataSpec.customData` to allow applications to pass custom data * Add `DataSpec.customData` to allow applications to pass custom data
through `DataSource` chains. through `DataSource` chains.
* Add a sample count parameter to `MediaCodecRenderer.processOutputBuffer`
and `AudioSink.handleBuffer` to allow batching multiple encoded frames
in one buffer.
* Add a `Format.Builder` and deprecate all `Format.create*` methods and * Add a `Format.Builder` and deprecate all `Format.create*` methods and
most `Format.copyWith*` methods. most `Format.copyWith*` methods.
* Split `Format.bitrate` into `Format.averageBitrate` and * Split `Format.bitrate` into `Format.averageBitrate` and
...@@ -133,6 +130,11 @@ ...@@ -133,6 +130,11 @@
directly instead. directly instead.
* Update `CachedContentIndex` to use `SecureRandom` for generating the * Update `CachedContentIndex` to use `SecureRandom` for generating the
initialization vector used to encrypt the cache contents. initialization vector used to encrypt the cache contents.
* Audio:
* Add a sample count parameter to `MediaCodecRenderer.processOutputBuffer`
and `AudioSink.handleBuffer` to allow batching multiple encoded frames
in one buffer.
* No longer use a `MediaCodec` in audio passthrough mode.
* DASH: * DASH:
* Merge trick play adaptation sets (i.e., adaptation sets marked with * Merge trick play adaptation sets (i.e., adaptation sets marked with
`http://dashif.org/guidelines/trickmode`) into the same `TrackGroup` as `http://dashif.org/guidelines/trickmode`) into the same `TrackGroup` as
......
...@@ -217,7 +217,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -217,7 +217,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@TunnelingSupport @TunnelingSupport
int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED; int tunnelingSupport = Util.SDK_INT >= 21 ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED;
boolean supportsFormatDrm = supportsFormatDrm(format); boolean supportsFormatDrm = supportsFormatDrm(format);
if (supportsFormatDrm && usePassthrough(format.channelCount, mimeType)) { if (supportsFormatDrm
&& usePassthrough(format.channelCount, mimeType)
&& MediaCodecUtil.getPassthroughDecoderInfo() != null) {
return RendererCapabilities.create(FORMAT_HANDLED, ADAPTIVE_NOT_SEAMLESS, tunnelingSupport); return RendererCapabilities.create(FORMAT_HANDLED, ADAPTIVE_NOT_SEAMLESS, tunnelingSupport);
} }
if ((MimeTypes.AUDIO_RAW.equals(mimeType) if ((MimeTypes.AUDIO_RAW.equals(mimeType)
...@@ -256,7 +258,10 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -256,7 +258,10 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
return Collections.emptyList(); return Collections.emptyList();
} }
if (usePassthrough(format.channelCount, mimeType)) { if (usePassthrough(format.channelCount, mimeType)) {
return Collections.singletonList(MediaCodecUtil.getPassthroughDecoderInfo()); @Nullable MediaCodecInfo codecInfo = MediaCodecUtil.getPassthroughDecoderInfo();
if (codecInfo != null) {
return Collections.singletonList(codecInfo);
}
} }
List<MediaCodecInfo> decoderInfos = List<MediaCodecInfo> decoderInfos =
mediaCodecSelector.getDecoderInfos( mediaCodecSelector.getDecoderInfos(
...@@ -273,19 +278,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -273,19 +278,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
return Collections.unmodifiableList(decoderInfos); return Collections.unmodifiableList(decoderInfos);
} }
/** @Override
* Returns whether encoded audio passthrough should be used for playing back the input format. protected boolean usePassthrough(int channelCount, String mimeType) {
* return getPassthroughEncoding(channelCount, mimeType) != C.ENCODING_INVALID;
* @param channelCount The number of channels in the input media, or {@link Format#NO_VALUE} if
* not known.
* @param mimeType The type of input media.
* @return Whether passthrough playback is supported.
* @throws DecoderQueryException If there was an error querying the available passthrough
* decoders.
*/
protected boolean usePassthrough(int channelCount, String mimeType) throws DecoderQueryException {
return getPassthroughEncoding(channelCount, mimeType) != C.ENCODING_INVALID
&& MediaCodecUtil.getPassthroughDecoderInfo() != null;
} }
@Override @Override
...@@ -423,20 +418,15 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -423,20 +418,15 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} else { } else {
channelMap = null; channelMap = null;
} }
configureAudioSink(encoding, channelCount, sampleRate, channelMap);
}
try { @Override
audioSink.configure( protected void onOutputPassthroughFormatChanged(Format outputFormat) throws ExoPlaybackException {
encoding, @C.Encoding
channelCount, int encoding = getPassthroughEncoding(outputFormat.channelCount, outputFormat.sampleMimeType);
sampleRate, configureAudioSink(
0, encoding, outputFormat.channelCount, outputFormat.sampleRate, /* channelMap= */ null);
channelMap,
inputFormat.encoderDelay,
inputFormat.encoderPadding);
} catch (AudioSink.ConfigurationException e) {
// TODO(internal: b/145658993) Use outputFormat instead.
throw createRendererException(e, inputFormat);
}
} }
/** /**
...@@ -602,7 +592,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -602,7 +592,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
protected boolean processOutputBuffer( protected boolean processOutputBuffer(
long positionUs, long positionUs,
long elapsedRealtimeUs, long elapsedRealtimeUs,
MediaCodec codec, @Nullable MediaCodec codec,
ByteBuffer buffer, ByteBuffer buffer,
int bufferIndex, int bufferIndex,
int bufferFlags, int bufferFlags,
...@@ -612,7 +602,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -612,7 +602,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
boolean isLastBuffer, boolean isLastBuffer,
Format format) Format format)
throws ExoPlaybackException { throws ExoPlaybackException {
if (codecNeedsEosBufferTimestampWorkaround if (codec != null
&& codecNeedsEosBufferTimestampWorkaround
&& bufferPresentationTimeUs == 0 && bufferPresentationTimeUs == 0
&& (bufferFlags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0 && (bufferFlags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0
&& getLargestQueuedPresentationTimeUs() != C.TIME_UNSET) { && getLargestQueuedPresentationTimeUs() != C.TIME_UNSET) {
...@@ -626,7 +617,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -626,7 +617,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} }
if (isDecodeOnlyBuffer) { if (isDecodeOnlyBuffer) {
codec.releaseOutputBuffer(bufferIndex, false); if (codec != null) {
codec.releaseOutputBuffer(bufferIndex, false);
}
decoderCounters.skippedOutputBufferCount++; decoderCounters.skippedOutputBufferCount++;
audioSink.handleDiscontinuity(); audioSink.handleDiscontinuity();
return true; return true;
...@@ -641,7 +634,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -641,7 +634,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} }
if (fullyConsumed) { if (fullyConsumed) {
codec.releaseOutputBuffer(bufferIndex, false); if (codec != null) {
codec.releaseOutputBuffer(bufferIndex, false);
}
decoderCounters.renderedOutputBufferCount++; decoderCounters.renderedOutputBufferCount++;
return true; return true;
} }
...@@ -769,6 +764,24 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media ...@@ -769,6 +764,24 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
return mediaFormat; return mediaFormat;
} }
private void configureAudioSink(
int encoding, int channelCount, int sampleRate, @Nullable int[] channelMap)
throws ExoPlaybackException {
try {
audioSink.configure(
encoding,
channelCount,
sampleRate,
/* specifiedBufferSize= */ 0,
channelMap,
inputFormat.encoderDelay,
inputFormat.encoderPadding);
} catch (AudioSink.ConfigurationException e) {
// TODO(internal: b/145658993) Use outputFormat instead.
throw createRendererException(e, inputFormat);
}
}
private void updateCurrentPosition() { private void updateCurrentPosition() {
long newCurrentPositionUs = audioSink.getCurrentPositionUs(isEnded()); long newCurrentPositionUs = audioSink.getCurrentPositionUs(isEnded());
if (newCurrentPositionUs != AudioSink.CURRENT_POSITION_NOT_SET) { if (newCurrentPositionUs != AudioSink.CURRENT_POSITION_NOT_SET) {
......
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.mediacodec;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.util.Assertions;
import java.nio.ByteBuffer;
/** Buffer that stores multiple encoded access units to allow batch processing. */
/* package */ final class BatchBuffer extends DecoderInputBuffer {
/** Arbitrary limit to the number of access unit in a full batch buffer. */
public static final int DEFAULT_BATCH_SIZE_ACCESS_UNITS = 32;
/**
* Arbitrary limit to the memory used by a full batch buffer to avoid using too much memory for
* very high bitrate. Equivalent of 75s of mp3 at highest bitrate (320kb/s) and 30s of AAC LC at
* highest bitrate (800kb/s). That limit is ignored for the first access unit to avoid stalling
* stream with huge access units.
*/
private static final int BATCH_SIZE_BYTES = 3 * 1000 * 1024;
private final DecoderInputBuffer nextAccessUnitBuffer;
private boolean hasPendingAccessUnit;
private long firstAccessUnitTimeUs;
private int accessUnitCount;
private int maxAccessUnitCount;
public BatchBuffer() {
super(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
nextAccessUnitBuffer =
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
clear();
}
/** Sets the maximum number of access units the buffer can contain before being full. */
public void setMaxAccessUnitCount(@IntRange(from = 1) int maxAccessUnitCount) {
Assertions.checkArgument(maxAccessUnitCount > 0);
this.maxAccessUnitCount = maxAccessUnitCount;
}
/** Gets the maximum number of access units the buffer can contain before being full. */
public int getMaxAccessUnitCount() {
return maxAccessUnitCount;
}
/** Resets the state of this object to what it was after construction. */
@Override
public void clear() {
flush();
maxAccessUnitCount = DEFAULT_BATCH_SIZE_ACCESS_UNITS;
}
/** Clear all access units from the BatchBuffer to empty it. */
public void flush() {
clearMainBuffer();
nextAccessUnitBuffer.clear();
hasPendingAccessUnit = false;
}
/** Clears the state of the batch buffer to be ready to receive a new sequence of access units. */
public void batchWasConsumed() {
clearMainBuffer();
if (hasPendingAccessUnit) {
putAccessUnit(nextAccessUnitBuffer);
hasPendingAccessUnit = false;
}
}
/**
* Gets the buffer to fill-out that will then be append to the batch buffer with {@link
* #commitNextAccessUnit()}.
*/
public DecoderInputBuffer getNextAccessUnitBuffer() {
return nextAccessUnitBuffer;
}
/** Gets the timestamp of the first access unit in the buffer. */
public long getFirstAccessUnitTimeUs() {
return firstAccessUnitTimeUs;
}
/** Gets the timestamp of the last access unit in the buffer. */
public long getLastAccessUnitTimeUs() {
return timeUs;
}
/** Gets the number of access units contained in this batch buffer. */
public int getAccessUnitCount() {
return accessUnitCount;
}
/** If the buffer contains no access units. */
public boolean isEmpty() {
return accessUnitCount == 0;
}
/** If more access units should be added to the batch buffer. */
public boolean isFull() {
return accessUnitCount >= maxAccessUnitCount
|| (data != null && data.position() >= BATCH_SIZE_BYTES)
|| hasPendingAccessUnit;
}
/**
* Appends the staged access unit in this batch buffer.
*
* @throws IllegalStateException If calling this method on a full or end of stream batch buffer.
* @throws IllegalArgumentException If the {@code accessUnit} is encrypted or has
* supplementalData, as batching of those state has not been implemented.
*/
public void commitNextAccessUnit() {
DecoderInputBuffer accessUnit = nextAccessUnitBuffer;
Assertions.checkState(!isFull() && !isEndOfStream());
Assertions.checkArgument(!accessUnit.isEncrypted() && !accessUnit.hasSupplementalData());
if (!canBatch(accessUnit)) {
hasPendingAccessUnit = true; // Delay the putAccessUnit until the batch buffer is empty.
return;
}
putAccessUnit(accessUnit);
}
private boolean canBatch(DecoderInputBuffer accessUnit) {
if (isEmpty()) {
return true; // Batching with an empty batch must always succeed or the stream will stall.
}
if (accessUnit.isDecodeOnly() != isDecodeOnly()) {
return false; // Decode only and non decode only access units can not be batched together.
}
@Nullable ByteBuffer accessUnitData = accessUnit.data;
if (accessUnitData != null
&& this.data != null
&& this.data.position() + accessUnitData.limit() >= BATCH_SIZE_BYTES) {
return false; // The batch buffer does not have the capacity to add this access unit.
}
return true;
}
private void putAccessUnit(DecoderInputBuffer accessUnit) {
@Nullable ByteBuffer accessUnitData = accessUnit.data;
if (accessUnitData != null) {
accessUnit.flip();
ensureSpaceForWrite(accessUnitData.remaining());
this.data.put(accessUnitData);
}
if (accessUnit.isEndOfStream()) {
setFlags(C.BUFFER_FLAG_END_OF_STREAM);
}
if (accessUnit.isDecodeOnly()) {
setFlags(C.BUFFER_FLAG_DECODE_ONLY);
}
if (accessUnit.isKeyFrame()) {
setFlags(C.BUFFER_FLAG_KEY_FRAME);
}
accessUnitCount++;
timeUs = accessUnit.timeUs;
if (accessUnitCount == 1) { // First read of the buffer
firstAccessUnitTimeUs = timeUs;
}
accessUnit.clear();
}
private void clearMainBuffer() {
super.clear();
accessUnitCount = 0;
firstAccessUnitTimeUs = C.TIME_UNSET;
timeUs = C.TIME_UNSET;
}
}
...@@ -514,7 +514,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -514,7 +514,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
setOutputSurfaceV23(codec, surface); setOutputSurfaceV23(codec, surface);
} else { } else {
releaseCodec(); releaseCodec();
maybeInitCodec(); maybeInitCodecOrPassthrough();
} }
} }
if (surface != null && surface != dummySurface) { if (surface != null && surface != dummySurface) {
...@@ -753,7 +753,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -753,7 +753,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
protected boolean processOutputBuffer( protected boolean processOutputBuffer(
long positionUs, long positionUs,
long elapsedRealtimeUs, long elapsedRealtimeUs,
MediaCodec codec, @Nullable MediaCodec codec,
ByteBuffer buffer, ByteBuffer buffer,
int bufferIndex, int bufferIndex,
int bufferFlags, int bufferFlags,
...@@ -763,6 +763,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -763,6 +763,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
boolean isLastBuffer, boolean isLastBuffer,
Format format) Format format)
throws ExoPlaybackException { throws ExoPlaybackException {
Assertions.checkNotNull(codec); // Can not render video without codec
if (initialPositionUs == C.TIME_UNSET) { if (initialPositionUs == C.TIME_UNSET) {
initialPositionUs = positionUs; initialPositionUs = positionUs;
} }
......
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.mediacodec;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.testutil.TestUtil;
import java.nio.ByteBuffer;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link BatchBuffer}. */
@RunWith(AndroidJUnit4.class)
public final class BatchBufferTest {
/** Bigger than {@link BatchBuffer#BATCH_SIZE_BYTES} */
private static final int BUFFER_SIZE_LARGER_THAN_BATCH_SIZE_BYTES = 100 * 1000 * 1000;
/** Smaller than {@link BatchBuffer#BATCH_SIZE_BYTES} */
private static final int BUFFER_SIZE_MUCH_SMALLER_THAN_BATCH_SIZE_BYTES = 100;
private static final byte[] TEST_ACCESS_UNIT =
TestUtil.buildTestData(BUFFER_SIZE_MUCH_SMALLER_THAN_BATCH_SIZE_BYTES);
private static final byte[] TEST_HUGE_ACCESS_UNIT =
TestUtil.buildTestData(BUFFER_SIZE_LARGER_THAN_BATCH_SIZE_BYTES);
private final BatchBuffer batchBuffer = new BatchBuffer();
@Test
public void newBatchBuffer_isEmpty() {
assertIsCleared(batchBuffer);
}
@Test
public void clear_empty_isEmpty() {
batchBuffer.clear();
assertIsCleared(batchBuffer);
}
@Test
public void clear_afterInsertingAccessUnit_isEmpty() {
batchBuffer.commitNextAccessUnit();
batchBuffer.clear();
assertIsCleared(batchBuffer);
}
@Test
public void commitNextAccessUnit_addsAccessUnit() {
batchBuffer.commitNextAccessUnit();
assertThat(batchBuffer.getAccessUnitCount()).isEqualTo(1);
}
@Test
public void commitNextAccessUnit_untilFull_isFullAndNotEmpty() {
fillBatchBuffer(batchBuffer);
assertThat(batchBuffer.isEmpty()).isFalse();
assertThat(batchBuffer.isFull()).isTrue();
}
@Test
public void commitNextAccessUnit_whenFull_throws() {
batchBuffer.setMaxAccessUnitCount(1);
batchBuffer.commitNextAccessUnit();
assertThrows(IllegalStateException.class, batchBuffer::commitNextAccessUnit);
}
@Test
public void commitNextAccessUnit_whenAccessUnitIsDecodeOnly_isDecodeOnly() {
batchBuffer.getNextAccessUnitBuffer().setFlags(C.BUFFER_FLAG_DECODE_ONLY);
batchBuffer.commitNextAccessUnit();
assertThat(batchBuffer.isDecodeOnly()).isTrue();
}
@Test
public void commitNextAccessUnit_whenAccessUnitIsEndOfStream_isEndOfSteam() {
batchBuffer.getNextAccessUnitBuffer().setFlags(C.BUFFER_FLAG_END_OF_STREAM);
batchBuffer.commitNextAccessUnit();
assertThat(batchBuffer.isEndOfStream()).isTrue();
}
@Test
public void commitNextAccessUnit_whenAccessUnitIsKeyFrame_isKeyFrame() {
batchBuffer.getNextAccessUnitBuffer().setFlags(C.BUFFER_FLAG_KEY_FRAME);
batchBuffer.commitNextAccessUnit();
assertThat(batchBuffer.isKeyFrame()).isTrue();
}
@Test
public void commitNextAccessUnit_withData_dataIsCopiedInTheBatch() {
batchBuffer.getNextAccessUnitBuffer().ensureSpaceForWrite(TEST_ACCESS_UNIT.length);
batchBuffer.getNextAccessUnitBuffer().data.put(TEST_ACCESS_UNIT);
batchBuffer.commitNextAccessUnit();
batchBuffer.flip();
assertThat(batchBuffer.getAccessUnitCount()).isEqualTo(1);
assertThat(batchBuffer.data).isEqualTo(ByteBuffer.wrap(TEST_ACCESS_UNIT));
}
@Test
public void commitNextAccessUnit_nextAccessUnit_isClear() {
batchBuffer.getNextAccessUnitBuffer().ensureSpaceForWrite(TEST_ACCESS_UNIT.length);
batchBuffer.getNextAccessUnitBuffer().data.put(TEST_ACCESS_UNIT);
batchBuffer.getNextAccessUnitBuffer().setFlags(C.BUFFER_FLAG_KEY_FRAME);
batchBuffer.commitNextAccessUnit();
DecoderInputBuffer nextAccessUnit = batchBuffer.getNextAccessUnitBuffer();
assertThat(nextAccessUnit.data).isNotNull();
assertThat(nextAccessUnit.data.position()).isEqualTo(0);
assertThat(nextAccessUnit.isKeyFrame()).isFalse();
}
@Test
public void commitNextAccessUnit_twice_bothAccessUnitAreConcatenated() {
// Commit TEST_ACCESS_UNIT
batchBuffer.getNextAccessUnitBuffer().ensureSpaceForWrite(TEST_ACCESS_UNIT.length);
batchBuffer.getNextAccessUnitBuffer().data.put(TEST_ACCESS_UNIT);
batchBuffer.commitNextAccessUnit();
// Commit TEST_ACCESS_UNIT again
batchBuffer.getNextAccessUnitBuffer().ensureSpaceForWrite(TEST_ACCESS_UNIT.length);
batchBuffer.getNextAccessUnitBuffer().data.put(TEST_ACCESS_UNIT);
batchBuffer.commitNextAccessUnit();
batchBuffer.flip();
byte[] expected = TestUtil.joinByteArrays(TEST_ACCESS_UNIT, TEST_ACCESS_UNIT);
assertThat(batchBuffer.data).isEqualTo(ByteBuffer.wrap(expected));
}
@Test
public void commitNextAccessUnit_whenAccessUnitIsHugeAndBatchBufferNotEmpty_isMarkedPending() {
batchBuffer.getNextAccessUnitBuffer().ensureSpaceForWrite(TEST_ACCESS_UNIT.length);
batchBuffer.getNextAccessUnitBuffer().data.put(TEST_ACCESS_UNIT);
batchBuffer.commitNextAccessUnit();
batchBuffer.getNextAccessUnitBuffer().ensureSpaceForWrite(TEST_HUGE_ACCESS_UNIT.length);
batchBuffer.getNextAccessUnitBuffer().data.put(TEST_HUGE_ACCESS_UNIT);
batchBuffer.commitNextAccessUnit();
batchBuffer.batchWasConsumed();
batchBuffer.flip();
assertThat(batchBuffer.getAccessUnitCount()).isEqualTo(1);
assertThat(batchBuffer.data).isEqualTo(ByteBuffer.wrap(TEST_HUGE_ACCESS_UNIT));
}
@Test
public void batchWasConsumed_whenNotEmpty_isEmpty() {
fillBatchBuffer(batchBuffer);
batchBuffer.batchWasConsumed();
assertIsCleared(batchBuffer);
}
@Test
public void batchWasConsumed_whenFull_isEmpty() {
fillBatchBuffer(batchBuffer);
batchBuffer.batchWasConsumed();
assertIsCleared(batchBuffer);
}
@Test
public void getMaxAccessUnitCount_whenSetToAPositiveValue_returnsIt() {
batchBuffer.setMaxAccessUnitCount(20);
assertThat(batchBuffer.getMaxAccessUnitCount()).isEqualTo(20);
}
@Test
public void setMaxAccessUnitCount_whenSetToNegative_throws() {
assertThrows(IllegalArgumentException.class, () -> batchBuffer.setMaxAccessUnitCount(-19));
}
@Test
public void setMaxAccessUnitCount_whenSetToZero_throws() {
assertThrows(IllegalArgumentException.class, () -> batchBuffer.setMaxAccessUnitCount(0));
}
@Test
public void setMaxAccessUnitCount_whenSetToTheNumberOfAccessUnitInTheBatch_isFull() {
batchBuffer.commitNextAccessUnit();
batchBuffer.setMaxAccessUnitCount(1);
assertThat(batchBuffer.isFull()).isTrue();
}
@Test
public void batchWasConsumed_whenAccessUnitIsPending_pendingAccessUnitIsInTheBatch() {
batchBuffer.commitNextAccessUnit();
batchBuffer.getNextAccessUnitBuffer().setFlags(C.BUFFER_FLAG_DECODE_ONLY);
batchBuffer.getNextAccessUnitBuffer().ensureSpaceForWrite(TEST_ACCESS_UNIT.length);
batchBuffer.getNextAccessUnitBuffer().data.put(TEST_ACCESS_UNIT);
batchBuffer.commitNextAccessUnit();
batchBuffer.batchWasConsumed();
batchBuffer.flip();
assertThat(batchBuffer.getAccessUnitCount()).isEqualTo(1);
assertThat(batchBuffer.isDecodeOnly()).isTrue();
assertThat(batchBuffer.data).isEqualTo(ByteBuffer.wrap(TEST_ACCESS_UNIT));
}
private static void fillBatchBuffer(BatchBuffer batchBuffer) {
int maxAccessUnit = batchBuffer.getMaxAccessUnitCount();
while (!batchBuffer.isFull()) {
assertThat(maxAccessUnit--).isNotEqualTo(0);
batchBuffer.commitNextAccessUnit();
}
}
private static void assertIsCleared(BatchBuffer batchBuffer) {
assertThat(batchBuffer.getFirstAccessUnitTimeUs()).isEqualTo(C.TIME_UNSET);
assertThat(batchBuffer.getLastAccessUnitTimeUs()).isEqualTo(C.TIME_UNSET);
assertThat(batchBuffer.getAccessUnitCount()).isEqualTo(0);
assertThat(batchBuffer.isEmpty()).isTrue();
assertThat(batchBuffer.isFull()).isFalse();
}
}
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