use of androidx.media3.exoplayer.upstream.Allocation in project media by androidx.
the class SampleDataQueue method readData.
/**
* Reads data from {@code allocationNode} and its following nodes.
*
* @param allocationNode The first {@link AllocationNode} containing data yet to be read.
* @param absolutePosition The absolute position from which data should be read.
* @param target The array into which data should be written.
* @param length The number of bytes to read.
* @return The first {@link AllocationNode} that contains unread bytes after this method returns.
*/
private static AllocationNode readData(AllocationNode allocationNode, long absolutePosition, byte[] target, int length) {
allocationNode = getNodeContainingPosition(allocationNode, absolutePosition);
int remaining = length;
while (remaining > 0) {
int toCopy = min(remaining, (int) (allocationNode.endPosition - absolutePosition));
Allocation allocation = allocationNode.allocation;
System.arraycopy(allocation.data, allocationNode.translateOffset(absolutePosition), target, length - remaining, toCopy);
remaining -= toCopy;
absolutePosition += toCopy;
if (absolutePosition == allocationNode.endPosition) {
allocationNode = allocationNode.next;
}
}
return allocationNode;
}
use of androidx.media3.exoplayer.upstream.Allocation in project media by androidx.
the class ExoPlayerTest method infiniteLoading_withSmallAllocations_oomIsPreventedByLoadControl_andThrowsStuckBufferingIllegalStateException.
@Test
public void infiniteLoading_withSmallAllocations_oomIsPreventedByLoadControl_andThrowsStuckBufferingIllegalStateException() {
DefaultLoadControl loadControl = new DefaultLoadControl.Builder().setTargetBufferBytes(10 * C.DEFAULT_BUFFER_SEGMENT_SIZE).build();
// Return no end of stream signal to prevent playback from ending.
FakeMediaPeriod.TrackDataFactory trackDataWithoutEos = (format, periodId) -> ImmutableList.of();
MediaSource continuouslyAllocatingMediaSource = new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT) {
@Override
protected MediaPeriod createMediaPeriod(MediaPeriodId id, TrackGroupArray trackGroupArray, Allocator allocator, MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher, DrmSessionManager drmSessionManager, DrmSessionEventListener.EventDispatcher drmEventDispatcher, @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, allocator, trackDataWithoutEos, mediaSourceEventDispatcher, drmSessionManager, drmEventDispatcher, /* deferOnPrepared= */
false) {
private final List<Allocation> allocations = new ArrayList<>();
private Callback callback;
@Override
public synchronized void prepare(Callback callback, long positionUs) {
this.callback = callback;
super.prepare(callback, positionUs);
}
@Override
public long getBufferedPositionUs() {
// Pretend not to make loading progress, so that continueLoading keeps being called.
return 0;
}
@Override
public long getNextLoadPositionUs() {
// Pretend not to make loading progress, so that continueLoading keeps being called.
return 0;
}
@Override
public boolean continueLoading(long positionUs) {
allocations.add(allocator.allocate());
callback.onContinueLoadingRequested(this);
return true;
}
};
}
};
ExoPlayerTestRunner testRunner = new ExoPlayerTestRunner.Builder(context).setMediaSources(continuouslyAllocatingMediaSource).setLoadControl(loadControl).build();
ExoPlaybackException exception = assertThrows(ExoPlaybackException.class, () -> testRunner.start().blockUntilEnded(TIMEOUT_MS));
assertThat(exception.type).isEqualTo(ExoPlaybackException.TYPE_UNEXPECTED);
assertThat(exception.getUnexpectedException()).isInstanceOf(IllegalStateException.class);
}
use of androidx.media3.exoplayer.upstream.Allocation in project media by androidx.
the class SampleQueueTest method readSingleSamples.
@Test
public void readSingleSamples() {
sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE);
assertAllocationCount(1);
// Nothing to read.
assertNoSamplesToRead(null);
sampleQueue.format(FORMAT_1);
// Read the format.
assertReadFormat(false, FORMAT_1);
// Nothing to read.
assertNoSamplesToRead(FORMAT_1);
sampleQueue.sampleMetadata(1000, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null);
// If formatRequired, should read the format rather than the sample.
assertReadFormat(true, FORMAT_1);
// Otherwise should read the sample.
assertReadSample(1000, /* isKeyFrame= */
true, /* isDecodeOnly= */
false, /* isEncrypted= */
false, DATA, /* offset= */
0, ALLOCATION_SIZE);
// Allocation should still be held.
assertAllocationCount(1);
sampleQueue.discardToRead();
// The allocation should have been released.
assertAllocationCount(0);
// Nothing to read.
assertNoSamplesToRead(FORMAT_1);
// Write a second sample followed by one byte that does not belong to it.
sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE);
sampleQueue.sampleMetadata(2000, 0, ALLOCATION_SIZE - 1, 1, null);
// If formatRequired, should read the format rather than the sample.
assertReadFormat(true, FORMAT_1);
// Read the sample.
assertReadSample(2000, /* isKeyFrame= */
false, /* isDecodeOnly= */
false, /* isEncrypted= */
false, DATA, /* offset= */
0, ALLOCATION_SIZE - 1);
// Allocation should still be held.
assertAllocationCount(1);
sampleQueue.discardToRead();
// The last byte written to the sample queue may belong to a sample whose metadata has yet to be
// written, so an allocation should still be held.
assertAllocationCount(1);
// Write metadata for a third sample containing the remaining byte.
sampleQueue.sampleMetadata(3000, 0, 1, 0, null);
// If formatRequired, should read the format rather than the sample.
assertReadFormat(true, FORMAT_1);
// Read the sample.
assertReadSample(3000, /* isKeyFrame= */
false, /* isDecodeOnly= */
false, /* isEncrypted= */
false, DATA, ALLOCATION_SIZE - 1, 1);
// Allocation should still be held.
assertAllocationCount(1);
sampleQueue.discardToRead();
// The allocation should have been released.
assertAllocationCount(0);
}
use of androidx.media3.exoplayer.upstream.Allocation in project media by androidx.
the class ExoPlayerTest method loading_withLargeAllocationCausingOom_playsRemainingMediaAndThenThrows.
@Test
public void loading_withLargeAllocationCausingOom_playsRemainingMediaAndThenThrows() {
Loader.Loadable loadable = new Loader.Loadable() {
@SuppressWarnings("UnusedVariable")
@Override
public void load() throws IOException {
// This test needs the allocation to cause an OOM.
@SuppressWarnings("unused") byte[] largeBuffer = new byte[Integer.MAX_VALUE];
}
@Override
public void cancelLoad() {
}
};
// Create 3 samples without end of stream signal to test that all 3 samples are
// still played before the sample stream exception is thrown.
FakeSampleStreamItem sample = oneByteSample(TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US, C.BUFFER_FLAG_KEY_FRAME);
FakeMediaPeriod.TrackDataFactory threeSamplesWithoutEos = (format, mediaPeriodId) -> ImmutableList.of(sample, sample, sample);
MediaSource largeBufferAllocatingMediaSource = new FakeMediaSource(new FakeTimeline(), ExoPlayerTestRunner.VIDEO_FORMAT) {
@Override
protected MediaPeriod createMediaPeriod(MediaPeriodId id, TrackGroupArray trackGroupArray, Allocator allocator, MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher, DrmSessionManager drmSessionManager, DrmSessionEventListener.EventDispatcher drmEventDispatcher, @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, allocator, threeSamplesWithoutEos, mediaSourceEventDispatcher, drmSessionManager, drmEventDispatcher, /* deferOnPrepared= */
false) {
private final Loader loader = new Loader("ExoPlayerTest");
@Override
public boolean continueLoading(long positionUs) {
super.continueLoading(positionUs);
if (!loader.isLoading()) {
loader.startLoading(loadable, new FakeLoaderCallback(), /* defaultMinRetryCount= */
1);
}
return true;
}
@Override
protected FakeSampleStream createSampleStream(Allocator allocator, @Nullable MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher, DrmSessionManager drmSessionManager, DrmSessionEventListener.EventDispatcher drmEventDispatcher, Format initialFormat, List<FakeSampleStreamItem> fakeSampleStreamItems) {
return new FakeSampleStream(allocator, mediaSourceEventDispatcher, drmSessionManager, drmEventDispatcher, initialFormat, fakeSampleStreamItems) {
@Override
public void maybeThrowError() throws IOException {
loader.maybeThrowError();
}
};
}
};
}
};
FakeRenderer renderer = new FakeRenderer(C.TRACK_TYPE_VIDEO);
ExoPlayerTestRunner testRunner = new ExoPlayerTestRunner.Builder(context).setMediaSources(largeBufferAllocatingMediaSource).setRenderers(renderer).build();
ExoPlaybackException exception = assertThrows(ExoPlaybackException.class, () -> testRunner.start().blockUntilEnded(TIMEOUT_MS));
assertThat(exception.type).isEqualTo(ExoPlaybackException.TYPE_SOURCE);
assertThat(exception.getSourceException()).isInstanceOf(Loader.UnexpectedLoaderException.class);
assertThat(exception.getSourceException().getCause()).isInstanceOf(OutOfMemoryError.class);
assertThat(renderer.sampleBufferReadCount).isEqualTo(3);
}
use of androidx.media3.exoplayer.upstream.Allocation in project media by androidx.
the class SampleDataQueue method readData.
/**
* Reads data from {@code allocationNode} and its following nodes.
*
* @param allocationNode The first {@link AllocationNode} containing data yet to be read.
* @param absolutePosition The absolute position from which data should be read.
* @param target The buffer into which data should be written.
* @param length The number of bytes to read.
* @return The first {@link AllocationNode} that contains unread bytes after this method returns.
*/
private static AllocationNode readData(AllocationNode allocationNode, long absolutePosition, ByteBuffer target, int length) {
allocationNode = getNodeContainingPosition(allocationNode, absolutePosition);
int remaining = length;
while (remaining > 0) {
int toCopy = min(remaining, (int) (allocationNode.endPosition - absolutePosition));
Allocation allocation = allocationNode.allocation;
target.put(allocation.data, allocationNode.translateOffset(absolutePosition), toCopy);
remaining -= toCopy;
absolutePosition += toCopy;
if (absolutePosition == allocationNode.endPosition) {
allocationNode = allocationNode.next;
}
}
return allocationNode;
}
Aggregations